From e7c594262f503edd1e436c5263d0c854dc888dfd Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 26 Apr 2021 15:04:26 -0700 Subject: [PATCH] Fix handling of uppercase characters in fuzzy finding --- zed/src/file_finder.rs | 6 +++--- zed/src/worktree.rs | 37 +++++++++++++++++++++--------------- zed/src/worktree/char_bag.rs | 10 ++++++++++ zed/src/worktree/fuzzy.rs | 23 ++++++++++++++++------ 4 files changed, 52 insertions(+), 24 deletions(-) diff --git a/zed/src/file_finder.rs b/zed/src/file_finder.rs index 4302ece217e7c10ab4e4684b3de07a458d36204e..a57730fa285c83d41ad65668c8e9d544d9a589b5 100644 --- a/zed/src/file_finder.rs +++ b/zed/src/file_finder.rs @@ -141,9 +141,9 @@ impl FileFinder { self.worktree(tree_id, app).map(|tree| { let prefix = if self.include_root_name { - tree.root_name_chars() + tree.root_name() } else { - &[] + "" }; let path = path_match.path.clone(); let path_string = path_match.path.to_string_lossy(); @@ -169,7 +169,7 @@ impl FileFinder { let highlight_color = ColorU::from_u32(0x304ee2ff); let bold = *Properties::new().weight(Weight::BOLD); - let mut full_path = prefix.iter().collect::(); + let mut full_path = prefix.to_string(); full_path.push_str(&path_string); let mut container = Container::new( diff --git a/zed/src/worktree.rs b/zed/src/worktree.rs index fb7ea918f1a527c451c9524b6d55c9fd8a1e6448..6dc5bcec023aef16701835577fcc0b3ce4addec5 100644 --- a/zed/src/worktree.rs +++ b/zed/src/worktree.rs @@ -68,16 +68,16 @@ struct FileHandleState { impl Worktree { pub fn new(path: impl Into>, ctx: &mut ModelContext) -> Self { let abs_path = path.into(); - let root_name_chars = abs_path.file_name().map_or(Vec::new(), |n| { - n.to_string_lossy().chars().chain(Some('/')).collect() - }); + let root_name = abs_path + .file_name() + .map_or(String::new(), |n| n.to_string_lossy().to_string() + "/"); let (scan_state_tx, scan_state_rx) = smol::channel::unbounded(); let id = ctx.model_id(); let snapshot = Snapshot { id, scan_id: 0, abs_path, - root_name_chars, + root_name, ignores: Default::default(), entries: Default::default(), }; @@ -224,7 +224,7 @@ pub struct Snapshot { id: usize, scan_id: usize, abs_path: Arc, - root_name_chars: Vec, + root_name: String, ignores: HashMap, (Arc, usize)>, entries: SumTree, } @@ -261,12 +261,10 @@ impl Snapshot { self.entry_for_path("").unwrap() } - pub fn root_name(&self) -> Option<&OsStr> { - self.abs_path.file_name() - } - - pub fn root_name_chars(&self) -> &[char] { - &self.root_name_chars + /// Returns the filename of the snapshot's root directory, + /// with a trailing slash. + pub fn root_name(&self) -> &str { + &self.root_name } fn entry_for_path(&self, path: impl AsRef) -> Option<&Entry> { @@ -613,7 +611,12 @@ impl BackgroundScanner { notify: Sender, worktree_id: usize, ) -> Self { - let root_char_bag = CharBag::from(snapshot.lock().root_name_chars.as_slice()); + let root_char_bag = snapshot + .lock() + .root_name + .chars() + .map(|c| c.to_ascii_lowercase()) + .collect(); let mut scanner = Self { root_char_bag, snapshot, @@ -1069,7 +1072,11 @@ impl BackgroundScanner { fn char_bag(&self, path: &Path) -> CharBag { let mut result = self.root_char_bag; - result.extend(path.to_string_lossy().chars()); + result.extend( + path.to_string_lossy() + .chars() + .map(|c| c.to_ascii_lowercase()), + ); result } } @@ -1465,7 +1472,7 @@ mod tests { abs_path: root_dir.path().into(), entries: Default::default(), ignores: Default::default(), - root_name_chars: Default::default(), + root_name: Default::default(), })), Arc::new(Mutex::new(Default::default())), notify_tx, @@ -1500,7 +1507,7 @@ mod tests { abs_path: root_dir.path().into(), entries: Default::default(), ignores: Default::default(), - root_name_chars: Default::default(), + root_name: Default::default(), })), Arc::new(Mutex::new(Default::default())), notify_tx, diff --git a/zed/src/worktree/char_bag.rs b/zed/src/worktree/char_bag.rs index b21949fe896e6b8b3600fb33bb44943bf151890b..e2f68a27d1d9a46d4c24ee37f4835fce8623fe76 100644 --- a/zed/src/worktree/char_bag.rs +++ b/zed/src/worktree/char_bag.rs @@ -1,3 +1,5 @@ +use std::iter::FromIterator; + #[derive(Copy, Clone, Debug, Default)] pub struct CharBag(u64); @@ -31,6 +33,14 @@ impl Extend for CharBag { } } +impl FromIterator for CharBag { + fn from_iter>(iter: T) -> Self { + let mut result = Self::default(); + result.extend(iter); + result + } +} + impl From<&str> for CharBag { fn from(s: &str) -> Self { let mut bag = Self(0); diff --git a/zed/src/worktree/fuzzy.rs b/zed/src/worktree/fuzzy.rs index b6d13f3288c89c1a3593058acef9a8eff46fda7f..849e6989b82f976800ab8b612fed87d70cd8703f 100644 --- a/zed/src/worktree/fuzzy.rs +++ b/zed/src/worktree/fuzzy.rs @@ -171,10 +171,16 @@ fn match_single_tree_paths<'a>( let mut lowercase_path_chars = Vec::new(); let prefix = if include_root_name { - snapshot.root_name_chars.as_slice() + snapshot.root_name() } else { - &[] - }; + "" + } + .chars() + .collect::>(); + let lowercase_prefix = prefix + .iter() + .map(|c| c.to_ascii_lowercase()) + .collect::>(); for path_entry in path_entries { if !path_entry.char_bag.is_superset(query_chars) { @@ -190,7 +196,7 @@ fn match_single_tree_paths<'a>( if !find_last_positions( last_positions, - prefix, + &lowercase_prefix, &lowercase_path_chars, &lowercase_query[..], ) { @@ -209,6 +215,7 @@ fn match_single_tree_paths<'a>( &path_chars, &lowercase_path_chars, &prefix, + &lowercase_prefix, smart_case, &last_positions, score_matrix, @@ -257,6 +264,7 @@ fn score_match( path: &[char], path_cased: &[char], prefix: &[char], + lowercase_prefix: &[char], smart_case: bool, last_positions: &[usize], score_matrix: &mut [Option], @@ -270,6 +278,7 @@ fn score_match( path, path_cased, prefix, + lowercase_prefix, smart_case, last_positions, score_matrix, @@ -300,6 +309,7 @@ fn recursive_score_match( path: &[char], path_cased: &[char], prefix: &[char], + lowercase_prefix: &[char], smart_case: bool, last_positions: &[usize], score_matrix: &mut [Option], @@ -328,7 +338,7 @@ fn recursive_score_match( let mut last_slash = 0; for j in path_idx..=limit { let path_char = if j < prefix.len() { - prefix[j] + lowercase_prefix[j] } else { path_cased[j - prefix.len()] }; @@ -404,6 +414,7 @@ fn recursive_score_match( path, path_cased, prefix, + lowercase_prefix, smart_case, last_positions, score_matrix, @@ -547,7 +558,7 @@ mod tests { abs_path: PathBuf::new().into(), ignores: Default::default(), entries: Default::default(), - root_name_chars: Vec::new(), + root_name: Default::default(), }, false, path_entries.into_iter(),