settings: Add tilde expansion support for LSP binary path (#41715)

Closes #38227

Release Notes:

- Added tilde expansion support for LSP binary path in `settings.json`
This commit is contained in:
Mayank Verma
2025-11-13 09:14:18 -05:00
committed by GitHub
parent f318bb5fd7
commit 92e64f9cf0
2 changed files with 73 additions and 3 deletions
+61
View File
@@ -1292,6 +1292,67 @@ async fn test_language_server_relative_path(cx: &mut gpui::TestAppContext) {
assert_eq!(lsp_path.to_string_lossy(), path!("lsp_on_path.exe"));
}
#[gpui::test]
async fn test_language_server_tilde_path(cx: &mut gpui::TestAppContext) {
init_test(cx);
let settings_json_contents = json!({
"languages": {
"Rust": {
"language_servers": ["tilde_lsp"]
}
},
"lsp": {
"tilde_lsp": {
"binary": {
"path": "~/.local/bin/rust-analyzer",
}
}
},
});
let fs = FakeFs::new(cx.executor());
fs.insert_tree(
path!("/root"),
json!({
".zed": {
"settings.json": settings_json_contents.to_string(),
},
"src": {
"main.rs": "fn main() {}",
}
}),
)
.await;
let project = Project::test(fs.clone(), [path!("/root").as_ref()], cx).await;
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
language_registry.add(rust_lang());
let mut tilde_lsp = language_registry.register_fake_lsp(
"Rust",
FakeLspAdapter {
name: "tilde_lsp",
..Default::default()
},
);
cx.run_until_parked();
project
.update(cx, |project, cx| {
project.open_local_buffer_with_lsp(path!("/root/src/main.rs"), cx)
})
.await
.unwrap();
let lsp_path = tilde_lsp.next().await.unwrap().binary.path;
let expected_path = paths::home_dir().join(".local/bin/rust-analyzer");
assert_eq!(
lsp_path, expected_path,
"Tilde path should expand to home directory"
);
}
#[gpui::test]
async fn test_reporting_fs_changes_to_language_servers(cx: &mut gpui::TestAppContext) {
init_test(cx);
+12 -3
View File
@@ -2386,16 +2386,25 @@ impl Snapshot {
/// Resolves a path to an executable using the following heuristics:
///
/// 1. If the path is relative and contains more than one component,
/// 1. If the path starts with `~`, it is expanded to the user's home directory.
/// 2. If the path is relative and contains more than one component,
/// it is joined to the worktree root path.
/// 2. If the path is relative and exists in the worktree
/// 3. If the path is relative and exists in the worktree
/// (even if falls under an exclusion filter),
/// it is joined to the worktree root path.
/// 3. Otherwise the path is returned unmodified.
/// 4. Otherwise the path is returned unmodified.
///
/// Relative paths that do not exist in the worktree may
/// still be found using the `PATH` environment variable.
pub fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
if let Some(path_str) = path.to_str() {
if let Some(remaining_path) = path_str.strip_prefix("~/") {
return home_dir().join(remaining_path);
} else if path_str == "~" {
return home_dir().to_path_buf();
}
}
if let Ok(rel_path) = RelPath::new(&path, self.path_style)
&& (path.components().count() > 1 || self.entry_for_path(&rel_path).is_some())
{