From 0ac06e0bd811acf0a9a282e1e5889776c0c458b6 Mon Sep 17 00:00:00 2001 From: sxyazi Date: Tue, 21 May 2024 02:38:41 +0800 Subject: [PATCH] .. --- Cargo.lock | 1 + yazi-adaptor/Cargo.toml | 1 + yazi-adaptor/src/adaptor.rs | 12 ++++--- yazi-adaptor/src/chafa.rs | 57 +++++++++++++++++++++------------- yazi-adaptor/src/kitty.rs | 2 +- yazi-adaptor/src/kitty_old.rs | 2 +- yazi-adaptor/src/lib.rs | 2 ++ yazi-adaptor/src/ueberzug.rs | 2 +- yazi-plugin/src/utils/image.rs | 6 ++-- 9 files changed, 52 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 87ea2830..ca66e99d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2693,6 +2693,7 @@ checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" name = "yazi-adaptor" version = "0.2.5" dependencies = [ + "ansi-to-tui", "anyhow", "arc-swap", "base64 0.22.1", diff --git a/yazi-adaptor/Cargo.toml b/yazi-adaptor/Cargo.toml index 21e584d7..ca61b09f 100644 --- a/yazi-adaptor/Cargo.toml +++ b/yazi-adaptor/Cargo.toml @@ -13,6 +13,7 @@ yazi-config = { path = "../yazi-config", version = "0.2.5" } yazi-shared = { path = "../yazi-shared", version = "0.2.5" } # External dependencies +ansi-to-tui = "3.1.0" anyhow = "1.0.86" arc-swap = "1.7.1" base64 = "0.22.1" diff --git a/yazi-adaptor/src/adaptor.rs b/yazi-adaptor/src/adaptor.rs index b85b5afc..954d43dc 100644 --- a/yazi-adaptor/src/adaptor.rs +++ b/yazi-adaptor/src/adaptor.rs @@ -3,10 +3,10 @@ use std::{env, fmt::Display, path::Path, sync::Arc}; use anyhow::Result; use ratatui::layout::Rect; use tracing::warn; -use yazi_shared::{env_exists, term::Term}; +use yazi_shared::env_exists; use super::{Iterm2, Kitty, KittyOld}; -use crate::{ueberzug::Ueberzug, Emulator, Sixel, SHOWN, TMUX}; +use crate::{Chafa, Emulator, Sixel, Ueberzug, SHOWN, TMUX}; #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum Adaptor { @@ -42,7 +42,8 @@ impl Adaptor { Self::KittyOld => KittyOld::image_show(path, max).await, Self::Iterm2 => Iterm2::image_show(path, max).await, Self::Sixel => Sixel::image_show(path, max).await, - _ => Ueberzug::image_show(path, max).await, + Self::X11 | Self::Wayland => Ueberzug::image_show(path, max).await, + Self::Chafa => Chafa::image_show(path, max).await, } } @@ -54,9 +55,10 @@ impl Adaptor { match self { Self::Kitty => Kitty::image_erase(area), Self::Iterm2 => Iterm2::image_erase(area), - Self::KittyOld => KittyOld::image_erase(), + Self::KittyOld => KittyOld::image_erase(area), Self::Sixel => Sixel::image_erase(area), - _ => Ueberzug::image_erase(area), + Self::X11 | Self::Wayland => Ueberzug::image_erase(area), + Self::Chafa => Chafa::image_erase(area), } } diff --git a/yazi-adaptor/src/chafa.rs b/yazi-adaptor/src/chafa.rs index 06086335..9217a470 100644 --- a/yazi-adaptor/src/chafa.rs +++ b/yazi-adaptor/src/chafa.rs @@ -1,20 +1,17 @@ -use std::{path::Path, process::Stdio}; +use std::{io::Write, path::Path, process::Stdio}; +use ansi_to_tui::IntoText; use anyhow::{bail, Result}; -use imagesize::ImageSize; use ratatui::layout::Rect; use tokio::process::Command; +use yazi_shared::term::Term; -use crate::Image; +use crate::Adaptor; pub(super) struct Chafa; impl Chafa { - pub(super) async fn image_show(path: &Path, rect: Rect) -> Result<(u32, u32)> { - let p = path.to_owned(); - let ImageSize { width: w, height: h } = - tokio::task::spawn_blocking(move || imagesize::size(p)).await??; - + pub(super) async fn image_show(path: &Path, max: Rect) -> Result { let output = Command::new("chafa") .args([ "-f", @@ -29,7 +26,7 @@ impl Chafa { "off", "--view-size", ]) - .arg(format!("{}x{}", rect.width, rect.height)) + .arg(format!("{}x{}", max.width, max.height)) .arg(path) .stdin(Stdio::null()) .stderr(Stdio::null()) @@ -40,24 +37,40 @@ impl Chafa { if !output.status.success() { bail!("chafa failed with status: {}", output.status); + } else if output.stdout.is_empty() { + bail!("chafa returned no output"); } - // output.stdout + let lines: Vec<_> = output.stdout.split(|&b| b == b'\n').collect(); + let Ok(Some(first)) = lines[0].into_text().map(|mut t| t.lines.pop()) else { + bail!("failed to parse chafa output"); + }; - let (max_w, max_h) = Image::max_pixel(rect); - if w <= max_w as usize && h <= max_h as usize { - return Ok((w as u32, h as u32)); - } + let area = Rect { + x: max.x, + y: max.y, + width: first.spans.into_iter().map(|s| s.content.chars().count() as u16).sum(), + height: lines.len() as u16, + }; - let ratio = f64::min(max_w as f64 / w as f64, max_h as f64 / h as f64); - Ok(((w as f64 * ratio).round() as u32, (h as f64 * ratio).round() as u32)) + Adaptor::shown_store(area); + Term::move_lock((max.x, max.y), |stderr| { + for (i, line) in lines.into_iter().enumerate() { + stderr.write_all(line)?; + Term::move_to(stderr, max.x, max.y + i as u16 + 1)?; + } + Ok(area) + }) } - pub(super) fn image_erase(_: Rect) -> Result<()> { - if let Some(tx) = &*DEMON { - Ok(tx.send(None)?) - } else { - bail!("uninitialized ueberzugpp"); - } + pub(super) fn image_erase(area: Rect) -> Result<()> { + let s = " ".repeat(area.width as usize); + Term::move_lock((0, 0), |stderr| { + for y in area.top()..area.bottom() { + Term::move_to(stderr, area.x, y)?; + write!(stderr, "{s}")?; + } + Ok(()) + }) } } diff --git a/yazi-adaptor/src/kitty.rs b/yazi-adaptor/src/kitty.rs index cd219343..46b6814d 100644 --- a/yazi-adaptor/src/kitty.rs +++ b/yazi-adaptor/src/kitty.rs @@ -3,7 +3,7 @@ use std::{io::Write, path::Path}; use anyhow::Result; use base64::{engine::general_purpose, Engine}; -use image::{DynamicImage, GenericImageView}; +use image::DynamicImage; use ratatui::layout::Rect; use yazi_shared::term::Term; diff --git a/yazi-adaptor/src/kitty_old.rs b/yazi-adaptor/src/kitty_old.rs index 03e878b2..1e2250e5 100644 --- a/yazi-adaptor/src/kitty_old.rs +++ b/yazi-adaptor/src/kitty_old.rs @@ -27,7 +27,7 @@ impl KittyOld { } #[inline] - pub(super) fn image_erase() -> Result<()> { + pub(super) fn image_erase(_: Rect) -> Result<()> { let mut stderr = LineWriter::new(stderr()); write!(stderr, "{}_Gq=1,a=d,d=A{}\\{}", START, ESCAPE, CLOSE)?; stderr.flush()?; diff --git a/yazi-adaptor/src/lib.rs b/yazi-adaptor/src/lib.rs index 00cc11f1..65675fc7 100644 --- a/yazi-adaptor/src/lib.rs +++ b/yazi-adaptor/src/lib.rs @@ -11,11 +11,13 @@ mod sixel; mod ueberzug; pub use adaptor::*; +use chafa::*; pub use emulator::*; use iterm2::*; use kitty::*; use kitty_old::*; use sixel::*; +use ueberzug::*; use yazi_shared::{env_exists, RoCell}; pub use crate::image::*; diff --git a/yazi-adaptor/src/ueberzug.rs b/yazi-adaptor/src/ueberzug.rs index 06c2fc6b..25224321 100644 --- a/yazi-adaptor/src/ueberzug.rs +++ b/yazi-adaptor/src/ueberzug.rs @@ -51,7 +51,7 @@ impl Ueberzug { tokio::task::spawn_blocking(move || imagesize::size(p)).await??; let area = Image::pixel_area((w as u32, h as u32), max); - tx.send(Some((path.to_owned(), max)))?; + tx.send(Some((path.to_owned(), area)))?; Adaptor::shown_store(area); Ok(area) diff --git a/yazi-plugin/src/utils/image.rs b/yazi-plugin/src/utils/image.rs index 9a13e684..acb72bf4 100644 --- a/yazi-plugin/src/utils/image.rs +++ b/yazi-plugin/src/utils/image.rs @@ -2,15 +2,15 @@ use mlua::{IntoLuaMulti, Lua, Table, Value}; use yazi_adaptor::{Image, ADAPTOR}; use super::Utils; -use crate::{elements::RectRef, url::UrlRef}; +use crate::{bindings::Cast, elements::{Rect, RectRef}, url::UrlRef}; impl Utils { pub(super) fn image(lua: &Lua, ya: &Table) -> mlua::Result<()> { ya.raw_set( "image_show", lua.create_async_function(|lua, (url, rect): (UrlRef, RectRef)| async move { - if let Ok(size) = ADAPTOR.image_show(&url, *rect).await { - size.into_lua_multi(lua) + if let Ok(area) = ADAPTOR.image_show(&url, *rect).await { + Rect::cast(lua, area)?.into_lua_multi(lua) } else { Value::Nil.into_lua_multi(lua) }