Fix pager overlay clear between pages (#3952)
should fix characters sometimes hanging around while scrolling the transcript.
This commit is contained in:
@@ -18,7 +18,9 @@ use ratatui::style::Stylize;
|
|||||||
use ratatui::text::Line;
|
use ratatui::text::Line;
|
||||||
use ratatui::text::Span;
|
use ratatui::text::Span;
|
||||||
use ratatui::text::Text;
|
use ratatui::text::Text;
|
||||||
|
use ratatui::widgets::Clear;
|
||||||
use ratatui::widgets::Paragraph;
|
use ratatui::widgets::Paragraph;
|
||||||
|
use ratatui::widgets::Widget;
|
||||||
use ratatui::widgets::WidgetRef;
|
use ratatui::widgets::WidgetRef;
|
||||||
|
|
||||||
pub(crate) enum Overlay {
|
pub(crate) enum Overlay {
|
||||||
@@ -98,6 +100,7 @@ impl PagerView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn render(&mut self, area: Rect, buf: &mut Buffer) {
|
fn render(&mut self, area: Rect, buf: &mut Buffer) {
|
||||||
|
Clear.render(area, buf);
|
||||||
self.render_header(area, buf);
|
self.render_header(area, buf);
|
||||||
let content_area = self.scroll_area(area);
|
let content_area = self.scroll_area(area);
|
||||||
self.update_last_content_height(content_area.height);
|
self.update_last_content_height(content_area.height);
|
||||||
@@ -139,6 +142,7 @@ impl PagerView {
|
|||||||
// Removed unused render_content_page (replaced by render_content_page_prepared)
|
// Removed unused render_content_page (replaced by render_content_page_prepared)
|
||||||
|
|
||||||
fn render_content_page_prepared(&self, area: Rect, buf: &mut Buffer, page: &[Line<'static>]) {
|
fn render_content_page_prepared(&self, area: Rect, buf: &mut Buffer, page: &[Line<'static>]) {
|
||||||
|
Clear.render(area, buf);
|
||||||
Paragraph::new(page.to_vec()).render_ref(area, buf);
|
Paragraph::new(page.to_vec()).render_ref(area, buf);
|
||||||
|
|
||||||
let visible = page.len();
|
let visible = page.len();
|
||||||
@@ -547,6 +551,17 @@ impl StaticOverlay {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use insta::assert_snapshot;
|
use insta::assert_snapshot;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use crate::history_cell::CommandOutput;
|
||||||
|
use crate::history_cell::HistoryCell;
|
||||||
|
use crate::history_cell::PatchEventType;
|
||||||
|
use crate::history_cell::new_patch_event;
|
||||||
|
use codex_core::protocol::FileChange;
|
||||||
|
use codex_protocol::parse_command::ParsedCommand;
|
||||||
use ratatui::Terminal;
|
use ratatui::Terminal;
|
||||||
use ratatui::backend::TestBackend;
|
use ratatui::backend::TestBackend;
|
||||||
|
|
||||||
@@ -610,6 +625,99 @@ mod tests {
|
|||||||
assert_snapshot!(term.backend());
|
assert_snapshot!(term.backend());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn buffer_to_text(buf: &Buffer, area: Rect) -> String {
|
||||||
|
let mut out = String::new();
|
||||||
|
for y in area.y..area.bottom() {
|
||||||
|
for x in area.x..area.right() {
|
||||||
|
let symbol = buf[(x, y)].symbol();
|
||||||
|
if symbol.is_empty() {
|
||||||
|
out.push(' ');
|
||||||
|
} else {
|
||||||
|
out.push(symbol.chars().next().unwrap_or(' '));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Trim trailing spaces for stability.
|
||||||
|
while out.ends_with(' ') {
|
||||||
|
out.pop();
|
||||||
|
}
|
||||||
|
out.push('\n');
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn transcript_overlay_apply_patch_scroll_vt100_clears_previous_page() {
|
||||||
|
let cwd = PathBuf::from("/repo");
|
||||||
|
let mut cells: Vec<Arc<dyn HistoryCell>> = Vec::new();
|
||||||
|
|
||||||
|
let mut approval_changes = HashMap::new();
|
||||||
|
approval_changes.insert(
|
||||||
|
PathBuf::from("foo.txt"),
|
||||||
|
FileChange::Add {
|
||||||
|
content: "hello\nworld\n".to_string(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let approval_cell: Arc<dyn HistoryCell> = Arc::new(new_patch_event(
|
||||||
|
PatchEventType::ApprovalRequest,
|
||||||
|
approval_changes,
|
||||||
|
&cwd,
|
||||||
|
));
|
||||||
|
cells.push(approval_cell);
|
||||||
|
|
||||||
|
let mut apply_changes = HashMap::new();
|
||||||
|
apply_changes.insert(
|
||||||
|
PathBuf::from("foo.txt"),
|
||||||
|
FileChange::Add {
|
||||||
|
content: "hello\nworld\n".to_string(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let apply_begin_cell: Arc<dyn HistoryCell> = Arc::new(new_patch_event(
|
||||||
|
PatchEventType::ApplyBegin {
|
||||||
|
auto_approved: false,
|
||||||
|
},
|
||||||
|
apply_changes,
|
||||||
|
&cwd,
|
||||||
|
));
|
||||||
|
cells.push(apply_begin_cell);
|
||||||
|
|
||||||
|
let apply_end_cell: Arc<dyn HistoryCell> =
|
||||||
|
Arc::new(crate::history_cell::new_user_approval_decision(vec![
|
||||||
|
"✓ Patch applied".green().bold().into(),
|
||||||
|
"src/foo.txt".dim().into(),
|
||||||
|
]));
|
||||||
|
cells.push(apply_end_cell);
|
||||||
|
|
||||||
|
let mut exec_cell = crate::history_cell::new_active_exec_command(
|
||||||
|
"exec-1".into(),
|
||||||
|
vec!["bash".into(), "-lc".into(), "ls".into()],
|
||||||
|
vec![ParsedCommand::Unknown { cmd: "ls".into() }],
|
||||||
|
);
|
||||||
|
exec_cell.complete_call(
|
||||||
|
"exec-1",
|
||||||
|
CommandOutput {
|
||||||
|
exit_code: 0,
|
||||||
|
stdout: "src\nREADME.md\n".into(),
|
||||||
|
stderr: String::new(),
|
||||||
|
formatted_output: "src\nREADME.md\n".into(),
|
||||||
|
},
|
||||||
|
Duration::from_millis(420),
|
||||||
|
);
|
||||||
|
let exec_cell: Arc<dyn HistoryCell> = Arc::new(exec_cell);
|
||||||
|
cells.push(exec_cell);
|
||||||
|
|
||||||
|
let mut overlay = TranscriptOverlay::new(cells);
|
||||||
|
let area = Rect::new(0, 0, 80, 12);
|
||||||
|
let mut buf = Buffer::empty(area);
|
||||||
|
|
||||||
|
overlay.render(area, &mut buf);
|
||||||
|
overlay.view.scroll_offset = 0;
|
||||||
|
overlay.view.wrap_cache = None;
|
||||||
|
overlay.render(area, &mut buf);
|
||||||
|
|
||||||
|
let snapshot = buffer_to_text(&buf, area);
|
||||||
|
assert_snapshot!("transcript_overlay_apply_patch_scroll_vt100", snapshot);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn transcript_overlay_keeps_scroll_pinned_at_bottom() {
|
fn transcript_overlay_keeps_scroll_pinned_at_bottom() {
|
||||||
let mut overlay = TranscriptOverlay::new(
|
let mut overlay = TranscriptOverlay::new(
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
source: tui/src/pager_overlay.rs
|
||||||
|
assertion_line: 721
|
||||||
|
expression: snapshot
|
||||||
|
---
|
||||||
|
/ T R A N S C R I P T / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
|
||||||
|
• Proposed Change foo.txt (+2 -0)
|
||||||
|
1 +hello
|
||||||
|
2 +world
|
||||||
|
|
||||||
|
• Change Approved foo.txt (+2 -0)
|
||||||
|
|
||||||
|
✓ Patch applied
|
||||||
|
─────────────────────────────────────────────────────────────────────────── 0% ─
|
||||||
|
↑/↓ scroll PgUp/PgDn page Home/End jump
|
||||||
|
q quit Esc edit prev
|
||||||
Reference in New Issue
Block a user