mirror of
https://github.com/outbackdingo/optimclaw.git
synced 2026-08-25 14:53:34 +00:00
Fix multiline message rendering in TUI
- Switch from List to Paragraph widget for message display - Split message content by newlines and render each line separately - Auto-scroll to show most recent messages - Add empty line between messages for readability - Wrap long lines properly Co-Authored-By: Claude Opus 4.5 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.5
parent
066df79595
commit
575269546b
+64
-27
@@ -5,7 +5,7 @@ use ratatui::{
|
||||
layout::{Constraint, Direction, Layout, Rect},
|
||||
style::{Color, Modifier, Style},
|
||||
text::{Line, Span, Text},
|
||||
widgets::{Block, Borders, Clear, List, ListItem, Paragraph, Wrap},
|
||||
widgets::{Block, Borders, Clear, Paragraph, Wrap},
|
||||
};
|
||||
|
||||
use crate::channels::cli::app::{AppState, InputMode, MessageRole, MessageStatus};
|
||||
@@ -34,35 +34,72 @@ pub fn render(frame: &mut Frame, app: &AppState) {
|
||||
|
||||
/// Render the message history.
|
||||
fn render_messages(frame: &mut Frame, app: &AppState, area: Rect) {
|
||||
let items: Vec<ListItem> = app
|
||||
.messages
|
||||
.iter()
|
||||
.map(|msg| {
|
||||
let (prefix, style) = match msg.role {
|
||||
MessageRole::User => ("You: ", Style::default().fg(Color::Cyan)),
|
||||
MessageRole::Agent => ("Agent: ", Style::default().fg(Color::Green)),
|
||||
MessageRole::System => (
|
||||
"",
|
||||
Style::default()
|
||||
.fg(Color::DarkGray)
|
||||
.add_modifier(Modifier::ITALIC),
|
||||
),
|
||||
};
|
||||
// Build all lines from all messages
|
||||
let mut lines: Vec<Line> = Vec::new();
|
||||
|
||||
let status_indicator = match msg.status {
|
||||
Some(MessageStatus::Pending) => " ⏳",
|
||||
Some(MessageStatus::InProgress) => " ⚙️",
|
||||
Some(MessageStatus::Complete) => " ✓",
|
||||
Some(MessageStatus::Error) => " ✗",
|
||||
None => "",
|
||||
};
|
||||
for msg in &app.messages {
|
||||
let (prefix, style) = match msg.role {
|
||||
MessageRole::User => ("You: ", Style::default().fg(Color::Cyan)),
|
||||
MessageRole::Agent => ("Agent: ", Style::default().fg(Color::Green)),
|
||||
MessageRole::System => (
|
||||
"",
|
||||
Style::default()
|
||||
.fg(Color::DarkGray)
|
||||
.add_modifier(Modifier::ITALIC),
|
||||
),
|
||||
};
|
||||
|
||||
let content = format!("{}{}{}", prefix, msg.content, status_indicator);
|
||||
ListItem::new(Text::styled(content, style))
|
||||
})
|
||||
.collect();
|
||||
let status_indicator = match msg.status {
|
||||
Some(MessageStatus::Pending) => " ⏳",
|
||||
Some(MessageStatus::InProgress) => " ⚙️",
|
||||
Some(MessageStatus::Complete) => " ✓",
|
||||
Some(MessageStatus::Error) => " ✗",
|
||||
None => "",
|
||||
};
|
||||
|
||||
let messages = List::new(items).block(Block::default().borders(Borders::ALL).title("Chat"));
|
||||
// Split content by newlines and create a line for each
|
||||
let content_lines: Vec<&str> = msg.content.lines().collect();
|
||||
for (i, line_text) in content_lines.iter().enumerate() {
|
||||
if i == 0 {
|
||||
// First line gets the prefix
|
||||
let line_content = if status_indicator.is_empty() {
|
||||
format!("{}{}", prefix, line_text)
|
||||
} else if content_lines.len() == 1 {
|
||||
format!("{}{}{}", prefix, line_text, status_indicator)
|
||||
} else {
|
||||
format!("{}{}", prefix, line_text)
|
||||
};
|
||||
lines.push(Line::styled(line_content, style));
|
||||
} else if i == content_lines.len() - 1 && !status_indicator.is_empty() {
|
||||
// Last line gets status indicator
|
||||
lines.push(Line::styled(
|
||||
format!("{}{}", line_text, status_indicator),
|
||||
style,
|
||||
));
|
||||
} else {
|
||||
// Middle lines just get the content
|
||||
lines.push(Line::styled(line_text.to_string(), style));
|
||||
}
|
||||
}
|
||||
|
||||
// Add empty line between messages for readability
|
||||
lines.push(Line::from(""));
|
||||
}
|
||||
|
||||
// Calculate scroll - show most recent messages
|
||||
let visible_height = area.height.saturating_sub(2) as usize; // Account for borders
|
||||
let total_lines = lines.len();
|
||||
let scroll_offset = if total_lines > visible_height {
|
||||
total_lines - visible_height
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let text = Text::from(lines);
|
||||
let messages = Paragraph::new(text)
|
||||
.block(Block::default().borders(Borders::ALL).title("Chat"))
|
||||
.wrap(Wrap { trim: false })
|
||||
.scroll((scroll_offset as u16, 0));
|
||||
|
||||
frame.render_widget(messages, area);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user