diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 69f90f395e..8c8da80a5c 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -54,7 +54,7 @@ struct Args { fn parse_path_with_position( argument_str: &str, ) -> Result, std::convert::Infallible> { - PathLikeWithPosition::parse_str(argument_str, |path_str| { + PathLikeWithPosition::parse_str(argument_str, |_, path_str| { Ok(Path::new(path_str).to_path_buf()) }) } diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs index b83bcb3d91..3161825aff 100644 --- a/crates/file_finder/src/file_finder.rs +++ b/crates/file_finder/src/file_finder.rs @@ -793,17 +793,18 @@ impl PickerDelegate for FileFinderDelegate { cx.notify(); Task::ready(()) } else { - let query = PathLikeWithPosition::parse_str(raw_query, |path_like_str| { - Ok::<_, std::convert::Infallible>(FileSearchQuery { - raw_query: raw_query.to_owned(), - file_query_end: if path_like_str == raw_query { - None - } else { - Some(path_like_str.len()) - }, + let query = + PathLikeWithPosition::parse_str(&raw_query, |normalized_query, path_like_str| { + Ok::<_, std::convert::Infallible>(FileSearchQuery { + raw_query: normalized_query.to_owned(), + file_query_end: if path_like_str == raw_query { + None + } else { + Some(path_like_str.len()) + }, + }) }) - }) - .expect("infallible"); + .expect("infallible"); if Path::new(query.path_like.path_query()).is_absolute() { self.lookup_absolute_path(query, cx) diff --git a/crates/file_finder/src/file_finder_tests.rs b/crates/file_finder/src/file_finder_tests.rs index 13c628a023..27d2d6ccf3 100644 --- a/crates/file_finder/src/file_finder_tests.rs +++ b/crates/file_finder/src/file_finder_tests.rs @@ -1855,9 +1855,9 @@ fn init_test(cx: &mut TestAppContext) -> Arc { } fn test_path_like(test_str: &str) -> PathLikeWithPosition { - PathLikeWithPosition::parse_str(test_str, |path_like_str| { + PathLikeWithPosition::parse_str(test_str, |normalized_query, path_like_str| { Ok::<_, std::convert::Infallible>(FileSearchQuery { - raw_query: test_str.to_owned(), + raw_query: normalized_query.to_owned(), file_query_end: if path_like_str == test_str { None } else { diff --git a/crates/terminal_view/src/terminal_view.rs b/crates/terminal_view/src/terminal_view.rs index 6a24fec3fb..490f0f3323 100644 --- a/crates/terminal_view/src/terminal_view.rs +++ b/crates/terminal_view/src/terminal_view.rs @@ -637,7 +637,7 @@ fn possible_open_targets( maybe_path: &String, cx: &mut ViewContext, ) -> Task, Metadata)>> { - let path_like = PathLikeWithPosition::parse_str(maybe_path.as_str(), |path_str| { + let path_like = PathLikeWithPosition::parse_str(maybe_path.as_str(), |_, path_str| { Ok::<_, std::convert::Infallible>(Path::new(path_str).to_path_buf()) }) .expect("infallible"); diff --git a/crates/util/src/paths.rs b/crates/util/src/paths.rs index 50ca95625a..64983fdf0e 100644 --- a/crates/util/src/paths.rs +++ b/crates/util/src/paths.rs @@ -107,13 +107,17 @@ impl

PathLikeWithPosition

{ /// Parses a string that possibly has `:row:column` suffix. /// Ignores trailing `:`s, so `test.rs:22:` is parsed as `test.rs:22`. /// If any of the row/column component parsing fails, the whole string is then parsed as a path like. + /// If on Windows, `s` will replace `/` with `\` for compatibility. pub fn parse_str( s: &str, - parse_path_like_str: impl Fn(&str) -> Result, + parse_path_like_str: impl Fn(&str, &str) -> Result, ) -> Result { + #[cfg(target_os = "windows")] + let s = &s.replace('/', "\\"); + let fallback = |fallback_str| { Ok(Self { - path_like: parse_path_like_str(fallback_str)?, + path_like: parse_path_like_str(s, fallback_str)?, row: None, column: None, }) @@ -125,7 +129,7 @@ impl

PathLikeWithPosition

{ { let is_absolute = trimmed.starts_with(r"\\?\"); if is_absolute { - return Self::parse_absolute_path(trimmed, parse_path_like_str); + return Self::parse_absolute_path(trimmed, |p| parse_path_like_str(s, p)); } } @@ -150,7 +154,7 @@ impl

PathLikeWithPosition

{ Ok(row) => { if maybe_col_str.is_empty() { Ok(Self { - path_like: parse_path_like_str(path_like_str)?, + path_like: parse_path_like_str(s, path_like_str)?, row: Some(row), column: None, }) @@ -159,12 +163,12 @@ impl

PathLikeWithPosition

{ maybe_col_str.split_once(':').unwrap_or((maybe_col_str, "")); match maybe_col_str.parse::() { Ok(col) => Ok(Self { - path_like: parse_path_like_str(path_like_str)?, + path_like: parse_path_like_str(s, path_like_str)?, row: Some(row), column: Some(col), }), Err(_) => Ok(Self { - path_like: parse_path_like_str(path_like_str)?, + path_like: parse_path_like_str(s, path_like_str)?, row: Some(row), column: None, }), @@ -172,7 +176,7 @@ impl

PathLikeWithPosition

{ } } Err(_) => Ok(Self { - path_like: parse_path_like_str(path_like_str)?, + path_like: parse_path_like_str(s, path_like_str)?, row: None, column: None, }), @@ -323,11 +327,13 @@ impl PathMatcher { mod tests { use super::*; - type TestPath = PathLikeWithPosition; + type TestPath = PathLikeWithPosition<(String, String)>; fn parse_str(s: &str) -> TestPath { - TestPath::parse_str(s, |s| Ok::<_, std::convert::Infallible>(s.to_string())) - .expect("infallible") + TestPath::parse_str(s, |normalized, s| { + Ok::<_, std::convert::Infallible>((normalized.to_string(), s.to_string())) + }) + .expect("infallible") } #[test] @@ -336,7 +342,7 @@ mod tests { ( "test_file.rs", PathLikeWithPosition { - path_like: "test_file.rs".to_string(), + path_like: ("test_file.rs".to_string(), "test_file.rs".to_string()), row: None, column: None, }, @@ -344,7 +350,7 @@ mod tests { ( "test_file.rs:1", PathLikeWithPosition { - path_like: "test_file.rs".to_string(), + path_like: ("test_file.rs:1".to_string(), "test_file.rs".to_string()), row: Some(1), column: None, }, @@ -352,7 +358,7 @@ mod tests { ( "test_file.rs:1:2", PathLikeWithPosition { - path_like: "test_file.rs".to_string(), + path_like: ("test_file.rs:1:2".to_string(), "test_file.rs".to_string()), row: Some(1), column: Some(2), }, @@ -384,7 +390,7 @@ mod tests { assert_eq!( actual, PathLikeWithPosition { - path_like: "test_file.rs".to_string(), + path_like: (input.to_string(), "test_file.rs".to_string()), row, column, }, @@ -401,7 +407,7 @@ mod tests { ( "test_file.rs:", PathLikeWithPosition { - path_like: "test_file.rs".to_string(), + path_like: ("test_file.rs:".to_string(), "test_file.rs".to_string()), row: None, column: None, }, @@ -409,7 +415,7 @@ mod tests { ( "test_file.rs:1:", PathLikeWithPosition { - path_like: "test_file.rs".to_string(), + path_like: ("test_file.rs:1:".to_string(), "test_file.rs".to_string()), row: Some(1), column: None, }, @@ -417,7 +423,10 @@ mod tests { ( "crates/file_finder/src/file_finder.rs:1902:13:", PathLikeWithPosition { - path_like: "crates/file_finder/src/file_finder.rs".to_string(), + path_like: ( + "crates/file_finder/src/file_finder.rs:1902:13:".to_string(), + "crates/file_finder/src/file_finder.rs".to_string(), + ), row: Some(1902), column: Some(13), }, @@ -429,7 +438,7 @@ mod tests { ( "test_file.rs:", PathLikeWithPosition { - path_like: "test_file.rs".to_string(), + path_like: ("test_file.rs:".to_string(), "test_file.rs".to_string()), row: None, column: None, }, @@ -437,7 +446,7 @@ mod tests { ( "test_file.rs:1:", PathLikeWithPosition { - path_like: "test_file.rs".to_string(), + path_like: ("test_file.rs:1:".to_string(), "test_file.rs".to_string()), row: Some(1), column: None, }, @@ -445,7 +454,10 @@ mod tests { ( "\\\\?\\C:\\Users\\someone\\test_file.rs:1902:13:", PathLikeWithPosition { - path_like: "C:\\Users\\someone\\test_file.rs".to_string(), + path_like: ( + "\\\\?\\C:\\Users\\someone\\test_file.rs:1902:13:".to_string(), + "C:\\Users\\someone\\test_file.rs".to_string(), + ), row: Some(1902), column: Some(13), }, @@ -453,7 +465,10 @@ mod tests { ( "\\\\?\\C:\\Users\\someone\\test_file.rs:1902:13:15:", PathLikeWithPosition { - path_like: "C:\\Users\\someone\\test_file.rs".to_string(), + path_like: ( + "\\\\?\\C:\\Users\\someone\\test_file.rs:1902:13:15:".to_string(), + "C:\\Users\\someone\\test_file.rs".to_string(), + ), row: Some(1902), column: Some(13), }, @@ -461,11 +476,36 @@ mod tests { ( "\\\\?\\C:\\Users\\someone\\test_file.rs:1902:::15:", PathLikeWithPosition { - path_like: "C:\\Users\\someone\\test_file.rs".to_string(), + path_like: ( + "\\\\?\\C:\\Users\\someone\\test_file.rs:1902:::15:".to_string(), + "C:\\Users\\someone\\test_file.rs".to_string(), + ), row: Some(1902), column: None, }, ), + ( + "crates/utils/paths.rs", + PathLikeWithPosition { + path_like: ( + "crates\\utils\\paths.rs".to_string(), + "crates\\utils\\paths.rs".to_string(), + ), + row: None, + column: None, + }, + ), + ( + "crates/utils/paths.rs:101", + PathLikeWithPosition { + path_like: ( + "crates\\utils\\paths.rs:101".to_string(), + "crates\\utils\\paths.rs".to_string(), + ), + row: Some(101), + column: None, + }, + ), ]; for (input, expected) in input_and_expected { diff --git a/crates/zed/src/zed/open_listener.rs b/crates/zed/src/zed/open_listener.rs index b94d7b50df..d9b46675d1 100644 --- a/crates/zed/src/zed/open_listener.rs +++ b/crates/zed/src/zed/open_listener.rs @@ -55,7 +55,7 @@ impl OpenRequest { fn parse_file_path(&mut self, file: &str) { if let Some(decoded) = urlencoding::decode(file).log_err() { if let Some(path_buf) = - PathLikeWithPosition::parse_str(&decoded, |s| PathBuf::try_from(s)).log_err() + PathLikeWithPosition::parse_str(&decoded, |_, s| PathBuf::try_from(s)).log_err() { self.open_paths.push(path_buf) } @@ -295,7 +295,7 @@ pub async fn handle_cli_connection( .map(|path_with_position_string| { PathLikeWithPosition::parse_str( &path_with_position_string, - |path_str| { + |_, path_str| { Ok::<_, std::convert::Infallible>( Path::new(path_str).to_path_buf(), )