feat: preview image over SSH

This commit is contained in:
sxyazi 2024-01-26 20:06:18 +08:00
parent c02d69590b
commit 8416ebb0f0
No known key found for this signature in database
3 changed files with 46 additions and 6 deletions

1
Cargo.lock generated
View file

@ -2623,6 +2623,7 @@ dependencies = [
"arc-swap", "arc-swap",
"base64", "base64",
"color_quant", "color_quant",
"crossterm",
"image", "image",
"imagesize", "imagesize",
"kamadak-exif", "kamadak-exif",

View file

@ -17,6 +17,7 @@ anyhow = "^1"
arc-swap = "^1" arc-swap = "^1"
base64 = "^0" base64 = "^0"
color_quant = "^1" color_quant = "^1"
crossterm = "^0"
image = "^0" image = "^0"
imagesize = "^0" imagesize = "^0"
kamadak-exif = "0" kamadak-exif = "0"

View file

@ -1,6 +1,7 @@
use std::{env, path::Path, sync::Arc}; use std::{env, io::{Read, Write}, path::Path, sync::Arc};
use anyhow::{anyhow, Result}; use anyhow::{anyhow, bail, Result};
use crossterm::terminal::{disable_raw_mode, enable_raw_mode};
use ratatui::layout::Rect; use ratatui::layout::Rect;
use tracing::warn; use tracing::warn;
use yazi_shared::{env_exists, term::Term}; use yazi_shared::{env_exists, term::Term};
@ -58,7 +59,7 @@ impl Adaptor {
None => warn!("[Adaptor] No special environment variables detected"), None => warn!("[Adaptor] No special environment variables detected"),
} }
let (term, program) = Self::term_program(); let (term, program) = Self::via_env();
match program.as_str() { match program.as_str() {
"iTerm.app" => return Emulator::Iterm2, "iTerm.app" => return Emulator::Iterm2,
"WezTerm" => return Emulator::WezTerm, "WezTerm" => return Emulator::WezTerm,
@ -77,7 +78,8 @@ impl Adaptor {
"xterm-ghostty" => return Emulator::Ghostty, "xterm-ghostty" => return Emulator::Ghostty,
_ => warn!("[Adaptor] Unknown TERM: {term}"), _ => warn!("[Adaptor] Unknown TERM: {term}"),
} }
Emulator::Unknown
Self::via_csi().unwrap_or(Emulator::Unknown)
} }
pub(super) fn detect() -> Self { pub(super) fn detect() -> Self {
@ -128,13 +130,13 @@ impl Adaptor {
Self::Chafa Self::Chafa
} }
pub(super) fn term_program() -> (String, String) { fn via_env() -> (String, String) {
fn tmux_env(name: &str) -> Result<String> { fn tmux_env(name: &str) -> Result<String> {
let output = std::process::Command::new("tmux").args(["show-environment", name]).output()?; let output = std::process::Command::new("tmux").args(["show-environment", name]).output()?;
String::from_utf8(output.stdout)? String::from_utf8(output.stdout)?
.trim() .trim()
.strip_prefix(&format!("{}=", name)) .strip_prefix(&format!("{name}="))
.map_or_else(|| Err(anyhow!("")), |s| Ok(s.to_string())) .map_or_else(|| Err(anyhow!("")), |s| Ok(s.to_string()))
} }
@ -148,6 +150,42 @@ impl Adaptor {
(term, program) (term, program)
} }
fn via_csi() -> Result<Emulator> {
enable_raw_mode()?;
std::io::stdout().write_all(b"\x1b[>q\x1b[c")?;
std::io::stdout().flush()?;
let mut stdin = std::io::stdin().lock();
let mut buf = String::with_capacity(100);
loop {
let mut c = [0; 1];
if stdin.read(&mut c)? == 0 {
break;
}
if c[0] == b'c' && buf.contains("\x1b[?") {
break;
}
buf.push(c[0] as char);
}
disable_raw_mode().ok();
let names = [
("kitty", Emulator::Kitty),
("Konsole", Emulator::Konsole),
("iTerm2", Emulator::Iterm2),
("WezTerm", Emulator::WezTerm),
("foot", Emulator::Foot),
("ghostty", Emulator::Ghostty),
];
for (name, emulator) in names.iter() {
if buf.contains(name) {
return Ok(*emulator);
}
}
Ok(Emulator::Unknown)
}
} }
impl ToString for Adaptor { impl ToString for Adaptor {