diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index 79a588a5d52a837c31582e83e3ca884bab0dcaa7..20dd639506afec2cbbab0d7cd5b7c2a94032b752 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -379,7 +379,7 @@ pub trait LspAdapterDelegate: Send + Sync { fn http_client(&self) -> Arc; fn worktree_id(&self) -> WorktreeId; fn worktree_root_path(&self) -> &Path; - fn resolve_executable_path(&self, path: PathBuf) -> PathBuf; + fn resolve_relative_path(&self, path: PathBuf) -> PathBuf; fn update_status(&self, language: LanguageServerName, status: BinaryStatus); fn registered_lsp_adapters(&self) -> Vec>; async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option>; diff --git a/crates/languages/src/json.rs b/crates/languages/src/json.rs index a6b5f9aec32eaabb90211b216fb2a9df417b178b..b6c3954cf228d90714a5eb5676d86a204b47b88d 100644 --- a/crates/languages/src/json.rs +++ b/crates/languages/src/json.rs @@ -296,7 +296,7 @@ impl LspAdapter for JsonLspAdapter { }); let project_options = cx.update(|cx| { language_server_settings(delegate.as_ref(), &self.name(), cx) - .and_then(|s| s.settings.clone()) + .and_then(|s| worktree_root(delegate, s.settings.clone())) }); if let Some(override_options) = project_options { @@ -320,6 +320,40 @@ impl LspAdapter for JsonLspAdapter { } } +fn worktree_root(delegate: &Arc, settings: Option) -> Option { + let Some(Value::Object(mut settings_map)) = settings else { + return settings; + }; + + let Some(Value::Object(json_config)) = settings_map.get_mut("json") else { + return Some(Value::Object(settings_map)); + }; + + let Some(Value::Array(schemas)) = json_config.get_mut("schemas") else { + return Some(Value::Object(settings_map)); + }; + + for schema in schemas.iter_mut() { + let Value::Object(schema_map) = schema else { + continue; + }; + let Some(Value::String(url)) = schema_map.get_mut("url") else { + continue; + }; + + if !url.starts_with(".") && !url.starts_with("~") { + continue; + } + + *url = delegate + .resolve_relative_path(url.clone().into()) + .to_string_lossy() + .into_owned(); + } + + Some(Value::Object(settings_map)) +} + async fn get_cached_server_binary( container_dir: PathBuf, node: &NodeRuntime, diff --git a/crates/languages/src/yaml.rs b/crates/languages/src/yaml.rs index 64d110bc4475474642d97a0c0c43de6495978ff0..e8bad8eb2059b02486fa2b7d7e14479dc57a23d6 100644 --- a/crates/languages/src/yaml.rs +++ b/crates/languages/src/yaml.rs @@ -156,7 +156,7 @@ impl LspAdapter for YamlLspAdapter { let project_options = cx.update(|cx| { language_server_settings(delegate.as_ref(), &Self::SERVER_NAME, cx) - .and_then(|s| s.settings.clone()) + .and_then(|s| worktree_root(delegate, s.settings.clone())) }); if let Some(override_options) = project_options { merge_json_value_into(override_options, &mut options); @@ -165,6 +165,38 @@ impl LspAdapter for YamlLspAdapter { } } +fn worktree_root(delegate: &Arc, settings: Option) -> Option { + let Some(Value::Object(mut settings_map)) = settings else { + return settings; + }; + + let Some(Value::Object(yaml_config)) = settings_map.get_mut("yaml") else { + return Some(Value::Object(settings_map)); + }; + + let Some(Value::Object(schemas)) = yaml_config.remove("schemas") else { + return Some(Value::Object(settings_map)); + }; + + let schemas = schemas + .into_iter() + .map(|(url, v)| { + if !url.starts_with(".") && !url.starts_with("~") { + (url, v) + } else { + let resolved_url = delegate + .resolve_relative_path(url.into()) + .to_string_lossy() + .into_owned(); + (resolved_url, v) + } + }) + .collect::>(); + + yaml_config.insert("schemas".into(), Value::Object(schemas)); + Some(Value::Object(settings_map)) +} + async fn get_cached_server_binary( container_dir: PathBuf, node: &NodeRuntime, diff --git a/crates/project/src/debugger/dap_store.rs b/crates/project/src/debugger/dap_store.rs index ab44cacf2d65607b669e160f4839642cef442238..6d320bc06e69ba4eb3cc12ee9b7f328fc5fb0e08 100644 --- a/crates/project/src/debugger/dap_store.rs +++ b/crates/project/src/debugger/dap_store.rs @@ -265,7 +265,7 @@ impl DapStore { DapBinary::Default => None, DapBinary::Custom(binary) => { let path = PathBuf::from(binary); - Some(worktree.read(cx).resolve_executable_path(path)) + Some(worktree.read(cx).resolve_relative_path(path)) } }); let user_args = dap_settings.and_then(|s| s.args.clone()); diff --git a/crates/project/src/lsp_store.rs b/crates/project/src/lsp_store.rs index 6be1b233b75de2cdd1572b0e36186e6994a1745b..d37674defb1abed9d77730827a6183aaf9ac87d6 100644 --- a/crates/project/src/lsp_store.rs +++ b/crates/project/src/lsp_store.rs @@ -713,7 +713,7 @@ impl LocalLspStore { env.extend(settings.env.unwrap_or_default()); Ok(LanguageServerBinary { - path: delegate.resolve_executable_path(path), + path: delegate.resolve_relative_path(path), env: Some(env), arguments: settings .arguments @@ -14069,8 +14069,8 @@ impl LspAdapterDelegate for LocalLspAdapterDelegate { self.worktree.abs_path().as_ref() } - fn resolve_executable_path(&self, path: PathBuf) -> PathBuf { - self.worktree.resolve_executable_path(path) + fn resolve_relative_path(&self, path: PathBuf) -> PathBuf { + self.worktree.resolve_relative_path(path) } async fn shell_env(&self) -> HashMap { diff --git a/crates/worktree/src/worktree.rs b/crates/worktree/src/worktree.rs index 77a9f48f33395aa5307b3cd6a63007408e9033ac..86589423022d3d4a6fcba4db58c188fa62074315 100644 --- a/crates/worktree/src/worktree.rs +++ b/crates/worktree/src/worktree.rs @@ -2495,7 +2495,7 @@ impl Snapshot { /// /// 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 { + pub fn resolve_relative_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);