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, to_main_tx,
from_main_rx, from_main_rx,
picker, picker,
prerender prerender,
// just assume shms work for now, who cares
true
)); ));
let from_converter_rx = from_converter_rx.into_stream(); let from_converter_rx = from_converter_rx.into_stream();
+20 -25
View File
@@ -52,7 +52,8 @@ pub async fn run_conversion_loop(
sender: Sender<Result<ConvertedPage, RenderError>>, sender: Sender<Result<ConvertedPage, RenderError>>,
receiver: Receiver<ConverterMsg>, receiver: Receiver<ConverterMsg>,
mut picker: Picker, mut picker: Picker,
prerender: usize prerender: usize,
shms_work: bool
) -> Result<(), SendError<Result<ConvertedPage, RenderError>>> { ) -> Result<(), SendError<Result<ConvertedPage, RenderError>>> {
let mut images = vec![]; let mut images = vec![];
let mut page: usize = 0; let mut page: usize = 0;
@@ -64,7 +65,8 @@ pub async fn run_conversion_loop(
page: usize, page: usize,
iteration: &mut usize, iteration: &mut usize,
prerender: usize, prerender: usize,
pid: u32 pid: u32,
shms_work: bool
) -> Result<Option<ConvertedPage>, RenderError> { ) -> Result<Option<ConvertedPage>, RenderError> {
if images.is_empty() || *iteration >= prerender { if images.is_empty() || *iteration >= prerender {
return Ok(None); return Ok(None);
@@ -117,10 +119,6 @@ pub async fn run_conversion_loop(
y: 0 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() { let txt_img = match picker.protocol_type() {
ProtocolType::Kitty => { ProtocolType::Kitty => {
let area = ratatui_image::protocol::ImageSource::round_pixel_size_to_cells( let area = ratatui_image::protocol::ImageSource::round_pixel_size_to_cells(
@@ -129,24 +127,20 @@ pub async fn run_conversion_loop(
picker.font_size() picker.font_size()
); );
match kittage::image::Image::shm_from( let mut img = if shms_work {
dyn_img, kittage::image::Image::shm_from(
&format!("__tdf_kittage_{pid}_page_{page_num}") dyn_img,
) { &format!("__tdf_kittage_{pid}_page_{page_num}")
Ok(mut img) => { )
img.num_or_id = .map_err(|e| RenderError::Converting(format!("Couldn't write to shm: {e}")))?
NumberOrId::Id(NonZeroU32::new(page_num as u32 + 1).unwrap()); } else {
ConvertedImage::Kitty { kittage::image::Image::from(dyn_img)
img: MaybeTransferred::NotYet(img), };
area
} img.num_or_id = NumberOrId::Id(NonZeroU32::new(page_num as u32 + 1).unwrap());
} ConvertedImage::Kitty {
// todo: fallback to non-shm image here without cloning dyn_img above img: MaybeTransferred::NotYet(img),
// Err(_) => ConvertedImage::Kitty(dyn_img.into()) area
Err(e) =>
return Err(RenderError::Converting(format!(
"Couldn't write to shm: {e}"
))),
} }
} }
_ => ConvertedImage::Generic( _ => ConvertedImage::Generic(
@@ -203,7 +197,8 @@ pub async fn run_conversion_loop(
page, page,
&mut iteration, &mut iteration,
prerender, prerender,
pid pid,
shms_work
) { ) {
Ok(None) => break, Ok(None) => break,
Ok(Some(img)) => sender.send(Ok(img))?, 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::{ use kittage::{
AsyncInputReader, ImageDimensions, ImageId, PixelFormat, AsyncInputReader, ImageDimensions, ImageId, NumberOrId, PixelFormat,
action::Action, action::Action,
delete::{ClearOrDelete, DeleteConfig, WhichToDelete}, delete::{ClearOrDelete, DeleteConfig, WhichToDelete},
display::DisplayConfig, display::DisplayConfig,
@@ -55,6 +61,26 @@ pub async fn run_action<'image, 'data, 'es>(
.map(|(_, i)| i) .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>( pub async fn display_kitty_images<'es>(
images: Vec<(usize, &mut MaybeTransferred, Rect)>, images: Vec<(usize, &mut MaybeTransferred, Rect)>,
ev_stream: &'es mut EventStream ev_stream: &'es mut EventStream
+11 -2
View File
@@ -29,7 +29,7 @@ use ratatui_image::picker::{Picker, ProtocolType};
use tdf::{ use tdf::{
PrerenderLimit, PrerenderLimit,
converter::{ConvertedPage, ConverterMsg, run_conversion_loop}, 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}, renderer::{self, RenderError, RenderInfo, RenderNotif},
tui::{BottomMessage, InputAction, MessageSetting, Tui} tui::{BottomMessage, InputAction, MessageSetting, Tui}
}; };
@@ -254,7 +254,12 @@ async fn main() -> Result<(), WrappedErr> {
let (to_main, from_converter) = flume::unbounded(); let (to_main, from_converter) = flume::unbounded();
let is_kitty = picker.protocol_type() == ProtocolType::Kitty; 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( let file_name = path.file_name().map_or_else(
|| "Unknown file".into(), || "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 // 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 // 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 // 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(_)) => (), TransmitError::Terminal(TerminalError::NoEntity(_)) => (),
_ => tui.set_msg(MessageSetting::Some(BottomMessage::Error(format!( _ => tui.set_msg(MessageSetting::Some(BottomMessage::Error(format!(
"{err_desc}: {enum_err}" "{err_desc}: {enum_err}"