diff --git a/codex-rs/Cargo.lock b/codex-rs/Cargo.lock index e8ce0bfe..a7f73e9c 100644 --- a/codex-rs/Cargo.lock +++ b/codex-rs/Cargo.lock @@ -1455,6 +1455,7 @@ dependencies = [ "codex-windows-sandbox", "color-eyre", "crossterm", + "derive_more 2.0.1", "diffy", "dirs", "dunce", @@ -1658,6 +1659,15 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "convert_case" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -2003,7 +2013,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ - "convert_case", + "convert_case 0.6.0", "proc-macro2", "quote", "syn 2.0.104", @@ -2016,6 +2026,7 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ + "convert_case 0.7.1", "proc-macro2", "quote", "syn 2.0.104", diff --git a/codex-rs/tui/Cargo.toml b/codex-rs/tui/Cargo.toml index ac00e905..b524d8bf 100644 --- a/codex-rs/tui/Cargo.toml +++ b/codex-rs/tui/Cargo.toml @@ -42,6 +42,7 @@ codex-ollama = { workspace = true } codex-protocol = { workspace = true } color-eyre = { workspace = true } crossterm = { workspace = true, features = ["bracketed-paste", "event-stream"] } +derive_more = { workspace = true, features = ["is_variant"] } diffy = { workspace = true } dirs = { workspace = true } dunce = { workspace = true } diff --git a/codex-rs/tui/src/custom_terminal.rs b/codex-rs/tui/src/custom_terminal.rs index bd37fe81..46d16a83 100644 --- a/codex-rs/tui/src/custom_terminal.rs +++ b/codex-rs/tui/src/custom_terminal.rs @@ -33,6 +33,7 @@ use crossterm::style::SetBackgroundColor; use crossterm::style::SetColors; use crossterm::style::SetForegroundColor; use crossterm::terminal::Clear; +use derive_more::IsVariant; use ratatui::backend::Backend; use ratatui::backend::ClearType; use ratatui::buffer::Buffer; @@ -120,8 +121,6 @@ where /// Last known position of the cursor. Used to find the new area when the viewport is inlined /// and the terminal resized. pub last_known_cursor_pos: Position, - - use_custom_flush: bool, } impl Drop for Terminal @@ -151,16 +150,12 @@ where let cursor_pos = backend.get_cursor_position()?; Ok(Self { backend, - buffers: [ - Buffer::empty(Rect::new(0, 0, 0, 0)), - Buffer::empty(Rect::new(0, 0, 0, 0)), - ], + buffers: [Buffer::empty(Rect::ZERO), Buffer::empty(Rect::ZERO)], current: 0, hidden_cursor: false, viewport_area: Rect::new(0, cursor_pos.y, 0, 0), last_known_screen_size: screen_size, last_known_cursor_pos: cursor_pos, - use_custom_flush: true, }) } @@ -173,11 +168,26 @@ where } } + /// Gets the current buffer as a reference. + fn current_buffer(&self) -> &Buffer { + &self.buffers[self.current] + } + /// Gets the current buffer as a mutable reference. - pub fn current_buffer_mut(&mut self) -> &mut Buffer { + fn current_buffer_mut(&mut self) -> &mut Buffer { &mut self.buffers[self.current] } + /// Gets the previous buffer as a reference. + fn previous_buffer(&self) -> &Buffer { + &self.buffers[1 - self.current] + } + + /// Gets the previous buffer as a mutable reference. + fn previous_buffer_mut(&mut self) -> &mut Buffer { + &mut self.buffers[1 - self.current] + } + /// Gets the backend pub const fn backend(&self) -> &B { &self.backend @@ -191,26 +201,12 @@ where /// Obtains a difference between the previous and the current buffer and passes it to the /// current backend for drawing. pub fn flush(&mut self) -> io::Result<()> { - let previous_buffer = &self.buffers[1 - self.current]; - let current_buffer = &self.buffers[self.current]; - - if self.use_custom_flush { - let updates = diff_buffers(previous_buffer, current_buffer); - if let Some(DrawCommand::Put { x, y, .. }) = updates - .iter() - .rev() - .find(|cmd| matches!(cmd, DrawCommand::Put { .. })) - { - self.last_known_cursor_pos = Position { x: *x, y: *y }; - } - draw(&mut self.backend, updates.into_iter()) - } else { - let updates = previous_buffer.diff(current_buffer); - if let Some((x, y, _)) = updates.last() { - self.last_known_cursor_pos = Position { x: *x, y: *y }; - } - self.backend.draw(updates.into_iter()) + let updates = diff_buffers(self.previous_buffer(), self.current_buffer()); + let last_put_command = updates.iter().rfind(|command| command.is_put()); + if let Some(&DrawCommand::Put { x, y, .. }) = last_put_command { + self.last_known_cursor_pos = Position { x, y }; } + draw(&mut self.backend, updates.into_iter()) } /// Updates the Terminal so that internal buffers match the requested area. @@ -224,8 +220,8 @@ where /// Sets the viewport area. pub fn set_viewport_area(&mut self, area: Rect) { - self.buffers[self.current].resize(area); - self.buffers[1 - self.current].resize(area); + self.current_buffer_mut().resize(area); + self.previous_buffer_mut().resize(area); self.viewport_area = area; } @@ -337,7 +333,7 @@ where self.swap_buffers(); - ratatui::backend::Backend::flush(&mut self.backend)?; + Backend::flush(&mut self.backend)?; Ok(()) } @@ -381,13 +377,13 @@ where .set_cursor_position(self.viewport_area.as_position())?; self.backend.clear_region(ClearType::AfterCursor)?; // Reset the back buffer to make sure the next update will redraw everything. - self.buffers[1 - self.current].reset(); + self.previous_buffer_mut().reset(); Ok(()) } /// Clears the inactive buffer and swaps it with the current buffer pub fn swap_buffers(&mut self) { - self.buffers[1 - self.current].reset(); + self.previous_buffer_mut().reset(); self.current = 1 - self.current; } @@ -400,13 +396,13 @@ where use ratatui::buffer::Cell; use unicode_width::UnicodeWidthStr; -#[derive(Debug)] -enum DrawCommand<'a> { - Put { x: u16, y: u16, cell: &'a Cell }, +#[derive(Debug, IsVariant)] +enum DrawCommand { + Put { x: u16, y: u16, cell: Cell }, ClearToEnd { x: u16, y: u16, bg: Color }, } -fn diff_buffers<'a>(a: &'a Buffer, b: &'a Buffer) -> Vec> { +fn diff_buffers(a: &Buffer, b: &Buffer) -> Vec { let previous_buffer = &a.content; let next_buffer = &b.content; @@ -455,7 +451,7 @@ fn diff_buffers<'a>(a: &'a Buffer, b: &'a Buffer) -> Vec> { updates.push(DrawCommand::Put { x, y, - cell: &next_buffer[i], + cell: next_buffer[i].clone(), }); } } @@ -468,9 +464,9 @@ fn diff_buffers<'a>(a: &'a Buffer, b: &'a Buffer) -> Vec> { updates } -fn draw<'a, I>(writer: &mut impl Write, commands: I) -> io::Result<()> +fn draw(writer: &mut impl Write, commands: I) -> io::Result<()> where - I: Iterator>, + I: Iterator, { let mut fg = Color::Reset; let mut bg = Color::Reset;