fix: match forward slashes in queries on Windows
Windows accepts both '/' and '\' as path separators, but zoxide only matched database paths using the separator as typed. As a result, `z bar/meow` failed to find `C:\Users\Alice\foo\bar\meow` even though `z bar\meow` succeeded. Canonicalize separators on Windows for both the query keywords and the database path before matching. Other platforms are unaffected, since '\' is a valid filename character there. Closes #1217
This commit is contained in:
parent
ee594e6906
commit
5365c43459
|
|
@ -83,7 +83,7 @@ impl<'a> Stream<'a> {
|
|||
None => return true,
|
||||
};
|
||||
|
||||
let path = util::to_lowercase(path);
|
||||
let path = util::normalize_separators(util::to_lowercase(path));
|
||||
let mut path = path.as_str();
|
||||
match path.rfind(keywords_last) {
|
||||
Some(idx) => {
|
||||
|
|
@ -149,7 +149,10 @@ impl StreamOptions {
|
|||
I: IntoIterator,
|
||||
I::Item: AsRef<str>,
|
||||
{
|
||||
self.keywords = keywords.into_iter().map(util::to_lowercase).collect();
|
||||
self.keywords = keywords
|
||||
.into_iter()
|
||||
.map(|keyword| util::normalize_separators(util::to_lowercase(keyword)))
|
||||
.collect();
|
||||
self
|
||||
}
|
||||
|
||||
|
|
@ -208,4 +211,20 @@ mod tests {
|
|||
let stream = Stream::new(db, options);
|
||||
assert_eq!(is_match, stream.filter_by_keywords(path));
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[rstest]
|
||||
// Forward slashes in the query match backslashes in the database
|
||||
#[case(&["bar/meow"], r"c:\users\alice\foo\bar\meow", true)]
|
||||
#[case(&["foo/bar"], r"c:\users\alice\foo\bar\meow", false)]
|
||||
// ...and vice versa
|
||||
#[case(&[r"bar\meow"], "c:/users/alice/foo/bar/meow", true)]
|
||||
// Mixed separators
|
||||
#[case(&["foo/bar", r"\meow"], r"c:\users\alice\foo\bar\meow", true)]
|
||||
fn query_separators(#[case] keywords: &[&str], #[case] path: &str, #[case] is_match: bool) {
|
||||
let db = &mut Database::new(PathBuf::new(), Vec::new(), |_| Vec::new(), false);
|
||||
let options = StreamOptions::new(0).with_keywords(keywords.iter());
|
||||
let stream = Stream::new(db, options);
|
||||
assert_eq!(is_match, stream.filter_by_keywords(path));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
13
src/util.rs
13
src/util.rs
|
|
@ -378,3 +378,16 @@ pub fn to_lowercase(s: impl AsRef<str>) -> String {
|
|||
let s = s.as_ref();
|
||||
if s.is_ascii() { s.to_ascii_lowercase() } else { s.to_lowercase() }
|
||||
}
|
||||
|
||||
/// Rewrite path separators to a single canonical form, so that queries match
|
||||
/// regardless of which separator was typed.
|
||||
///
|
||||
/// On Windows both `/` and `\` are accepted by the OS, so they are treated as
|
||||
/// equivalent. Elsewhere `\` is a valid filename character and is left alone.
|
||||
pub fn normalize_separators(s: String) -> String {
|
||||
#[cfg(windows)]
|
||||
if s.contains('/') {
|
||||
return s.replace('/', "\\");
|
||||
}
|
||||
s
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue