Skip to content

Commit

Permalink
noice
Browse files Browse the repository at this point in the history
  • Loading branch information
alexpasmantier committed Sep 30, 2024
1 parent d2b0fe9 commit c9ee129
Show file tree
Hide file tree
Showing 8 changed files with 371 additions and 276 deletions.
1 change: 1 addition & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub enum UnitTvChannel {
#[default]
ENV,
FILES,
GREP,
OTHER,
}

Expand Down
29 changes: 17 additions & 12 deletions src/components/channels.rs
Original file line number Diff line number Diff line change
@@ -1,76 +1,81 @@
use color_eyre::Result;
use tokio::sync::mpsc::UnboundedSender;
use tracing::info;

use crate::action::Action;
use crate::cli::UnitTvChannel;
use crate::components::finders::Entry;
use crate::components::previewers;
use crate::components::{
finders::{EnvVarFinder, FileFinder, NucleoEnvVarFinder},
previewers::{EnvVarPreviewer, FilePreviewer},
};
use crate::components::finders::{EnvVarFinder, FileFinder, GrepFinder};

use super::finders::Finder;

pub enum TvChannel {
Env(EnvChannel),
Files(FilesChannel),
Grep(GrepChannel),
}

impl TvChannel {
pub fn find(&mut self, pattern: &str) {
match self {
TvChannel::Env(channel) => channel.finder.find(pattern),
TvChannel::Files(channel) => channel.finder.find(pattern),
TvChannel::Grep(channel) => channel.finder.find(pattern),
}
}

// FIXME: could we avoid collecting here?
pub fn results(&mut self, num_entries: u32, offset: u32) -> Vec<Entry> {
match self {
TvChannel::Env(channel) => channel.finder.results(num_entries, offset).collect(),
TvChannel::Files(channel) => channel.finder.results(num_entries, offset).collect(),
TvChannel::Grep(channel) => channel.finder.results(num_entries, offset).collect(),
}
}

pub fn get_result(&self, index: u32) -> Option<Entry> {
match self {
TvChannel::Env(channel) => channel.finder.get_result(index),
TvChannel::Files(channel) => channel.finder.get_result(index),
TvChannel::Grep(channel) => channel.finder.get_result(index),
}
}

pub fn result_count(&self) -> u32 {
match self {
TvChannel::Env(channel) => channel.finder.result_count(),
TvChannel::Files(channel) => channel.finder.result_count(),
TvChannel::Grep(channel) => channel.finder.result_count(),
}
}

pub fn total_count(&self) -> u32 {
match self {
TvChannel::Env(channel) => channel.finder.total_count(),
TvChannel::Files(channel) => channel.finder.total_count(),
TvChannel::Grep(channel) => channel.finder.total_count(),
}
}
}

pub fn get_tv_channel(channel: UnitTvChannel) -> TvChannel {
match channel {
UnitTvChannel::ENV => TvChannel::Env(EnvChannel {
finder: NucleoEnvVarFinder::new(),
finder: EnvVarFinder::new(),
}),
UnitTvChannel::FILES => TvChannel::Files(FilesChannel {
finder: FileFinder::new(),
}),
UnitTvChannel::GREP => TvChannel::Grep(GrepChannel {
finder: GrepFinder::new(),
}),
_ => unimplemented!(),
}
}

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

pub struct FilesChannel {
pub finder: FileFinder,
}

pub struct GrepChannel {
pub finder: GrepFinder,
}
4 changes: 2 additions & 2 deletions src/components/finders.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use devicons::FileIcon;

mod env;
mod env_nucleo;
mod files;
mod grep;

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

use super::previewers::PreviewType;

Expand Down
195 changes: 115 additions & 80 deletions src/components/finders/env.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
use std::{collections::HashMap, env::vars, path::Path};
use devicons::FileIcon;
use nucleo::{
pattern::{CaseMatching, Normalization},
Config, Nucleo,
};
use std::sync::Arc;

use devicons::{icon_for_file, File, FileIcon};
use fuzzy_matcher::skim::SkimMatcherV2;
use tracing::info;

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

Expand All @@ -15,101 +19,54 @@ struct EnvVar {
}

pub struct EnvVarFinder {
env_vars: Vec<EnvVar>,
matcher: SkimMatcherV2,
matcher: Nucleo<EnvVar>,
last_pattern: String,
file_icon: FileIcon,
cache: HashMap<String, Vec<Entry>>,
result_count: u32,
total_count: u32,
pub entries: Vec<Entry>,
}

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

impl EnvVarFinder {
pub fn new() -> Self {
let mut env_vars = Vec::new();
for (name, value) in vars() {
env_vars.push(EnvVar { name, value });
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();
});
}
let file_icon = icon_for_file("config", None);
let total_count = env_vars.len() as u32;
EnvVarFinder {
env_vars,
matcher: SkimMatcherV2::default(),
file_icon,
cache: HashMap::new(),
matcher,
last_pattern: String::new(),
file_icon: FileIcon::from(FILE_ICON_STR),
result_count: 0,
total_count,
entries: Vec::new(),
total_count: 0,
}
}

const MATCHER_TICK_TIMEOUT: u64 = 10;
}

impl Finder for EnvVarFinder {
// TDOO: replace this by a nucleo matcher
fn find(&mut self, pattern: &str) {
let mut results: Vec<Entry> = Vec::new();
// try to get from cache
if let Some(entries) = self.cache.get(pattern) {
results.extend(entries.iter().cloned());
} else {
for env_var in &self.env_vars {
if pattern.is_empty() {
results.push(Entry {
name: env_var.name.clone(),
display_name: None,
preview: Some(env_var.value.clone()),
name_match_ranges: None,
preview_match_ranges: None,
icon: Some(self.file_icon.clone()),
line_number: None,
preview_type: PreviewType::EnvVar,
});
if pattern != self.last_pattern {
self.matcher.pattern.reparse(
0,
pattern,
CaseMatching::Smart,
Normalization::Smart,
if pattern.starts_with(&self.last_pattern) {
true
} else {
let preview_match_ranges = if let Some((_, indices)) =
self.matcher.fuzzy(&env_var.value, pattern, true)
{
Some(indices.iter().map(|i| (*i as u32, *i as u32 + 1)).collect())
} else {
None
};
let name_match_ranges = if let Some((_, indices)) =
self.matcher.fuzzy(&env_var.name, pattern, true)
{
Some(indices.iter().map(|i| (*i as u32, *i as u32 + 1)).collect())
} else {
None
};
if preview_match_ranges.is_some() || name_match_ranges.is_some() {
results.push(Entry {
name: env_var.name.clone(),
display_name: None,
preview: Some(env_var.value.clone()),
name_match_ranges,
preview_match_ranges,
icon: Some(self.file_icon.clone()),
line_number: None,
preview_type: PreviewType::EnvVar,
});
}
}
}
// cache the results
self.cache.insert(pattern.to_string(), results.clone());
false
},
);
self.last_pattern = pattern.to_string();
}
self.result_count = results.len() as u32;
self.entries = results;
}

fn results(&mut self, num_entries: u32, offset: u32) -> impl Iterator<Item = Entry> {
self.entries
.iter()
.skip(offset as usize)
.take(num_entries as usize)
.cloned()
}

fn get_result(&self, index: u32) -> Option<Entry> {
self.entries.get(index as usize).cloned()
}

fn result_count(&self) -> u32 {
Expand All @@ -119,4 +76,82 @@ impl Finder for EnvVarFinder {
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,
})
})
}
}
Loading

0 comments on commit c9ee129

Please sign in to comment.