fix(tui/resume): apply theme bg/fg + border to dialog block for consistent theming across all popups

This commit is contained in:
James Peter
2025-09-04 09:26:01 +10:00
parent 165d52d2e6
commit 538e3e1091
3 changed files with 64 additions and 9 deletions
@@ -129,10 +129,14 @@ impl BottomPaneView<'_> for ResumeSelectionView {
fn render(&self, area: Rect, buf: &mut Buffer) {
if area.height == 0 || area.width == 0 { return; }
// Clear and draw a bordered block that uses the active theme colors.
// Other popups (e.g., list_selection_view) already do this; mirroring
// that treatment ensures dialogs respect dark/light themes.
Clear.render(area, buf);
let block = Block::default()
.borders(Borders::ALL)
.border_style(Style::default().fg(crate::colors::light_blue()))
.border_style(Style::default().fg(crate::colors::border()))
.style(Style::default().bg(crate::colors::background()).fg(crate::colors::text()))
.title(self.title.clone())
.title_alignment(Alignment::Center);
let inner = block.inner(area);
@@ -205,6 +209,8 @@ impl BottomPaneView<'_> for ResumeSelectionView {
Span::styled("Esc", Style::default().fg(crate::colors::error())),
Span::raw(" Cancel"),
]);
Paragraph::new(footer_line).render(footer, buf);
Paragraph::new(footer_line)
.style(Style::default().bg(crate::colors::background()).fg(crate::colors::text()))
.render(footer, buf);
}
}
+14 -6
View File
@@ -3093,7 +3093,7 @@ impl HistoryCell for CollapsibleReasoningCell {
pub(crate) struct StreamingContentCell {
pub(crate) id: Option<String>,
pub(crate) lines: Vec<Line<'static>>,
// Show an ellipsis on a new line while streaming is in progress
// Show an ellipsis appended to the last line while streaming
pub(crate) show_ellipsis: bool,
}
@@ -3193,9 +3193,7 @@ impl HistoryCell for StreamingContentCell {
}
}
}
let mut total = total.saturating_add(2);
if self.show_ellipsis { total = total.saturating_add(1); }
total
total.saturating_add(2)
}
fn custom_render_with_skip(&self, area: Rect, buf: &mut Buffer, skip_rows: u16) {
// Render with a 1-row top and bottom padding, all using the assistant bg tint.
@@ -3255,9 +3253,19 @@ impl HistoryCell for StreamingContentCell {
_is_first_output_line = false;
}
if !text_buf.is_empty() { segs.push(Seg::Text(std::mem::take(&mut text_buf))); }
// Append an ellipsis line as its own segment when streaming
// If streaming, append an ellipsis span to the last line of the last segment
if self.show_ellipsis {
segs.push(Seg::Text(vec![Line::from("…".dim())]));
if let Some(last) = segs.last_mut() {
match last {
Seg::Text(lines) | Seg::Bullet(lines) | Seg::Code(lines) => {
if let Some(last_line) = lines.last_mut() {
let mut spans = std::mem::take(&mut last_line.spans);
spans.push(Span::styled(" …", Style::default().fg(crate::colors::text_dim())));
last_line.spans = spans;
}
}
}
}
}
// Streaming-style top padding row
+42 -1
View File
@@ -621,12 +621,53 @@ impl StreamController {
message.len()
);
let committed = state.collector.committed_count();
// Heuristic fix: if the very first committed line looks like
// a truncated title (prefix of the final first line), drop it
// from the committed region so the final replaces it.
let cfg = self.config.clone();
// Render current buffer preview
let prior_src = state.collector.full_render_source_preview();
let mut prior_lines: Vec<ratatui::text::Line<'static>> = Vec::new();
crate::markdown::append_markdown(&prior_src, &mut prior_lines, &cfg);
// Extract first non-blank among the already committed lines
let committed_first = if committed > 0 {
let mut out = String::new();
for l in prior_lines.iter().take(committed) {
if !crate::render::line_utils::is_blank_line_trim(l) {
out = l.spans.iter().map(|s| s.content.clone()).collect::<Vec<_>>().join("");
break;
}
}
out
} else { String::new() };
// Render final message's first line
let mut final_lines: Vec<ratatui::text::Line<'static>> = Vec::new();
let mut msg_preview = message.to_string();
if !msg_preview.ends_with('\n') { msg_preview.push('\n'); }
crate::markdown::append_markdown(&msg_preview, &mut final_lines, &cfg);
let final_first = final_lines.iter()
.find(|l| !crate::render::line_utils::is_blank_line_trim(l))
.map(|l| l.spans.iter().map(|s| s.content.clone()).collect::<Vec<_>>().join(""))
.unwrap_or_default();
let mut committed_adj = committed;
if committed > 0
&& !committed_first.is_empty()
&& final_first.starts_with(&committed_first)
&& final_first.len() > committed_first.len()
&& committed_first.chars().count() <= 16
{
committed_adj = committed.saturating_sub(1);
tracing::debug!(
"reasoning prefix-upgrade: committed_first='{}' -> final_first='{}' (committed {}->{}))",
committed_first, final_first, committed, committed_adj
);
}
let mut msg = message.to_owned();
if !msg.ends_with('\n') { msg.push('\n'); }
let state_mut = self.state_mut(kind);
state_mut
.collector
.replace_with_and_mark_committed(&msg, committed);
.replace_with_and_mark_committed(&msg, committed_adj);
return self.finalize(kind, immediate, sink);
}
// For Answer (or empty message), finalize existing streamed content.