Skip to content

Commit

Permalink
progress
Browse files Browse the repository at this point in the history
  • Loading branch information
alexpasmantier committed Sep 29, 2024
1 parent e1e657a commit 7f13c15
Show file tree
Hide file tree
Showing 6 changed files with 225 additions and 62 deletions.
6 changes: 3 additions & 3 deletions src/components/channels.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::cli::UnitTvChannel;
use crate::components::finders::Entry;
use crate::components::previewers;
use crate::components::{
finders::{EnvVarFinder, FileFinder},
finders::{EnvVarFinder, FileFinder, NucleoEnvVarFinder},
previewers::{EnvVarPreviewer, FilePreviewer},
};

Expand Down Expand Up @@ -58,7 +58,7 @@ impl TvChannel {
pub fn get_tv_channel(channel: UnitTvChannel) -> TvChannel {
match channel {
UnitTvChannel::ENV => TvChannel::Env(EnvChannel {
finder: EnvVarFinder::new(),
finder: NucleoEnvVarFinder::new(),
}),
UnitTvChannel::FILES => TvChannel::Files(FilesChannel {
finder: FileFinder::new(),
Expand All @@ -68,7 +68,7 @@ pub fn get_tv_channel(channel: UnitTvChannel) -> TvChannel {
}

pub struct EnvChannel {
pub finder: EnvVarFinder,
pub finder: NucleoEnvVarFinder,
}

pub struct FilesChannel {
Expand Down
2 changes: 2 additions & 0 deletions src/components/finders.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use devicons::FileIcon;

mod env;
mod env_nucleo;
mod files;

// finder types
pub use env::EnvVarFinder;
pub use env_nucleo::NucleoEnvVarFinder;
pub use files::FileFinder;

use super::previewers::PreviewType;
Expand Down
157 changes: 157 additions & 0 deletions src/components/finders/env_nucleo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
use devicons::FileIcon;
use nucleo::{
pattern::{CaseMatching, Normalization},
Config, Nucleo,
};
use std::sync::Arc;

use tracing::info;

use crate::components::{
finders::{Entry, Finder},
fuzzy::MATCHER,
previewers::PreviewType,
};

struct EnvVar {
name: String,
value: String,
}

pub struct NucleoEnvVarFinder {
matcher: Nucleo<EnvVar>,
last_pattern: String,
file_icon: FileIcon,
result_count: u32,
total_count: u32,
}

const NUM_THREADS: usize = 1;
const FILE_ICON_STR: &str = "config";

impl NucleoEnvVarFinder {
pub fn new() -> Self {
let matcher = Nucleo::new(Config::DEFAULT, Arc::new(|| {}), Some(NUM_THREADS), 2);
let injector = matcher.injector();
for (name, value) in std::env::vars() {
let _ = injector.push(EnvVar { name, value }, |e, cols| {
cols[0] = e.name.clone().into();
cols[1] = e.value.clone().into();
});
}
NucleoEnvVarFinder {
matcher,
last_pattern: String::new(),
file_icon: FileIcon::from(FILE_ICON_STR),
result_count: 0,
total_count: 0,
}
}

const MATCHER_TICK_TIMEOUT: u64 = 10;
}

impl Finder for NucleoEnvVarFinder {
fn find(&mut self, pattern: &str) {
if pattern != self.last_pattern {
self.matcher.pattern.reparse(
0,
pattern,
CaseMatching::Smart,
Normalization::Smart,
if pattern.starts_with(&self.last_pattern) {
true
} else {
false
},
);
self.last_pattern = pattern.to_string();
}
}

fn result_count(&self) -> u32 {
self.result_count
}

fn total_count(&self) -> u32 {
self.total_count
}

// FIXME: find a trick to match name + value but not orthogonally like nucleo does
fn results(&mut self, num_entries: u32, offset: u32) -> impl Iterator<Item = Entry> {
let status = self.matcher.tick(Self::MATCHER_TICK_TIMEOUT);
let snapshot = self.matcher.snapshot();
if status.changed {
self.result_count = snapshot.matched_item_count();
self.total_count = snapshot.item_count();
}
let mut name_indices = Vec::new();
let mut value_indices = Vec::new();
let mut matcher = MATCHER.lock();
let icon = self.file_icon.clone();
let mut should_add_name_indices = false;
let mut should_add_value_indices = false;

snapshot
.matched_items(offset..(num_entries + offset).min(snapshot.matched_item_count()))
.map(move |item| {
snapshot.pattern().column_pattern(0).indices(
item.matcher_columns[0].slice(..),
&mut matcher,
&mut name_indices,
);
name_indices.sort_unstable();
name_indices.dedup();
should_add_name_indices = !name_indices.is_empty();
let name_indices = name_indices.drain(..);

snapshot.pattern().column_pattern(1).indices(
item.matcher_columns[1].slice(..),
&mut matcher,
&mut value_indices,
);
value_indices.sort_unstable();
value_indices.dedup();
should_add_value_indices = !value_indices.is_empty();
info!("value_indices: {:?}", value_indices);
let value_indices = value_indices.drain(..);

Entry {
name: item.matcher_columns[0].to_string(),
display_name: None,
preview: Some(item.matcher_columns[1].to_string()),
name_match_ranges: if should_add_name_indices {
Some(name_indices.map(|i| (i, i + 1)).collect())
} else {
None
},
preview_match_ranges: if should_add_value_indices {
Some(value_indices.map(|i| (i, i + 1)).collect())
} else {
None
},
icon: Some(icon),
line_number: None,
preview_type: PreviewType::Files,
}
})
}

fn get_result(&self, index: u32) -> Option<Entry> {
let snapshot = self.matcher.snapshot();
snapshot.get_matched_item(index).and_then(|item| {
let name = item.matcher_columns[0].to_string();
let value = item.matcher_columns[1].to_string();
Some(Entry {
name,
display_name: None,
preview: Some(value),
name_match_ranges: None,
preview_match_ranges: None,
icon: None,
line_number: None,
preview_type: PreviewType::EnvVar,
})
})
}
}
6 changes: 3 additions & 3 deletions src/components/finders/files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ pub struct FileFinder {

impl FileFinder {
pub fn new() -> Self {
let high_matcher = Nucleo::new(Config::DEFAULT.match_paths(), Arc::new(|| {}), None, 1);
let matcher = Nucleo::new(Config::DEFAULT.match_paths(), Arc::new(|| {}), None, 1);
// start loading files in the background
tokio::spawn(load_files(
std::env::current_dir().unwrap(),
high_matcher.injector(),
matcher.injector(),
));
FileFinder {
matcher: high_matcher,
matcher,
last_pattern: String::new(),
result_count: 0,
total_count: 0,
Expand Down
114 changes: 58 additions & 56 deletions src/components/previewers/files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use image::Rgb;
use ratatui_image::picker::Picker;
use std::collections::HashMap;
use std::io::BufRead;
use std::path::Path;
use std::sync::Arc;
use tokio::sync::Mutex;

Expand Down Expand Up @@ -43,80 +44,81 @@ impl FilePreviewer {
const MAX_FILE_SIZE: u64 = 4 * 1024 * 1024;

pub async fn preview(&mut self, entry: &finders::Entry) -> Arc<Preview> {
let mut entry = entry.clone();
entry.name = entry.name.replace(" ", "\\ ");
let path = Path::new(&entry.name);
// check if we have that preview in the cache
if let Some(preview) = self.cache.lock().await.get(&entry.name) {
return preview.clone();
}
if let Ok(metadata) = std::fs::metadata(&entry.name) {
if let Ok(metadata) = std::fs::metadata(path) {
if metadata.len() > Self::MAX_FILE_SIZE {
return Arc::new(file_too_large(&entry.name));
}
} else {
warn!("Error getting metadata for {:?}", entry);
}
let cache = self.cache.clone();
let is_image = match infer::get_from_path(path) {
Ok(Some(t)) => t.mime_type().contains("image"),
_ => false,
};
// images
if let Ok(Some(t)) = infer::get_from_path(&entry.name) {
if t.mime_type().contains("image") {
// insert a loading preview into the cache
self.cache.lock().await.insert(
entry.name.clone(),
Arc::new(Preview {
title: entry.name.clone(),
content: PreviewContent::Loading,
if is_image {
// insert a loading preview into the cache
self.cache.lock().await.insert(
entry.name.clone(),
Arc::new(Preview {
title: entry.name.clone(),
content: PreviewContent::Loading,
target_line: 0,
}),
);
// load the image in the background
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 {
title: entry_c.name.clone(),
content: PreviewContent::Image(image),
target_line: 0,
}),
);
// load the image in the background
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 {
title: entry_c.name.clone(),
content: PreviewContent::Image(image),
target_line: 0,
});
cache
.lock()
.await
.insert(entry_c.name.clone(), preview.clone());
});
cache
.lock()
.await
.insert(entry_c.name.clone(), preview.clone());
}
});
} else {
// text
let cache = self.cache.clone();
let syntax_set = self.syntax_set.clone();
let syntax_theme = self.syntax_theme.clone();
let entry_c = entry.clone();
tokio::spawn(async move {
debug!("Computing highlights for {:?}", entry_c.name);
let preview = match compute_highlights(&entry_c.name, &syntax_set, &syntax_theme) {
Ok(highlighted_lines) => Preview {
title: entry_c.name.clone(),
content: PreviewContent::HighlightedText(highlighted_lines),
target_line: entry_c.line_number.unwrap_or(0) as u16,
},
Err(e) => {
warn!("Error computing highlights: {:?}", e);
preview_not_supported(&entry_c.name)
}
});
}
};
cache
.lock()
.await
.insert(entry_c.name.clone(), Arc::new(preview.clone()));
});
}
// text
let cache = self.cache.clone();
let syntax_set = self.syntax_set.clone();
let syntax_theme = self.syntax_theme.clone();
let entry_c = entry.clone();
tokio::spawn(async move {
debug!("Computing highlights for {:?}", entry_c.name);
let preview = match compute_highlights(&entry_c.name, &syntax_set, &syntax_theme) {
Ok(highlighted_lines) => Preview {
title: entry_c.name.clone(),
content: PreviewContent::HighlightedText(highlighted_lines),
target_line: entry.line_number.unwrap_or(0) as u16,
},
Err(e) => {
warn!("Error computing highlights: {:?}", e);
preview_not_supported(&entry_c.name)
}
};
cache
.lock()
.await
.insert(entry_c.name.clone(), Arc::new(preview.clone()));
});
return Arc::new(Preview {
title: entry.name.clone(),
content: PreviewContent::Loading,
target_line: entry.line_number.unwrap_or(0) as u16,
target_line: 0,
});
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/components/television.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ impl Television {
self.picker_state.select(Some(new_index));
if new_index == 0 {
self.picker_view_offset = 0;
self.relative_picker_state.select(Some(0));
return;
}
if self.relative_picker_state.selected().unwrap_or(0)
== self.results_area_height as usize - 3
Expand Down

0 comments on commit 7f13c15

Please sign in to comment.