feat(input-bar): wire slash-command callback + AllCommands (J2)
J2 closes the trigger-gap discovered in J review (2026-05-27): J migrated CommandHelpWindow as a window but the v1.5.6 trigger-path was never ported. J2 restores it: - InputBar.cs adds ImGuiInputTextFlags.CallbackEdit + character-level callback that reads data.BufTextSpan, detects /-prefix, extracts command word, and calls _commandHelpWindow.Value.UpdateContent(desc) - AllCommands.cs (new file, 1:1 port from v1.5.6) populates a static Dictionary<string, TextCommand> from Sheets.TextCommandSheet at startup; Plugin.CommandManager.Commands is the fallback for non-hardcoded commands - CommandHelpWindow injected into InputBar via Lazy<T> ctor param to break the InputBar <-> CommandHelpWindow circular dep; PluginHostFactory DI-reg extended with the Lazy wrapper accordingly Closes the smoke-step-9 gap. Phase-3 windows are now all reachable end-to-end (R1 InputPreview, R2 CommandHelpWindow, R3 DebuggerWindow).
This commit is contained in:
@@ -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<string, TextCommand> Commands = BuildCommands();
|
||||||
|
|
||||||
|
private static Dictionary<string, TextCommand> BuildCommands()
|
||||||
|
{
|
||||||
|
var dict = new Dictionary<string, TextCommand>(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);
|
||||||
|
}
|
||||||
@@ -142,7 +142,8 @@ internal static class PluginHostFactory
|
|||||||
sp.GetRequiredService<ThemeRegistry>(),
|
sp.GetRequiredService<ThemeRegistry>(),
|
||||||
sp.GetRequiredService<Ui.StyleEngine.TokenResolver>(),
|
sp.GetRequiredService<Ui.StyleEngine.TokenResolver>(),
|
||||||
sp.GetRequiredService<ILogger<Ui.Components.InputBar>>(),
|
sp.GetRequiredService<ILogger<Ui.Components.InputBar>>(),
|
||||||
() => sp.GetRequiredService<Plugin>().SettingsWindow.Toggle()
|
() => sp.GetRequiredService<Plugin>().SettingsWindow.Toggle(),
|
||||||
|
new Lazy<Ui.CommandHelpWindow>(() => sp.GetRequiredService<Ui.CommandHelpWindow>())
|
||||||
));
|
));
|
||||||
services.AddSingleton(sp => new Ui.Components.Settings.TabSidebar(
|
services.AddSingleton(sp => new Ui.Components.Settings.TabSidebar(
|
||||||
sp.GetRequiredService<FontManager>()
|
sp.GetRequiredService<FontManager>()
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
using System.Text;
|
||||||
using Dalamud.Bindings.ImGui;
|
using Dalamud.Bindings.ImGui;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using Dalamud.Interface.Utility.Raii;
|
using Dalamud.Interface.Utility.Raii;
|
||||||
using HellionChat.Code;
|
using HellionChat.Code;
|
||||||
using HellionChat.GameFunctions;
|
using HellionChat.GameFunctions;
|
||||||
using HellionChat.Themes;
|
using HellionChat.Themes;
|
||||||
|
using HellionChat.Ui;
|
||||||
using HellionChat.Ui.StyleEngine;
|
using HellionChat.Ui.StyleEngine;
|
||||||
using HellionChat.Util;
|
using HellionChat.Util;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
@@ -31,6 +33,7 @@ internal sealed class InputBar
|
|||||||
private readonly TokenResolver _resolver;
|
private readonly TokenResolver _resolver;
|
||||||
private readonly ILogger<InputBar> _logger;
|
private readonly ILogger<InputBar> _logger;
|
||||||
private readonly Action _onOpenSettings;
|
private readonly Action _onOpenSettings;
|
||||||
|
private readonly Lazy<CommandHelpWindow> _commandHelpWindow;
|
||||||
|
|
||||||
private string _pendingMessage = string.Empty;
|
private string _pendingMessage = string.Empty;
|
||||||
private bool _isFocused;
|
private bool _isFocused;
|
||||||
@@ -45,7 +48,8 @@ internal sealed class InputBar
|
|||||||
ThemeRegistry themes,
|
ThemeRegistry themes,
|
||||||
TokenResolver resolver,
|
TokenResolver resolver,
|
||||||
ILogger<InputBar> logger,
|
ILogger<InputBar> logger,
|
||||||
Action onOpenSettings
|
Action onOpenSettings,
|
||||||
|
Lazy<CommandHelpWindow> commandHelpWindow
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
_symbolPicker = symbolPicker;
|
_symbolPicker = symbolPicker;
|
||||||
@@ -54,6 +58,7 @@ internal sealed class InputBar
|
|||||||
_resolver = resolver;
|
_resolver = resolver;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_onOpenSettings = onOpenSettings;
|
_onOpenSettings = onOpenSettings;
|
||||||
|
_commandHelpWindow = commandHelpWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string PendingMessage => _pendingMessage;
|
public string PendingMessage => _pendingMessage;
|
||||||
@@ -221,15 +226,42 @@ internal sealed class InputBar
|
|||||||
"##hellion-input",
|
"##hellion-input",
|
||||||
ref _pendingMessage,
|
ref _pendingMessage,
|
||||||
BufferCapacity,
|
BufferCapacity,
|
||||||
ImGuiInputTextFlags.EnterReturnsTrue
|
ImGuiInputTextFlags.EnterReturnsTrue | ImGuiInputTextFlags.CallbackEdit,
|
||||||
|
SlashCommandCallback
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
_commandHelpWindow.Value.IsOpen = false;
|
||||||
TrySend(activeTab);
|
TrySend(activeTab);
|
||||||
}
|
}
|
||||||
_isFocused = ImGui.IsItemFocused();
|
_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)
|
private void TrySend(Tab? activeTab)
|
||||||
{
|
{
|
||||||
var text = _pendingMessage.Trim();
|
var text = _pendingMessage.Trim();
|
||||||
|
|||||||
Reference in New Issue
Block a user