diff --git a/yazi-adapter/src/dimension.rs b/yazi-adapter/src/dimension.rs index 673377e9..3a551a4d 100644 --- a/yazi-adapter/src/dimension.rs +++ b/yazi-adapter/src/dimension.rs @@ -4,36 +4,61 @@ use crossterm::terminal::WindowSize; use crate::EMULATOR; -pub struct Dimension; +#[derive(Clone, Copy, Debug)] +pub struct Dimension { + pub rows: u16, + pub columns: u16, + pub width: u16, + pub height: u16, +} + +impl From for Dimension { + fn from(s: WindowSize) -> Self { + Self { rows: s.rows, columns: s.columns, width: s.width, height: s.height } + } +} + +impl From for WindowSize { + fn from(d: Dimension) -> Self { + Self { rows: d.rows, columns: d.columns, width: d.width, height: d.height } + } +} impl Dimension { - pub fn available() -> WindowSize { + pub fn available() -> Self { let mut size = WindowSize { rows: 0, columns: 0, width: 0, height: 0 }; if let Ok(s) = crossterm::terminal::window_size() { _ = mem::replace(&mut size, s); } - if size.rows == 0 || size.columns == 0 { + if size.columns == 0 || size.rows == 0 { if let Ok((cols, rows)) = crossterm::terminal::size() { size.columns = cols; size.rows = rows; } } - // TODO: Use `CSI 14 t` to get the actual size of the terminal - // if size.width == 0 || size.height == 0 {} - - size + size.into() } - #[inline] - pub fn ratio() -> Option<(f64, f64)> { - let s = Self::available(); - Some(if s.width == 0 || s.height == 0 { - let s = EMULATOR.get().cell_size?; - (s.0 as f64, s.1 as f64) + pub fn ratio(self) -> Option<(f64, f64)> { + if self.rows == 0 || self.columns == 0 || self.width == 0 || self.height == 0 { + None } else { - (f64::from(s.width) / f64::from(s.columns), f64::from(s.height) / f64::from(s.rows)) + Some((self.width as f64 / self.columns as f64, self.height as f64 / self.rows as f64)) + } + } + + pub fn cell_size() -> Option<(f64, f64)> { + let emu = EMULATOR.get(); + Some(if emu.force_16t { + (emu.csi_16t.0 as f64, emu.csi_16t.1 as f64) + } else if let Some(r) = Self::available().ratio() { + r + } else if emu.csi_16t.0 != 0 && emu.csi_16t.1 != 0 { + (emu.csi_16t.0 as f64, emu.csi_16t.1 as f64) + } else { + None? }) } } diff --git a/yazi-adapter/src/drivers/ueberzug.rs b/yazi-adapter/src/drivers/ueberzug.rs index 7989254b..42af1e3e 100644 --- a/yazi-adapter/src/drivers/ueberzug.rs +++ b/yazi-adapter/src/drivers/ueberzug.rs @@ -53,12 +53,12 @@ impl Ueberzug { }) .await??; - let area = Dimension::ratio() - .map(|(r1, r2)| Rect { + let area = Dimension::cell_size() + .map(|(cw, ch)| Rect { x: max.x, y: max.y, - width: max.width.min((w.min(YAZI.preview.max_width as _) as f64 / r1).ceil() as _), - height: max.height.min((h.min(YAZI.preview.max_height as _) as f64 / r2).ceil() as _), + width: max.width.min((w.min(YAZI.preview.max_width as _) as f64 / cw).ceil() as _), + height: max.height.min((h.min(YAZI.preview.max_height as _) as f64 / ch).ceil() as _), }) .unwrap_or(max); diff --git a/yazi-adapter/src/emulator.rs b/yazi-adapter/src/emulator.rs index e8119808..41b8e2c2 100644 --- a/yazi-adapter/src/emulator.rs +++ b/yazi-adapter/src/emulator.rs @@ -7,13 +7,14 @@ use tokio::time::sleep; use tracing::{debug, error, warn}; use yazi_shared::{Either, tty::{Handle, TTY}}; -use crate::{Adapter, Brand, Mux, TMUX, Unknown}; +use crate::{Adapter, Brand, Dimension, Mux, TMUX, Unknown}; #[derive(Clone, Copy, Debug)] pub struct Emulator { pub kind: Either, pub light: bool, - pub cell_size: Option<(u16, u16)>, + pub csi_16t: (u16, u16), + pub force_16t: bool, } impl Default for Emulator { @@ -55,15 +56,22 @@ impl Emulator { }) }; + let csi_16t = Self::csi_16t(&resp).unwrap_or_default(); Ok(Self { kind, light: Self::light_bg(&resp).unwrap_or_default(), - cell_size: Self::cell_size(&resp), + csi_16t, + force_16t: Self::force_16t(csi_16t), }) } pub const fn unknown() -> Self { - Self { kind: Either::Right(Unknown::default()), light: false, cell_size: None } + Self { + kind: Either::Right(Unknown::default()), + light: false, + csi_16t: (0, 0), + force_16t: false, + } } pub fn adapters(self) -> &'static [Adapter] { @@ -160,7 +168,7 @@ impl Emulator { ); } - fn cell_size(resp: &str) -> Option<(u16, u16)> { + fn csi_16t(resp: &str) -> Option<(u16, u16)> { let b = resp.split_once("\x1b[6;")?.1.as_bytes(); let h: Vec<_> = b.iter().copied().take_while(|&c| c.is_ascii_digit()).collect(); @@ -189,4 +197,14 @@ impl Emulator { } } } + + fn force_16t((w, h): (u16, u16)) -> bool { + if w == 0 || h == 0 { + return false; + } + + Dimension::available() + .ratio() + .is_none_or(|(rw, rh)| rw.floor() as u16 != w || rh.floor() as u16 != h) + } } diff --git a/yazi-adapter/src/image.rs b/yazi-adapter/src/image.rs index efa4a0b6..d9b56593 100644 --- a/yazi-adapter/src/image.rs +++ b/yazi-adapter/src/image.rs @@ -65,21 +65,21 @@ impl Image { } pub(super) fn max_pixel(rect: Rect) -> (u32, u32) { - Dimension::ratio() - .map(|(r1, r2)| { - let (w, h) = ((rect.width as f64 * r1) as u32, (rect.height as f64 * r2) as u32); + Dimension::cell_size() + .map(|(cw, ch)| { + let (w, h) = ((rect.width as f64 * cw) as u32, (rect.height as f64 * ch) as u32); (w.min(YAZI.preview.max_width), h.min(YAZI.preview.max_height)) }) .unwrap_or((YAZI.preview.max_width, YAZI.preview.max_height)) } pub(super) fn pixel_area(size: (u32, u32), rect: Rect) -> Rect { - Dimension::ratio() - .map(|(r1, r2)| Rect { + Dimension::cell_size() + .map(|(cw, ch)| Rect { x: rect.x, y: rect.y, - width: (size.0 as f64 / r1).ceil() as u16, - height: (size.1 as f64 / r2).ceil() as u16, + width: (size.0 as f64 / cw).ceil() as u16, + height: (size.1 as f64 / ch).ceil() as u16, }) .unwrap_or(rect) } diff --git a/yazi-core/src/mgr/mgr.rs b/yazi-core/src/mgr/mgr.rs index bd415165..7771fc2b 100644 --- a/yazi-core/src/mgr/mgr.rs +++ b/yazi-core/src/mgr/mgr.rs @@ -30,7 +30,7 @@ impl Mgr { if pos.origin == Origin::Hovered { self.active().hovered_rect_based(pos) } else { - pos.rect(Dimension::available()) + pos.rect(Dimension::available().into()) } } diff --git a/yazi-core/src/tab/tab.rs b/yazi-core/src/tab/tab.rs index cb317e52..88983d7f 100644 --- a/yazi-core/src/tab/tab.rs +++ b/yazi-core/src/tab/tab.rs @@ -77,7 +77,7 @@ impl Tab { } pub fn hovered_rect_based(&self, pos: Position) -> Rect { - let ws = Dimension::available(); + let ws = Dimension::available().into(); if let Some(r) = self.hovered_rect() { Position::sticky(ws, r, pos.offset) } else { diff --git a/yazi-fm/src/app/commands/update_notify.rs b/yazi-fm/src/app/commands/update_notify.rs index 376b6680..f100fb9c 100644 --- a/yazi-fm/src/app/commands/update_notify.rs +++ b/yazi-fm/src/app/commands/update_notify.rs @@ -1,4 +1,3 @@ -use crossterm::terminal::WindowSize; use ratatui::layout::Rect; use yazi_adapter::Dimension; use yazi_shared::event::CmdCow; @@ -7,7 +6,7 @@ use crate::{app::App, notify}; impl App { pub(crate) fn update_notify(&mut self, cmd: CmdCow) { - let WindowSize { rows, columns, .. } = Dimension::available(); + let Dimension { rows, columns, .. } = Dimension::available(); let area = notify::Notify::available(Rect { x: 0, y: 0, width: columns, height: rows }); diff --git a/yazi-fm/src/cmp/cmp.rs b/yazi-fm/src/cmp/cmp.rs index f8284591..d105c10a 100644 --- a/yazi-fm/src/cmp/cmp.rs +++ b/yazi-fm/src/cmp/cmp.rs @@ -38,7 +38,7 @@ impl Widget for Cmp<'_> { .collect(); let input_area = self.cx.mgr.area(self.cx.input.position); - let mut area = Position::sticky(Dimension::available(), input_area, Offset { + let mut area = Position::sticky(Dimension::available().into(), input_area, Offset { x: 1, y: 0, width: input_area.width.saturating_sub(2), diff --git a/yazi-plugin/src/bindings/mod.rs b/yazi-plugin/src/bindings/mod.rs index 2d4a0019..7a8b9765 100644 --- a/yazi-plugin/src/bindings/mod.rs +++ b/yazi-plugin/src/bindings/mod.rs @@ -1,3 +1,3 @@ #![allow(clippy::module_inception)] -yazi_macro::mod_flat!(cha chan icon image input layer mouse permit range window); +yazi_macro::mod_flat!(cha chan icon image input layer mouse permit range); diff --git a/yazi-plugin/src/bindings/window.rs b/yazi-plugin/src/bindings/window.rs deleted file mode 100644 index f0688414..00000000 --- a/yazi-plugin/src/bindings/window.rs +++ /dev/null @@ -1,37 +0,0 @@ -use mlua::{FromLua, UserData}; -use yazi_adapter::Dimension; - -#[derive(Debug, Clone, Copy, FromLua)] -pub struct Window { - pub rows: u16, - pub cols: u16, - pub width: u16, - pub height: u16, -} - -impl Window { - pub fn get() -> Self { - let ws = Dimension::available(); - Self { rows: ws.rows, cols: ws.columns, width: ws.width, height: ws.height } - } -} - -impl From for crossterm::terminal::WindowSize { - fn from(value: Window) -> Self { - crossterm::terminal::WindowSize { - rows: value.rows, - columns: value.cols, - width: value.width, - height: value.height, - } - } -} - -impl UserData for Window { - fn add_fields>(fields: &mut F) { - fields.add_field_method_get("rows", |_, me| Ok(me.rows)); - fields.add_field_method_get("cols", |_, me| Ok(me.cols)); - fields.add_field_method_get("width", |_, me| Ok(me.width)); - fields.add_field_method_get("height", |_, me| Ok(me.height)); - } -}