diff --git a/benches/utils.rs b/benches/utils.rs index 28d847e..7267bad 100644 --- a/benches/utils.rs +++ b/benches/utils.rs @@ -87,12 +87,15 @@ pub fn start_rendering_loop( }; to_render_tx.send(RenderNotif::Area(main_area)).unwrap(); + let cell_height_px = size.height / size.rows; + let cell_width_px = size.width / size.columns; std::thread::spawn(move || { start_rendering( &str_path, to_main_tx, from_main_rx, - size, + cell_height_px, + cell_width_px, tdf::PrerenderLimit::All, black, white diff --git a/src/kitty.rs b/src/kitty.rs index c4c7428..8bb730e 100644 --- a/src/kitty.rs +++ b/src/kitty.rs @@ -1,7 +1,18 @@ -use std::io::Write; +use std::{io::Write, num::NonZeroU32}; -use crossterm::event::EventStream; -use kittage::{AsyncInputReader, ImageId, action::Action, error::TransmitError}; +use crossterm::{cursor::MoveTo, event::EventStream, execute}; +use kittage::{ + AsyncInputReader, ImageDimensions, ImageId, PixelFormat, + action::Action, + delete::{ClearOrDelete, DeleteConfig, WhichToDelete}, + display::DisplayConfig, + error::TransmitError, + image::Image, + medium::Medium +}; +use ratatui::prelude::Rect; + +use crate::converter::MaybeTransferred; #[derive(Debug)] pub struct DbgWriter { @@ -46,3 +57,115 @@ pub async fn run_action<'image, 'data, 'es>( .await .map(|(_, i)| i) } + +pub async fn display_kitty_images( + images: Vec<(usize, &mut MaybeTransferred, Rect)>, + ev_stream: &mut EventStream +) -> Result<(), (Vec, String)> { + run_action( + Action::Delete(DeleteConfig { + effect: ClearOrDelete::Clear, + which: WhichToDelete::All + }), + ev_stream + ) + .await + .map_err(|e| (vec![], format!("Couldn't clear previous images: {e}")))?; + + let mut err = None; + for (page_num, img, area) in images { + let config = DisplayConfig::default(); + + execute!(std::io::stdout(), MoveTo(area.x, area.y)).unwrap(); + + log::debug!("looking at (area {area:?}) img {img:#?}"); + + let this_err = match img { + MaybeTransferred::NotYet(image, _map) => { + let mut fake_image = Image { + num_or_id: image.num_or_id, + format: PixelFormat::Rgb24( + ImageDimensions { + width: 0, + height: 0 + }, + None + ), + medium: Medium::Direct { + chunk_size: None, + data: (&[]).into() + } + }; + std::mem::swap(image, &mut fake_image); + + log::debug!("Actually trying to display an image now: {fake_image:?}..."); + + let res = run_action( + Action::TransmitAndDisplay { + image: fake_image, + config, + placement_id: None + }, + ev_stream + ) + .await; + + log::debug!("And it should've gone through: {res:?}!..."); + + match res { + Ok(img_id) => { + // We need the `_map` to be dropped here, but can't explicitly carry it + // over to here. So we're just relying on the overwrite of `img` to + // drop `_map` (and thus unmap the memory) for us + *img = MaybeTransferred::Transferred(img_id); + Ok(()) + } + Err(e) => Err(match e { + TransmitError::Writing(action, e) => { + let num = if let Action::TransmitAndDisplay { + image: failed_img, .. + } = *action + { + *image = failed_img; + None + } else { + Some(page_num) + }; + + (num, e.to_string()) + } + _ => (Some(page_num), e.to_string()) + }) + } + } + MaybeTransferred::Transferred(image_id) => { + let e = run_action( + Action::Display { + image_id: *image_id, + placement_id: NonZeroU32::new(1).unwrap(), + config + }, + ev_stream + ) + .await + .map(|_| ()) + .map_err(|e| (None, e.to_string())); + + log::debug!("Just tried to display: {e:?}"); + e + } + }; + + if let Err((id, e)) = this_err { + let e = err.get_or_insert_with(|| (vec![], e)); + if let Some(id) = id { + e.0.push(id); + } + } + } + + match err { + Some(e) => Err(e), + None => Ok(()) + } +} diff --git a/src/main.rs b/src/main.rs index 4e1ed0a..aec99d2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,21 +19,16 @@ use flume::{Sender, r#async::RecvStream}; use flexi_logger::FileSpec; use futures_util::{FutureExt, stream::StreamExt}; use kittage::{ - ImageDimensions, PixelFormat, action::Action, - delete::{ClearOrDelete, DeleteConfig, WhichToDelete}, - display::{DisplayConfig, DisplayLocation}, - error::TransmitError, - image::Image as KImage, - medium::Medium + delete::{ClearOrDelete, DeleteConfig, WhichToDelete} }; use notify::{Event, EventKind, RecursiveMode, Watcher}; use ratatui::{Terminal, backend::CrosstermBackend}; use ratatui_image::picker::{Picker, ProtocolType}; use tdf::{ PrerenderLimit, - converter::{ConvertedPage, ConverterMsg, MaybeTransferred, run_conversion_loop}, - kitty::run_action, + converter::{ConvertedPage, ConverterMsg, run_conversion_loop}, + kitty::{display_kitty_images, run_action}, renderer::{self, RenderError, RenderInfo, RenderNotif}, tui::{BottomMessage, InputAction, MessageSetting, Tui} }; @@ -236,12 +231,16 @@ async fn main() -> Result<(), WrappedErr> { .prerender .and_then(NonZeroUsize::new) .map_or(PrerenderLimit::All, PrerenderLimit::Limited); + + let cell_height_px = window_size.height / window_size.rows; + let cell_width_px = window_size.width / window_size.columns; std::thread::spawn(move || { renderer::start_rendering( &file_path, render_tx, render_rx, - window_size, + cell_height_px, + cell_width_px, prerender, black, white @@ -419,107 +418,16 @@ async fn enter_redraw_loop( to_display = tui.render(f, &main_area); })?; - let mut maybe_err = Ok(()); - let mut to_replace = Vec::new(); - for (page_num, img, area) in to_display { - let config = DisplayConfig { - location: DisplayLocation { - x: area.x.into(), - y: area.y.into(), - ..DisplayLocation::default() - }, - ..DisplayConfig::default() - }; + let maybe_err = display_kitty_images(to_display, &mut ev_stream).await; - log::debug!("looking at img {img:#?}"); - - maybe_err = match img { - MaybeTransferred::NotYet(image, _map) => { - let mut fake_image = KImage { - num_or_id: image.num_or_id, - format: PixelFormat::Rgb24( - ImageDimensions { - width: 0, - height: 0 - }, - None - ), - medium: Medium::Direct { - chunk_size: None, - data: (&[]).into() - } - }; - std::mem::swap(image, &mut fake_image); - - log::debug!("Actually trying to display an image now: {fake_image:?}..."); - - let res = run_action( - Action::TransmitAndDisplay { - image: fake_image, - config, - placement_id: None - }, - &mut ev_stream - ) - .await; - - log::debug!("And it should've gone through: {res:?}!..."); - - match res { - Ok(img_id) => { - // We need the `_map` to be dropped here, but can't explicitly carry it - // over to here. So we're just relying on the overwrite of `img` to - // drop `_map` (and thus unmap the memory) for us - *img = MaybeTransferred::Transferred(img_id); - Ok(()) - } - Err(e) => Err(match e { - TransmitError::Writing(action, e) => { - if let Action::TransmitAndDisplay { - image: failed_img, .. - } = *action - { - *image = failed_img; - } else { - to_replace.push(page_num); - } - - e.to_string() - } - _ => { - to_replace.push(page_num); - e.to_string() - } - }) - } - } - MaybeTransferred::Transferred(image_id) => { - let e = run_action( - Action::Display { - image_id: *image_id, - placement_id: NonZeroU32::new(1).unwrap(), - config - }, - &mut ev_stream - ) - .await - .map(|_| ()) - .map_err(|e| e.to_string()); - - log::debug!("Just tried to display: {e:?}"); - e - } - }; - } - - for page_num in to_replace { - tui.page_failed_display(page_num); - } - - if let Err(e) = maybe_err { + if let Err((to_replace, e)) = maybe_err { tui.set_msg(MessageSetting::Some(BottomMessage::Error(format!( "Couldn't transfer image to the terminal: {e}" )))); + + for page_num in to_replace { + tui.page_failed_display(page_num); + } } execute!(stdout().lock(), EndSynchronizedUpdate)?; diff --git a/src/renderer.rs b/src/renderer.rs index 173a84b..708eb25 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -1,6 +1,5 @@ use std::{thread::sleep, time::Duration}; -use crossterm::terminal::WindowSize; use flume::{Receiver, SendError, Sender, TryRecvError}; use itertools::Itertools; use mupdf::{ @@ -78,7 +77,8 @@ pub fn start_rendering( path: &str, sender: Sender>, receiver: Receiver, - size: WindowSize, + col_h: u16, + col_w: u16, prerender: PrerenderLimit, black: i32, white: i32 @@ -88,9 +88,7 @@ pub fn start_rendering( let mut search_term = None; // And although the font size could theoretically change, we aren't accounting for that right - // now, so we just keep this out of the loop. - let col_w = size.width / size.columns; - let col_h = size.height / size.rows; + // now, so we just use the values passed in. let mut stored_doc = None; let mut invert = false;