diff --git a/HellionChat/AllCommands.cs b/HellionChat/AllCommands.cs new file mode 100644 index 0000000..30d6d2e --- /dev/null +++ b/HellionChat/AllCommands.cs @@ -0,0 +1,36 @@ +using Lumina.Excel.Sheets; + +namespace HellionChat; + +// Ported 1:1 from v1.5.6 ChatLogWindow.SetUpAllCommands. Provides a fast +// lookup from slash-command string to the game's TextCommand row so the +// InputBar callback can feed descriptions to CommandHelpWindow without +// hitting the sheet on every keystroke. +internal static class AllCommands +{ + private static readonly Dictionary Commands = BuildCommands(); + + private static Dictionary BuildCommands() + { + var dict = new Dictionary(StringComparer.Ordinal); + foreach (var command in Sheets.TextCommandSheet) + { + if (!command.Command.IsEmpty) + dict.TryAdd(command.Command.ToString(), command); + + if (!command.ShortCommand.IsEmpty) + dict.TryAdd(command.ShortCommand.ToString(), command); + + if (!command.Alias.IsEmpty) + dict.TryAdd(command.Alias.ToString(), command); + + if (!command.ShortAlias.IsEmpty) + dict.TryAdd(command.ShortAlias.ToString(), command); + } + + return dict; + } + + public static bool TryGetValue(string command, out TextCommand textCommand) => + Commands.TryGetValue(command, out textCommand); +} diff --git a/HellionChat/PluginHostFactory.cs b/HellionChat/PluginHostFactory.cs index 4c99d0c..f56ffbd 100644 --- a/HellionChat/PluginHostFactory.cs +++ b/HellionChat/PluginHostFactory.cs @@ -142,7 +142,8 @@ internal static class PluginHostFactory sp.GetRequiredService(), sp.GetRequiredService(), sp.GetRequiredService>(), - () => sp.GetRequiredService().SettingsWindow.Toggle() + () => sp.GetRequiredService().SettingsWindow.Toggle(), + new Lazy(() => sp.GetRequiredService()) )); services.AddSingleton(sp => new Ui.Components.Settings.TabSidebar( sp.GetRequiredService() diff --git a/HellionChat/Ui/Components/InputBar.cs b/HellionChat/Ui/Components/InputBar.cs index 95d65ca..f588de5 100644 --- a/HellionChat/Ui/Components/InputBar.cs +++ b/HellionChat/Ui/Components/InputBar.cs @@ -1,10 +1,12 @@ using System.Numerics; +using System.Text; using Dalamud.Bindings.ImGui; using Dalamud.Interface; using Dalamud.Interface.Utility.Raii; using HellionChat.Code; using HellionChat.GameFunctions; using HellionChat.Themes; +using HellionChat.Ui; using HellionChat.Ui.StyleEngine; using HellionChat.Util; using Microsoft.Extensions.Logging; @@ -31,6 +33,7 @@ internal sealed class InputBar private readonly TokenResolver _resolver; private readonly ILogger _logger; private readonly Action _onOpenSettings; + private readonly Lazy _commandHelpWindow; private string _pendingMessage = string.Empty; private bool _isFocused; @@ -45,7 +48,8 @@ internal sealed class InputBar ThemeRegistry themes, TokenResolver resolver, ILogger logger, - Action onOpenSettings + Action onOpenSettings, + Lazy commandHelpWindow ) { _symbolPicker = symbolPicker; @@ -54,6 +58,7 @@ internal sealed class InputBar _resolver = resolver; _logger = logger; _onOpenSettings = onOpenSettings; + _commandHelpWindow = commandHelpWindow; } public string PendingMessage => _pendingMessage; @@ -221,15 +226,42 @@ internal sealed class InputBar "##hellion-input", ref _pendingMessage, BufferCapacity, - ImGuiInputTextFlags.EnterReturnsTrue + ImGuiInputTextFlags.EnterReturnsTrue | ImGuiInputTextFlags.CallbackEdit, + SlashCommandCallback ) ) { + _commandHelpWindow.Value.IsOpen = false; TrySend(activeTab); } _isFocused = ImGui.IsItemFocused(); } + // v1.5.6 character-level slash-detect: fires on every edit so CommandHelpWindow + // stays in sync with what the user is typing without a per-frame poll. + private int SlashCommandCallback(scoped ref ImGuiInputTextCallbackData data) + { + _commandHelpWindow.Value.IsOpen = false; + if (data.BufTextLen == 0) + return 0; + + var text = Encoding.UTF8.GetString(data.BufTextSpan); + if (!text.StartsWith('/')) + return 0; + + var spaceIdx = text.IndexOf(' '); + var command = spaceIdx > 0 ? text[..spaceIdx] : text; + + if (AllCommands.TryGetValue(command, out var textCommand)) + _commandHelpWindow.Value.UpdateContent(textCommand.Description); + else if ( + Plugin.CommandManager.Commands.TryGetValue(command, out var info) && info.ShowInHelp + ) + _commandHelpWindow.Value.UpdateContent(info.HelpMessage); + + return 0; + } + private void TrySend(Tab? activeTab) { var text = _pendingMessage.Trim();