feat(tui): make system/status output height dynamic and refactor rendering

- Introduce `system_status_message` helper to determine the message shown in the system/status pane.
- Calculate wrapped line count based on available width, clamp visible rows to 1–5, and set the layout constraint dynamically.
- Update `render_system_output` to accept the pre‑computed message, choose color based on error prefix, and render each line individually, defaulting to “Ready” when empty.
- Adjust UI layout to use the new dynamic constraint for the system/status section.
This commit is contained in:
2025-10-13 23:00:34 +02:00
parent c9daf68fea
commit c997b19b53

View File

@@ -273,6 +273,8 @@ pub fn render_chat(frame: &mut Frame<'_>, app: &mut ChatApp) {
0
};
let status_message = system_status_message(app);
let mut constraints = vec![Constraint::Min(8)]; // Messages
if thinking_height > 0 {
@@ -284,7 +286,12 @@ pub fn render_chat(frame: &mut Frame<'_>, app: &mut ChatApp) {
}
constraints.push(Constraint::Length(input_height)); // Input
constraints.push(Constraint::Length(4)); // System/Status output (2 lines content + 2 borders)
let status_visual_lines = calculate_wrapped_line_count(status_message.lines(), available_width);
let status_visible_rows = status_visual_lines.clamp(1, 5);
let status_height = status_visible_rows as u16 + 2; // +2 for borders
constraints.push(Constraint::Length(status_height)); // System/Status output (dynamic)
constraints.push(Constraint::Length(3)); // Mode and shortcuts bar
let layout = Layout::default()
@@ -309,7 +316,7 @@ pub fn render_chat(frame: &mut Frame<'_>, app: &mut ChatApp) {
render_input(frame, layout[idx], app);
idx += 1;
render_system_output(frame, layout[idx], app);
render_system_output(frame, layout[idx], app, &status_message);
idx += 1;
render_status(frame, layout[idx], app);
@@ -1865,15 +1872,13 @@ fn render_input(frame: &mut Frame<'_>, area: Rect, app: &mut ChatApp) {
}
}
fn render_system_output(frame: &mut Frame<'_>, area: Rect, app: &ChatApp) {
let theme = app.theme();
fn system_status_message(app: &ChatApp) -> String {
let system_status = app.system_status();
// Priority: system_status > error > status > "Ready"
let display_message = if !system_status.is_empty() {
if !system_status.is_empty() {
system_status.to_string()
} else if let Some(error) = app.error_message() {
format!("Error: {}", error)
format!("Error: {error}")
} else {
let status = app.status_message();
if status.is_empty() || status == "Ready" {
@@ -1881,15 +1886,31 @@ fn render_system_output(frame: &mut Frame<'_>, area: Rect, app: &ChatApp) {
} else {
status.to_string()
}
}
}
fn render_system_output(frame: &mut Frame<'_>, area: Rect, app: &ChatApp, message: &str) {
let theme = app.theme();
let color = if message.starts_with("Error:") {
theme.error
} else {
theme.info
};
// Create a simple paragraph with wrapping enabled
let line = Line::from(Span::styled(
display_message,
Style::default().fg(theme.info),
));
let text_lines: Vec<Line> = if message.is_empty() {
vec![Line::from(Span::styled(
"Ready",
Style::default().fg(color),
))]
} else {
message
.lines()
.map(|line| Line::from(Span::styled(line.to_string(), Style::default().fg(color))))
.collect()
};
let paragraph = Paragraph::new(line)
let paragraph = Paragraph::new(text_lines)
.style(Style::default().bg(theme.background))
.block(
Block::default()