feat(ui): #17 ChatPanel input field + slash commands + reply-to-last-tell
ChatPanel gains an Enter-to-submit input field via the I.1 InputTextSubmit widget. Submitted text routes through ChatInputParser to a SendChatCmd published on ctx.Commands; LiveCommandBus (I.3) handles the wire send + ChatLog echo. Recognised prefixes (ported from holtburger commands.rs): /say msg or no prefix -> Say /t Name msg or /tell -> Tell (first whitespace token = target) /r msg -> Tell (target = LastIncomingTellSender) /g msg -> General /f msg -> Fellowship /a msg -> Allegiance /m msg -> Monarch /p msg -> Patron /v msg -> Vassals /cv msg -> CoVassals /lfg msg -> Lfg /trade msg -> Trade /role msg -> Roleplay /society msg -> Society /olthoi msg -> Olthoi Edge cases: empty / whitespace / cmd-without-message / /r without prior tell -> null (no-op). Unknown /xyz prefix -> Say with literal text (matches holtburger's Talk(command) default arm). ChatVM.LastIncomingTellSender populated only on incoming Tell entries; discriminated by SenderGuid != 0 (OnSelfSent echoes always carry 0). 32 new tests: - ChatInputParserTests: 22 covering every prefix + edge case - ChatVMLastTellSenderTests: 6 covering capture + skip rules - ChatPanelInputTests: 6 using FakePanelRenderer + recording ICommandBus to assert publish behaviour UI.Abstractions.Tests: 60 -> 92. Solution total: 934 green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8e6e5a0b61
commit
f14296c75f
6 changed files with 710 additions and 10 deletions
|
|
@ -0,0 +1,139 @@
|
|||
using AcDream.Core.Chat;
|
||||
using AcDream.UI.Abstractions.Panels.Chat;
|
||||
|
||||
namespace AcDream.UI.Abstractions.Tests.Panels.Chat;
|
||||
|
||||
/// <summary>
|
||||
/// Phase I.4: when the user submits text via the chat input field, the
|
||||
/// panel must publish a <see cref="SendChatCmd"/> to the command bus.
|
||||
/// We exercise the full Render path with the <see cref="FakePanelRenderer"/>
|
||||
/// pre-loading a "submitted" string and a recording bus capturing the
|
||||
/// resulting command.
|
||||
/// </summary>
|
||||
public sealed class ChatPanelInputTests
|
||||
{
|
||||
private sealed class RecordingBus : ICommandBus
|
||||
{
|
||||
public List<object> Published { get; } = new();
|
||||
public void Publish<T>(T command) where T : notnull => Published.Add(command);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Submit_PlainText_PublishesSayCommand()
|
||||
{
|
||||
var log = new ChatLog();
|
||||
var vm = new ChatVM(log);
|
||||
var panel = new ChatPanel(vm);
|
||||
var bus = new RecordingBus();
|
||||
var renderer = new FakePanelRenderer
|
||||
{
|
||||
InputTextSubmitNextSubmitted = "hello world",
|
||||
InputTextSubmitNextBufferAfter = "",
|
||||
};
|
||||
|
||||
panel.Render(new PanelContext(0.016f, bus), renderer);
|
||||
|
||||
var cmd = Assert.Single(bus.Published);
|
||||
var sendCmd = Assert.IsType<SendChatCmd>(cmd);
|
||||
Assert.Equal(ChatChannelKind.Say, sendCmd.Channel);
|
||||
Assert.Null(sendCmd.TargetName);
|
||||
Assert.Equal("hello world", sendCmd.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Submit_TellSlashCommand_PublishesTellCommand()
|
||||
{
|
||||
var log = new ChatLog();
|
||||
var vm = new ChatVM(log);
|
||||
var panel = new ChatPanel(vm);
|
||||
var bus = new RecordingBus();
|
||||
var renderer = new FakePanelRenderer
|
||||
{
|
||||
InputTextSubmitNextSubmitted = "/t Bestie ping",
|
||||
InputTextSubmitNextBufferAfter = "",
|
||||
};
|
||||
|
||||
panel.Render(new PanelContext(0.016f, bus), renderer);
|
||||
|
||||
var sendCmd = Assert.IsType<SendChatCmd>(Assert.Single(bus.Published));
|
||||
Assert.Equal(ChatChannelKind.Tell, sendCmd.Channel);
|
||||
Assert.Equal("Bestie", sendCmd.TargetName);
|
||||
Assert.Equal("ping", sendCmd.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Submit_ReplySlashCommand_UsesLastIncomingTellSender()
|
||||
{
|
||||
var log = new ChatLog();
|
||||
var vm = new ChatVM(log);
|
||||
log.OnTellReceived("Bestie", "ping", senderGuid: 0x5000_00AAu);
|
||||
|
||||
var panel = new ChatPanel(vm);
|
||||
var bus = new RecordingBus();
|
||||
var renderer = new FakePanelRenderer
|
||||
{
|
||||
InputTextSubmitNextSubmitted = "/r back at you",
|
||||
InputTextSubmitNextBufferAfter = "",
|
||||
};
|
||||
|
||||
panel.Render(new PanelContext(0.016f, bus), renderer);
|
||||
|
||||
var sendCmd = Assert.IsType<SendChatCmd>(Assert.Single(bus.Published));
|
||||
Assert.Equal(ChatChannelKind.Tell, sendCmd.Channel);
|
||||
Assert.Equal("Bestie", sendCmd.TargetName);
|
||||
Assert.Equal("back at you", sendCmd.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Submit_EmptyOrWhitespace_PublishesNothing()
|
||||
{
|
||||
var log = new ChatLog();
|
||||
var vm = new ChatVM(log);
|
||||
var panel = new ChatPanel(vm);
|
||||
var bus = new RecordingBus();
|
||||
var renderer = new FakePanelRenderer
|
||||
{
|
||||
InputTextSubmitNextSubmitted = " ",
|
||||
InputTextSubmitNextBufferAfter = "",
|
||||
};
|
||||
|
||||
panel.Render(new PanelContext(0.016f, bus), renderer);
|
||||
|
||||
Assert.Empty(bus.Published);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NoSubmit_PublishesNothing()
|
||||
{
|
||||
// Most frames: user is typing or idle; submitted == null.
|
||||
var log = new ChatLog();
|
||||
var vm = new ChatVM(log);
|
||||
var panel = new ChatPanel(vm);
|
||||
var bus = new RecordingBus();
|
||||
var renderer = new FakePanelRenderer
|
||||
{
|
||||
InputTextSubmitNextSubmitted = null,
|
||||
};
|
||||
|
||||
panel.Render(new PanelContext(0.016f, bus), renderer);
|
||||
|
||||
Assert.Empty(bus.Published);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_AlwaysCallsInputTextSubmit_ToShowTheField()
|
||||
{
|
||||
var log = new ChatLog();
|
||||
var vm = new ChatVM(log);
|
||||
var panel = new ChatPanel(vm);
|
||||
var bus = new RecordingBus();
|
||||
var renderer = new FakePanelRenderer
|
||||
{
|
||||
InputTextSubmitNextSubmitted = null,
|
||||
};
|
||||
|
||||
panel.Render(new PanelContext(0.016f, bus), renderer);
|
||||
|
||||
Assert.Contains(renderer.Calls, c => c.Method == "InputTextSubmit");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue