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:
parent
593afb2d9e
commit
1a21902460
6 changed files with 53 additions and 54 deletions
|
@ -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()
|
|
@ -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;
|
||||||
|
|
|
@ -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::{
|
||||||
|
|
|
@ -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<_>>()
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue