perf: checkpoint

This commit is contained in:
Alexandre Pasmantier 2025-01-15 21:12:54 +01:00
parent 4a62feb524
commit 96560a68e3
8 changed files with 93 additions and 46 deletions

View File

@ -176,24 +176,10 @@ impl Previewer {
// if we got a preview, cache it // if we got a preview, cache it
if let Some(preview) = preview { if let Some(preview) = preview {
self.cache.lock().insert(entry.name.clone(), &preview); self.cache.lock().insert(entry.name.clone(), &preview);
Some(preview) return Some(preview);
} else {
None
} }
} 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) { pub fn set_config(&mut self, config: PreviewerConfig) {

View File

@ -23,7 +23,6 @@ impl BasicPreviewer {
title: entry.name.clone(), title: entry.name.clone(),
content: PreviewContent::PlainTextWrapped(entry.name.clone()), content: PreviewContent::PlainTextWrapped(entry.name.clone()),
icon: entry.icon, icon: entry.icon,
..Default::default()
}) })
} }
} }

View File

@ -36,7 +36,6 @@ impl EnvVarPreviewer {
PreviewContent::Empty PreviewContent::Empty
}, },
icon: entry.icon, icon: entry.icon,
..Default::default()
}); });
self.cache.insert(entry.clone(), preview.clone()); self.cache.insert(entry.clone(), preview.clone());
preview preview

View File

@ -1,4 +1,3 @@
use color_eyre::Result;
use parking_lot::Mutex; use parking_lot::Mutex;
use rustc_hash::{FxBuildHasher, FxHashSet}; use rustc_hash::{FxBuildHasher, FxHashSet};
use std::collections::HashSet; use std::collections::HashSet;
@ -9,6 +8,10 @@ use std::sync::{
atomic::{AtomicU8, Ordering}, atomic::{AtomicU8, Ordering},
Arc, 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 syntect::{highlighting::Theme, parsing::SyntaxSet};
use tracing::{debug, warn}; 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( pub fn try_preview(
entry: &entry::Entry, entry: &entry::Entry,
cache: &Arc<Mutex<PreviewCache>>, cache: &Arc<Mutex<PreviewCache>>,
@ -137,29 +144,45 @@ pub fn try_preview(
) { ) {
debug!("Computing preview for {:?}", entry.name); debug!("Computing preview for {:?}", entry.name);
let path = PathBuf::from(&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) { if matches!(FileType::from(&path), FileType::Text) {
debug!("File is text-based: {:?}", entry.name); debug!("File is text-based: {:?}", entry.name);
match File::open(path) { match File::open(path) {
Ok(file) => { Ok(file) => {
// compute the highlighted version in the background // compute the highlighted version in the background
let mut reader = BufReader::new(file); match read_into_lines_capped(file, PARTIAL_BUFREAD_SIZE) {
ReadResult::Full(lines) => {
reader.seek(std::io::SeekFrom::Start(0)).unwrap(); let preview = compute_highlighted_text_preview(
let preview = compute_highlighted_text_preview( entry,
entry, &lines
reader.lines().map_while(Result::ok).collect(), .iter()
syntax_set, .map(|l| preprocess_line(l).0 + "\n")
syntax_theme, .collect::<Vec<_>>(),
); syntax_set,
cache.lock().insert(entry.name.clone(), &preview); syntax_theme,
in_flight_previews.lock().remove(&entry.name); );
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::<Vec<_>>(),
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) => { Err(e) => {
warn!("Error opening file: {:?}", e); warn!("Error opening file: {:?}", e);
@ -177,7 +200,7 @@ pub fn try_preview(
fn compute_highlighted_text_preview( fn compute_highlighted_text_preview(
entry: &entry::Entry, entry: &entry::Entry,
lines: Vec<&str>, lines: &[String],
syntax_set: &SyntaxSet, syntax_set: &SyntaxSet,
syntax_theme: &Theme, syntax_theme: &Theme,
) -> Arc<Preview> { ) -> Arc<Preview> {
@ -185,12 +208,6 @@ fn compute_highlighted_text_preview(
"Computing highlights in the background for {:?}", "Computing highlights in the background for {:?}",
entry.name entry.name
); );
let lines: Vec<String> = 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( match syntax::compute_highlights_for_path(
&PathBuf::from(&entry.name), &PathBuf::from(&entry.name),

View File

@ -31,7 +31,6 @@ const FILL_CHAR_EMPTY: char = ' ';
#[allow(clippy::needless_pass_by_value)] #[allow(clippy::needless_pass_by_value)]
pub fn build_preview_paragraph<'a>( pub fn build_preview_paragraph<'a>(
//preview_block: Block<'_>,
inner: Rect, inner: Rect,
preview_content: PreviewContent, preview_content: PreviewContent,
target_line: Option<u16>, target_line: Option<u16>,

View File

@ -1,6 +1,8 @@
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use std::fmt::Debug; use std::fmt::Debug;
use std::fs::File; use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
use std::io::Read; use std::io::Read;
use std::path::Path; use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
@ -14,6 +16,51 @@ use crate::strings::{
}; };
use crate::threads::default_num_threads; use crate::threads::default_num_threads;
pub struct PartialReadResult {
pub lines: Vec<String>,
pub bytes_read: usize,
}
pub enum ReadResult {
Partial(PartialReadResult),
Full(Vec<String>),
Error(String),
}
pub fn read_into_lines_capped<R>(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! { lazy_static::lazy_static! {
pub static ref DEFAULT_NUM_THREADS: usize = default_num_threads().into(); pub static ref DEFAULT_NUM_THREADS: usize = default_num_threads().into();
} }

View File

@ -224,7 +224,7 @@ pub fn replace_non_printable(
input: &[u8], input: &[u8],
config: &ReplaceNonPrintableConfig, config: &ReplaceNonPrintableConfig,
) -> (String, Vec<i16>) { ) -> (String, Vec<i16>) {
let mut output = String::new(); let mut output = String::with_capacity(input.len());
let mut offsets = Vec::new(); let mut offsets = Vec::new();
let mut cumulative_offset: i16 = 0; let mut cumulative_offset: i16 = 0;

View File

@ -8,7 +8,7 @@ use tracing::warn;
pub fn compute_highlights_for_path( pub fn compute_highlights_for_path(
file_path: &Path, file_path: &Path,
lines: Vec<String>, lines: &[String],
syntax_set: &SyntaxSet, syntax_set: &SyntaxSet,
syntax_theme: &Theme, syntax_theme: &Theme,
) -> color_eyre::Result<Vec<Vec<(Style, String)>>> { ) -> color_eyre::Result<Vec<Vec<(Style, String)>>> {