From 72f999edc7848961b99c4b98bf1e62d12fa35798 Mon Sep 17 00:00:00 2001 From: Benjamin Carlsson Date: Sun, 11 Oct 2026 15:49:24 +0000 Subject: [PATCH] Simplify the custom terminal drawing API (#53156) ## What changed Remove `Terminal::autoresize` and the fallible `try_draw` helpers. Render directly in `draw_with_size`, retaining automatic size updates and the existing buffer flush and cursor handling. Update the cursor-ordering test to use `draw`, preserving its assertion that the cursor moves before it is shown. GitOrigin-RevId: 5889e9603d772945660e7ae35690d2b7326b10ae --- codex-rs/tui/src/custom_terminal.rs | 87 +++-------------------------- 1 file changed, 8 insertions(+), 79 deletions(-) diff --git a/codex-rs/tui/src/custom_terminal.rs b/codex-rs/tui/src/custom_terminal.rs index 60081516bd..d7957f8ecf 100644 --- a/codex-rs/tui/src/custom_terminal.rs +++ b/codex-rs/tui/src/custom_terminal.rs @@ -326,25 +326,8 @@ where self.visible_history_rows = self.visible_history_rows.min(area.top()); } - /// Queries the backend for size and resizes if it doesn't match the previous size. - pub fn autoresize(&mut self) -> io::Result<()> { - let screen_size = self.size()?; - if screen_size != self.last_known_screen_size { - self.resize(screen_size)?; - } - Ok(()) - } - /// Draws a single frame to the terminal. - /// - /// Returns a [`CompletedFrame`] if successful, otherwise a [`std::io::Error`]. - /// - /// If the render callback passed to this method can fail, use [`try_draw`] instead. - /// - /// Applications should call `draw` or [`try_draw`] in a loop to continuously render the - /// terminal. These methods are the main entry points for drawing to the terminal. - /// - /// [`try_draw`]: Terminal::try_draw + /// Applications should call `draw` in a loop to continuously render the terminal. /// /// This method will: /// @@ -367,71 +350,20 @@ where } /// Draws a single frame using a screen size already obtained by the caller. - pub(crate) fn draw_with_size(&mut self, screen_size: Size, render: F) -> io::Result<()> + pub(crate) fn draw_with_size( + &mut self, + screen_size: Size, + render_callback: F, + ) -> io::Result<()> where F: FnOnce(&mut Frame), - { - self.try_draw_with_size(screen_size, |frame| { - render(frame); - io::Result::Ok(()) - }) - } - - /// Tries to draw a single frame to the terminal. - /// - /// Returns [`Result::Ok`] containing a [`CompletedFrame`] if successful, otherwise - /// [`Result::Err`] containing the [`std::io::Error`] that caused the failure. - /// - /// This is the equivalent of [`Terminal::draw`] but the render callback is a function or - /// closure that returns a `Result` instead of nothing. - /// - /// Applications should call `try_draw` or [`draw`] in a loop to continuously render the - /// terminal. These methods are the main entry points for drawing to the terminal. - /// - /// [`draw`]: Terminal::draw - /// - /// This method will: - /// - /// - autoresize the terminal if necessary - /// - call the render callback, passing it a [`Frame`] reference to render to - /// - flush the current internal state by copying the current buffer to the backend - /// - move the cursor to the last known position if it was set during the rendering closure - /// - return a [`CompletedFrame`] with the current buffer and the area of the terminal - /// - /// The render callback passed to `try_draw` can return any [`Result`] with an error type that - /// can be converted into an [`std::io::Error`] using the [`Into`] trait. This makes it possible - /// to use the `?` operator to propagate errors that occur during rendering. If the render - /// callback returns an error, the error will be returned from `try_draw` as an - /// [`std::io::Error`] and the terminal will not be updated. - /// - /// The [`CompletedFrame`] returned by this method can be useful for debugging or testing - /// purposes, but it is often not used in regular applicationss. - /// - /// The render callback should fully render the entire frame when called, including areas that - /// are unchanged from the previous frame. This is because each frame is compared to the - /// previous frame to determine what has changed, and only the changes are written to the - /// terminal. If the render function does not fully render the frame, the terminal will not be - /// in a consistent state. - pub fn try_draw(&mut self, render_callback: F) -> io::Result<()> - where - F: FnOnce(&mut Frame) -> Result<(), E>, - E: Into, - { - let screen_size = self.size()?; - self.try_draw_with_size(screen_size, render_callback) - } - - fn try_draw_with_size(&mut self, screen_size: Size, render_callback: F) -> io::Result<()> - where - F: FnOnce(&mut Frame) -> Result<(), E>, - E: Into, { if screen_size != self.last_known_screen_size { self.resize(screen_size)?; } let mut frame = self.get_frame(); - render_callback(&mut frame).map_err(Into::into)?; + render_callback(&mut frame); // We can't change the cursor position right away because we have to flush the frame to // stdout first. But we also can't keep the frame around, since it holds a &mut to @@ -1348,10 +1280,7 @@ mod tests { )); terminal - .try_draw(|frame| { - frame.set_cursor_position(cursor_position); - io::Result::Ok(()) - }) + .draw(|frame| frame.set_cursor_position(cursor_position)) .expect("draw"); let mut expected_move = Vec::new();