feat: add @mention highlighting in chat lines with new SplitMentions method

This commit is contained in:
HueByte
2026-02-19 18:59:12 +01:00
parent d9a66749e7
commit 246eb2b0bb
2 changed files with 47 additions and 3 deletions
+30 -1
View File
@@ -453,11 +453,40 @@ public class UserListSource : IListDataSource
/// <summary> /// <summary>
/// Shared color attributes for chat rendering (timestamps, system messages). /// Shared color attributes for chat rendering (timestamps, system messages).
/// </summary> /// </summary>
public static class ChatColors public static partial class ChatColors
{ {
public static readonly Attribute TimestampAttr = new(Color.DarkGray, Color.Black); public static readonly Attribute TimestampAttr = new(Color.DarkGray, Color.Black);
public static readonly Attribute SystemAttr = new(new Color(0, 180, 180), Color.Black); public static readonly Attribute SystemAttr = new(new Color(0, 180, 180), Color.Black);
public static readonly Attribute MentionHighlightAttr = new(Color.White, new Color(80, 40, 0)); public static readonly Attribute MentionHighlightAttr = new(Color.White, new Color(80, 40, 0));
public static readonly Attribute MentionTextAttr = new(new Color(255, 180, 50), Color.Black);
/// <summary>
/// Split text around @mentions, giving each @word the MentionTextAttr accent color.
/// Non-mention text uses the provided default color.
/// </summary>
public static List<ChatSegment> SplitMentions(string text, Attribute? defaultColor = null)
{
var segments = new List<ChatSegment>();
int lastIndex = 0;
foreach (Match match in MentionRegex().Matches(text))
{
if (match.Index > lastIndex)
segments.Add(new ChatSegment(text[lastIndex..match.Index], defaultColor));
segments.Add(new ChatSegment(match.Value, MentionTextAttr));
lastIndex = match.Index + match.Length;
}
if (lastIndex < text.Length)
segments.Add(new ChatSegment(text[lastIndex..], defaultColor));
return segments;
}
// Matches @username (letters, digits, underscores, hyphens — same as channel name chars)
[GeneratedRegex(@"@[\w-]+")]
private static partial Regex MentionRegex();
} }
/// <summary> /// <summary>
+17 -2
View File
@@ -872,12 +872,13 @@ public sealed class MainWindow : Runnable
default: default:
var contentLines = message.Content.Split('\n'); var contentLines = message.Content.Split('\n');
var firstLine = contentLines[0].TrimEnd('\r'); var firstLine = contentLines[0].TrimEnd('\r');
lines.Add(BuildChatLine(time, senderName, senderColor, $" {firstLine}")); lines.Add(BuildChatLineWithMentions(time, senderName, senderColor, $" {firstLine}"));
// Continuation lines indented to align with first line's content // Continuation lines indented to align with first line's content
var indent = new string(' ', $"[{time}] {senderName} ".Length); var indent = new string(' ', $"[{time}] {senderName} ".Length);
for (int i = 1; i < contentLines.Length; i++) for (int i = 1; i < contentLines.Length; i++)
{ {
lines.Add(new ChatLine($"{indent}{contentLines[i].TrimEnd('\r')}")); var contText = $"{indent}{contentLines[i].TrimEnd('\r')}";
lines.Add(new ChatLine(ChatColors.SplitMentions(contText)));
} }
break; break;
} }
@@ -913,4 +914,18 @@ public sealed class MainWindow : Runnable
}; };
return new ChatLine(segments); return new ChatLine(segments);
} }
/// <summary>
/// Build a chat line with @mention highlighting in the suffix text.
/// </summary>
private static ChatLine BuildChatLineWithMentions(string time, string senderName, Attribute? senderColor, string suffix)
{
var segments = new List<ChatSegment>
{
new($"[{time}] ", ChatColors.TimestampAttr),
new(senderName, senderColor),
};
segments.AddRange(ChatColors.SplitMentions(suffix));
return new ChatLine(segments);
}
} }