Move fuzzy mod out of worktree

We now match against arbitrary strings in addition to paths.

Co-Authored-By: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
Nathan Sobo 2021-08-04 17:46:53 -06:00
parent 593afb2d9e
commit 1a21902460
6 changed files with 53 additions and 54 deletions

View file

@ -1,5 +1,9 @@
use super::{char_bag::CharBag, EntryKind, Snapshot}; mod char_bag;
use crate::util;
use crate::{
util,
worktree::{EntryKind, Snapshot},
};
use gpui::executor; use gpui::executor;
use std::{ use std::{
borrow::Cow, borrow::Cow,
@ -9,6 +13,8 @@ use std::{
sync::Arc, sync::Arc,
}; };
pub use char_bag::CharBag;
const BASE_DISTANCE_PENALTY: f64 = 0.6; const BASE_DISTANCE_PENALTY: f64 = 0.6;
const ADDITIONAL_DISTANCE_PENALTY: f64 = 0.05; const ADDITIONAL_DISTANCE_PENALTY: f64 = 0.05;
const MIN_DISTANCE_PENALTY: f64 = 0.2; const MIN_DISTANCE_PENALTY: f64 = 0.2;
@ -367,7 +373,7 @@ impl<'a> Matcher<'a> {
results: &mut Vec<PathMatch>, results: &mut Vec<PathMatch>,
cancel_flag: &AtomicBool, cancel_flag: &AtomicBool,
) { ) {
let tree_id = snapshot.id; let tree_id = snapshot.id();
let prefix = path_prefix.chars().collect::<Vec<_>>(); let prefix = path_prefix.chars().collect::<Vec<_>>();
let lowercase_prefix = prefix let lowercase_prefix = prefix
.iter() .iter()

View file

@ -2,6 +2,7 @@ pub mod assets;
pub mod editor; pub mod editor;
pub mod file_finder; pub mod file_finder;
pub mod fs; pub mod fs;
mod fuzzy;
pub mod language; pub mod language;
pub mod menus; pub mod menus;
mod operation_queue; mod operation_queue;

View file

@ -2,9 +2,9 @@ use std::{cmp, sync::Arc};
use crate::{ use crate::{
editor::{self, Editor}, editor::{self, Editor},
fuzzy::{match_strings, StringMatch, StringMatchCandidate},
settings::ThemeRegistry, settings::ThemeRegistry,
workspace::Workspace, workspace::Workspace,
worktree::fuzzy::{match_strings, StringMatch, StringMatchCandidate},
AppState, Settings, AppState, Settings,
}; };
use gpui::{ use gpui::{

View file

@ -911,7 +911,7 @@ impl WorkspaceHandle for ViewHandle<Workspace> {
let tree_id = tree.id(); let tree_id = tree.id();
tree.read(cx) tree.read(cx)
.files(0) .files(0)
.map(move |f| (tree_id, f.path().clone())) .map(move |f| (tree_id, f.path.clone()))
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>()
} }

View file

@ -1,11 +1,11 @@
mod char_bag;
pub(crate) mod fuzzy;
mod ignore; mod ignore;
use self::{char_bag::CharBag, ignore::IgnoreStack}; use self::ignore::IgnoreStack;
use crate::{ use crate::{
editor::{self, Buffer, History, Operation, Rope}, editor::{self, Buffer, History, Operation, Rope},
fs::{self, Fs}, fs::{self, Fs},
fuzzy,
fuzzy::CharBag,
language::LanguageRegistry, language::LanguageRegistry,
rpc::{self, proto}, rpc::{self, proto},
sum_tree::{self, Cursor, Edit, SumTree}, sum_tree::{self, Cursor, Edit, SumTree},
@ -1116,6 +1116,10 @@ pub struct Snapshot {
} }
impl Snapshot { impl Snapshot {
pub fn id(&self) -> usize {
self.id
}
pub fn build_update(&self, other: &Self, worktree_id: u64) -> proto::UpdateWorktree { pub fn build_update(&self, other: &Self, worktree_id: u64) -> proto::UpdateWorktree {
let mut updated_entries = Vec::new(); let mut updated_entries = Vec::new();
let mut removed_entries = Vec::new(); let mut removed_entries = Vec::new();
@ -1214,7 +1218,7 @@ impl Snapshot {
self.entries_by_path self.entries_by_path
.cursor::<(), ()>() .cursor::<(), ()>()
.filter(move |entry| entry.path.as_ref() != empty_path) .filter(move |entry| entry.path.as_ref() != empty_path)
.map(|entry| entry.path()) .map(|entry| &entry.path)
} }
pub fn visible_files(&self, start: usize) -> FileIter { pub fn visible_files(&self, start: usize) -> FileIter {
@ -1248,17 +1252,17 @@ impl Snapshot {
} }
pub fn inode_for_path(&self, path: impl AsRef<Path>) -> Option<u64> { pub fn inode_for_path(&self, path: impl AsRef<Path>) -> Option<u64> {
self.entry_for_path(path.as_ref()).map(|e| e.inode()) self.entry_for_path(path.as_ref()).map(|e| e.inode)
} }
fn insert_entry(&mut self, mut entry: Entry) -> Entry { fn insert_entry(&mut self, mut entry: Entry) -> Entry {
if !entry.is_dir() && entry.path().file_name() == Some(&GITIGNORE) { if !entry.is_dir() && entry.path.file_name() == Some(&GITIGNORE) {
let (ignore, err) = Gitignore::new(self.abs_path.join(entry.path())); let (ignore, err) = Gitignore::new(self.abs_path.join(&entry.path));
if let Some(err) = err { if let Some(err) = err {
log::error!("error in ignore file {:?} - {:?}", entry.path(), err); log::error!("error in ignore file {:?} - {:?}", &entry.path, err);
} }
let ignore_dir_path = entry.path().parent().unwrap(); let ignore_dir_path = entry.path.parent().unwrap();
self.ignores self.ignores
.insert(ignore_dir_path.into(), (Arc::new(ignore), self.scan_id)); .insert(ignore_dir_path.into(), (Arc::new(ignore), self.scan_id));
} }
@ -1381,10 +1385,10 @@ impl Snapshot {
impl fmt::Debug for Snapshot { impl fmt::Debug for Snapshot {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for entry in self.entries_by_path.cursor::<(), ()>() { for entry in self.entries_by_path.cursor::<(), ()>() {
for _ in entry.path().ancestors().skip(1) { for _ in entry.path.ancestors().skip(1) {
write!(f, " ")?; write!(f, " ")?;
} }
writeln!(f, "{:?} (inode: {})", entry.path(), entry.inode())?; writeln!(f, "{:?} (inode: {})", entry.path, entry.inode)?;
} }
Ok(()) Ok(())
} }
@ -1535,19 +1539,19 @@ impl File {
} }
pub fn entry_id(&self) -> (usize, Arc<Path>) { pub fn entry_id(&self) -> (usize, Arc<Path>) {
(self.worktree.id(), self.path()) (self.worktree.id(), self.path.clone())
} }
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Entry { pub struct Entry {
id: usize, pub id: usize,
kind: EntryKind, pub kind: EntryKind,
path: Arc<Path>, pub path: Arc<Path>,
inode: u64, pub inode: u64,
mtime: SystemTime, pub mtime: SystemTime,
is_symlink: bool, pub is_symlink: bool,
is_ignored: bool, pub is_ignored: bool,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -1579,23 +1583,11 @@ impl Entry {
} }
} }
pub fn path(&self) -> &Arc<Path> { pub fn is_dir(&self) -> bool {
&self.path
}
pub fn inode(&self) -> u64 {
self.inode
}
pub fn is_ignored(&self) -> bool {
self.is_ignored
}
fn is_dir(&self) -> bool {
matches!(self.kind, EntryKind::Dir | EntryKind::PendingDir) matches!(self.kind, EntryKind::Dir | EntryKind::PendingDir)
} }
fn is_file(&self) -> bool { pub fn is_file(&self) -> bool {
matches!(self.kind, EntryKind::File(_)) matches!(self.kind, EntryKind::File(_))
} }
} }
@ -1619,7 +1611,7 @@ impl sum_tree::Item for Entry {
} }
EntrySummary { EntrySummary {
max_path: self.path().clone(), max_path: self.path.clone(),
file_count, file_count,
visible_file_count, visible_file_count,
} }
@ -1630,7 +1622,7 @@ impl sum_tree::KeyedItem for Entry {
type Key = PathKey; type Key = PathKey;
fn key(&self) -> Self::Key { fn key(&self) -> Self::Key {
PathKey(self.path().clone()) PathKey(self.path.clone())
} }
} }
@ -2147,7 +2139,7 @@ impl BackgroundScanner {
let mut edits = Vec::new(); let mut edits = Vec::new();
for mut entry in snapshot.child_entries(&job.path).cloned() { for mut entry in snapshot.child_entries(&job.path).cloned() {
let was_ignored = entry.is_ignored; let was_ignored = entry.is_ignored;
entry.is_ignored = ignore_stack.is_path_ignored(entry.path(), entry.is_dir()); entry.is_ignored = ignore_stack.is_path_ignored(&entry.path, entry.is_dir());
if entry.is_dir() { if entry.is_dir() {
let child_ignore_stack = if entry.is_ignored { let child_ignore_stack = if entry.is_ignored {
IgnoreStack::all() IgnoreStack::all()
@ -2156,7 +2148,7 @@ impl BackgroundScanner {
}; };
job.ignore_queue job.ignore_queue
.send(UpdateIgnoreStatusJob { .send(UpdateIgnoreStatusJob {
path: entry.path().clone(), path: entry.path.clone(),
ignore_stack: child_ignore_stack, ignore_stack: child_ignore_stack,
ignore_queue: job.ignore_queue.clone(), ignore_queue: job.ignore_queue.clone(),
}) })
@ -2333,9 +2325,9 @@ impl<'a> Iterator for ChildEntriesIter<'a> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if let Some(item) = self.cursor.item() { if let Some(item) = self.cursor.item() {
if item.path().starts_with(self.parent_path) { if item.path.starts_with(self.parent_path) {
self.cursor self.cursor
.seek_forward(&PathSearch::Successor(item.path()), Bias::Left, &()); .seek_forward(&PathSearch::Successor(&item.path), Bias::Left, &());
Some(item) Some(item)
} else { } else {
None None
@ -2930,8 +2922,8 @@ mod tests {
let tree = tree.read(cx); let tree = tree.read(cx);
let tracked = tree.entry_for_path("tracked-dir/tracked-file1").unwrap(); let tracked = tree.entry_for_path("tracked-dir/tracked-file1").unwrap();
let ignored = tree.entry_for_path("ignored-dir/ignored-file1").unwrap(); let ignored = tree.entry_for_path("ignored-dir/ignored-file1").unwrap();
assert_eq!(tracked.is_ignored(), false); assert_eq!(tracked.is_ignored, false);
assert_eq!(ignored.is_ignored(), true); assert_eq!(ignored.is_ignored, true);
}); });
std::fs::write(dir.path().join("tracked-dir/tracked-file2"), "").unwrap(); std::fs::write(dir.path().join("tracked-dir/tracked-file2"), "").unwrap();
@ -2942,9 +2934,9 @@ mod tests {
let dot_git = tree.entry_for_path(".git").unwrap(); let dot_git = tree.entry_for_path(".git").unwrap();
let tracked = tree.entry_for_path("tracked-dir/tracked-file2").unwrap(); let tracked = tree.entry_for_path("tracked-dir/tracked-file2").unwrap();
let ignored = tree.entry_for_path("ignored-dir/ignored-file2").unwrap(); let ignored = tree.entry_for_path("ignored-dir/ignored-file2").unwrap();
assert_eq!(tracked.is_ignored(), false); assert_eq!(tracked.is_ignored, false);
assert_eq!(ignored.is_ignored(), true); assert_eq!(ignored.is_ignored, true);
assert_eq!(dot_git.is_ignored(), true); assert_eq!(dot_git.is_ignored, true);
}); });
} }
@ -3177,9 +3169,9 @@ mod tests {
let mut visible_files = self.visible_files(0); let mut visible_files = self.visible_files(0);
for entry in self.entries_by_path.cursor::<(), ()>() { for entry in self.entries_by_path.cursor::<(), ()>() {
if entry.is_file() { if entry.is_file() {
assert_eq!(files.next().unwrap().inode(), entry.inode); assert_eq!(files.next().unwrap().inode, entry.inode);
if !entry.is_ignored { if !entry.is_ignored {
assert_eq!(visible_files.next().unwrap().inode(), entry.inode); assert_eq!(visible_files.next().unwrap().inode, entry.inode);
} }
} }
} }
@ -3192,14 +3184,14 @@ mod tests {
bfs_paths.push(path); bfs_paths.push(path);
let ix = stack.len(); let ix = stack.len();
for child_entry in self.child_entries(path) { for child_entry in self.child_entries(path) {
stack.insert(ix, child_entry.path()); stack.insert(ix, &child_entry.path);
} }
} }
let dfs_paths = self let dfs_paths = self
.entries_by_path .entries_by_path
.cursor::<(), ()>() .cursor::<(), ()>()
.map(|e| e.path().as_ref()) .map(|e| e.path.as_ref())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
assert_eq!(bfs_paths, dfs_paths); assert_eq!(bfs_paths, dfs_paths);
@ -3214,7 +3206,7 @@ mod tests {
fn to_vec(&self) -> Vec<(&Path, u64, bool)> { fn to_vec(&self) -> Vec<(&Path, u64, bool)> {
let mut paths = Vec::new(); let mut paths = Vec::new();
for entry in self.entries_by_path.cursor::<(), ()>() { for entry in self.entries_by_path.cursor::<(), ()>() {
paths.push((entry.path().as_ref(), entry.inode(), entry.is_ignored())); paths.push((entry.path.as_ref(), entry.inode, entry.is_ignored));
} }
paths.sort_by(|a, b| a.0.cmp(&b.0)); paths.sort_by(|a, b| a.0.cmp(&b.0));
paths paths