From 613d7a92da09698978ae0e98b4f66a1ae36b122e Mon Sep 17 00:00:00 2001 From: itsjunetime Date: Sun, 8 Feb 2026 23:43:56 -0600 Subject: [PATCH] Maybe fixed tmux for kitty --- Cargo.lock | 11 +++---- Cargo.toml | 5 ++-- ratatui-image | 2 +- src/kitty.rs | 81 +++++++++++++++++++++++++++++++++++---------------- src/main.rs | 23 ++++++++++----- src/tui.rs | 7 +++-- 6 files changed, 86 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 518e284..a9d4aab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1526,9 +1526,9 @@ dependencies = [ [[package]] name = "kittage" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be6b61789e2841119b210569d4acd950d47dae805f8d3235190d28cb40677632" +checksum = "c81351cedc5b58dec7e5131ab6cb35c437bfeed6b4a16c9faf019a993a4056c9" dependencies = [ "base64-simd", "crossterm", @@ -2398,7 +2398,7 @@ dependencies = [ [[package]] name = "ratatui-image" version = "10.0.5" -source = "git+https://github.com/itsjunetime/ratatui-image.git?rev=a276a87cb8e2976442c6cc59db831db81551da89#a276a87cb8e2976442c6cc59db831db81551da89" +source = "git+https://github.com/itsjunetime/ratatui-image.git?rev=8ad154a219c1e4832a378bd07aaf39b3ddff959b#8ad154a219c1e4832a378bd07aaf39b3ddff959b" dependencies = [ "base64-simd", "icy_sixel", @@ -2869,6 +2869,7 @@ dependencies = [ "ratatui", "ratatui-image", "rayon", + "smallvec", "tokio", "xflags", ] @@ -3535,9 +3536,9 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winmmf" -version = "0.5.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71505e812c82834e7a5a31481592e5c244d7f9177a28fb88817dfa8360b40021" +checksum = "859506e40270a5938da41bb216376bae2e681ed8027392bddc068d62d74243f8" dependencies = [ "fixedstr", "microseh", diff --git a/Cargo.toml b/Cargo.toml index b0b0963..b01498e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ name = "tdf" ratatui = { git = "https://github.com/itsjunetime/ratatui.git", rev = "720ac2d0cad1ac6424364fea74856fec9c100cb1", default-features = false, features = [ "crossterm", "layout-cache" ] } # ratatui = { path = "./ratatui/ratatui/" } # We're using this to have the vb64 feature (for faster base64 encoding, since that does take up a good bit of time when converting images to the `Protocol`. It also just includes a few more features that I'm waiting on main to upstream -ratatui-image = { git = "https://github.com/itsjunetime/ratatui-image.git", rev = "a276a87cb8e2976442c6cc59db831db81551da89", default-features = false } +ratatui-image = { git = "https://github.com/itsjunetime/ratatui-image.git", rev = "8ad154a219c1e4832a378bd07aaf39b3ddff959b", default-features = false } # ratatui-image = { path = "./ratatui-image", default-features = false } crossterm = { version = "0.29.0", features = ["event-stream"] } # crossterm = { path = "../crossterm", features = ["event-stream"] } @@ -41,10 +41,11 @@ nix = { version = "0.31.0", features = ["signal"] } mupdf = { git = "https://github.com/messense/mupdf-rs.git", rev = "2e0fae910fac8048c7008211fc4d3b9f5d227a07", default-features = false, features = ["svg", "system-fonts", "img"] } rayon = { version = "1", default-features = false } # kittage = { path = "../kittage/", features = ["crossterm-tokio", "image-crate", "log"] } -kittage = { version = "0.1.1", features = ["crossterm-tokio", "image-crate", "log"] } +kittage = { version = "0.1.2", features = ["crossterm-tokio", "image-crate", "log"] } memmap2 = "0" csscolorparser = { version = "0.8.0", default-features = false } debounce = "0.2.2" +smallvec = "1" # logging log = "0.4.27" diff --git a/ratatui-image b/ratatui-image index a276a87..8ad154a 160000 --- a/ratatui-image +++ b/ratatui-image @@ -1 +1 @@ -Subproject commit a276a87cb8e2976442c6cc59db831db81551da89 +Subproject commit 8ad154a219c1e4832a378bd07aaf39b3ddff959b diff --git a/src/kitty.rs b/src/kitty.rs index f97842b..d2bfba9 100644 --- a/src/kitty.rs +++ b/src/kitty.rs @@ -14,9 +14,11 @@ use kittage::{ display::{CursorMovementPolicy, DisplayConfig, DisplayLocation}, error::TransmitError, image::Image, - medium::Medium + medium::Medium, + tmux::TmuxWriter }; use ratatui::layout::Position; +use smallvec::SmallVec; use crate::converter::MaybeTransferred; @@ -30,7 +32,7 @@ pub struct KittyReadyToDisplay<'tui> { pub enum KittyDisplay<'tui> { NoChange, ClearImages, - DisplayImages(Vec>) + DisplayImages(SmallVec<[KittyReadyToDisplay<'tui>; 1]>) } pub struct DbgWriter { @@ -62,6 +64,7 @@ impl Write for DbgWriter { pub async fn run_action<'es>( action: Action<'_, '_>, + is_tmux: bool, ev_stream: &'es mut EventStream ) -> Result::Error>> { let writer = DbgWriter { @@ -69,13 +72,21 @@ pub async fn run_action<'es>( #[cfg(debug_assertions)] buf: String::new() }; - action - .execute_async(writer, ev_stream) - .await - .map(|(_, i)| i) + + if is_tmux { + action + .execute_async(TmuxWriter::new(writer), ev_stream) + .await + .map(|(_, i)| i) + } else { + action + .execute_async(writer, ev_stream) + .await + .map(|(_, i)| i) + } } -pub async fn do_shms_work(ev_stream: &mut EventStream) -> bool { +pub async fn do_shms_work(is_tmux: bool, ev_stream: &mut EventStream) -> bool { let img = DynamicImage::new_rgb8(1, 1); let pid = std::process::id(); let Ok(mut k_img) = kittage::image::Image::shm_from(img, &format!("tdf_test_{pid}")) else { @@ -87,24 +98,42 @@ pub async fn do_shms_work(ev_stream: &mut EventStream) -> bool { enable_raw_mode().unwrap(); - let res = run_action(Action::Query(&k_img), ev_stream).await; + let res = run_action(Action::Query(&k_img), is_tmux, ev_stream).await; disable_raw_mode().unwrap(); res.is_ok() } +pub struct DisplayErr { + pub page_nums_failed_to_transfer: Vec, + pub user_facing_err: &'static str, + pub source: E +} + +impl DisplayErr { + pub fn new( + page_nums_failed_to_transfer: Vec, + user_facing_err: &'static str, + source: E + ) -> Self { + Self { + page_nums_failed_to_transfer, + user_facing_err, + source + } + } + + fn new_no_imgs(user_facing_err: &'static str, source: E) -> Self { + Self::new(vec![], user_facing_err, source) + } +} + pub async fn display_kitty_images<'es>( display: KittyDisplay<'_>, + is_tmux: bool, ev_stream: &'es mut EventStream -) -> Result< - (), - ( - Vec, - &'static str, - TransmitError<<&'es mut EventStream as AsyncInputReader>::Error> - ) -> { +) -> Result<(), DisplayErr::Error>>> { let images = match display { KittyDisplay::NoChange => return Ok(()), KittyDisplay::DisplayImages(_) | KittyDisplay::ClearImages => { @@ -113,10 +142,11 @@ pub async fn display_kitty_images<'es>( effect: ClearOrDelete::Clear, which: WhichToDelete::All }), + is_tmux, ev_stream ) .await - .map_err(|e| (vec![], "Couldn't clear previous images", e))?; + .map_err(|e| DisplayErr::new_no_imgs("Couldn't clear previous images", e))?; let KittyDisplay::DisplayImages(images) = display else { return Ok(()); @@ -169,17 +199,13 @@ pub async fn display_kitty_images<'es>( config, placement_id: None }, + is_tmux, ev_stream ) .await; - match res { - Ok(img_id) => { - *img = MaybeTransferred::Transferred(img_id); - Ok(()) - } - Err(e) => Err((page_num, e)) - } + res.map(|img_id| *img = MaybeTransferred::Transferred(img_id)) + .map_err(|e| (page_num, e)) } MaybeTransferred::Transferred(image_id) => run_action( Action::Display { @@ -187,6 +213,7 @@ pub async fn display_kitty_images<'es>( placement_id: *image_id, config }, + is_tmux, ev_stream ) .await @@ -203,7 +230,11 @@ pub async fn display_kitty_images<'es>( } match err { - Some((replace, e)) => Err((replace, "Couldn't transfer image to the terminal", e)), + Some((replace, e)) => Err(DisplayErr::new( + replace, + "Couldn't transfer image to the terminal", + e + )), None => Ok(()) } } diff --git a/src/main.rs b/src/main.rs index 1a09964..9b8a8f0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -38,7 +38,7 @@ use ratatui_image::{ use tdf::{ PrerenderLimit, converter::{ConvertedPage, ConverterMsg, run_conversion_loop}, - kitty::{KittyDisplay, display_kitty_images, do_shms_work, run_action}, + kitty::{DisplayErr, KittyDisplay, display_kitty_images, do_shms_work, run_action}, renderer::{self, MUPDF_BLACK, MUPDF_WHITE, RenderError, RenderInfo, RenderNotif}, tui::{BottomMessage, InputAction, MessageSetting, Tui} }; @@ -289,8 +289,9 @@ async fn inner_main() -> Result<(), WrappedErr> { let (to_main, from_converter) = flume::unbounded(); let is_kitty = picker.protocol_type() == ProtocolType::Kitty; + let is_tmux = picker.is_tmux(); - let shms_work = is_kitty && do_shms_work(&mut ev_stream).await; + let shms_work = is_kitty && do_shms_work(is_tmux, &mut ev_stream).await; tokio::spawn(run_conversion_loop( to_main, from_main, picker, 20, shms_work @@ -320,6 +321,7 @@ async fn inner_main() -> Result<(), WrappedErr> { effect: ClearOrDelete::Delete, which: WhichToDelete::IdRange(NonZeroU32::new(1).unwrap()..=NonZeroU32::MAX) }), + is_tmux, &mut ev_stream ) .await @@ -348,6 +350,7 @@ async fn inner_main() -> Result<(), WrappedErr> { to_converter, from_converter, fullscreen, + is_tmux, tui, &mut term, main_area, @@ -376,6 +379,7 @@ async fn enter_redraw_loop( to_converter: Sender, mut from_converter: RecvStream<'_, Result>, mut fullscreen: bool, + is_tmux: bool, mut tui: Tui, term: &mut Terminal>, mut main_area: tdf::tui::RenderLayout, @@ -452,10 +456,15 @@ async fn enter_redraw_loop( to_display = tui.render(f, &main_area, font_size); })?; - let maybe_err = display_kitty_images(to_display, &mut ev_stream).await; + let maybe_err = display_kitty_images(to_display, is_tmux, &mut ev_stream).await; - if let Err((to_replace, err_desc, enum_err)) = maybe_err { - match enum_err { + if let Err(DisplayErr { + page_nums_failed_to_transfer, + user_facing_err, + source + }) = maybe_err + { + match source { // This is the error that kitty & ghostty provide us when they delete an // image due to memory constraints, so if we get it, we just fix it by // re-rendering so it don't display it to the user @@ -465,11 +474,11 @@ async fn enter_redraw_loop( // they were, we re-render them? idk TransmitError::Terminal(TerminalError::NoEntity(_)) => (), _ => tui.set_msg(MessageSetting::Some(BottomMessage::Error(format!( - "{err_desc}: {enum_err}" + "{user_facing_err}: {source}" )))) } - for page_num in to_replace { + for page_num in page_nums_failed_to_transfer { tui.page_failed_display(page_num); // So that they get re-rendered and sent over again to_renderer.send(RenderNotif::PageNeedsReRender(page_num))?; diff --git a/src/tui.rs b/src/tui.rs index 4134aae..475c716 100644 --- a/src/tui.rs +++ b/src/tui.rs @@ -23,6 +23,7 @@ use ratatui::{ widgets::{Block, Borders, Clear, Padding, Paragraph, Wrap} }; use ratatui_image::{FontSize, Image}; +use smallvec::SmallVec; use crate::{ FitOrFill, @@ -333,7 +334,7 @@ impl Tui { .cell_pan_from_top .min(img_cell_h.saturating_sub(img_section_h.ceil() as u16)); - KittyDisplay::DisplayImages(vec![KittyReadyToDisplay { + KittyDisplay::DisplayImages(SmallVec::from([KittyReadyToDisplay { img, page_num, pos: Position { @@ -349,7 +350,7 @@ impl Tui { rows: img_area.height, ..DisplayLocation::default() } - }]) + }])) } #[must_use] @@ -491,7 +492,7 @@ impl Tui { display_loc: DisplayLocation::default() }) }) - .collect::>(); + .collect::>(); // we want to set this at the very end so it doesn't get set somewhere halfway through and // then the whole diffing thing messes it up