mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
feat: Chafa integration (#1066)
This commit is contained in:
parent
a68e151194
commit
7177317465
12 changed files with 170 additions and 91 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -2693,6 +2693,7 @@ checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
|
||||||
name = "yazi-adaptor"
|
name = "yazi-adaptor"
|
||||||
version = "0.2.5"
|
version = "0.2.5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"ansi-to-tui",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ yazi-config = { path = "../yazi-config", version = "0.2.5" }
|
||||||
yazi-shared = { path = "../yazi-shared", version = "0.2.5" }
|
yazi-shared = { path = "../yazi-shared", version = "0.2.5" }
|
||||||
|
|
||||||
# External dependencies
|
# External dependencies
|
||||||
|
ansi-to-tui = "3.1.0"
|
||||||
anyhow = "1.0.86"
|
anyhow = "1.0.86"
|
||||||
arc-swap = "1.7.1"
|
arc-swap = "1.7.1"
|
||||||
base64 = "0.22.1"
|
base64 = "0.22.1"
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@ use std::{env, fmt::Display, path::Path, sync::Arc};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
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;
|
||||||
|
|
||||||
use super::{Iterm2, Kitty, KittyOld};
|
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)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
pub enum Adaptor {
|
pub enum Adaptor {
|
||||||
|
|
@ -36,48 +36,39 @@ impl Display for Adaptor {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Adaptor {
|
impl Adaptor {
|
||||||
pub async fn image_show(self, path: &Path, rect: Rect) -> Result<(u32, u32)> {
|
pub async fn image_show(self, path: &Path, max: Rect) -> Result<Rect> {
|
||||||
match self {
|
match self {
|
||||||
Self::Kitty => Kitty::image_show(path, rect).await,
|
Self::Kitty => Kitty::image_show(path, max).await,
|
||||||
Self::KittyOld => KittyOld::image_show(path, rect).await,
|
Self::KittyOld => KittyOld::image_show(path, max).await,
|
||||||
Self::Iterm2 => Iterm2::image_show(path, rect).await,
|
Self::Iterm2 => Iterm2::image_show(path, max).await,
|
||||||
Self::Sixel => Sixel::image_show(path, rect).await,
|
Self::Sixel => Sixel::image_show(path, max).await,
|
||||||
_ => Ueberzug::image_show(path, rect).await,
|
Self::X11 | Self::Wayland => Ueberzug::image_show(path, max).await,
|
||||||
|
Self::Chafa => Chafa::image_show(path, max).await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn image_hide(self) -> Result<()> {
|
pub fn image_hide(self) -> Result<()> {
|
||||||
if let Some(rect) = SHOWN.swap(None) { self.image_erase(*rect) } else { Ok(()) }
|
if let Some(area) = SHOWN.swap(None) { self.image_erase(*area) } else { Ok(()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn image_erase(self, rect: Rect) -> Result<()> {
|
pub fn image_erase(self, area: Rect) -> Result<()> {
|
||||||
match self {
|
match self {
|
||||||
Self::Kitty => Kitty::image_erase(rect),
|
Self::Kitty => Kitty::image_erase(area),
|
||||||
Self::Iterm2 => Iterm2::image_erase(rect),
|
Self::Iterm2 => Iterm2::image_erase(area),
|
||||||
Self::KittyOld => KittyOld::image_erase(),
|
Self::KittyOld => KittyOld::image_erase(area),
|
||||||
Self::Sixel => Sixel::image_erase(rect),
|
Self::Sixel => Sixel::image_erase(area),
|
||||||
_ => Ueberzug::image_erase(rect),
|
Self::X11 | Self::Wayland => Ueberzug::image_erase(area),
|
||||||
|
Self::Chafa => Chafa::image_erase(area),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn shown_load(self) -> Option<Rect> { SHOWN.load_full().map(|r| *r) }
|
pub fn shown_load(self) -> Option<Rect> { SHOWN.load_full().map(|r| *r) }
|
||||||
|
|
||||||
pub(super) fn start(self) { Ueberzug::start(self); }
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn shown_store(rect: Rect, size: (u32, u32)) {
|
pub(super) fn shown_store(area: Rect) { SHOWN.store(Some(Arc::new(area))); }
|
||||||
SHOWN.store(Some(Arc::new(
|
|
||||||
Term::ratio()
|
pub(super) fn start(self) { Ueberzug::start(self); }
|
||||||
.map(|(r1, r2)| 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,
|
|
||||||
})
|
|
||||||
.unwrap_or(rect),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn needs_ueberzug(self) -> bool {
|
pub(super) fn needs_ueberzug(self) -> bool {
|
||||||
|
|
|
||||||
76
yazi-adaptor/src/chafa.rs
Normal file
76
yazi-adaptor/src/chafa.rs
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
use std::{io::Write, path::Path, process::Stdio};
|
||||||
|
|
||||||
|
use ansi_to_tui::IntoText;
|
||||||
|
use anyhow::{bail, Result};
|
||||||
|
use ratatui::layout::Rect;
|
||||||
|
use tokio::process::Command;
|
||||||
|
use yazi_shared::term::Term;
|
||||||
|
|
||||||
|
use crate::Adaptor;
|
||||||
|
|
||||||
|
pub(super) struct Chafa;
|
||||||
|
|
||||||
|
impl Chafa {
|
||||||
|
pub(super) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
|
||||||
|
let output = Command::new("chafa")
|
||||||
|
.args([
|
||||||
|
"-f",
|
||||||
|
"symbols",
|
||||||
|
"--relative",
|
||||||
|
"off",
|
||||||
|
"--polite",
|
||||||
|
"on",
|
||||||
|
"--passthrough",
|
||||||
|
"none",
|
||||||
|
"--animate",
|
||||||
|
"off",
|
||||||
|
"--view-size",
|
||||||
|
])
|
||||||
|
.arg(format!("{}x{}", max.width, max.height))
|
||||||
|
.arg(path)
|
||||||
|
.stdin(Stdio::null())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.stderr(Stdio::null())
|
||||||
|
.kill_on_drop(true)
|
||||||
|
.output()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
bail!("chafa failed with status: {}", output.status);
|
||||||
|
} else if output.stdout.is_empty() {
|
||||||
|
bail!("chafa returned no output");
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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,
|
||||||
|
};
|
||||||
|
|
||||||
|
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(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(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -57,7 +57,7 @@ impl Image {
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
let (mut w, mut h) = Self::max_size(rect);
|
let (mut w, mut h) = Self::max_pixel(rect);
|
||||||
if (5..=8).contains(&orientation) {
|
if (5..=8).contains(&orientation) {
|
||||||
(w, h) = (h, w);
|
(w, h) = (h, w);
|
||||||
}
|
}
|
||||||
|
|
@ -76,7 +76,7 @@ impl Image {
|
||||||
.await?
|
.await?
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn max_size(rect: Rect) -> (u32, u32) {
|
pub(super) fn max_pixel(rect: Rect) -> (u32, u32) {
|
||||||
Term::ratio()
|
Term::ratio()
|
||||||
.map(|(r1, r2)| {
|
.map(|(r1, r2)| {
|
||||||
let (w, h) = ((rect.width as f64 * r1) as u32, (rect.height as f64 * r2) as u32);
|
let (w, h) = ((rect.width as f64 * r1) as u32, (rect.height as f64 * r2) as u32);
|
||||||
|
|
@ -85,6 +85,17 @@ impl Image {
|
||||||
.unwrap_or((PREVIEW.max_width, PREVIEW.max_height))
|
.unwrap_or((PREVIEW.max_width, PREVIEW.max_height))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn pixel_area(size: (u32, u32), rect: Rect) -> Rect {
|
||||||
|
Term::ratio()
|
||||||
|
.map(|(r1, r2)| 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,
|
||||||
|
})
|
||||||
|
.unwrap_or(rect)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn filter() -> FilterType {
|
fn filter() -> FilterType {
|
||||||
match PREVIEW.image_filter.as_str() {
|
match PREVIEW.image_filter.as_str() {
|
||||||
|
|
|
||||||
|
|
@ -12,24 +12,24 @@ use crate::{adaptor::Adaptor, CLOSE, START};
|
||||||
pub(super) struct Iterm2;
|
pub(super) struct Iterm2;
|
||||||
|
|
||||||
impl Iterm2 {
|
impl Iterm2 {
|
||||||
pub(super) async fn image_show(path: &Path, rect: Rect) -> Result<(u32, u32)> {
|
pub(super) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
|
||||||
let img = Image::downscale(path, rect).await?;
|
let img = Image::downscale(path, max).await?;
|
||||||
let size = (img.width(), img.height());
|
let area = Image::pixel_area((img.width(), img.height()), max);
|
||||||
let b = Self::encode(img).await?;
|
let b = Self::encode(img).await?;
|
||||||
|
|
||||||
Adaptor::Iterm2.image_hide()?;
|
Adaptor::Iterm2.image_hide()?;
|
||||||
Adaptor::shown_store(rect, size);
|
Adaptor::shown_store(area);
|
||||||
Term::move_lock((rect.x, rect.y), |stderr| {
|
Term::move_lock((max.x, max.y), |stderr| {
|
||||||
stderr.write_all(&b)?;
|
stderr.write_all(&b)?;
|
||||||
Ok(size)
|
Ok(area)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn image_erase(rect: Rect) -> Result<()> {
|
pub(super) fn image_erase(area: Rect) -> Result<()> {
|
||||||
let s = " ".repeat(rect.width as usize);
|
let s = " ".repeat(area.width as usize);
|
||||||
Term::move_lock((0, 0), |stderr| {
|
Term::move_lock((0, 0), |stderr| {
|
||||||
for y in rect.top()..rect.bottom() {
|
for y in area.top()..area.bottom() {
|
||||||
Term::move_to(stderr, rect.x, y)?;
|
Term::move_to(stderr, area.x, y)?;
|
||||||
write!(stderr, "{s}")?;
|
write!(stderr, "{s}")?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -313,27 +313,27 @@ static DIACRITICS: [char; 297] = [
|
||||||
pub(super) struct Kitty;
|
pub(super) struct Kitty;
|
||||||
|
|
||||||
impl Kitty {
|
impl Kitty {
|
||||||
pub(super) async fn image_show(path: &Path, rect: Rect) -> Result<(u32, u32)> {
|
pub(super) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
|
||||||
let img = Image::downscale(path, rect).await?;
|
let img = Image::downscale(path, max).await?;
|
||||||
let size = (img.width(), img.height());
|
let area = Image::pixel_area((img.width(), img.height()), max);
|
||||||
|
|
||||||
let b1 = Self::encode(img).await?;
|
let b1 = Self::encode(img).await?;
|
||||||
let b2 = Self::place(&rect)?;
|
let b2 = Self::place(&area)?;
|
||||||
|
|
||||||
Adaptor::Kitty.image_hide()?;
|
Adaptor::Kitty.image_hide()?;
|
||||||
Adaptor::shown_store(rect, size);
|
Adaptor::shown_store(area);
|
||||||
Term::move_lock((rect.x, rect.y), |stderr| {
|
Term::move_lock((area.x, area.y), |stderr| {
|
||||||
stderr.write_all(&b1)?;
|
stderr.write_all(&b1)?;
|
||||||
stderr.write_all(&b2)?;
|
stderr.write_all(&b2)?;
|
||||||
Ok(size)
|
Ok(area)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn image_erase(rect: Rect) -> Result<()> {
|
pub(super) fn image_erase(area: Rect) -> Result<()> {
|
||||||
let s = " ".repeat(rect.width as usize);
|
let s = " ".repeat(area.width as usize);
|
||||||
Term::move_lock((0, 0), |stderr| {
|
Term::move_lock((0, 0), |stderr| {
|
||||||
for y in rect.top()..rect.bottom() {
|
for y in area.top()..area.bottom() {
|
||||||
Term::move_to(stderr, rect.x, y)?;
|
Term::move_to(stderr, area.x, y)?;
|
||||||
write!(stderr, "{s}")?;
|
write!(stderr, "{s}")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -388,11 +388,11 @@ impl Kitty {
|
||||||
.await?
|
.await?
|
||||||
}
|
}
|
||||||
|
|
||||||
fn place(rect: &Rect) -> Result<Vec<u8>> {
|
fn place(area: &Rect) -> Result<Vec<u8>> {
|
||||||
let mut buf = Vec::with_capacity(rect.width as usize * rect.height as usize * 3 + 50);
|
let mut buf = Vec::with_capacity(area.width as usize * area.height as usize * 3 + 50);
|
||||||
for y in 0..rect.height {
|
for y in 0..area.height {
|
||||||
write!(buf, "\x1b[{};{}H\x1b[38;5;1m", rect.y + y + 1, rect.x + 1)?;
|
write!(buf, "\x1b[{};{}H\x1b[38;5;1m", area.y + y + 1, area.x + 1)?;
|
||||||
for x in 0..rect.width {
|
for x in 0..area.width {
|
||||||
write!(buf, "\u{10EEEE}")?;
|
write!(buf, "\u{10EEEE}")?;
|
||||||
write!(buf, "{}", *DIACRITICS.get(y as usize).unwrap_or(&DIACRITICS[0]))?;
|
write!(buf, "{}", *DIACRITICS.get(y as usize).unwrap_or(&DIACRITICS[0]))?;
|
||||||
write!(buf, "{}", *DIACRITICS.get(x as usize).unwrap_or(&DIACRITICS[0]))?;
|
write!(buf, "{}", *DIACRITICS.get(x as usize).unwrap_or(&DIACRITICS[0]))?;
|
||||||
|
|
|
||||||
|
|
@ -13,21 +13,21 @@ use crate::{adaptor::Adaptor, CLOSE, ESCAPE, START};
|
||||||
pub(super) struct KittyOld;
|
pub(super) struct KittyOld;
|
||||||
|
|
||||||
impl KittyOld {
|
impl KittyOld {
|
||||||
pub(super) async fn image_show(path: &Path, rect: Rect) -> Result<(u32, u32)> {
|
pub(super) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
|
||||||
let img = Image::downscale(path, rect).await?;
|
let img = Image::downscale(path, max).await?;
|
||||||
let size = (img.width(), img.height());
|
let area = Image::pixel_area((img.width(), img.height()), max);
|
||||||
let b = Self::encode(img).await?;
|
let b = Self::encode(img).await?;
|
||||||
|
|
||||||
Adaptor::KittyOld.image_hide()?;
|
Adaptor::KittyOld.image_hide()?;
|
||||||
Adaptor::shown_store(rect, size);
|
Adaptor::shown_store(area);
|
||||||
Term::move_lock((rect.x, rect.y), |stderr| {
|
Term::move_lock((area.x, area.y), |stderr| {
|
||||||
stderr.write_all(&b)?;
|
stderr.write_all(&b)?;
|
||||||
Ok(size)
|
Ok(area)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn image_erase() -> Result<()> {
|
pub(super) fn image_erase(_: Rect) -> Result<()> {
|
||||||
let mut stderr = LineWriter::new(stderr());
|
let mut stderr = LineWriter::new(stderr());
|
||||||
write!(stderr, "{}_Gq=1,a=d,d=A{}\\{}", START, ESCAPE, CLOSE)?;
|
write!(stderr, "{}_Gq=1,a=d,d=A{}\\{}", START, ESCAPE, CLOSE)?;
|
||||||
stderr.flush()?;
|
stderr.flush()?;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#![allow(clippy::unit_arg)]
|
#![allow(clippy::unit_arg)]
|
||||||
|
|
||||||
mod adaptor;
|
mod adaptor;
|
||||||
|
mod chafa;
|
||||||
mod emulator;
|
mod emulator;
|
||||||
mod image;
|
mod image;
|
||||||
mod iterm2;
|
mod iterm2;
|
||||||
|
|
@ -10,11 +11,13 @@ mod sixel;
|
||||||
mod ueberzug;
|
mod ueberzug;
|
||||||
|
|
||||||
pub use adaptor::*;
|
pub use adaptor::*;
|
||||||
|
use chafa::*;
|
||||||
pub use emulator::*;
|
pub use emulator::*;
|
||||||
use iterm2::*;
|
use iterm2::*;
|
||||||
use kitty::*;
|
use kitty::*;
|
||||||
use kitty_old::*;
|
use kitty_old::*;
|
||||||
use sixel::*;
|
use sixel::*;
|
||||||
|
use ueberzug::*;
|
||||||
use yazi_shared::{env_exists, RoCell};
|
use yazi_shared::{env_exists, RoCell};
|
||||||
|
|
||||||
pub use crate::image::*;
|
pub use crate::image::*;
|
||||||
|
|
|
||||||
|
|
@ -12,24 +12,24 @@ use crate::{adaptor::Adaptor, Image, CLOSE, ESCAPE, START};
|
||||||
pub(super) struct Sixel;
|
pub(super) struct Sixel;
|
||||||
|
|
||||||
impl Sixel {
|
impl Sixel {
|
||||||
pub(super) async fn image_show(path: &Path, rect: Rect) -> Result<(u32, u32)> {
|
pub(super) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
|
||||||
let img = Image::downscale(path, rect).await?;
|
let img = Image::downscale(path, max).await?;
|
||||||
let size = (img.width(), img.height());
|
let area = Image::pixel_area((img.width(), img.height()), max);
|
||||||
let b = Self::encode(img).await?;
|
let b = Self::encode(img).await?;
|
||||||
|
|
||||||
Adaptor::Sixel.image_hide()?;
|
Adaptor::Sixel.image_hide()?;
|
||||||
Adaptor::shown_store(rect, size);
|
Adaptor::shown_store(area);
|
||||||
Term::move_lock((rect.x, rect.y), |stderr| {
|
Term::move_lock((area.x, area.y), |stderr| {
|
||||||
stderr.write_all(&b)?;
|
stderr.write_all(&b)?;
|
||||||
Ok(size)
|
Ok(area)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn image_erase(rect: Rect) -> Result<()> {
|
pub(super) fn image_erase(area: Rect) -> Result<()> {
|
||||||
let s = " ".repeat(rect.width as usize);
|
let s = " ".repeat(area.width as usize);
|
||||||
Term::move_lock((0, 0), |stderr| {
|
Term::move_lock((0, 0), |stderr| {
|
||||||
for y in rect.top()..rect.bottom() {
|
for y in area.top()..area.bottom() {
|
||||||
Term::move_to(stderr, rect.x, y)?;
|
Term::move_to(stderr, area.x, y)?;
|
||||||
write!(stderr, "{s}")?;
|
write!(stderr, "{s}")?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -41,25 +41,20 @@ impl Ueberzug {
|
||||||
DEMON.init(Some(tx))
|
DEMON.init(Some(tx))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn image_show(path: &Path, rect: Rect) -> Result<(u32, u32)> {
|
pub(super) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
|
||||||
if let Some(tx) = &*DEMON {
|
let Some(tx) = &*DEMON else {
|
||||||
tx.send(Some((path.to_path_buf(), rect)))?;
|
|
||||||
Adaptor::shown_store(rect, (0, 0));
|
|
||||||
} else {
|
|
||||||
bail!("uninitialized ueberzugpp");
|
bail!("uninitialized ueberzugpp");
|
||||||
}
|
};
|
||||||
|
|
||||||
let path = path.to_owned();
|
let p = path.to_owned();
|
||||||
let ImageSize { width: w, height: h } =
|
let ImageSize { width: w, height: h } =
|
||||||
tokio::task::spawn_blocking(move || imagesize::size(path)).await??;
|
tokio::task::spawn_blocking(move || imagesize::size(p)).await??;
|
||||||
|
|
||||||
let (max_w, max_h) = Image::max_size(rect);
|
let area = Image::pixel_area((w as u32, h as u32), max);
|
||||||
if w <= max_w as usize && h <= max_h as usize {
|
tx.send(Some((path.to_owned(), area)))?;
|
||||||
return Ok((w as u32, h as u32));
|
|
||||||
}
|
|
||||||
|
|
||||||
let ratio = f64::min(max_w as f64 / w as f64, max_h as f64 / h as f64);
|
Adaptor::shown_store(area);
|
||||||
Ok(((w as f64 * ratio).round() as u32, (h as f64 * ratio).round() as u32))
|
Ok(area)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn image_erase(_: Rect) -> Result<()> {
|
pub(super) fn image_erase(_: Rect) -> Result<()> {
|
||||||
|
|
@ -77,6 +72,7 @@ impl Ueberzug {
|
||||||
.env("SPDLOG_LEVEL", if cfg!(debug_assertions) { "debug" } else { "" })
|
.env("SPDLOG_LEVEL", if cfg!(debug_assertions) { "debug" } else { "" })
|
||||||
.kill_on_drop(true)
|
.kill_on_drop(true)
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
|
.stdout(Stdio::null())
|
||||||
.stderr(Stdio::null())
|
.stderr(Stdio::null())
|
||||||
.spawn();
|
.spawn();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,15 @@ use mlua::{IntoLuaMulti, Lua, Table, Value};
|
||||||
use yazi_adaptor::{Image, ADAPTOR};
|
use yazi_adaptor::{Image, ADAPTOR};
|
||||||
|
|
||||||
use super::Utils;
|
use super::Utils;
|
||||||
use crate::{elements::RectRef, url::UrlRef};
|
use crate::{bindings::Cast, elements::{Rect, RectRef}, url::UrlRef};
|
||||||
|
|
||||||
impl Utils {
|
impl Utils {
|
||||||
pub(super) fn image(lua: &Lua, ya: &Table) -> mlua::Result<()> {
|
pub(super) fn image(lua: &Lua, ya: &Table) -> mlua::Result<()> {
|
||||||
ya.raw_set(
|
ya.raw_set(
|
||||||
"image_show",
|
"image_show",
|
||||||
lua.create_async_function(|lua, (url, rect): (UrlRef, RectRef)| async move {
|
lua.create_async_function(|lua, (url, rect): (UrlRef, RectRef)| async move {
|
||||||
if let Ok(size) = ADAPTOR.image_show(&url, *rect).await {
|
if let Ok(area) = ADAPTOR.image_show(&url, *rect).await {
|
||||||
size.into_lua_multi(lua)
|
Rect::cast(lua, area)?.into_lua_multi(lua)
|
||||||
} else {
|
} else {
|
||||||
Value::Nil.into_lua_multi(lua)
|
Value::Nil.into_lua_multi(lua)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue