diff --git a/src/EchoHub.Client/Commands/CommandHandler.cs b/src/EchoHub.Client/Commands/CommandHandler.cs index c33d4d5..19df340 100644 --- a/src/EchoHub.Client/Commands/CommandHandler.cs +++ b/src/EchoHub.Client/Commands/CommandHandler.cs @@ -136,20 +136,8 @@ public class CommandHandler if (string.IsNullOrWhiteSpace(args)) return new CommandResult(true, "Usage: /send [-s|-m|-l]", IsError: true); - // Parse optional size flag (-s, -m, -l) - string? size = null; - var parts = args.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); - var targetParts = new List(); - - foreach (var part in parts) - { - if (part is "-s" or "-m" or "-l") - size = part[1..]; // "s", "m", or "l" - else - targetParts.Add(part); - } - - var target = string.Join(' ', targetParts).Trim('"'); + // Extract optional size flag from end or start, respecting quoted paths + var (target, size) = ParsePathAndSizeFlag(args); if (string.IsNullOrWhiteSpace(target)) return new CommandResult(true, "Usage: /send [-s|-m|-l]", IsError: true); @@ -186,7 +174,7 @@ public class CommandHandler if (string.IsNullOrWhiteSpace(args)) return new CommandResult(true, "Usage: /avatar ", IsError: true); - var target = args.Trim().Trim('"'); + var target = StripQuotes(args.Trim()); if (OnSetAvatar is not null) await OnSetAvatar(target); @@ -362,6 +350,51 @@ public class CommandHandler """); } + /// + /// Extract a file path (possibly quoted) and an optional size flag (-s, -m, -l). + /// The flag can appear before or after the path. + /// + private static (string Path, string? Size) ParsePathAndSizeFlag(string args) + { + var trimmed = args.Trim(); + string? size = null; + + // Check for flag at the end: "path" -m or path -m + if (trimmed.Length > 3) + { + var suffix = trimmed[^2..]; + if (suffix is "-s" or "-m" or "-l" && trimmed[^3] == ' ') + { + size = suffix[1..]; + trimmed = trimmed[..^3].TrimEnd(); + } + } + + // Check for flag at the start: -m "path" or -m path + if (size is null && trimmed.Length > 3) + { + var prefix = trimmed[..2]; + if (prefix is "-s" or "-m" or "-l" && trimmed[2] == ' ') + { + size = prefix[1..]; + trimmed = trimmed[3..].TrimStart(); + } + } + + return (StripQuotes(trimmed), size); + } + + /// + /// Remove matching surrounding quotes (double or single) from a string. + /// + private static string StripQuotes(string s) + { + if (s.Length >= 2 && + ((s[0] == '"' && s[^1] == '"') || (s[0] == '\'' && s[^1] == '\''))) + return s[1..^1]; + return s; + } + private static bool IsValidHex(string s) => s.All(c => char.IsAsciiHexDigit(c)); } diff --git a/src/EchoHub.Client/UI/ProfileViewDialog.cs b/src/EchoHub.Client/UI/ProfileViewDialog.cs index 096c315..8e14631 100644 --- a/src/EchoHub.Client/UI/ProfileViewDialog.cs +++ b/src/EchoHub.Client/UI/ProfileViewDialog.cs @@ -140,12 +140,20 @@ public sealed class ProfileViewDialog dialog.Add(bioView); row += 3; - // ASCII Avatar + // ASCII Avatar — render with color tags if (!string.IsNullOrWhiteSpace(profile.AvatarAscii)) { row++; - var avatarLines = profile.AvatarAscii.Split('\n').Length; - var avatarHeight = Math.Min(avatarLines + 2, 6); + var rawLines = profile.AvatarAscii.Split('\n'); + var avatarSource = new ChatListSource(); + foreach (var line in rawLines) + { + avatarSource.Add(ChatLine.HasColorTags(line) + ? ChatLine.FromColoredText(line) + : new ChatLine(line)); + } + + var avatarHeight = Math.Min(rawLines.Length + 2, 24); var avatarFrame = new FrameView { Title = "Avatar", @@ -154,9 +162,22 @@ public sealed class ProfileViewDialog Width = Dim.Fill(2), Height = avatarHeight }; - avatarFrame.Add(new Label { Text = profile.AvatarAscii, X = 0, Y = 0 }); + var avatarList = new ListView + { + X = 0, + Y = 0, + Width = Dim.Fill(), + Height = Dim.Fill(), + Source = avatarSource + }; + avatarFrame.Add(avatarList); dialog.Add(avatarFrame); - // Grow dialog to fit avatar + + // Grow dialog to fit avatar + widen for art + var artWidth = rawLines.Max(l => ChatLine.HasColorTags(l) + ? ChatLine.FromColoredText(l).TextLength + : l.Length); + dialog.Width = Math.Max(50, artWidth + 6); dialog.Height = row + avatarHeight + 4; }