From 96560a68e31b8ba71f10dd4574bddd4c7cc19645 Mon Sep 17 00:00:00 2001 From: Alexandre Pasmantier Date: Wed, 15 Jan 2025 21:12:54 +0100 Subject: [PATCH] perf: checkpoint --- .../television-previewers/src/previewers.rs | 18 +---- .../src/previewers/basic.rs | 1 - .../src/previewers/env.rs | 1 - .../src/previewers/files.rs | 67 ++++++++++++------- crates/television-screen/src/preview.rs | 1 - crates/television-utils/src/files.rs | 47 +++++++++++++ crates/television-utils/src/strings.rs | 2 +- crates/television-utils/src/syntax.rs | 2 +- 8 files changed, 93 insertions(+), 46 deletions(-) diff --git a/crates/television-previewers/src/previewers.rs b/crates/television-previewers/src/previewers.rs index e6fe199..f456280 100644 --- a/crates/television-previewers/src/previewers.rs +++ b/crates/television-previewers/src/previewers.rs @@ -176,24 +176,10 @@ impl Previewer { // if we got a preview, cache it if let Some(preview) = preview { self.cache.lock().insert(entry.name.clone(), &preview); - Some(preview) - } else { - None + return Some(preview); } - } else { - debug!("Not past debounce duration"); - // partial preview - let preview = match &entry.preview_type { - PreviewType::Basic => Some(self.basic.preview(entry)), - PreviewType::EnvVar => Some(self.env_var.preview(entry)), - PreviewType::Files => self.file.preview(entry), - PreviewType::Command(cmd) => { - self.command.partial_preview(entry, cmd) - } - PreviewType::None => Some(Arc::new(Preview::default())), - }; - Some(preview) } + None } pub fn set_config(&mut self, config: PreviewerConfig) { diff --git a/crates/television-previewers/src/previewers/basic.rs b/crates/television-previewers/src/previewers/basic.rs index 3a014f7..323ac04 100644 --- a/crates/television-previewers/src/previewers/basic.rs +++ b/crates/television-previewers/src/previewers/basic.rs @@ -23,7 +23,6 @@ impl BasicPreviewer { title: entry.name.clone(), content: PreviewContent::PlainTextWrapped(entry.name.clone()), icon: entry.icon, - ..Default::default() }) } } diff --git a/crates/television-previewers/src/previewers/env.rs b/crates/television-previewers/src/previewers/env.rs index 0774b73..bbe2055 100644 --- a/crates/television-previewers/src/previewers/env.rs +++ b/crates/television-previewers/src/previewers/env.rs @@ -36,7 +36,6 @@ impl EnvVarPreviewer { PreviewContent::Empty }, icon: entry.icon, - ..Default::default() }); self.cache.insert(entry.clone(), preview.clone()); preview diff --git a/crates/television-previewers/src/previewers/files.rs b/crates/television-previewers/src/previewers/files.rs index 63749b7..60db82b 100644 --- a/crates/television-previewers/src/previewers/files.rs +++ b/crates/television-previewers/src/previewers/files.rs @@ -1,4 +1,3 @@ -use color_eyre::Result; use parking_lot::Mutex; use rustc_hash::{FxBuildHasher, FxHashSet}; use std::collections::HashSet; @@ -9,6 +8,10 @@ use std::sync::{ atomic::{AtomicU8, Ordering}, Arc, }; +use television_utils::files::{read_into_lines_capped, ReadResult}; +use television_utils::strings::{ + replace_non_printable, ReplaceNonPrintableConfig, +}; use syntect::{highlighting::Theme, parsing::SyntaxSet}; use tracing::{debug, warn}; @@ -127,6 +130,10 @@ impl FilePreviewer { } } +/// The size of the buffer used to read the file in bytes. +/// This ends up being the max size of partial previews. +const PARTIAL_BUFREAD_SIZE: usize = 16 * 1024; + pub fn try_preview( entry: &entry::Entry, cache: &Arc>, @@ -137,29 +144,45 @@ pub fn try_preview( ) { debug!("Computing preview for {:?}", entry.name); let path = PathBuf::from(&entry.name); - // check file size - if get_file_size(&path).map_or(false, |s| s > MAX_FILE_SIZE) { - debug!("File too large: {:?}", entry.name); - let preview = meta::file_too_large(&entry.name); - cache.lock().insert(entry.name.clone(), &preview); - } if matches!(FileType::from(&path), FileType::Text) { debug!("File is text-based: {:?}", entry.name); match File::open(path) { Ok(file) => { // compute the highlighted version in the background - let mut reader = BufReader::new(file); - - reader.seek(std::io::SeekFrom::Start(0)).unwrap(); - let preview = compute_highlighted_text_preview( - entry, - reader.lines().map_while(Result::ok).collect(), - syntax_set, - syntax_theme, - ); - cache.lock().insert(entry.name.clone(), &preview); - in_flight_previews.lock().remove(&entry.name); + match read_into_lines_capped(file, PARTIAL_BUFREAD_SIZE) { + ReadResult::Full(lines) => { + let preview = compute_highlighted_text_preview( + entry, + &lines + .iter() + .map(|l| preprocess_line(l).0 + "\n") + .collect::>(), + syntax_set, + syntax_theme, + ); + cache.lock().insert(entry.name.clone(), &preview); + in_flight_previews.lock().remove(&entry.name); + } + ReadResult::Partial(p) => { + let preview = compute_highlighted_text_preview( + entry, + &p.lines + .iter() + .map(|l| preprocess_line(l).0 + "\n") + .collect::>(), + syntax_set, + syntax_theme, + ); + cache.lock().insert(entry.name.clone(), &preview); + in_flight_previews.lock().remove(&entry.name); + } + ReadResult::Error(e) => { + warn!("Error reading file: {:?}", e); + let p = meta::not_supported(&entry.name); + cache.lock().insert(entry.name.clone(), &p); + } + } } Err(e) => { warn!("Error opening file: {:?}", e); @@ -177,7 +200,7 @@ pub fn try_preview( fn compute_highlighted_text_preview( entry: &entry::Entry, - lines: Vec<&str>, + lines: &[String], syntax_set: &SyntaxSet, syntax_theme: &Theme, ) -> Arc { @@ -185,12 +208,6 @@ fn compute_highlighted_text_preview( "Computing highlights in the background for {:?}", entry.name ); - let lines: Vec = lines - .iter() - // we need to add a newline here because sublime syntaxes expect one - // to be present at the end of each line - .map(|line| preprocess_line(&line).0 + "\n") - .collect(); match syntax::compute_highlights_for_path( &PathBuf::from(&entry.name), diff --git a/crates/television-screen/src/preview.rs b/crates/television-screen/src/preview.rs index 180b4aa..aadd306 100644 --- a/crates/television-screen/src/preview.rs +++ b/crates/television-screen/src/preview.rs @@ -31,7 +31,6 @@ const FILL_CHAR_EMPTY: char = ' '; #[allow(clippy::needless_pass_by_value)] pub fn build_preview_paragraph<'a>( - //preview_block: Block<'_>, inner: Rect, preview_content: PreviewContent, target_line: Option, diff --git a/crates/television-utils/src/files.rs b/crates/television-utils/src/files.rs index cf51987..dba455f 100644 --- a/crates/television-utils/src/files.rs +++ b/crates/television-utils/src/files.rs @@ -1,6 +1,8 @@ use rustc_hash::FxHashSet; use std::fmt::Debug; use std::fs::File; +use std::io::BufRead; +use std::io::BufReader; use std::io::Read; use std::path::Path; use std::path::PathBuf; @@ -14,6 +16,51 @@ use crate::strings::{ }; use crate::threads::default_num_threads; +pub struct PartialReadResult { + pub lines: Vec, + pub bytes_read: usize, +} + +pub enum ReadResult { + Partial(PartialReadResult), + Full(Vec), + Error(String), +} + +pub fn read_into_lines_capped(r: R, max_bytes: usize) -> ReadResult +where + R: Read, +{ + let mut buf_reader = BufReader::new(r); + let mut line = String::new(); + let mut lines = Vec::new(); + let mut bytes_read = 0; + + loop { + line.clear(); + match buf_reader.read_line(&mut line) { + Ok(0) => break, + Ok(_) => { + if bytes_read > max_bytes { + break; + } + lines.push(line.trim_end().to_string()); + bytes_read += line.len(); + } + Err(e) => { + warn!("Error reading file: {:?}", e); + return ReadResult::Error(format!("{e:?}")); + } + } + } + + if bytes_read > max_bytes { + ReadResult::Partial(PartialReadResult { lines, bytes_read }) + } else { + ReadResult::Full(lines) + } +} + lazy_static::lazy_static! { pub static ref DEFAULT_NUM_THREADS: usize = default_num_threads().into(); } diff --git a/crates/television-utils/src/strings.rs b/crates/television-utils/src/strings.rs index 9c44dfe..3f03222 100644 --- a/crates/television-utils/src/strings.rs +++ b/crates/television-utils/src/strings.rs @@ -224,7 +224,7 @@ pub fn replace_non_printable( input: &[u8], config: &ReplaceNonPrintableConfig, ) -> (String, Vec) { - let mut output = String::new(); + let mut output = String::with_capacity(input.len()); let mut offsets = Vec::new(); let mut cumulative_offset: i16 = 0; diff --git a/crates/television-utils/src/syntax.rs b/crates/television-utils/src/syntax.rs index ff30452..eb860a1 100644 --- a/crates/television-utils/src/syntax.rs +++ b/crates/television-utils/src/syntax.rs @@ -8,7 +8,7 @@ use tracing::warn; pub fn compute_highlights_for_path( file_path: &Path, - lines: Vec, + lines: &[String], syntax_set: &SyntaxSet, syntax_theme: &Theme, ) -> color_eyre::Result>> {