fall back to stdout if shms don't work

This commit is contained in:
itsjunetime
2025-06-09 21:45:02 -06:00
parent 62c92141e3
commit fc063efd42
4 changed files with 63 additions and 31 deletions
+3 -1
View File
@@ -122,7 +122,9 @@ pub fn start_converting_loop(
to_main_tx,
from_main_rx,
picker,
prerender
prerender,
// just assume shms work for now, who cares
true
));
let from_converter_rx = from_converter_rx.into_stream();
+15 -20
View File
@@ -52,7 +52,8 @@ pub async fn run_conversion_loop(
sender: Sender<Result<ConvertedPage, RenderError>>,
receiver: Receiver<ConverterMsg>,
mut picker: Picker,
prerender: usize
prerender: usize,
shms_work: bool
) -> Result<(), SendError<Result<ConvertedPage, RenderError>>> {
let mut images = vec![];
let mut page: usize = 0;
@@ -64,7 +65,8 @@ pub async fn run_conversion_loop(
page: usize,
iteration: &mut usize,
prerender: usize,
pid: u32
pid: u32,
shms_work: bool
) -> Result<Option<ConvertedPage>, RenderError> {
if images.is_empty() || *iteration >= prerender {
return Ok(None);
@@ -117,10 +119,6 @@ pub async fn run_conversion_loop(
y: 0
};
// We don't actually want to Crop this image, but we've already
// verified (with the ImageSurface stuff) that the image is the correct
// size for the area given, so to save ratatui the work of having to
// resize it, we tell them to crop it to fit.
let txt_img = match picker.protocol_type() {
ProtocolType::Kitty => {
let area = ratatui_image::protocol::ImageSource::round_pixel_size_to_cells(
@@ -129,26 +127,22 @@ pub async fn run_conversion_loop(
picker.font_size()
);
match kittage::image::Image::shm_from(
let mut img = if shms_work {
kittage::image::Image::shm_from(
dyn_img,
&format!("__tdf_kittage_{pid}_page_{page_num}")
) {
Ok(mut img) => {
img.num_or_id =
NumberOrId::Id(NonZeroU32::new(page_num as u32 + 1).unwrap());
)
.map_err(|e| RenderError::Converting(format!("Couldn't write to shm: {e}")))?
} else {
kittage::image::Image::from(dyn_img)
};
img.num_or_id = NumberOrId::Id(NonZeroU32::new(page_num as u32 + 1).unwrap());
ConvertedImage::Kitty {
img: MaybeTransferred::NotYet(img),
area
}
}
// todo: fallback to non-shm image here without cloning dyn_img above
// Err(_) => ConvertedImage::Kitty(dyn_img.into())
Err(e) =>
return Err(RenderError::Converting(format!(
"Couldn't write to shm: {e}"
))),
}
}
_ => ConvertedImage::Generic(
picker
.new_protocol(dyn_img, img_area, Resize::None)
@@ -203,7 +197,8 @@ pub async fn run_conversion_loop(
page,
&mut iteration,
prerender,
pid
pid,
shms_work
) {
Ok(None) => break,
Ok(Some(img)) => sender.send(Ok(img))?,
+29 -3
View File
@@ -1,8 +1,14 @@
use std::io::Write;
use std::{io::Write, num::NonZeroU32};
use crossterm::{cursor::MoveTo, event::EventStream, execute};
use crossterm::{
cursor::MoveTo,
event::EventStream,
execute,
terminal::{disable_raw_mode, enable_raw_mode}
};
use image::DynamicImage;
use kittage::{
AsyncInputReader, ImageDimensions, ImageId, PixelFormat,
AsyncInputReader, ImageDimensions, ImageId, NumberOrId, PixelFormat,
action::Action,
delete::{ClearOrDelete, DeleteConfig, WhichToDelete},
display::DisplayConfig,
@@ -55,6 +61,26 @@ pub async fn run_action<'image, 'data, 'es>(
.map(|(_, i)| i)
}
pub async fn do_shms_work(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_kittage_test_{pid}"))
else {
return false;
};
// apparently the terminal won't respond to queries unless they have an Id instead of a number
k_img.num_or_id = NumberOrId::Id(NonZeroU32::new(u32::MAX).unwrap());
enable_raw_mode().unwrap();
let res = run_action(Action::Query(&k_img), ev_stream).await;
disable_raw_mode().unwrap();
res.is_ok()
}
pub async fn display_kitty_images<'es>(
images: Vec<(usize, &mut MaybeTransferred, Rect)>,
ev_stream: &'es mut EventStream
+11 -2
View File
@@ -29,7 +29,7 @@ use ratatui_image::picker::{Picker, ProtocolType};
use tdf::{
PrerenderLimit,
converter::{ConvertedPage, ConverterMsg, run_conversion_loop},
kitty::{display_kitty_images, run_action},
kitty::{display_kitty_images, do_shms_work, run_action},
renderer::{self, RenderError, RenderInfo, RenderNotif},
tui::{BottomMessage, InputAction, MessageSetting, Tui}
};
@@ -254,7 +254,12 @@ async fn main() -> Result<(), WrappedErr> {
let (to_main, from_converter) = flume::unbounded();
let is_kitty = picker.protocol_type() == ProtocolType::Kitty;
tokio::spawn(run_conversion_loop(to_main, from_main, picker, 20));
let shms_work = is_kitty && do_shms_work(&mut ev_stream).await;
tokio::spawn(run_conversion_loop(
to_main, from_main, picker, 20, shms_work
));
let file_name = path.file_name().map_or_else(
|| "Unknown file".into(),
@@ -430,6 +435,10 @@ async fn enter_redraw_loop(
// 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
//
// [TODO] maybe when we detect that an image was deleted, we probe the
// terminal for the pages around it to see if they were deleted too and if
// they were, we re-render them? idk
TransmitError::Terminal(TerminalError::NoEntity(_)) => (),
_ => tui.set_msg(MessageSetting::Some(BottomMessage::Error(format!(
"{err_desc}: {enum_err}"