diff --git a/HellionChat/Resources/HellionStrings.Designer.cs b/HellionChat/Resources/HellionStrings.Designer.cs
index 2aaddc8..a9d7037 100644
--- a/HellionChat/Resources/HellionStrings.Designer.cs
+++ b/HellionChat/Resources/HellionStrings.Designer.cs
@@ -402,4 +402,9 @@ internal class HellionStrings
// Hellion Chat — v1.3.0 Honorific title slot tooltip
internal static string ChatHeader_HonorificTitle_Tooltip => Get(nameof(ChatHeader_HonorificTitle_Tooltip));
+
+ // Hellion Chat — v1.4.8 DbViewer full-text search toggle
+ internal static string DbViewer_FullTextToggle => Get(nameof(DbViewer_FullTextToggle));
+ internal static string DbViewer_FullTextToggle_Hint_Indexing => Get(nameof(DbViewer_FullTextToggle_Hint_Indexing));
+ internal static string DbViewer_FullTextToggle_Hint_PhraseMode => Get(nameof(DbViewer_FullTextToggle_Hint_PhraseMode));
}
diff --git a/HellionChat/Resources/HellionStrings.de.resx b/HellionChat/Resources/HellionStrings.de.resx
index e9fc2ff..59542f7 100644
--- a/HellionChat/Resources/HellionStrings.de.resx
+++ b/HellionChat/Resources/HellionStrings.de.resx
@@ -917,4 +917,13 @@
Custom-Titel von Honorific
+
+ Volltext-Suche
+
+
+ Der Volltext-Index wird noch gebaut. Die lokale Suche bleibt verfügbar.
+
+
+ Sucht nach der exakten Wortfolge. Mehrere Wörter werden nur gefunden, wenn sie zusammen und in dieser Reihenfolge stehen. Wer rohe FTS5-MATCH-Syntax nutzen will, setzt eigene Anführungszeichen um den Suchbegriff.
+
diff --git a/HellionChat/Resources/HellionStrings.resx b/HellionChat/Resources/HellionStrings.resx
index 8940f46..f0a13b0 100644
--- a/HellionChat/Resources/HellionStrings.resx
+++ b/HellionChat/Resources/HellionStrings.resx
@@ -917,4 +917,13 @@
Custom title from Honorific
+
+ Full-text search
+
+
+ The full-text index is still being built. The local filter remains available.
+
+
+ Searches for the exact phrase. Multi-word queries match only when the words appear together in order. To use raw FTS5 MATCH syntax, wrap your term in double quotes yourself.
+
diff --git a/HellionChat/Ui/DbViewer.cs b/HellionChat/Ui/DbViewer.cs
index 1326a29..6773fba 100644
--- a/HellionChat/Ui/DbViewer.cs
+++ b/HellionChat/Ui/DbViewer.cs
@@ -33,6 +33,12 @@ public class DbViewer : Window
private int CurrentPage = 1;
private string SimpleSearchTerm = "";
+
+ // v1.4.8 H2: opt-in full-text search across the whole DB via FTS5.
+ // Transient UI state (per-session), not persisted -- users opt in fresh
+ // every time so they always see the page-filter as the default mode.
+ private bool UseFullTextSearch;
+
private bool OnlyCurrentCharacter = true;
private readonly Dictionary SelectedChannels;
@@ -233,6 +239,24 @@ public class DbViewer : Window
tooltipRight: Language.Page_ArrowRight_Tooltip
);
+ // Full-text search toggle (v1.4.8 H2). IsFtsIndexBuilt is a cached
+ // volatile bool in MessageStore -- single field read per frame, no
+ // SELECT count(*). ImRaii.Disabled blocks any click while the index
+ // is still being built, so no defensive force-off branch needed
+ // inside the if-body. UseFullTextSearch is transient UI state, so we
+ // do not call SaveConfig here.
+ var ftsReady = Plugin.MessageManager.Store.IsFtsIndexBuilt;
+ using (ImRaii.Disabled(!ftsReady))
+ {
+ if (ImGui.Checkbox(HellionStrings.DbViewer_FullTextToggle, ref UseFullTextSearch))
+ Filtered = Filter(Messages);
+ }
+ ImGuiUtil.HelpMarker(
+ ftsReady
+ ? HellionStrings.DbViewer_FullTextToggle_Hint_PhraseMode
+ : HellionStrings.DbViewer_FullTextToggle_Hint_Indexing
+ );
+
ImGui.SameLine(ImGui.GetContentRegionMax().X - width);
ImGui.SetNextItemWidth(width);
if (
@@ -452,6 +476,20 @@ public class DbViewer : Window
if (SimpleSearchTerm == "")
return new ConcurrentStack(messages.Reverse().OrderByDescending(m => m.Date));
+ // Full-text mode bypasses the page-bounded messages array and queries
+ // the FTS5 index across the whole DB. IsFtsIndexBuilt re-check guards
+ // against the (rare) case of the toggle being on while the index is
+ // mid-rebuild -- ImRaii.Disabled prevents the user from flipping it,
+ // but a Dispose-and-reopen during indexing could leave UseFullTextSearch
+ // true while ftsReady flipped back to false; the local fallback below
+ // still serves the page.
+ if (UseFullTextSearch && Plugin.MessageManager.Store.IsFtsIndexBuilt)
+ {
+ var hexIds = Plugin.MessageManager.Store.FullTextSearch(SimpleSearchTerm);
+ var resolved = Plugin.MessageManager.Store.LoadByGuids(hexIds);
+ return new ConcurrentStack(resolved.OrderByDescending(m => m.Date));
+ }
+
return new ConcurrentStack(
messages
.Reverse()