Skip to content

Commit

Permalink
add proximity to current file in fuzzy finder scoring
Browse files Browse the repository at this point in the history
  • Loading branch information
Kl4rry committed May 30, 2024
1 parent 7b1221b commit 2f9aa72
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 20 deletions.
28 changes: 28 additions & 0 deletions Cargo.lock

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

4 changes: 1 addition & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ version = "0.1.0"
anyhow = "1.0.68"
arboard = "3.2.0"
bitflags = "2.5.0"



blake3 = "1.5.1"
cb = { package = "crossbeam-channel", version = "0.5.8" }
cc = "1.0.79"
Expand Down Expand Up @@ -41,6 +38,7 @@ notify = "6.0.0"
num-traits = "0.2.15"
once_cell = "1.17.1"
opener = "0.7.0"
proximity-sort = "1.3.0"
rayon = "1.7.0"
ropey = "1.5.1"
serde = "1.0.152"
Expand Down
1 change: 1 addition & 0 deletions crates/ferrite-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ memchr = { workspace = true }
notify = { workspace = true }
once_cell = { workspace = true }
opener = { workspace = true }
proximity-sort = { workspace = true }
rayon = { workspace = true }
ropey = { workspace = true }
serde = { workspace = true, features = ["derive"] }
Expand Down
13 changes: 13 additions & 0 deletions crates/ferrite-core/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ impl Engine {
file_finder = Some(SearchBuffer::new(
FileFindProvider(daemon.subscribe()),
proxy.dup(),
None,
));
file_daemon = Some(daemon);
}
Expand Down Expand Up @@ -397,6 +398,12 @@ impl Engine {
self.palette.reset();
match cmd_parser::parse_cmd(&content) {
Ok(cmd) => match cmd {
Command::Path => match self.try_get_current_buffer_path() {
Some(path) => self.palette.set_msg(path.to_string_lossy()),
None => self
.palette
.set_error("No path has been set for the current buffer"),
},
Command::About => {
self.palette.set_msg(format!(
"ferrite\nVersion: {}\nCommit: {}",
Expand Down Expand Up @@ -874,6 +881,7 @@ impl Engine {
self.buffer_finder = Some(SearchBuffer::new(
BufferFindProvider(buffers.into()),
self.proxy.dup(),
self.try_get_current_buffer_path(),
));
}

Expand All @@ -883,6 +891,7 @@ impl Engine {
self.file_finder = Some(SearchBuffer::new(
FileFindProvider(self.file_daemon.subscribe()),
self.proxy.dup(),
self.try_get_current_buffer_path(),
));
}

Expand Down Expand Up @@ -1066,6 +1075,10 @@ impl Engine {
}
}
}

fn try_get_current_buffer_path(&self) -> Option<PathBuf> {
self.get_current_buffer()?.file().map(|p| p.to_owned())
}
}

impl Drop for Engine {
Expand Down
1 change: 1 addition & 0 deletions crates/ferrite-core/src/palette/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub enum Command {
Case(Case),
Split(Direction),
About,
Path,
Pwd,
New,
Reload,
Expand Down
2 changes: 2 additions & 0 deletions crates/ferrite-core/src/palette/cmd_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ pub fn parse_cmd(input: &str) -> Result<Command, CommandParseError> {
("encoding", [encoding, ..]) => Command::Encoding(encoding.take().map(|encoding| encoding.unwrap_string())),
("indent", [indent, ..]) => Command::Indent(indent.take().map(|indent| indent.unwrap_string())),
("about", [..]) => Command::About,
("path", [..]) => Command::Path,
("git-reload", [..]) => Command::GitReload,
("new", [..]) => Command::New,
("pwd", [..]) => Command::Pwd,
Expand Down Expand Up @@ -117,6 +118,7 @@ static COMMANDS: Lazy<Vec<CommandTemplate>> = Lazy::new(|| {
CommandTemplate::new("pwd", None, true),
CommandTemplate::new("indent", Some(("indent", CommandTemplateArg::String)), true),
CommandTemplate::new("about", None, true),
CommandTemplate::new("path", None, true),
CommandTemplate::new("git-reload", None, true),
CommandTemplate::new("reload", None, true).add_alias("r"),
CommandTemplate::new("logger", None, true).add_alias("log"),
Expand Down
17 changes: 10 additions & 7 deletions crates/ferrite-core/src/search_buffer.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{borrow::Cow, sync::Arc, thread};
use std::{borrow::Cow, path::PathBuf, sync::Arc, thread};

use cb::select;
use ferrite_utility::{graphemes::RopeGraphemeExt, line_ending::LineEnding};
Expand Down Expand Up @@ -34,6 +34,7 @@ where
pub fn new<T: SearchOptionProvider<Matchable = M> + Send + Sync + 'static>(
option_provder: T,
proxy: Box<dyn EventLoopProxy>,
path: Option<PathBuf>,
) -> Self {
let mut search_field = Buffer::new();
search_field.set_view_lines(1);
Expand Down Expand Up @@ -77,7 +78,7 @@ where
continue;
}

let output = fuzzy_match::fuzzy_match(&query, (*options).clone());
let output = fuzzy_match::fuzzy_match(&query, (*options).clone(), path.as_deref());
let result = SearchResult {
matches: output,
total: options.len(),
Expand Down Expand Up @@ -120,17 +121,19 @@ where
self.choice.take()
}

pub fn get_matches(&mut self) -> &[FuzzyMatch<M>] {
if let Ok(result) = self.rx.try_recv() {
fn poll_rx(&mut self) {
while let Ok(result) = self.rx.try_recv() {
self.result = result;
}
}

pub fn get_matches(&mut self) -> &[FuzzyMatch<M>] {
self.poll_rx();
&self.result.matches
}

pub fn get_total(&mut self) -> usize {
if let Ok(result) = self.rx.try_recv() {
self.result = result;
}
self.poll_rx();
self.result.total
}

Expand Down
64 changes: 54 additions & 10 deletions crates/ferrite-core/src/search_buffer/fuzzy_match.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::cmp;
use std::{cmp, path::Path};

use rayon::prelude::*;
use sublime_fuzzy::{ContinuousMatch, FuzzySearch, Scoring};
Expand All @@ -8,6 +8,7 @@ use super::Matchable;
#[derive(Debug, Clone)]
pub struct FuzzyMatch<T: Matchable> {
pub score: i64,
pub proximity: i64,
pub item: T,
pub matches: Vec<MatchIndex>,
}
Expand Down Expand Up @@ -44,24 +45,33 @@ impl<T: Matchable> PartialOrd for FuzzyMatch<T> {
impl<T: Matchable> Ord for FuzzyMatch<T> {
fn cmp(&self, other: &Self) -> cmp::Ordering {
match self.score.cmp(&other.score) {
cmp::Ordering::Equal => lexical_sort::natural_lexical_cmp(
&self.item.as_match_str(),
&self.item.as_match_str(),
),
cmp::Ordering::Equal => match self.proximity.cmp(&other.proximity) {
cmp::Ordering::Equal => lexical_sort::natural_lexical_cmp(
&self.item.as_match_str(),
&self.item.as_match_str(),
),
cmp::Ordering::Greater => cmp::Ordering::Less,
cmp::Ordering::Less => cmp::Ordering::Greater,
},
cmp::Ordering::Greater => cmp::Ordering::Less,
cmp::Ordering::Less => cmp::Ordering::Greater,
}
}
}

pub fn fuzzy_match<T: Send + Sync + Matchable>(term: &str, items: Vec<T>) -> Vec<FuzzyMatch<T>> {
pub fn fuzzy_match<T: Send + Sync + Matchable>(
term: &str,
items: Vec<T>,
path: Option<&Path>,
) -> Vec<FuzzyMatch<T>> {
let scoring = Scoring::emphasize_distance();
let mut matches: Vec<_> = items
.into_par_iter()
.filter_map(|item| {
if term.is_empty() {
return Some(FuzzyMatch {
score: 0,
proximity: 0,
item,
matches: Vec::new(),
});
Expand All @@ -70,10 +80,44 @@ pub fn fuzzy_match<T: Send + Sync + Matchable>(term: &str, items: Vec<T>) -> Vec
FuzzySearch::new(term, &item.as_match_str())
.score_with(&scoring)
.best_match()
.map(|m| FuzzyMatch {
score: m.score() as i64,
item,
matches: m.continuous_matches().map(|m| m.into()).collect(),
.map(|m| {
let proximity = match path {
Some(path) => {
let mut missed = false;
let mut path = path.iter();
Path::new(&*item.as_match_str())
.components()
.skip_while(|c| matches!(c, std::path::Component::CurDir))
.map(|c| {
// if we've already missed, each additional dir is one further away
if missed {
return -1;
}

// we want to score positively if c matches the next segment from target path
if let Some(p) = path.next() {
if p == c.as_os_str() {
// matching path segment!
return 1;
} else {
// non-matching path segment
missed = true;
}
}

-1
})
.sum()
}
None => 0,
};

FuzzyMatch {
score: m.score() as i64,
proximity,
item,
matches: m.continuous_matches().map(|m| m.into()).collect(),
}
})
})
.collect();
Expand Down

0 comments on commit 2f9aa72

Please sign in to comment.