From 74541028b2898ca4847e3ff09e3bd5c887c8435b Mon Sep 17 00:00:00 2001 From: Alexandre Pasmantier Date: Fri, 11 Oct 2024 00:15:31 +0200 Subject: [PATCH] improvements on temp plain text previews --- Cargo.toml | 2 +- TODO.md | 10 +++- src/components/channels.rs | 1 - src/components/previewers/files.rs | 83 +++++++++++++++++------------- 4 files changed, 55 insertions(+), 41 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ae4cd91..e472f52 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -78,6 +78,6 @@ debug = "none" strip = "symbols" debug-assertions = false overflow-checks = false -lto = "fat" +lto = "thin" panic = "abort" diff --git a/TODO.md b/TODO.md index a95ac67..273caab 100644 --- a/TODO.md +++ b/TODO.md @@ -14,6 +14,10 @@ - [x] use nucleo for env - [ ] better keymaps - [ ] mutualize placeholder previews in cache (really not a priority) +- [ ] better abstractions for channels / separation / isolation so that others can contribute new ones easily +- [ ] channel selection in the UI (separate menu or top panel or something) +- [ ] only render highlighted lines that are visible +- [ ] only ever read a portion of the file for the temp preview ## feature ideas - [ ] some sort of iterative fuzzy file explorer (preview contents of folders on the right, enter to go in etc.) maybe @@ -25,6 +29,8 @@ - [ ] text in documents (pdfs, archives, ...) (rga, adapters) https://github.com/jrmuizel/pdf-extract - [x] fd - [ ] recent directories -- [ ] git +- [ ] git (commits, branches, status, diff, ...) - [ ] makefile commands -- +- [ ] remote files (s3, ...) +- [ ] custom actions as part of a channel (mappable) + diff --git a/src/components/channels.rs b/src/components/channels.rs index 850ad58..5abbb2a 100644 --- a/src/components/channels.rs +++ b/src/components/channels.rs @@ -19,7 +19,6 @@ impl TvChannel { } } - // FIXME: could we avoid collecting here? pub fn results(&mut self, num_entries: u32, offset: u32) -> Vec { match self { TvChannel::Env(channel) => channel.finder.results(num_entries, offset).collect(), diff --git a/src/components/previewers/files.rs b/src/components/previewers/files.rs index 8942c36..8dcac96 100644 --- a/src/components/previewers/files.rs +++ b/src/components/previewers/files.rs @@ -1,8 +1,8 @@ use color_eyre::Result; -use image::Rgb; +use image::{ImageReader, Rgb}; use ratatui_image::picker::Picker; use std::fs::File; -use std::io::{BufRead, BufReader, Read}; +use std::io::{BufRead, BufReader, Read, Seek}; use std::path::{Path, PathBuf}; use std::sync::Arc; use syntect::easy::HighlightLines; @@ -27,7 +27,7 @@ pub struct FilePreviewer { cache: Arc>, syntax_set: Arc, syntax_theme: Arc, - //image_picker: Arc>, + image_picker: Arc>, } impl FilePreviewer { @@ -35,38 +35,42 @@ impl FilePreviewer { let syntax_set = SyntaxSet::load_defaults_nonewlines(); let theme_set = ThemeSet::load_defaults(); info!("getting image picker"); - //let image_picker = get_image_picker(); + let image_picker = get_image_picker(); info!("got image picker"); FilePreviewer { cache: Arc::new(Mutex::new(PreviewCache::default())), syntax_set: Arc::new(syntax_set), syntax_theme: Arc::new(theme_set.themes["base16-ocean.dark"].clone()), - //image_picker: Arc::new(Mutex::new(image_picker)), + image_picker: Arc::new(Mutex::new(image_picker)), } } - //async fn compute_image_preview(&self, entry: &finders::Entry) { - // let cache = self.cache.clone(); - // let picker = self.image_picker.clone(); - // let entry_c = entry.clone(); - // tokio::spawn(async move { - // info!("Loading image: {:?}", entry_c.name); - // if let Ok(dyn_image) = ImageReader::open(entry_c.name.clone()).unwrap().decode() { - // let image = picker.lock().await.new_resize_protocol(dyn_image); - // let preview = Arc::new(Preview::new( - // entry_c.name.clone(), - // PreviewContent::Image(image), - // )); - // cache - // .lock() - // .await - // .insert(entry_c.name.clone(), preview.clone()); - // } - // }); - //} + async fn compute_image_preview(&self, entry: &finders::Entry) { + let cache = self.cache.clone(); + let picker = self.image_picker.clone(); + let entry_c = entry.clone(); + tokio::spawn(async move { + info!("Loading image: {:?}", entry_c.name); + if let Ok(dyn_image) = ImageReader::open(entry_c.name.clone()).unwrap().decode() { + let image = picker.lock().await.new_resize_protocol(dyn_image); + let preview = Arc::new(Preview::new( + entry_c.name.clone(), + PreviewContent::Image(image), + )); + cache + .lock() + .await + .insert(entry_c.name.clone(), preview.clone()); + } + }); + } - async fn compute_highlighted_text_preview(&self, entry: &finders::Entry, lines: Vec) { + async fn compute_highlighted_text_preview( + &self, + entry: &finders::Entry, + reader: BufReader, + ) { let cache = self.cache.clone(); let syntax_set = self.syntax_set.clone(); let syntax_theme = self.syntax_theme.clone(); @@ -76,10 +80,11 @@ impl FilePreviewer { "Computing highlights in the background for {:?}", entry_c.name ); + let lines: Vec = reader.lines().map_while(Result::ok).collect(); match compute_highlights( &PathBuf::from(&entry_c.name), - lines.clone(), + lines, &syntax_set, &syntax_theme, ) { @@ -88,7 +93,7 @@ impl FilePreviewer { cache.lock().await.insert( entry_c.name.clone(), Arc::new(Preview::new( - entry_c.name.clone(), + entry_c.name, PreviewContent::HighlightedText(highlighted_lines), )), ); @@ -165,20 +170,18 @@ impl FilePreviewer { debug!("Computing preview for {:?}", entry.name); match self.get_file_type(&path_buf) { FileType::Text => { - match File::open(&path_buf) { Ok(file) => { // insert a non-highlighted version of the preview into the cache - let reader = BufReader::new(file); + let reader = BufReader::new(&file); let preview = plain_text_preview(&entry.name, reader); self.cache_preview(entry.name.clone(), preview.clone()) .await; - if let PreviewContent::PlainText(ref lines) = preview.content { - // compute the highlighted version in the background - self.compute_highlighted_text_preview(entry, lines.to_vec()) - .await; - } + // compute the highlighted version in the background + let mut reader = BufReader::new(file.try_clone().unwrap()); + reader.seek(std::io::SeekFrom::Start(0)).unwrap(); + self.compute_highlighted_text_preview(entry, reader).await; preview } Err(e) => { @@ -196,7 +199,7 @@ impl FilePreviewer { self.cache_preview(entry.name.clone(), preview.clone()) .await; // compute the image preview in the background - //self.compute_image_preview(entry).await; + self.compute_image_preview(entry).await; preview } FileType::Other => { @@ -227,9 +230,12 @@ fn get_image_picker() -> Picker { picker } -fn plain_text_preview(title: &str, reader: BufReader) -> Arc { +/// This should be enough to most standard terminal sizes +const TEMP_PLAIN_TEXT_PREVIEW_HEIGHT: usize = 200; + +fn plain_text_preview(title: &str, reader: BufReader<&File>) -> Arc { debug!("Creating plain text preview for {:?}", title); - let mut lines = Vec::new(); + let mut lines = Vec::with_capacity(TEMP_PLAIN_TEXT_PREVIEW_HEIGHT); for maybe_line in reader.lines() { match maybe_line { Ok(line) => lines.push(preprocess_line(&line)), @@ -238,6 +244,9 @@ fn plain_text_preview(title: &str, reader: BufReader) -> Arc { return not_supported(title); } } + if lines.len() >= TEMP_PLAIN_TEXT_PREVIEW_HEIGHT { + break; + } } Arc::new(Preview::new( title.to_string(),