Skip to content

Commit a89b5d8

Browse files
authored
fix: only quote paths on Windows to prevent macOS/Linux spawn() errors (#156)
## Summary Fixes a regression introduced in #151 where path quoting broke the Java extension on macOS and Linux. Closes #155 ## Problem PR #151 added double-quote wrapping to paths to fix spaces-in-path issues on Windows. However, this broke macOS and Linux because: - On Windows, Zed's proxy uses shell mode, where quotes are interpreted and stripped - On macOS/Linux, the proxy uses `spawn()` with `shell: false`, which treats quotes as **literal filename characters** This caused "No such file or directory (os error 2)" errors on macOS/Linux because the system was looking for files like `"/path/to/java"` (with literal quotes in the filename). ## Solution - Only apply path quoting on Windows via runtime `current_platform()` check - Extract `format_path_for_os()` helper function for testability - Add unit tests covering Windows, Mac, and Linux behavior
1 parent c8f8292 commit a89b5d8

File tree

1 file changed

+39
-16
lines changed

1 file changed

+39
-16
lines changed

src/util.rs

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -247,29 +247,45 @@ fn get_tag_at(github_tags: &Value, index: usize) -> Option<&str> {
247247
})
248248
}
249249

250-
/// Converts a [`Path`] into a double-quoted [`String`].
250+
/// Formats a path string with platform-specific quoting.
251251
///
252-
/// This function performs two steps in one: it converts the path to a string
253-
/// and wraps the result in double quotes (e.g., `"path/to/file"`).
252+
/// On Windows, wraps the path in double quotes for shell mode compatibility.
253+
/// On Unix, returns the path unquoted since spawn() treats quotes as literals.
254+
fn format_path_for_os(path_str: String, os: Os) -> String {
255+
if os == Os::Windows {
256+
format!("\"{}\"", path_str)
257+
} else {
258+
path_str
259+
}
260+
}
261+
262+
/// Converts a [`Path`] into a [`String`], with platform-specific quoting.
263+
///
264+
/// On Windows, the path is wrapped in double quotes (e.g., `"C:\path\to\file"`)
265+
/// for compatibility with shell mode. On Unix-like systems, the path is returned
266+
/// unquoted, as the proxy uses `spawn()` with `shell: false` which treats quotes
267+
/// as literal filename characters, causing "No such file or directory" errors.
254268
///
255269
/// # Arguments
256270
///
257-
/// * `path` - The path of type `AsRef<Path>` to be converted and quoted.
271+
/// * `path` - The path of type `AsRef<Path>` to be converted.
258272
///
259273
/// # Returns
260274
///
261-
/// Returns a `String` representing the `path` enclosed in double quotes.
275+
/// Returns a `String` representing the path, quoted on Windows, unquoted on Unix.
262276
///
263277
/// # Errors
264278
///
265279
/// This function will return an error when the string conversion fails
266280
pub fn path_to_quoted_string<P: AsRef<Path>>(path: P) -> zed::Result<String> {
267-
path.as_ref()
281+
let path_str = path
282+
.as_ref()
268283
.to_path_buf()
269284
.into_os_string()
270285
.into_string()
271-
.map(|s| format!("\"{}\"", s))
272-
.map_err(|_| PATH_TO_STR_ERROR.to_string())
286+
.map_err(|_| PATH_TO_STR_ERROR.to_string())?;
287+
288+
Ok(format_path_for_os(path_str, current_platform().0))
273289
}
274290

275291
/// Remove all files or directories that aren't equal to [`filename`].
@@ -356,19 +372,26 @@ mod tests {
356372
use super::*;
357373

358374
#[test]
359-
fn test_path_to_quoted_string_windows() {
360-
let path = PathBuf::from("C:\\Users\\User Name\\Projects\\zed-extension-java");
361-
let escaped = path_to_quoted_string(&path).unwrap();
375+
fn test_format_path_for_os_windows() {
376+
let path = "C:\\Users\\User Name\\Projects\\zed-extension-java".to_string();
377+
let result = format_path_for_os(path, Os::Windows);
362378
assert_eq!(
363-
escaped,
379+
result,
364380
"\"C:\\Users\\User Name\\Projects\\zed-extension-java\""
365381
);
366382
}
367383

368384
#[test]
369-
fn test_path_to_quoted_string_unix() {
370-
let path = PathBuf::from("/home/username/Projects/zed extension java");
371-
let escaped = path_to_quoted_string(&path).unwrap();
372-
assert_eq!(escaped, "\"/home/username/Projects/zed extension java\"");
385+
fn test_format_path_for_os_unix() {
386+
let path = "/home/username/Projects/zed extension java".to_string();
387+
let result = format_path_for_os(path, Os::Mac);
388+
assert_eq!(result, "/home/username/Projects/zed extension java");
389+
}
390+
391+
#[test]
392+
fn test_format_path_for_os_linux() {
393+
let path = "/home/username/Projects/zed extension java".to_string();
394+
let result = format_path_for_os(path, Os::Linux);
395+
assert_eq!(result, "/home/username/Projects/zed extension java");
373396
}
374397
}

0 commit comments

Comments
 (0)