paths: Fix using relative path as custom_data_dir (#35256)

devjasperwang created

This PR fixes issue of incorrect LSP path args caused by using a
relative path when customizing data directory.

command:
```bash
.\target\debug\zed.exe --user-data-dir=.\target\data
```

before:
```log
2025-07-29T14:17:18+08:00 INFO  [lsp] starting language server process. binary path: "F:\\nvm\\nodejs\\node.exe", working directory: "F:\\zed\\target\\data\\config", args: [".\\target\\data\\languages\\json-language-server\\node_modules/vscode-langservers-extracted/bin/vscode-json-language-server", "--stdio"]
2025-07-29T14:17:18+08:00 INFO  [project::prettier_store] Installing default prettier and plugins: [("prettier", "3.6.2")]
2025-07-29T14:17:18+08:00 ERROR [lsp] cannot read LSP message headers
2025-07-29T14:17:18+08:00 ERROR [lsp] Shutdown request failure, server json-language-server (id 1): server shut down

2025-07-29T14:17:43+08:00 ERROR [project] Invalid file path provided to LSP request: ".\\target\\data\\config\\settings.json"
Thread "main" panicked with "called `Result::unwrap()` on an `Err` value: ()" at crates\project\src\lsp_store.rs:7203:54
https://github.com/zed-industries/zed/blob/cfd5b8ff10cd88a97988292c964689f67301520b/src/crates\project\src\lsp_store.rs#L7203 (may not be uploaded, line may be incorrect if files modified)
```

after:
```log
2025-07-29T14:24:20+08:00 INFO  [lsp] starting language server process. binary path: "F:\\nvm\\nodejs\\node.exe", working directory: "F:\\zed\\target\\data\\config", args: ["F:\\zed\\target\\data\\languages\\json-language-server\\node_modules/vscode-langservers-extracted/bin/vscode-json-language-server", "--stdio"]
```

Release Notes:

- N/A

Change summary

crates/paths/src/paths.rs | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)

Detailed changes

crates/paths/src/paths.rs 🔗

@@ -35,6 +35,7 @@ pub fn remote_server_dir_relative() -> &'static Path {
 
 /// Sets a custom directory for all user data, overriding the default data directory.
 /// This function must be called before any other path operations that depend on the data directory.
+/// The directory's path will be canonicalized to an absolute path by a blocking FS operation.
 /// The directory will be created if it doesn't exist.
 ///
 /// # Arguments
@@ -50,13 +51,20 @@ pub fn remote_server_dir_relative() -> &'static Path {
 ///
 /// Panics if:
 /// * Called after the data directory has been initialized (e.g., via `data_dir` or `config_dir`)
+/// * The directory's path cannot be canonicalized to an absolute path
 /// * The directory cannot be created
 pub fn set_custom_data_dir(dir: &str) -> &'static PathBuf {
     if CURRENT_DATA_DIR.get().is_some() || CONFIG_DIR.get().is_some() {
         panic!("set_custom_data_dir called after data_dir or config_dir was initialized");
     }
     CUSTOM_DATA_DIR.get_or_init(|| {
-        let path = PathBuf::from(dir);
+        let mut path = PathBuf::from(dir);
+        if path.is_relative() {
+            let abs_path = path
+                .canonicalize()
+                .expect("failed to canonicalize custom data directory's path to an absolute path");
+            path = PathBuf::from(util::paths::SanitizedPath::from(abs_path))
+        }
         std::fs::create_dir_all(&path).expect("failed to create custom data directory");
         path
     })