@@ -261,7 +261,10 @@ impl DapStore {
.get(&adapter.name());
let user_installed_path = dap_settings.and_then(|s| match &s.binary {
DapBinary::Default => None,
- DapBinary::Custom(binary) => Some(PathBuf::from(binary)),
+ DapBinary::Custom(binary) => {
+ // if `binary` is absolute, `.join()` will keep it unmodified
+ Some(worktree.read(cx).abs_path().join(PathBuf::from(binary)))
+ }
});
let user_args = dap_settings.map(|s| s.args.clone());
let user_env = dap_settings.map(|s| s.env.clone());
@@ -563,8 +563,8 @@ impl LocalLspStore {
allow_binary_download: bool,
cx: &mut App,
) -> Task<Result<LanguageServerBinary>> {
- if let Some(settings) = settings.binary.as_ref()
- && settings.path.is_some()
+ if let Some(settings) = &settings.binary
+ && let Some(path) = settings.path.as_ref().map(PathBuf::from)
{
let settings = settings.clone();
@@ -573,7 +573,8 @@ impl LocalLspStore {
env.extend(settings.env.unwrap_or_default());
Ok(LanguageServerBinary {
- path: PathBuf::from(&settings.path.unwrap()),
+ // if `path` is absolute, `.join()` will keep it unmodified
+ path: delegate.worktree_root_path().join(path),
env: Some(env),
arguments: settings
.arguments
@@ -1208,6 +1208,73 @@ async fn test_managing_language_servers(cx: &mut gpui::TestAppContext) {
);
}
+#[gpui::test]
+async fn test_language_server_relative_path(cx: &mut gpui::TestAppContext) {
+ init_test(cx);
+
+ let settings_json_contents = json!({
+ "languages": {
+ "Rust": {
+ "language_servers": ["my_fake_lsp"]
+ }
+ },
+ "lsp": {
+ "my_fake_lsp": {
+ "binary": {
+ "path": path!("relative_path/to/my_fake_lsp_binary.exe").to_string(),
+ }
+ }
+ },
+ });
+
+ let fs = FakeFs::new(cx.executor());
+ fs.insert_tree(
+ path!("/the-root"),
+ json!({
+ ".zed": {
+ "settings.json": settings_json_contents.to_string(),
+ },
+ "relative_path": {
+ "to": {
+ "my_fake_lsp.exe": "",
+ },
+ },
+ "src": {
+ "main.rs": "",
+ }
+ }),
+ )
+ .await;
+
+ let project = Project::test(fs.clone(), [path!("/the-root").as_ref()], cx).await;
+ let language_registry = project.read_with(cx, |project, _| project.languages().clone());
+ language_registry.add(rust_lang());
+
+ let mut fake_rust_servers = language_registry.register_fake_lsp(
+ "Rust",
+ FakeLspAdapter {
+ name: "my_fake_lsp",
+ ..Default::default()
+ },
+ );
+
+ cx.run_until_parked();
+
+ // Start the language server by opening a buffer with a compatible file extension.
+ project
+ .update(cx, |project, cx| {
+ project.open_local_buffer_with_lsp(path!("/the-root/src/main.rs"), cx)
+ })
+ .await
+ .unwrap();
+
+ let lsp_path = fake_rust_servers.next().await.unwrap().binary.path;
+ assert_eq!(
+ lsp_path.to_string_lossy(),
+ path!("/the-root/relative_path/to/my_fake_lsp_binary.exe"),
+ );
+}
+
#[gpui::test]
async fn test_reporting_fs_changes_to_language_servers(cx: &mut gpui::TestAppContext) {
init_test(cx);
@@ -2352,8 +2352,8 @@ impl Snapshot {
self.entries_by_path.first()
}
- /// TODO: what's the difference between `root_dir` and `abs_path`?
- /// is there any? if so, document it.
+ /// Returns `None` for a single file worktree, or `Some(self.abs_path())` if
+ /// it is a directory.
pub fn root_dir(&self) -> Option<Arc<Path>> {
self.root_entry()
.filter(|entry| entry.is_dir())