Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"] }
Expand All @@ -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"
Expand Down
2 changes: 1 addition & 1 deletion ratatui-image
Submodule ratatui-image updated 2 files
+6 −6 Cargo.lock
+5 −0 src/picker.rs
81 changes: 56 additions & 25 deletions src/kitty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -30,7 +32,7 @@ pub struct KittyReadyToDisplay<'tui> {
pub enum KittyDisplay<'tui> {
NoChange,
ClearImages,
DisplayImages(Vec<KittyReadyToDisplay<'tui>>)
DisplayImages(SmallVec<[KittyReadyToDisplay<'tui>; 1]>)
}

pub struct DbgWriter<W: Write> {
Expand Down Expand Up @@ -62,20 +64,29 @@ impl<W: Write> Write for DbgWriter<W> {

pub async fn run_action<'es>(
action: Action<'_, '_>,
is_tmux: bool,
ev_stream: &'es mut EventStream
) -> Result<ImageId, TransmitError<<&'es mut EventStream as AsyncInputReader>::Error>> {
let writer = DbgWriter {
w: std::io::stdout().lock(),
#[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 {
Expand All @@ -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<E> {
pub page_nums_failed_to_transfer: Vec<usize>,
pub user_facing_err: &'static str,
pub source: E
}

impl<E> DisplayErr<E> {
pub fn new(
page_nums_failed_to_transfer: Vec<usize>,
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<usize>,
&'static str,
TransmitError<<&'es mut EventStream as AsyncInputReader>::Error>
)
> {
) -> Result<(), DisplayErr<TransmitError<<&'es mut EventStream as AsyncInputReader>::Error>>> {
let images = match display {
KittyDisplay::NoChange => return Ok(()),
KittyDisplay::DisplayImages(_) | KittyDisplay::ClearImages => {
Expand All @@ -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(());
Expand Down Expand Up @@ -169,24 +199,21 @@ 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 {
image_id: *image_id,
placement_id: *image_id,
config
},
is_tmux,
ev_stream
)
.await
Expand All @@ -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(())
}
}
23 changes: 16 additions & 7 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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}
};
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -348,6 +350,7 @@ async fn inner_main() -> Result<(), WrappedErr> {
to_converter,
from_converter,
fullscreen,
is_tmux,
tui,
&mut term,
main_area,
Expand Down Expand Up @@ -376,6 +379,7 @@ async fn enter_redraw_loop(
to_converter: Sender<ConverterMsg>,
mut from_converter: RecvStream<'_, Result<ConvertedPage, RenderError>>,
mut fullscreen: bool,
is_tmux: bool,
mut tui: Tui,
term: &mut Terminal<CrosstermBackend<Stdout>>,
mut main_area: tdf::tui::RenderLayout,
Expand Down Expand Up @@ -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
Expand All @@ -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))?;
Expand Down
7 changes: 4 additions & 3 deletions src/tui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use ratatui::{
widgets::{Block, Borders, Clear, Padding, Paragraph, Wrap}
};
use ratatui_image::{FontSize, Image};
use smallvec::SmallVec;

use crate::{
FitOrFill,
Expand Down Expand Up @@ -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 {
Expand All @@ -349,7 +350,7 @@ impl Tui {
rows: img_area.height,
..DisplayLocation::default()
}
}])
}]))
}

#[must_use]
Expand Down Expand Up @@ -491,7 +492,7 @@ impl Tui {
display_loc: DisplayLocation::default()
})
})
.collect::<Vec<_>>();
.collect::<SmallVec<_>>();

// 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
Expand Down
Loading