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<Ui.StyleEngine.TokenResolver>(),
|
||||
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(
|
||||
sp.GetRequiredService<FontManager>()
|
||||
|
||||
@@ -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<InputBar> _logger;
|
||||
private readonly Action _onOpenSettings;
|
||||
private readonly Lazy<CommandHelpWindow> _commandHelpWindow;
|
||||
|
||||
private string _pendingMessage = string.Empty;
|
||||
private bool _isFocused;
|
||||
@@ -45,7 +48,8 @@ internal sealed class InputBar
|
||||
ThemeRegistry themes,
|
||||
TokenResolver resolver,
|
||||
ILogger<InputBar> logger,
|
||||
Action onOpenSettings
|
||||
Action onOpenSettings,
|
||||
Lazy<CommandHelpWindow> 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();
|
||||
|
||||
Reference in New Issue
Block a user