diff --git a/HellionChat/Configuration.cs b/HellionChat/Configuration.cs index 0f9c8f4..2777af9 100755 --- a/HellionChat/Configuration.cs +++ b/HellionChat/Configuration.cs @@ -1,13 +1,11 @@ using System.Collections; using System.Linq; -using System.Text.RegularExpressions; using Dalamud; using Dalamud.Bindings.ImGui; using Dalamud.Configuration; using Dalamud.Game.ClientState.Keys; using Dalamud.Game.Text.SeStringHandling.Payloads; using Dalamud.Interface.FontIdentifier; -using HellionChat._Helpers; using HellionChat.Code; using HellionChat.GameFunctions.Types; using HellionChat.Resources; @@ -473,10 +471,6 @@ public class Tab public bool EnableNotificationSound; public uint NotificationSoundId = 1; - // UI-8: optional regex applied on top of the channel filter. Null or - // empty means no filter, today's behaviour unchanged. - public string? MessageRegex; - [NonSerialized] public uint Unread; @@ -530,32 +524,11 @@ public class Tab [NonSerialized] internal float _cardHoverAlpha; - // UI-8: compiled-regex cache. Recompiled only when MessageRegex changes; - // _compiledRegexKey is the validation key (mirrors the _cachedTint* keys). - [NonSerialized] - private Regex? _compiledRegex; - - [NonSerialized] - private string? _compiledRegexKey; - public bool Matches(Message message) { if (!message.Matches(SelectedChannels, ExtraChatAll, ExtraChatChannels)) return false; - // UI-8: optional regex content filter, AND-constraint after the channel - // check. An empty pattern or an invalid one (cached regex is null) lets - // every message through, so existing tabs behave unchanged. - if (!string.IsNullOrEmpty(MessageRegex)) - { - var text = string.Join( - "", - message.Content.OfType().Select(c => c.Content) - ); - if (!RegexRouteMatcher.IsMatch(GetCompiledRegex(), text)) - return false; - } - // Temp tabs are bound to a single conversation partner — other tells // matching the channel filter must not land here. if (IsTempTab && TellTarget?.IsSet() == true) @@ -564,20 +537,6 @@ public class Tab return true; } - // UI-8: lazily compiles MessageRegex and caches the result. Recompiles only - // when the pattern string changed (validation-key pattern, same idea as the - // _cachedTint* caches). An invalid pattern caches a null regex. - private Regex? GetCompiledRegex() - { - if (_compiledRegexKey != MessageRegex) - { - (_compiledRegex, _) = RegexRouteMatcher.Compile(MessageRegex); - _compiledRegexKey = MessageRegex; - } - - return _compiledRegex; - } - public void AddMessage(Message message, bool unread = true) { Messages.AddPrune(message, MessageManager.MessageDisplayLimit); @@ -632,7 +591,6 @@ public class Tab TellTarget = TellTarget.Clone(), EnableNotificationSound = EnableNotificationSound, NotificationSoundId = NotificationSoundId, - MessageRegex = MessageRegex, IsGreeted = IsGreeted, }; } diff --git a/HellionChat/Plugin.cs b/HellionChat/Plugin.cs index 2699afc..318f7a5 100755 --- a/HellionChat/Plugin.cs +++ b/HellionChat/Plugin.cs @@ -201,10 +201,10 @@ public sealed class Plugin : IAsyncDalamudPlugin // Schema gate: v1.4.x+ requires config v16+. Users on older schemas // must install v1.4.2 first to run the migration chain. v19 adds the - // per-tab MessageRegex field (UI-8) and the top-level CustomSoundVolume, - // WindowOpacityInactive, WorldSuffixMode and NameFormMode fields — all - // additive with defaults, so v16-v18 configs load cleanly and get their - // Version stamp bumped after the gate. + // top-level CustomSoundVolume, WindowOpacityInactive, WorldSuffixMode + // and NameFormMode fields — all additive with defaults, so v16-v18 + // configs load cleanly and get their Version stamp bumped after the + // gate. if (Config.Version < 16) { throw new InvalidOperationException( diff --git a/HellionChat/Resources/HellionStrings.Designer.cs b/HellionChat/Resources/HellionStrings.Designer.cs index b90d755..4f16eb2 100644 --- a/HellionChat/Resources/HellionStrings.Designer.cs +++ b/HellionChat/Resources/HellionStrings.Designer.cs @@ -470,11 +470,6 @@ internal class HellionStrings internal static string ChatLog_Insert_MapFlag => Get(nameof(ChatLog_Insert_MapFlag)); internal static string ChatLog_Insert_ItemLink => Get(nameof(ChatLog_Insert_ItemLink)); - // v1.5.6: per-tab regex filter - internal static string Settings_Tabs_MessageRegex_Name => Get(nameof(Settings_Tabs_MessageRegex_Name)); - internal static string Settings_Tabs_MessageRegex_Description => Get(nameof(Settings_Tabs_MessageRegex_Description)); - internal static string Settings_Tabs_MessageRegex_Invalid => Get(nameof(Settings_Tabs_MessageRegex_Invalid)); - // v1.5.6: plugin-disclosure warning internal static string Settings_Chat_NotifyPluginDisclosure_Name => Get(nameof(Settings_Chat_NotifyPluginDisclosure_Name)); internal static string Settings_Chat_NotifyPluginDisclosure_Description => Get(nameof(Settings_Chat_NotifyPluginDisclosure_Description)); diff --git a/HellionChat/Resources/HellionStrings.resx b/HellionChat/Resources/HellionStrings.resx index 1c90b1c..061432e 100644 --- a/HellionChat/Resources/HellionStrings.resx +++ b/HellionChat/Resources/HellionStrings.resx @@ -1091,17 +1091,6 @@ Insert linked item <item> - - - Message filter (regex) - - - Only keep messages whose text matches this regular expression. Applied on top of the channel filter. Leave empty to disable. Matching is case-insensitive. - - - Invalid pattern: {0} - - Warn before sending plugin-only symbols diff --git a/HellionChat/Ui/SettingsTabs/Tabs.cs b/HellionChat/Ui/SettingsTabs/Tabs.cs index 08816c9..865c5a6 100755 --- a/HellionChat/Ui/SettingsTabs/Tabs.cs +++ b/HellionChat/Ui/SettingsTabs/Tabs.cs @@ -1,10 +1,8 @@ using Dalamud.Bindings.ImGui; using Dalamud.Game.ClientState.Objects.SubKinds; using Dalamud.Interface; -using Dalamud.Interface.Colors; using Dalamud.Interface.Utility.Raii; using FFXIVClientStructs.FFXIV.Client.UI; -using HellionChat._Helpers; using HellionChat.Code; using HellionChat.Resources; using HellionChat.Util; @@ -240,25 +238,6 @@ internal sealed class Tabs : ISettingsTab } } } - // UI-8: optional regex filter for this tab. - var regexBuffer = tab.MessageRegex ?? string.Empty; - if (ImGui.InputText($"{HellionStrings.Settings_Tabs_MessageRegex_Name}##regex-{i}", ref regexBuffer, 256)) - tab.MessageRegex = string.IsNullOrEmpty(regexBuffer) ? null : regexBuffer; - ImGuiUtil.HelpMarker(HellionStrings.Settings_Tabs_MessageRegex_Description); - - // Validity feedback: the settings window is not a hot path, so a - // per-frame Compile is fine. An invalid pattern shows a red line and - // the tab behaves as if no regex were set. - if (!string.IsNullOrEmpty(tab.MessageRegex)) - { - var (_, regexError) = RegexRouteMatcher.Compile(tab.MessageRegex); - if (regexError is not null) - ImGui.TextColored( - ImGuiColors.DalamudRed, - string.Format(HellionStrings.Settings_Tabs_MessageRegex_Invalid, regexError) - ); - } - ImGui.Checkbox(Language.Options_Tabs_PopOut, ref tab.PopOut); if (tab.PopOut) { diff --git a/HellionChat/_Helpers/RegexRouteMatcher.cs b/HellionChat/_Helpers/RegexRouteMatcher.cs deleted file mode 100644 index 1555793..0000000 --- a/HellionChat/_Helpers/RegexRouteMatcher.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using System.Text.RegularExpressions; - -namespace HellionChat._Helpers; - -// UI-8 pure decision helper for the optional per-tab regex filter. Compiling a -// user pattern can throw (invalid syntax) and matching a pathological pattern -// can hang (catastrophic backtracking), so both are contained here. Kept free -// of Dalamud types so the Build Suite can test compile/match/timeout in -// isolation. -// TEST-MIRROR: ../../../Hellion Build test/Ui/RegexRouteMatcherTests.cs -public static class RegexRouteMatcher -{ - // A match must never block the message-routing hot path. 100ms is far - // beyond any sane pattern yet short enough that a runaway pattern fails - // fast instead of freezing the chat. - public static readonly TimeSpan MatchTimeout = TimeSpan.FromMilliseconds(100); - - // Compiles a user pattern. Null/empty pattern -> (null, null): "no filter". - // Invalid pattern -> (null, errorMessage): the tab then behaves as if no - // regex were set (see IsMatch). - public static (Regex? Regex, string? Error) Compile(string? pattern) - { - if (string.IsNullOrEmpty(pattern)) - return (null, null); - - try - { - var regex = new Regex(pattern, RegexOptions.IgnoreCase, MatchTimeout); - return (regex, null); - } - catch (ArgumentException ex) - { - return (null, ex.Message); - } - } - - // Runs the filter. A null regex (no filter, or an invalid pattern) returns - // true so nothing is filtered out. A timeout on a pathological pattern is - // treated as "no match" rather than a crash. - public static bool IsMatch(Regex? regex, string text) - { - if (regex is null) - return true; - - try - { - return regex.IsMatch(text); - } - catch (RegexMatchTimeoutException) - { - return false; - } - } -}