mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
feat: fallback to CSI 16 t for certain terminals that do not support TIOCGWINSZ (#2004)
This commit is contained in:
parent
11cf555b47
commit
9d3c0c72fe
5 changed files with 65 additions and 38 deletions
2
.github/workflows/draft.yml
vendored
2
.github/workflows/draft.yml
vendored
|
|
@ -4,8 +4,6 @@ on:
|
||||||
push:
|
push:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
tags: ["v[0-9]+.[0-9]+.[0-9]+"]
|
tags: ["v[0-9]+.[0-9]+.[0-9]+"]
|
||||||
schedule:
|
|
||||||
- cron: "0 */6 * * *"
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
|
|
|
||||||
40
Cargo.lock
generated
40
Cargo.lock
generated
|
|
@ -117,9 +117,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.93"
|
version = "1.0.94"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775"
|
checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arbitrary"
|
name = "arbitrary"
|
||||||
|
|
@ -366,9 +366,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.21"
|
version = "4.5.23"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f"
|
checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
|
|
@ -376,9 +376,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.21"
|
version = "4.5.23"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec"
|
checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
|
|
@ -429,9 +429,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_lex"
|
name = "clap_lex"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7"
|
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clipboard-win"
|
name = "clipboard-win"
|
||||||
|
|
@ -777,9 +777,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fdeflate"
|
name = "fdeflate"
|
||||||
version = "0.3.6"
|
version = "0.3.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "07c6f4c64c1d33a3111c4466f7365ebdcc37c5bd1ea0d62aae2e3d722aacbedb"
|
checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"simd-adler32",
|
"simd-adler32",
|
||||||
]
|
]
|
||||||
|
|
@ -2562,9 +2562,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.3.36"
|
version = "0.3.37"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
|
checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"deranged",
|
"deranged",
|
||||||
"itoa",
|
"itoa",
|
||||||
|
|
@ -2585,9 +2585,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time-macros"
|
name = "time-macros"
|
||||||
version = "0.2.18"
|
version = "0.2.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
|
checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-conv",
|
"num-conv",
|
||||||
"time-core",
|
"time-core",
|
||||||
|
|
@ -2605,9 +2605,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.41.1"
|
version = "1.42.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33"
|
checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
|
@ -2634,9 +2634,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-stream"
|
name = "tokio-stream"
|
||||||
version = "0.1.16"
|
version = "0.1.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1"
|
checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
|
|
@ -2645,9 +2645,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-util"
|
name = "tokio-util"
|
||||||
version = "0.7.12"
|
version = "0.7.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a"
|
checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
|
|
||||||
10
Cargo.toml
10
Cargo.toml
|
|
@ -11,10 +11,10 @@ strip = true
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
ansi-to-tui = "7.0.0"
|
ansi-to-tui = "7.0.0"
|
||||||
anyhow = "1.0.93"
|
anyhow = "1.0.94"
|
||||||
base64 = "0.22.1"
|
base64 = "0.22.1"
|
||||||
bitflags = "2.6.0"
|
bitflags = "2.6.0"
|
||||||
clap = { version = "4.5.21", features = [ "derive" ] }
|
clap = { version = "4.5.23", features = [ "derive" ] }
|
||||||
crossterm = { version = "0.28.1", features = [ "event-stream" ] }
|
crossterm = { version = "0.28.1", features = [ "event-stream" ] }
|
||||||
dirs = "5.0.1"
|
dirs = "5.0.1"
|
||||||
futures = "0.3.31"
|
futures = "0.3.31"
|
||||||
|
|
@ -29,9 +29,9 @@ scopeguard = "1.2.0"
|
||||||
serde = { version = "1.0.215", features = [ "derive" ] }
|
serde = { version = "1.0.215", features = [ "derive" ] }
|
||||||
serde_json = "1.0.133"
|
serde_json = "1.0.133"
|
||||||
shell-words = "1.1.0"
|
shell-words = "1.1.0"
|
||||||
tokio = { version = "1.41.1", features = [ "full" ] }
|
tokio = { version = "1.42.0", features = [ "full" ] }
|
||||||
tokio-stream = "0.1.16"
|
tokio-stream = "0.1.17"
|
||||||
tokio-util = "0.7.12"
|
tokio-util = "0.7.13"
|
||||||
tracing = { version = "0.1.41", features = [ "max_level_debug", "release_max_level_debug" ] }
|
tracing = { version = "0.1.41", features = [ "max_level_debug", "release_max_level_debug" ] }
|
||||||
unicode-width = "0.2.0"
|
unicode-width = "0.2.0"
|
||||||
uzers = "0.12.1"
|
uzers = "0.12.1"
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@ use std::mem;
|
||||||
|
|
||||||
use crossterm::terminal::WindowSize;
|
use crossterm::terminal::WindowSize;
|
||||||
|
|
||||||
|
use crate::EMULATOR;
|
||||||
|
|
||||||
pub struct Dimension;
|
pub struct Dimension;
|
||||||
|
|
||||||
impl Dimension {
|
impl Dimension {
|
||||||
|
|
@ -27,9 +29,10 @@ impl Dimension {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn ratio() -> Option<(f64, f64)> {
|
pub fn ratio() -> Option<(f64, f64)> {
|
||||||
let s = Self::available();
|
let s = Self::available();
|
||||||
if s.width == 0 || s.height == 0 {
|
Some(if s.width == 0 || s.height == 0 {
|
||||||
return None;
|
(EMULATOR.cell_size?.0 as f64, EMULATOR.cell_size?.1 as f64)
|
||||||
}
|
} else {
|
||||||
Some((f64::from(s.width) / f64::from(s.columns), f64::from(s.height) / f64::from(s.rows)))
|
(f64::from(s.width) / f64::from(s.columns), f64::from(s.height) / f64::from(s.rows))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,18 +11,21 @@ use crate::{Adapter, Brand, Mux, TMUX, Unknown};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct Emulator {
|
pub struct Emulator {
|
||||||
pub kind: Either<Brand, Unknown>,
|
pub kind: Either<Brand, Unknown>,
|
||||||
pub light: bool,
|
pub light: bool,
|
||||||
|
pub cell_size: Option<(u16, u16)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Emulator {
|
impl Default for Emulator {
|
||||||
fn default() -> Self { Self { kind: Either::Right(Unknown::default()), light: false } }
|
fn default() -> Self {
|
||||||
|
Self { kind: Either::Right(Unknown::default()), light: false, cell_size: None }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Emulator {
|
impl Emulator {
|
||||||
pub fn detect() -> Self {
|
pub fn detect() -> Self {
|
||||||
if let Some(brand) = Brand::from_env() {
|
if let Some(brand) = Brand::from_env() {
|
||||||
Self { kind: Either::Left(brand), light: Self::detect_base().unwrap_or_default().light }
|
Self { kind: Either::Left(brand), ..Self::detect_base().unwrap_or_default() }
|
||||||
} else {
|
} else {
|
||||||
Self::detect_full().unwrap_or_default()
|
Self::detect_full().unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
@ -37,6 +40,7 @@ impl Emulator {
|
||||||
SavePosition,
|
SavePosition,
|
||||||
Print(Mux::csi("\x1b_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA\x1b\\")), // Detect KGP
|
Print(Mux::csi("\x1b_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA\x1b\\")), // Detect KGP
|
||||||
Print(Mux::csi("\x1b[>q")), // Request terminal version
|
Print(Mux::csi("\x1b[>q")), // Request terminal version
|
||||||
|
Print("\x1b[16t"), // Request cell size
|
||||||
Print("\x1b]11;?\x07"), // Request background color
|
Print("\x1b]11;?\x07"), // Request background color
|
||||||
Print(Mux::csi("\x1b[0c")), // Request device attributes
|
Print(Mux::csi("\x1b[0c")), // Request device attributes
|
||||||
RestorePosition
|
RestorePosition
|
||||||
|
|
@ -52,7 +56,11 @@ impl Emulator {
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Self { kind, light: Self::light_bg(&resp).unwrap_or_default() })
|
Ok(Self {
|
||||||
|
kind,
|
||||||
|
light: Self::light_bg(&resp).unwrap_or_default(),
|
||||||
|
cell_size: Self::cell_size(&resp),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn adapters(self) -> &'static [Adapter] {
|
pub fn adapters(self) -> &'static [Adapter] {
|
||||||
|
|
@ -117,7 +125,7 @@ impl Emulator {
|
||||||
match timeout(Duration::from_secs(10), read).await {
|
match timeout(Duration::from_secs(10), read).await {
|
||||||
Err(e) => error!("read_until_da1 timed out: {buf:?}, error: {e:?}"),
|
Err(e) => error!("read_until_da1 timed out: {buf:?}, error: {e:?}"),
|
||||||
Ok(Err(e)) => error!("read_until_da1 failed: {buf:?}, error: {e:?}"),
|
Ok(Err(e)) => error!("read_until_da1 failed: {buf:?}, error: {e:?}"),
|
||||||
Ok(Ok(())) => {}
|
Ok(Ok(())) => debug!("read_until_da1: {buf:?}"),
|
||||||
}
|
}
|
||||||
String::from_utf8_lossy(&buf).into_owned()
|
String::from_utf8_lossy(&buf).into_owned()
|
||||||
}
|
}
|
||||||
|
|
@ -128,12 +136,30 @@ impl Emulator {
|
||||||
|
|
||||||
execute!(
|
execute!(
|
||||||
LineWriter::new(stderr()),
|
LineWriter::new(stderr()),
|
||||||
|
Print("\x1b[16t"), // Request cell size
|
||||||
Print("\x1b]11;?\x07"), // Request background color
|
Print("\x1b]11;?\x07"), // Request background color
|
||||||
Print(Mux::csi("\x1b[0c")), // Request device attributes
|
Print(Mux::csi("\x1b[0c")), // Request device attributes
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let resp = futures::executor::block_on(Self::read_until_da1());
|
let resp = futures::executor::block_on(Self::read_until_da1());
|
||||||
Ok(Self { light: Self::light_bg(&resp).unwrap_or_default(), ..Default::default() })
|
Ok(Self {
|
||||||
|
light: Self::light_bg(&resp).unwrap_or_default(),
|
||||||
|
cell_size: Self::cell_size(&resp),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cell_size(resp: &str) -> Option<(u16, u16)> {
|
||||||
|
let b = resp.split_at(resp.find("\x1b[6;")? + 4).1.as_bytes();
|
||||||
|
|
||||||
|
let h: Vec<_> = b.iter().copied().take_while(|&c| c.is_ascii_digit()).collect();
|
||||||
|
b.get(h.len()).filter(|&&c| c == b';')?;
|
||||||
|
|
||||||
|
let w: Vec<_> = b[h.len() + 1..].iter().copied().take_while(|&c| c.is_ascii_digit()).collect();
|
||||||
|
b.get(h.len() + 1 + w.len()).filter(|&&c| c == b't')?;
|
||||||
|
|
||||||
|
let (w, h) = unsafe { (String::from_utf8_unchecked(w), String::from_utf8_unchecked(h)) };
|
||||||
|
Some((w.parse().ok()?, h.parse().ok()?))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn light_bg(resp: &str) -> Result<bool> {
|
fn light_bg(resp: &str) -> Result<bool> {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue