Skip to content

Commit

Permalink
noice
Browse files Browse the repository at this point in the history
  • Loading branch information
alexpasmantier committed Sep 28, 2024
1 parent 12a9c5c commit 27e23a4
Show file tree
Hide file tree
Showing 15 changed files with 363 additions and 310 deletions.
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,15 @@ crossterm = { version = "0.28.1", features = ["serde", "event-stream"] }
derive_deref = "1.1.1"
directories = "5.0.1"
futures = "0.3.30"
fuzzy-matcher = "0.3.7"
human-panic = "2.0.1"
ignore = "0.4.23"
json5 = "0.4.1"
lazy_static = "1.5.0"
libc = "0.2.158"
nucleo = "0.5.0"
nucleo-matcher = "0.3.1"
parking_lot = "0.12.3"
pretty_assertions = "1.4.0"
ratatui = { version = "0.28.1", features = ["serde", "macros"] }
rust-devicons = "0.2.2"
Expand Down
2 changes: 1 addition & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
- [ ] maybe filter out image types etc. for now

## bugs
- [ ] sanitize input (tabs, \0, etc)
- [ ] sanitize input (tabs, \0, etc) (see https://github.com/autobib/nucleo-picker/blob/d51dec9efd523e88842c6eda87a19c0a492f4f36/src/lib.rs#L212-L227)

## improvements
- [ ] async finder initialization
Expand Down
18 changes: 6 additions & 12 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@
/// │ └────────────────────────┘ └────────────────────┘ │
/// │ │
/// └──────────────────────────────────────────────────────────────────────────────────────────────────────┘
use std::sync::{Arc, Mutex};
use std::sync::Arc;

use color_eyre::Result;
use serde::{Deserialize, Serialize};
use tokio::sync::mpsc;
use tokio::sync::{mpsc, Mutex};
use tracing::{debug, info};

use crate::{
Expand Down Expand Up @@ -144,7 +144,7 @@ impl App {
loop {
// handle event and convert to action
if let Some(event) = self.event_rx.recv().await {
let action = self.convert_event_to_action(event);
let action = self.convert_event_to_action(event).await;
action_tx.send(action)?;
}

Expand All @@ -158,13 +158,13 @@ impl App {
Ok(())
}

fn convert_event_to_action(&self, event: Event<Key>) -> Action {
async fn convert_event_to_action(&self, event: Event<Key>) -> Action {
match event {
Event::Input(keycode) => {
info!("{:?}", keycode);
// if the current component is the television
// and the mode is input, we want to handle
if self.television.lock().unwrap().is_input_focused() {
if self.television.lock().await.is_input_focused() {
match keycode {
Key::Backspace => return Action::DeletePrevChar,
Key::Delete => return Action::DeleteNextChar,
Expand Down Expand Up @@ -219,13 +219,7 @@ impl App {
Action::Render => self.render_tx.send(RenderingTask::Render)?,
_ => {}
}
if let Some(action) = self
.television
.lock()
.unwrap()
.update(action.clone())
.await?
{
if let Some(action) = self.television.lock().await.update(action.clone()).await? {
self.action_tx.send(action)?
};
}
Expand Down
2 changes: 1 addition & 1 deletion src/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use crate::{action::Action, config::Config};

pub mod channels;
mod finders;
mod fuzzy;
mod input;
mod pickers;
mod previewers;
pub mod television;
mod utils;
Expand Down
63 changes: 39 additions & 24 deletions src/components/channels.rs
Original file line number Diff line number Diff line change
@@ -1,61 +1,76 @@
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::pickers::{self, Picker};
use crate::components::previewers;
use crate::components::{
finders::{EnvVarFinder, FileFinder},
previewers::{EnvVarPreviewer, FilePreviewer},
};

use super::finders::Finder;

pub enum TvChannel {
Env(pickers::env::EnvVarPicker),
Files(pickers::files::FilePicker),
Env(EnvChannel),
Files(FilesChannel),
}

impl TvChannel {
pub fn register_action_handler(&mut self, tx: UnboundedSender<Action>) -> Result<()> {
pub fn find(&mut self, pattern: &str) {
match self {
TvChannel::Files(picker) => picker.register_action_handler(tx),
_ => Ok(()),
TvChannel::Env(channel) => channel.finder.find(pattern),
TvChannel::Files(channel) => channel.finder.find(pattern),
}
}

pub async fn load_entries(&mut self, pattern: &str) -> Result<()> {
pub fn results(&mut self, num_entries: u32, offset: u32) -> Vec<Entry> {
match self {
TvChannel::Env(picker) => picker.load_entries(pattern).await,
TvChannel::Files(picker) => picker.load_entries(pattern).await,
TvChannel::Env(channel) => channel.finder.results(num_entries, offset).collect(),
TvChannel::Files(channel) => channel.finder.results(num_entries, offset).collect(),
}
}

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

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

pub fn get_preview(&mut self, entry: &Entry) -> previewers::Preview {
if entry.name.is_empty() {
return previewers::Preview::default();
}
pub fn total_count(&self) -> u32 {
match self {
TvChannel::Env(picker) => picker.get_preview(entry),
TvChannel::Files(picker) => picker.get_preview(entry),
TvChannel::Env(channel) => channel.finder.total_count(),
TvChannel::Files(channel) => channel.finder.total_count(),
}
}
}

pub async fn get_tv_channel(channel: UnitTvChannel) -> TvChannel {
pub fn get_tv_channel(channel: UnitTvChannel) -> TvChannel {
match channel {
UnitTvChannel::ENV => TvChannel::Env(pickers::env::EnvVarPicker::new().await),
UnitTvChannel::FILES => TvChannel::Files(pickers::files::FilePicker::new().await),
UnitTvChannel::ENV => TvChannel::Env(EnvChannel {
finder: EnvVarFinder::new(),
}),
UnitTvChannel::FILES => TvChannel::Files(FilesChannel {
finder: FileFinder::new(),
}),
_ => unimplemented!(),
}
}

pub struct EnvChannel {
pub finder: EnvVarFinder,
}

pub struct FilesChannel {
pub finder: FileFinder,
}
16 changes: 11 additions & 5 deletions src/components/finders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@ pub struct Entry {
pub name: String,
display_name: Option<String>,
pub preview: Option<String>,
pub score: i64,
pub name_match_ranges: Option<Vec<(usize, usize)>>,
pub preview_match_ranges: Option<Vec<(usize, usize)>>,
pub name_match_ranges: Option<Vec<(u32, u32)>>,
pub preview_match_ranges: Option<Vec<(u32, u32)>>,
pub icon: Option<FileIcon>,
pub line_number: Option<usize>,
}
Expand All @@ -29,7 +28,6 @@ pub const ENTRY_PLACEHOLDER: Entry = Entry {
name: String::new(),
display_name: None,
preview: None,
score: 0,
name_match_ranges: None,
preview_match_ranges: None,
icon: None,
Expand All @@ -42,5 +40,13 @@ pub const ENTRY_PLACEHOLDER: Entry = Entry {
/// # Methods
/// - `find`: Find entries based on a pattern.
pub trait Finder {
async fn find(&mut self, pattern: &str) -> impl Iterator<Item = Entry>;
fn find(&mut self, pattern: &str);

fn results(&mut self, num_entries: u32, offset: u32) -> impl Iterator<Item = Entry>;

fn get_result(&self, index: u32) -> Option<Entry>;

fn result_count(&self) -> u32;

fn total_count(&self) -> u32;
}
50 changes: 37 additions & 13 deletions src/components/finders/env.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::{cmp::max, collections::HashMap, env::vars, path::Path};
use std::{collections::HashMap, env::vars, path::Path};

use futures::{stream, Stream};
use fuzzy_matcher::skim::SkimMatcherV2;
use rust_devicons::{icon_for_file, File, FileIcon};
use tracing::info;

use crate::components::finders::{Entry, Finder};

Expand All @@ -16,6 +16,9 @@ pub struct EnvVarFinder {
matcher: SkimMatcherV2,
file_icon: FileIcon,
cache: HashMap<String, Vec<Entry>>,
result_count: u32,
total_count: u32,
pub entries: Vec<Entry>,
}

impl EnvVarFinder {
Expand All @@ -25,17 +28,22 @@ impl EnvVarFinder {
env_vars.push(EnvVar { name, value });
}
let file_icon = icon_for_file(&File::new(&Path::new("config")), None);
let total_count = env_vars.len() as u32;
EnvVarFinder {
env_vars,
matcher: SkimMatcherV2::default(),
file_icon,
cache: HashMap::new(),
result_count: 0,
total_count,
entries: Vec::new(),
}
}
}

impl Finder for EnvVarFinder {
async fn find(&mut self, pattern: &str) -> impl Iterator<Item = Entry> {
// 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) {
Expand All @@ -47,27 +55,23 @@ impl Finder for EnvVarFinder {
name: env_var.name.clone(),
display_name: None,
preview: Some(env_var.value.clone()),
score: 0,
name_match_ranges: None,
preview_match_ranges: None,
icon: Some(self.file_icon.clone()),
line_number: None,
});
} else {
let mut final_score = 0;
let preview_match_ranges = if let Some((score, indices)) =
let preview_match_ranges = if let Some((_, indices)) =
self.matcher.fuzzy(&env_var.value, pattern, true)
{
final_score = max(final_score, score);
Some(indices.iter().map(|i| (*i, *i + 1)).collect())
Some(indices.iter().map(|i| (*i as u32, *i as u32 + 1)).collect())
} else {
None
};
let name_match_ranges = if let Some((score, indices)) =
let name_match_ranges = if let Some((_, indices)) =
self.matcher.fuzzy(&env_var.name, pattern, true)
{
final_score = max(final_score, score);
Some(indices.iter().map(|i| (*i, *i + 1)).collect())
Some(indices.iter().map(|i| (*i as u32, *i as u32 + 1)).collect())
} else {
None
};
Expand All @@ -76,7 +80,6 @@ impl Finder for EnvVarFinder {
name: env_var.name.clone(),
display_name: None,
preview: Some(env_var.value.clone()),
score: final_score,
name_match_ranges,
preview_match_ranges,
icon: Some(self.file_icon.clone()),
Expand All @@ -88,6 +91,27 @@ impl Finder for EnvVarFinder {
// cache the results
self.cache.insert(pattern.to_string(), results.clone());
}
results.into_iter()
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 {
self.result_count
}

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

0 comments on commit 27e23a4

Please sign in to comment.