Add Banner role for colorized banner art rendering
Seto Elkahfi committed
Apr 14, 2026 at 18:42 UTC
c385aa96ddccc2d7deafeb398085a2c8091dfb59
1 file changed
+27
-3
src/chat.rs
+27
-3
index 79ecbf9..c85a611 100644
--- a/src/chat.rs
+++ b/src/chat.rs
@@ -25,6 +25,8 @@ enum Role {
User,
Assistant,
System,
+ /// Banner art — rendered with per-character digit colorization.
+ Banner,
}
struct ChatMessage {
@@ -53,6 +55,13 @@ impl ChatMessage {
text: text.into(),
}
}
+
+ fn banner(text: impl Into<String>) -> Self {
+ Self {
+ role: Role::Banner,
+ text: text.into(),
+ }
+ }
}
// ── App state ────────────────────────────────────────────────────────────────
@@ -89,7 +98,7 @@ impl App {
fn new() -> Self {
let mut messages = Vec::new();
for line in BANNER_ART.lines() {
- messages.push(ChatMessage::system(line));
+ messages.push(ChatMessage::banner(line));
}
messages.push(ChatMessage::system(""));
messages.push(ChatMessage::system(format!(
@@ -161,12 +170,16 @@ impl App {
}
}
+fn banner_char_color(_ch: char) -> Color {
+ Color::White
+}
+
/// Estimate how many terminal rows a message takes once wrapped.
fn wrapped_line_count(text: &str, role: Role, width: usize) -> u16 {
let prefix_len = match role {
Role::User => 6, // "you > "
- Role::Assistant => 7, // "siGit > " — wait, that's 8. Let's just use 7 for "siGit> "
- Role::System => 0,
+ Role::Assistant => 8, // "siGit > "
+ Role::System | Role::Banner => 0,
};
let effective = if width > prefix_len {
width - prefix_len
@@ -343,6 +356,17 @@ fn render_chat_message<'a>(lines: &mut Vec<Line<'a>>, msg: &ChatMessage) {
)));
}
}
+ Role::Banner => {
+ for segment in &text_lines {
+ let spans: Vec<Span<'_>> = segment
+ .chars()
+ .map(|ch| {
+ Span::styled(ch.to_string(), Style::default().fg(banner_char_color(ch)))
+ })
+ .collect();
+ lines.push(Line::from(spans));
+ }
+ }
}
}