feat(messages): render sender names through the name-aware path

This commit is contained in:
2026-05-31 00:31:48 +02:00
parent 8fcb10cf51
commit 83b1708d5d
4 changed files with 141 additions and 8 deletions
+26 -1
View File
@@ -38,6 +38,13 @@ internal sealed class ChunkRenderer
_ = _logger;
}
// B2-1/B2-2 render-observability: the formatted sender text the real draw
// path actually produced (post-ForDisplay). A SelfTest reads this after
// driving DrawChunks to prove the WorldSuffixMode/NameFormMode reformat
// reached the real render entry — never the helper in isolation. null until
// a sender span is reformatted for display.
internal string? LastRenderedSenderText { get; private set; }
public void DrawChunks(
IReadOnlyList<Chunk> chunks,
bool wrap = true,
@@ -51,7 +58,25 @@ internal sealed class ChunkRenderer
// the list unchanged when nothing applies, so non-sender lists and the
// neutral default cost only a quick scan.
if (!Plugin.Config.ScreenshotMode)
chunks = SenderNameDisplay.ForDisplay(chunks);
{
var displayed = SenderNameDisplay.ForDisplay(chunks);
// ForDisplay only allocates a NEW list when it actually reformatted
// a sender span (same reference on the neutral default / non-sender
// lists). So this scan runs only when a sender name was reformatted
// for display — zero overhead on the neutral-default hot path.
if (!ReferenceEquals(displayed, chunks))
{
chunks = displayed;
foreach (var c in chunks)
{
if (c.Source == ChunkSource.Sender && c is TextChunk reformatted)
{
LastRenderedSenderText = reformatted.Content;
break;
}
}
}
}
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero);
+33 -7
View File
@@ -88,12 +88,25 @@ internal sealed class MessageList
private void DrawCompactRow(Message message)
{
// B2-1/B2-2: render the sender through DrawChunks (the name-aware path
// that applies WorldSuffixMode/NameFormMode via ForDisplay), not as a
// flat SenderSource.TextValue string. message.Sender already carries the
// channel brackets/colon as ChunkSource.None wrappers (MessageManager
// .cs:300-314), so the separator is rendered by the chunks. 1.5.6 parity
// (ChatLogWindow.cs:1965: DrawChunks(message.Sender) + SameLine).
var timestamp = FormatTimestamp(message.Date);
var sender = message.SenderSource.TextValue;
ImGui.TextUnformatted(
string.IsNullOrEmpty(sender) ? timestamp : $"{timestamp} {sender}: "
);
ImGui.SameLine(0f, 0f);
if (message.Sender.Count > 0)
{
ImGui.TextUnformatted($"{timestamp} ");
ImGui.SameLine(0f, 0f);
_chunkRenderer.DrawChunks(message.Sender, wrap: true, handler: _handler, lineWidth: 0f);
ImGui.SameLine(0f, 0f);
}
else
{
ImGui.TextUnformatted(timestamp);
ImGui.SameLine(0f, 0f);
}
_chunkRenderer.DrawChunks(message.Content, wrap: true, handler: _handler, lineWidth: 0f);
}
@@ -128,9 +141,22 @@ internal sealed class MessageList
private void DrawCardRow(Message message)
{
// B2-1/B2-2: sender via DrawChunks (name-aware path), on its own line
// with content below — 1.5.6 card parity (ChatLogWindow.cs:1913, no
// SameLine after the sender). The 1.5.6 channel-colour push on the
// sender is deferred styling polish (masterplan §6 -> v1.9.0); plain
// text here.
var timestamp = FormatTimestamp(message.Date);
var sender = message.SenderSource.TextValue;
ImGui.TextUnformatted(string.IsNullOrEmpty(sender) ? timestamp : $"{timestamp} {sender}");
if (message.Sender.Count > 0)
{
ImGui.TextUnformatted($"{timestamp} ");
ImGui.SameLine(0f, 0f);
_chunkRenderer.DrawChunks(message.Sender, wrap: true, handler: _handler, lineWidth: 0f);
}
else
{
ImGui.TextUnformatted(timestamp);
}
_chunkRenderer.DrawChunks(message.Content, wrap: true, handler: _handler, lineWidth: 0f);
}