diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 9add77c864..32ccd47a89 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -3519,9 +3519,9 @@ mod tests { " > .git", " > a", " v b", - " > [EDITOR: ''] <== selected", " > 3", " > 4", + " > [EDITOR: ''] <== selected", " a-different-filename.tar.gz", " > C", " .dockerignore", @@ -3542,10 +3542,10 @@ mod tests { " > .git", " > a", " v b", - " > [PROCESSING: 'new-dir']", - " > 3 <== selected", + " > 3", " > 4", - " a-different-filename.tar.gz", + " > [PROCESSING: 'new-dir']", + " a-different-filename.tar.gz <== selected", " > C", " .dockerignore", ] @@ -3559,10 +3559,10 @@ mod tests { " > .git", " > a", " v b", - " > 3 <== selected", + " > 3", " > 4", " > new-dir", - " a-different-filename.tar.gz", + " a-different-filename.tar.gz <== selected", " > C", " .dockerignore", ] @@ -3576,10 +3576,10 @@ mod tests { " > .git", " > a", " v b", - " > [EDITOR: '3'] <== selected", + " > 3", " > 4", " > new-dir", - " a-different-filename.tar.gz", + " [EDITOR: 'a-different-filename.tar.gz'] <== selected", " > C", " .dockerignore", ] @@ -3594,10 +3594,10 @@ mod tests { " > .git", " > a", " v b", - " > 3 <== selected", + " > 3", " > 4", " > new-dir", - " a-different-filename.tar.gz", + " a-different-filename.tar.gz <== selected", " > C", " .dockerignore", ] @@ -3844,8 +3844,8 @@ mod tests { &[ // "v root1", - " one.two.txt <== selected", - " one.txt", + " one.txt <== selected", + " one.two.txt", ] ); @@ -3862,9 +3862,9 @@ mod tests { &[ // "v root1", - " one.two copy.txt <== selected", - " one.two.txt", " one.txt", + " one copy.txt <== selected", + " one.two.txt", ] ); @@ -3878,10 +3878,10 @@ mod tests { &[ // "v root1", - " one.two copy 1.txt <== selected", - " one.two copy.txt", - " one.two.txt", " one.txt", + " one copy.txt", + " one copy 1.txt <== selected", + " one.two.txt", ] ); } @@ -4074,8 +4074,8 @@ mod tests { " > b", " four.txt", " one.txt", - " three copy.txt <== selected", " three.txt", + " three copy.txt <== selected", " two.txt", ] ); @@ -4105,8 +4105,8 @@ mod tests { " > b", " four.txt", " one.txt", - " three copy.txt", " three.txt", + " three copy.txt", " two.txt", ] ); diff --git a/crates/util/src/paths.rs b/crates/util/src/paths.rs index 3143cb49e3..cd5beedf47 100644 --- a/crates/util/src/paths.rs +++ b/crates/util/src/paths.rs @@ -9,9 +9,8 @@ use std::{ use globset::{Glob, GlobSet, GlobSetBuilder}; use regex::Regex; use serde::{Deserialize, Serialize}; -use unicase::UniCase; -use crate::{maybe, NumericPrefixWithSuffix}; +use crate::NumericPrefixWithSuffix; /// Returns the path to the user's home directory. pub fn home_dir() -> &'static PathBuf { @@ -282,34 +281,29 @@ pub fn compare_paths( let a_is_file = components_a.peek().is_none() && a_is_file; let b_is_file = components_b.peek().is_none() && b_is_file; let ordering = a_is_file.cmp(&b_is_file).then_with(|| { - let maybe_numeric_ordering = maybe!({ - let path_a = Path::new(component_a.as_os_str()); - let num_and_remainder_a = if a_is_file { + let path_a = Path::new(component_a.as_os_str()); + let num_and_remainder_a = NumericPrefixWithSuffix::from_numeric_prefixed_str( + if a_is_file { path_a.file_stem() } else { path_a.file_name() } .and_then(|s| s.to_str()) - .and_then(NumericPrefixWithSuffix::from_numeric_prefixed_str)?; + .unwrap_or_default(), + ); - let path_b = Path::new(component_b.as_os_str()); - let num_and_remainder_b = if b_is_file { + let path_b = Path::new(component_b.as_os_str()); + let num_and_remainder_b = NumericPrefixWithSuffix::from_numeric_prefixed_str( + if b_is_file { path_b.file_stem() } else { path_b.file_name() } .and_then(|s| s.to_str()) - .and_then(NumericPrefixWithSuffix::from_numeric_prefixed_str)?; + .unwrap_or_default(), + ); - num_and_remainder_a.partial_cmp(&num_and_remainder_b) - }); - - maybe_numeric_ordering.unwrap_or_else(|| { - let name_a = UniCase::new(component_a.as_os_str().to_string_lossy()); - let name_b = UniCase::new(component_b.as_os_str().to_string_lossy()); - - name_a.cmp(&name_b) - }) + num_and_remainder_a.cmp(&num_and_remainder_b) }); if !ordering.is_eq() { return ordering; @@ -350,6 +344,18 @@ mod tests { (Path::new("test_dirs/1.46/bar_2"), true), ] ); + let mut paths = vec![ + (Path::new("root1/one.txt"), true), + (Path::new("root1/one.two.txt"), true), + ]; + paths.sort_by(|&a, &b| compare_paths(a, b)); + assert_eq!( + paths, + vec![ + (Path::new("root1/one.txt"), true), + (Path::new("root1/one.two.txt"), true), + ] + ); } #[test] diff --git a/crates/util/src/util.rs b/crates/util/src/util.rs index 25ef363035..40a5cf6212 100644 --- a/crates/util/src/util.rs +++ b/crates/util/src/util.rs @@ -644,27 +644,27 @@ impl RangeExt for RangeInclusive { /// This is useful for turning regular alphanumerically sorted sequences as `1-abc, 10, 11-def, .., 2, 21-abc` /// into `1-abc, 2, 10, 11-def, .., 21-abc` #[derive(Debug, PartialEq, Eq)] -pub struct NumericPrefixWithSuffix<'a>(i32, &'a str); +pub struct NumericPrefixWithSuffix<'a>(Option, &'a str); impl<'a> NumericPrefixWithSuffix<'a> { - pub fn from_numeric_prefixed_str(str: &'a str) -> Option { + pub fn from_numeric_prefixed_str(str: &'a str) -> Self { let i = str.chars().take_while(|c| c.is_ascii_digit()).count(); let (prefix, remainder) = str.split_at(i); - match prefix.parse::() { - Ok(prefix) => Some(NumericPrefixWithSuffix(prefix, remainder)), - Err(_) => None, - } + let prefix = prefix.parse().ok(); + Self(prefix, remainder) } } - impl Ord for NumericPrefixWithSuffix<'_> { fn cmp(&self, other: &Self) -> Ordering { - let NumericPrefixWithSuffix(num_a, remainder_a) = self; - let NumericPrefixWithSuffix(num_b, remainder_b) = other; - num_a - .cmp(num_b) - .then_with(|| UniCase::new(remainder_a).cmp(&UniCase::new(remainder_b))) + match (self.0, other.0) { + (None, None) => UniCase::new(self.1).cmp(&UniCase::new(other.1)), + (None, Some(_)) => Ordering::Greater, + (Some(_), None) => Ordering::Less, + (Some(a), Some(b)) => a + .cmp(&b) + .then_with(|| UniCase::new(self.1).cmp(&UniCase::new(other.1))), + } } } @@ -737,66 +737,62 @@ mod tests { let target = "1a"; assert_eq!( NumericPrefixWithSuffix::from_numeric_prefixed_str(target), - Some(NumericPrefixWithSuffix(1, "a")) + NumericPrefixWithSuffix(Some(1), "a") ); let target = "12ab"; assert_eq!( NumericPrefixWithSuffix::from_numeric_prefixed_str(target), - Some(NumericPrefixWithSuffix(12, "ab")) + NumericPrefixWithSuffix(Some(12), "ab") ); let target = "12_ab"; assert_eq!( NumericPrefixWithSuffix::from_numeric_prefixed_str(target), - Some(NumericPrefixWithSuffix(12, "_ab")) + NumericPrefixWithSuffix(Some(12), "_ab") ); let target = "1_2ab"; assert_eq!( NumericPrefixWithSuffix::from_numeric_prefixed_str(target), - Some(NumericPrefixWithSuffix(1, "_2ab")) + NumericPrefixWithSuffix(Some(1), "_2ab") ); let target = "1.2"; assert_eq!( NumericPrefixWithSuffix::from_numeric_prefixed_str(target), - Some(NumericPrefixWithSuffix(1, ".2")) + NumericPrefixWithSuffix(Some(1), ".2") ); let target = "1.2_a"; assert_eq!( NumericPrefixWithSuffix::from_numeric_prefixed_str(target), - Some(NumericPrefixWithSuffix(1, ".2_a")) + NumericPrefixWithSuffix(Some(1), ".2_a") ); let target = "12.2_a"; assert_eq!( NumericPrefixWithSuffix::from_numeric_prefixed_str(target), - Some(NumericPrefixWithSuffix(12, ".2_a")) + NumericPrefixWithSuffix(Some(12), ".2_a") ); let target = "12a.2_a"; assert_eq!( NumericPrefixWithSuffix::from_numeric_prefixed_str(target), - Some(NumericPrefixWithSuffix(12, "a.2_a")) + NumericPrefixWithSuffix(Some(12), "a.2_a") ); } #[test] fn test_numeric_prefix_with_suffix() { let mut sorted = vec!["1-abc", "10", "11def", "2", "21-abc"]; - sorted.sort_by_key(|s| { - NumericPrefixWithSuffix::from_numeric_prefixed_str(s).unwrap_or_else(|| { - panic!("Cannot convert string `{s}` into NumericPrefixWithSuffix") - }) - }); + sorted.sort_by_key(|s| NumericPrefixWithSuffix::from_numeric_prefixed_str(s)); assert_eq!(sorted, ["1-abc", "2", "10", "11def", "21-abc"]); for numeric_prefix_less in ["numeric_prefix_less", "aaa", "~™£"] { assert_eq!( NumericPrefixWithSuffix::from_numeric_prefixed_str(numeric_prefix_less), - None, + NumericPrefixWithSuffix(None, numeric_prefix_less), "String without numeric prefix `{numeric_prefix_less}` should not be converted into NumericPrefixWithSuffix" ) }