mirror of
https://github.com/hanzoai/dev.git
synced 2026-10-25 03:32:32 +00:00
3.7 KiB
3.7 KiB
Proposed Changes: Reliable image sizing for ratatui-image
This approach avoids Picker::from_query_stdio() races by measuring terminal cell size via /dev/tty once and feeding that to Picker::from_fontsize. It removes the startup timing constraint and yields accurate image scaling.
1) codex-rs/tui/src/terminal_info.rs
Add a helper that returns the exact cell size in pixels (width, height). Place it near the bottom, above DEFAULT_CELL_ASPECT_RATIO so it can reuse internal helpers.
pub fn get_cell_size_pixels() -> Option<(u16, u16)> {
// Open /dev/tty for reading and writing
let mut tty_w = OpenOptions::new().write(true).open("/dev/tty").ok()?;
let mut tty_r = OpenOptions::new().read(true).open("/dev/tty").ok()?;
// Try direct cell size query (CSI 16 t) -> expect: CSI 6;height;width t
tty_w.write_all(b"\x1b[16t").ok()?;
tty_w.flush().ok()?;
if let Some(reply) = read_reply(&mut tty_r, Duration::from_millis(100)) {
if let Some((kind, height, width)) = parse_three_nums(&reply) {
if kind == 6 && width > 0 && height > 0 {
return Some((width as u16, height as u16));
}
}
}
// Fallback: window size in pixels (CSI 14 t) -> CSI 4;win_h;win_w t
tty_w.write_all(b"\x1b[14t").ok()?;
tty_w.flush().ok()?;
let (mut win_h, mut win_w) = (0u32, 0u32);
if let Some(reply) = read_reply(&mut tty_r, Duration::from_millis(100)) {
if let Some((kind, h, w)) = parse_three_nums(&reply) {
if kind == 4 {
win_h = h;
win_w = w;
}
}
}
// Text area in characters (CSI 18 t) -> CSI 8;rows;cols t
tty_w.write_all(b"\x1b[18t").ok()?;
tty_w.flush().ok()?;
let (mut rows, mut cols) = (0u32, 0u32);
if let Some(reply) = read_reply(&mut tty_r, Duration::from_millis(100)) {
if let Some((kind, r, c)) = parse_three_nums(&reply) {
if kind == 8 {
rows = r;
cols = c;
}
}
}
if win_h > 0 && win_w > 0 && rows > 0 && cols > 0 {
let cell_w = (win_w as f32 / cols as f32).round() as u16;
let cell_h = (win_h as f32 / rows as f32).round() as u16;
if cell_w > 0 && cell_h > 0 {
return Some((cell_w, cell_h));
}
}
None
}
2) codex-rs/tui/src/chatwidget.rs
- Add a cached cell-size field to
ChatWidget:
// Cached cell size (width,height) in pixels
cached_cell_size: std::cell::OnceCell<(u16, u16)>,
- Add a helper to compute the picker font size once, with fallback:
impl ChatWidget<'_> {
fn measured_font_size(&self) -> (u16, u16) {
let default_guess = if std::env::var("TERM_PROGRAM").unwrap_or_default() == "iTerm.app" {
(7, 15)
} else {
(8, 16)
};
*self.cached_cell_size.get_or_init(|| {
crate::terminal_info::get_cell_size_pixels().unwrap_or(default_guess)
})
}
// ...
}
- Use
measured_font_size()when creating thePicker(two places):
- In the branch where we create a new picker (around the first
Picker::from_fontsize(...)):
// Replace the conditional guessed font size block with
let picker = Picker::from_fontsize(self.measured_font_size());
- In
render_screenshot_highlevel, whencached_pickerisNone:
// Replace the guessed font size block with
*cached_picker = Some(Picker::from_fontsize(self.measured_font_size()));
Notes
- No changes to the event thread ordering are required.
- This approach avoids races with
stdinand makes screenshot images fill the intended area usingResize::Fit. - Keep the existing aspect‑ratio calculation in
popup_area_top_right; it remains correct.