diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 1e1c13d9ab..f910ba6963 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -8320,6 +8320,7 @@ async fn test_language_server_restart_due_to_settings_change(cx: &mut gpui::Test project_settings.lsp.insert( "Some other server name".into(), LspSettings { + binary: None, settings: None, initialization_options: Some(json!({ "some other init value": false @@ -8338,6 +8339,7 @@ async fn test_language_server_restart_due_to_settings_change(cx: &mut gpui::Test project_settings.lsp.insert( language_server_name.into(), LspSettings { + binary: None, settings: None, initialization_options: Some(json!({ "anotherInitValue": false @@ -8356,6 +8358,7 @@ async fn test_language_server_restart_due_to_settings_change(cx: &mut gpui::Test project_settings.lsp.insert( language_server_name.into(), LspSettings { + binary: None, settings: None, initialization_options: Some(json!({ "anotherInitValue": false @@ -8374,6 +8377,7 @@ async fn test_language_server_restart_due_to_settings_change(cx: &mut gpui::Test project_settings.lsp.insert( language_server_name.into(), LspSettings { + binary: None, settings: None, initialization_options: None, }, diff --git a/crates/extension/src/extension_lsp_adapter.rs b/crates/extension/src/extension_lsp_adapter.rs index 41bfa9b29e..4f6206683d 100644 --- a/crates/extension/src/extension_lsp_adapter.rs +++ b/crates/extension/src/extension_lsp_adapter.rs @@ -19,7 +19,7 @@ pub struct ExtensionLspAdapter { pub(crate) host: Arc, } -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for ExtensionLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName(self.config.name.clone().into()) diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index 37e28d5cd6..b44bf83017 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -282,7 +282,7 @@ pub trait LspAdapterDelegate: Send + Sync { async fn read_text_file(&self, path: PathBuf) -> Result; } -#[async_trait] +#[async_trait(?Send)] pub trait LspAdapter: 'static + Send + Sync { fn name(&self) -> LanguageServerName; @@ -306,7 +306,7 @@ pub trait LspAdapter: 'static + Send + Sync { // We only want to cache when we fall back to the global one, // because we don't want to download and overwrite our global one // for each worktree we might have open. - if let Some(binary) = self.check_if_user_installed(delegate.as_ref()).await { + if let Some(binary) = self.check_if_user_installed(delegate.as_ref(), cx).await { log::info!( "found user-installed language server for {}. path: {:?}, arguments: {:?}", language.name(), @@ -380,6 +380,7 @@ pub trait LspAdapter: 'static + Send + Sync { async fn check_if_user_installed( &self, _: &dyn LspAdapterDelegate, + _: &AsyncAppContext, ) -> Option { None } @@ -1457,7 +1458,7 @@ impl Default for FakeLspAdapter { } #[cfg(any(test, feature = "test-support"))] -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for FakeLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName(self.name.into()) diff --git a/crates/languages/src/astro.rs b/crates/languages/src/astro.rs index 2ed3853e07..95aa150d61 100644 --- a/crates/languages/src/astro.rs +++ b/crates/languages/src/astro.rs @@ -30,7 +30,7 @@ impl AstroLspAdapter { } } -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for AstroLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("astro-language-server".into()) diff --git a/crates/languages/src/c.rs b/crates/languages/src/c.rs index 28ceedf7ad..7c4d992c23 100644 --- a/crates/languages/src/c.rs +++ b/crates/languages/src/c.rs @@ -14,7 +14,7 @@ use util::{ pub struct CLspAdapter; -#[async_trait] +#[async_trait(?Send)] impl super::LspAdapter for CLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("clangd".into()) diff --git a/crates/languages/src/clojure.rs b/crates/languages/src/clojure.rs index 139d741db2..6fae33636c 100644 --- a/crates/languages/src/clojure.rs +++ b/crates/languages/src/clojure.rs @@ -12,7 +12,7 @@ use util::{ #[derive(Copy, Clone)] pub struct ClojureLspAdapter; -#[async_trait] +#[async_trait(?Send)] impl super::LspAdapter for ClojureLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("clojure-lsp".into()) diff --git a/crates/languages/src/csharp.rs b/crates/languages/src/csharp.rs index 297e397cdd..4d9f26328c 100644 --- a/crates/languages/src/csharp.rs +++ b/crates/languages/src/csharp.rs @@ -15,7 +15,7 @@ use util::{github::GitHubLspBinaryVersion, ResultExt}; pub struct OmniSharpAdapter; -#[async_trait] +#[async_trait(?Send)] impl super::LspAdapter for OmniSharpAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("OmniSharp".into()) diff --git a/crates/languages/src/css.rs b/crates/languages/src/css.rs index 8baae44703..fbc856efbd 100644 --- a/crates/languages/src/css.rs +++ b/crates/languages/src/css.rs @@ -31,7 +31,7 @@ impl CssLspAdapter { } } -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for CssLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("vscode-css-language-server".into()) diff --git a/crates/languages/src/dart.rs b/crates/languages/src/dart.rs index 5c0d0c21a1..12ac699ee0 100644 --- a/crates/languages/src/dart.rs +++ b/crates/languages/src/dart.rs @@ -13,7 +13,7 @@ use std::{ pub struct DartLanguageServer; -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for DartLanguageServer { fn name(&self) -> LanguageServerName { LanguageServerName("dart".into()) diff --git a/crates/languages/src/deno.rs b/crates/languages/src/deno.rs index abb9dccbfb..1aed3930fb 100644 --- a/crates/languages/src/deno.rs +++ b/crates/languages/src/deno.rs @@ -56,7 +56,7 @@ impl DenoLspAdapter { } } -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for DenoLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("deno-language-server".into()) diff --git a/crates/languages/src/dockerfile.rs b/crates/languages/src/dockerfile.rs index c3cd4411e9..35ee844d89 100644 --- a/crates/languages/src/dockerfile.rs +++ b/crates/languages/src/dockerfile.rs @@ -29,7 +29,7 @@ impl DockerfileLspAdapter { } } -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for DockerfileLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("docker-langserver".into()) diff --git a/crates/languages/src/elixir.rs b/crates/languages/src/elixir.rs index 471f466c84..b4479c0fd8 100644 --- a/crates/languages/src/elixir.rs +++ b/crates/languages/src/elixir.rs @@ -65,7 +65,7 @@ impl Settings for ElixirSettings { pub struct ElixirLspAdapter; -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for ElixirLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("elixir-ls".into()) @@ -292,7 +292,7 @@ async fn get_cached_server_binary_elixir_ls( pub struct NextLspAdapter; -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for NextLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("next-ls".into()) @@ -446,7 +446,7 @@ pub struct LocalLspAdapter { pub arguments: Vec, } -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for LocalLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("local-ls".into()) diff --git a/crates/languages/src/elm.rs b/crates/languages/src/elm.rs index 37b156db91..5f99649ee9 100644 --- a/crates/languages/src/elm.rs +++ b/crates/languages/src/elm.rs @@ -34,7 +34,7 @@ impl ElmLspAdapter { } } -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for ElmLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName(SERVER_NAME.into()) diff --git a/crates/languages/src/erlang.rs b/crates/languages/src/erlang.rs index 2b6d33ed41..a868055703 100644 --- a/crates/languages/src/erlang.rs +++ b/crates/languages/src/erlang.rs @@ -6,7 +6,7 @@ use std::{any::Any, path::PathBuf}; pub struct ErlangLspAdapter; -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for ErlangLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("erlang_ls".into()) diff --git a/crates/languages/src/gleam.rs b/crates/languages/src/gleam.rs index 9eb22c179e..e9a5b6a48a 100644 --- a/crates/languages/src/gleam.rs +++ b/crates/languages/src/gleam.rs @@ -21,7 +21,7 @@ fn server_binary_arguments() -> Vec { pub struct GleamLspAdapter; -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for GleamLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("gleam".into()) diff --git a/crates/languages/src/go.rs b/crates/languages/src/go.rs index 4710facc4b..505ba7bd04 100644 --- a/crates/languages/src/go.rs +++ b/crates/languages/src/go.rs @@ -32,7 +32,7 @@ lazy_static! { static ref GOPLS_VERSION_REGEX: Regex = Regex::new(r"\d+\.\d+\.\d+").unwrap(); } -#[async_trait] +#[async_trait(?Send)] impl super::LspAdapter for GoLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("gopls".into()) @@ -57,6 +57,7 @@ impl super::LspAdapter for GoLspAdapter { async fn check_if_user_installed( &self, delegate: &dyn LspAdapterDelegate, + _: &AsyncAppContext, ) -> Option { let env = delegate.shell_env().await; let path = delegate.which("gopls".as_ref()).await?; diff --git a/crates/languages/src/haskell.rs b/crates/languages/src/haskell.rs index 0e8c59d623..224910a04d 100644 --- a/crates/languages/src/haskell.rs +++ b/crates/languages/src/haskell.rs @@ -6,7 +6,7 @@ use std::{any::Any, path::PathBuf}; pub struct HaskellLanguageServer; -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for HaskellLanguageServer { fn name(&self) -> LanguageServerName { LanguageServerName("hls".into()) diff --git a/crates/languages/src/html.rs b/crates/languages/src/html.rs index 713a432de3..3935d20456 100644 --- a/crates/languages/src/html.rs +++ b/crates/languages/src/html.rs @@ -31,7 +31,7 @@ impl HtmlLspAdapter { } } -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for HtmlLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("vscode-html-language-server".into()) diff --git a/crates/languages/src/json.rs b/crates/languages/src/json.rs index 1813f4c270..1b32876155 100644 --- a/crates/languages/src/json.rs +++ b/crates/languages/src/json.rs @@ -83,7 +83,7 @@ impl JsonLspAdapter { } } -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for JsonLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("json-language-server".into()) diff --git a/crates/languages/src/lua.rs b/crates/languages/src/lua.rs index cad9004480..d0f60378ff 100644 --- a/crates/languages/src/lua.rs +++ b/crates/languages/src/lua.rs @@ -16,7 +16,7 @@ use util::{ #[derive(Copy, Clone)] pub struct LuaLspAdapter; -#[async_trait] +#[async_trait(?Send)] impl super::LspAdapter for LuaLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("lua-language-server".into()) diff --git a/crates/languages/src/nu.rs b/crates/languages/src/nu.rs index 691ecfd52f..58c8e30dc3 100644 --- a/crates/languages/src/nu.rs +++ b/crates/languages/src/nu.rs @@ -6,7 +6,7 @@ use std::{any::Any, path::PathBuf}; pub struct NuLanguageServer; -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for NuLanguageServer { fn name(&self) -> LanguageServerName { LanguageServerName("nu".into()) diff --git a/crates/languages/src/ocaml.rs b/crates/languages/src/ocaml.rs index 0dc4bfcd2b..74f5f60299 100644 --- a/crates/languages/src/ocaml.rs +++ b/crates/languages/src/ocaml.rs @@ -12,7 +12,7 @@ const OPERATOR_CHAR: [char; 17] = [ pub struct OCamlLspAdapter; -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for OCamlLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("ocamllsp".into()) diff --git a/crates/languages/src/php.rs b/crates/languages/src/php.rs index 1405614210..0fcb2b3b23 100644 --- a/crates/languages/src/php.rs +++ b/crates/languages/src/php.rs @@ -34,7 +34,7 @@ impl IntelephenseLspAdapter { } } -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for IntelephenseLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("intelephense".into()) diff --git a/crates/languages/src/prisma.rs b/crates/languages/src/prisma.rs index 0731cc8d11..17fcb5fd3f 100644 --- a/crates/languages/src/prisma.rs +++ b/crates/languages/src/prisma.rs @@ -29,7 +29,7 @@ impl PrismaLspAdapter { } } -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for PrismaLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("prisma-language-server".into()) diff --git a/crates/languages/src/purescript.rs b/crates/languages/src/purescript.rs index df3cb5b5a9..8787826a18 100644 --- a/crates/languages/src/purescript.rs +++ b/crates/languages/src/purescript.rs @@ -33,7 +33,7 @@ impl PurescriptLspAdapter { } } -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for PurescriptLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("purescript-language-server".into()) diff --git a/crates/languages/src/python.rs b/crates/languages/src/python.rs index bf1cae7d9d..bd9eab3ced 100644 --- a/crates/languages/src/python.rs +++ b/crates/languages/src/python.rs @@ -28,7 +28,7 @@ impl PythonLspAdapter { } } -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for PythonLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("pyright".into()) diff --git a/crates/languages/src/ruby.rs b/crates/languages/src/ruby.rs index ced781bfbf..8a634b6bc4 100644 --- a/crates/languages/src/ruby.rs +++ b/crates/languages/src/ruby.rs @@ -6,7 +6,7 @@ use std::{any::Any, path::PathBuf, sync::Arc}; pub struct RubyLanguageServer; -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for RubyLanguageServer { fn name(&self) -> LanguageServerName { LanguageServerName("solargraph".into()) diff --git a/crates/languages/src/rust.rs b/crates/languages/src/rust.rs index 2d3925e7d6..2a58bc6015 100644 --- a/crates/languages/src/rust.rs +++ b/crates/languages/src/rust.rs @@ -2,12 +2,15 @@ use anyhow::{anyhow, bail, Result}; use async_compression::futures::bufread::GzipDecoder; use async_trait::async_trait; use futures::{io::BufReader, StreamExt}; +use gpui::AsyncAppContext; pub use language::*; use lazy_static::lazy_static; use lsp::LanguageServerBinary; +use project::project_settings::ProjectSettings; use regex::Regex; +use settings::Settings; use smol::fs::{self, File}; -use std::{any::Any, borrow::Cow, env::consts, path::PathBuf, str, sync::Arc}; +use std::{any::Any, borrow::Cow, env::consts, path::PathBuf, sync::Arc}; use util::{ async_maybe, fs::remove_matching, @@ -17,10 +20,41 @@ use util::{ pub struct RustLspAdapter; -#[async_trait] +impl RustLspAdapter { + const SERVER_NAME: &'static str = "rust-analyzer"; +} + +#[async_trait(?Send)] impl LspAdapter for RustLspAdapter { fn name(&self) -> LanguageServerName { - LanguageServerName("rust-analyzer".into()) + LanguageServerName(Self::SERVER_NAME.into()) + } + + async fn check_if_user_installed( + &self, + _delegate: &dyn LspAdapterDelegate, + cx: &AsyncAppContext, + ) -> Option { + let binary = cx + .update(|cx| { + ProjectSettings::get_global(cx) + .lsp + .get(Self::SERVER_NAME) + .and_then(|s| s.binary.clone()) + }) + .ok()??; + + let path = binary.path?; + Some(LanguageServerBinary { + path: path.into(), + arguments: binary + .arguments + .unwrap_or_default() + .iter() + .map(|arg| arg.into()) + .collect(), + env: None, + }) } async fn fetch_latest_server_version( diff --git a/crates/languages/src/svelte.rs b/crates/languages/src/svelte.rs index aff9a6db7d..721c2e6640 100644 --- a/crates/languages/src/svelte.rs +++ b/crates/languages/src/svelte.rs @@ -30,7 +30,7 @@ impl SvelteLspAdapter { } } -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for SvelteLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("svelte-language-server".into()) diff --git a/crates/languages/src/tailwind.rs b/crates/languages/src/tailwind.rs index 69ac629c7c..c49f5d8590 100644 --- a/crates/languages/src/tailwind.rs +++ b/crates/languages/src/tailwind.rs @@ -32,7 +32,7 @@ impl TailwindLspAdapter { } } -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for TailwindLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("tailwindcss-language-server".into()) diff --git a/crates/languages/src/terraform.rs b/crates/languages/src/terraform.rs index d201b8aeff..d5973cc5da 100644 --- a/crates/languages/src/terraform.rs +++ b/crates/languages/src/terraform.rs @@ -19,7 +19,7 @@ fn terraform_ls_binary_arguments() -> Vec { pub struct TerraformLspAdapter; -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for TerraformLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("terraform-ls".into()) diff --git a/crates/languages/src/toml.rs b/crates/languages/src/toml.rs index 1ca6bb8d1d..dee6a19aa7 100644 --- a/crates/languages/src/toml.rs +++ b/crates/languages/src/toml.rs @@ -12,7 +12,7 @@ use util::{github::GitHubLspBinaryVersion, ResultExt}; pub struct TaploLspAdapter; -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for TaploLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("taplo-ls".into()) diff --git a/crates/languages/src/typescript.rs b/crates/languages/src/typescript.rs index b05a370a6c..bf220130a9 100644 --- a/crates/languages/src/typescript.rs +++ b/crates/languages/src/typescript.rs @@ -50,7 +50,7 @@ struct TypeScriptVersions { server_version: String, } -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for TypeScriptLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("typescript-language-server".into()) @@ -224,7 +224,7 @@ impl EsLintLspAdapter { } } -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for EsLintLspAdapter { fn workspace_configuration(&self, workspace_root: &Path, cx: &mut AppContext) -> Value { let eslint_user_settings = ProjectSettings::get_global(cx) diff --git a/crates/languages/src/uiua.rs b/crates/languages/src/uiua.rs index 229c0804f5..8833673a27 100644 --- a/crates/languages/src/uiua.rs +++ b/crates/languages/src/uiua.rs @@ -6,7 +6,7 @@ use std::{any::Any, path::PathBuf}; pub struct UiuaLanguageServer; -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for UiuaLanguageServer { fn name(&self) -> LanguageServerName { LanguageServerName("uiua".into()) diff --git a/crates/languages/src/vue.rs b/crates/languages/src/vue.rs index f90364c66b..e29516a5df 100644 --- a/crates/languages/src/vue.rs +++ b/crates/languages/src/vue.rs @@ -38,7 +38,7 @@ impl VueLspAdapter { } } } -#[async_trait] +#[async_trait(?Send)] impl super::LspAdapter for VueLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("vue-language-server".into()) diff --git a/crates/languages/src/yaml.rs b/crates/languages/src/yaml.rs index fe115b09b3..5c288c22b6 100644 --- a/crates/languages/src/yaml.rs +++ b/crates/languages/src/yaml.rs @@ -33,7 +33,7 @@ impl YamlLspAdapter { } } -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for YamlLspAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("yaml-language-server".into()) diff --git a/crates/languages/src/zig.rs b/crates/languages/src/zig.rs index 3e6f3b8824..8d6c836f22 100644 --- a/crates/languages/src/zig.rs +++ b/crates/languages/src/zig.rs @@ -3,6 +3,7 @@ use async_compression::futures::bufread::GzipDecoder; use async_tar::Archive; use async_trait::async_trait; use futures::{io::BufReader, StreamExt}; +use gpui::AsyncAppContext; use language::{LanguageServerName, LspAdapter, LspAdapterDelegate}; use lsp::LanguageServerBinary; use smol::fs; @@ -14,7 +15,7 @@ use util::{github::GitHubLspBinaryVersion, ResultExt}; pub struct ZlsAdapter; -#[async_trait] +#[async_trait(?Send)] impl LspAdapter for ZlsAdapter { fn name(&self) -> LanguageServerName { LanguageServerName("zls".into()) @@ -43,6 +44,7 @@ impl LspAdapter for ZlsAdapter { async fn check_if_user_installed( &self, delegate: &dyn LspAdapterDelegate, + _cx: &AsyncAppContext, ) -> Option { let env = delegate.shell_env().await; let path = delegate.which("zls".as_ref()).await?; diff --git a/crates/project/src/project_settings.rs b/crates/project/src/project_settings.rs index 2d659725a7..9e0c595ee6 100644 --- a/crates/project/src/project_settings.rs +++ b/crates/project/src/project_settings.rs @@ -41,9 +41,16 @@ pub enum GitGutterSetting { Hide, } +#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] +pub struct BinarySettings { + pub path: Option, + pub arguments: Option>, +} + #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub struct LspSettings { + pub binary: Option, pub initialization_options: Option, pub settings: Option, }