Use LanguageServerName in more places (#18167)

Conrad Irwin created

This pushes the new LanguageServerName type to more places.

As both languages and language servers were identified by Arc<str>, it
was
sometimes hard to tell which was intended.

Release Notes:

- N/A

Change summary

crates/activity_indicator/src/activity_indicator.rs           |  7 
crates/collab/src/tests/remote_editing_collaboration_tests.rs |  2 
crates/extension/src/wasm_host/wit/since_v0_1_0.rs            |  4 
crates/extension/src/wasm_host/wit/since_v0_2_0.rs            |  4 
crates/gpui/src/shared_string.rs                              |  7 
crates/language/src/language.rs                               | 57 ++++
crates/language/src/language_settings.rs                      | 32 +-
crates/language_tools/src/lsp_log.rs                          |  2 
crates/languages/src/c.rs                                     |  7 
crates/languages/src/go.rs                                    |  7 
crates/languages/src/python.rs                                | 21 +
crates/languages/src/rust.rs                                  |  8 
crates/languages/src/tailwind.rs                              |  9 
crates/languages/src/typescript.rs                            | 13 
crates/languages/src/vtsls.rs                                 |  8 
crates/languages/src/yaml.rs                                  |  8 
crates/project/src/lsp_store.rs                               | 24 +-
crates/project/src/prettier_store.rs                          |  4 
crates/project/src/project_settings.rs                        |  3 
crates/remote_server/src/remote_editing_tests.rs              |  8 
20 files changed, 150 insertions(+), 85 deletions(-)

Detailed changes

crates/activity_indicator/src/activity_indicator.rs 🔗

@@ -19,7 +19,10 @@ use workspace::{item::ItemHandle, StatusItemView, Workspace};
 actions!(activity_indicator, [ShowErrorMessage]);
 
 pub enum Event {
-    ShowError { lsp_name: Arc<str>, error: String },
+    ShowError {
+        lsp_name: LanguageServerName,
+        error: String,
+    },
 }
 
 pub struct ActivityIndicator {
@@ -123,7 +126,7 @@ impl ActivityIndicator {
         self.statuses.retain(|status| {
             if let LanguageServerBinaryStatus::Failed { error } = &status.status {
                 cx.emit(Event::ShowError {
-                    lsp_name: status.name.0.clone(),
+                    lsp_name: status.name.clone(),
                     error: error.clone(),
                 });
                 false

crates/extension/src/wasm_host/wit/since_v0_1_0.rs 🔗

@@ -9,10 +9,10 @@ use futures::{io::BufReader, FutureExt as _};
 use futures::{lock::Mutex, AsyncReadExt};
 use indexed_docs::IndexedDocsDatabase;
 use isahc::config::{Configurable, RedirectPolicy};
-use language::LanguageName;
 use language::{
     language_settings::AllLanguageSettings, LanguageServerBinaryStatus, LspAdapterDelegate,
 };
+use language::{LanguageName, LanguageServerName};
 use project::project_settings::ProjectSettings;
 use semantic_version::SemanticVersion;
 use std::{
@@ -366,7 +366,7 @@ impl ExtensionImports for WasmState {
                             .and_then(|key| {
                                 ProjectSettings::get(location, cx)
                                     .lsp
-                                    .get(&Arc::<str>::from(key))
+                                    .get(&LanguageServerName(key.into()))
                             })
                             .cloned()
                             .unwrap_or_default();

crates/extension/src/wasm_host/wit/since_v0_2_0.rs 🔗

@@ -9,10 +9,10 @@ use futures::{io::BufReader, FutureExt as _};
 use futures::{lock::Mutex, AsyncReadExt};
 use indexed_docs::IndexedDocsDatabase;
 use isahc::config::{Configurable, RedirectPolicy};
-use language::LanguageName;
 use language::{
     language_settings::AllLanguageSettings, LanguageServerBinaryStatus, LspAdapterDelegate,
 };
+use language::{LanguageName, LanguageServerName};
 use project::project_settings::ProjectSettings;
 use semantic_version::SemanticVersion;
 use std::{
@@ -412,7 +412,7 @@ impl ExtensionImports for WasmState {
                             .and_then(|key| {
                                 ProjectSettings::get(location, cx)
                                     .lsp
-                                    .get(&Arc::<str>::from(key))
+                                    .get(&LanguageServerName::from_proto(key))
                             })
                             .cloned()
                             .unwrap_or_default();

crates/gpui/src/shared_string.rs 🔗

@@ -9,6 +9,13 @@ use util::arc_cow::ArcCow;
 #[derive(Deref, DerefMut, Eq, PartialEq, PartialOrd, Ord, Hash, Clone)]
 pub struct SharedString(ArcCow<'static, str>);
 
+impl SharedString {
+    /// creates a static SharedString
+    pub const fn new_static(s: &'static str) -> Self {
+        Self(ArcCow::Borrowed(s))
+    }
+}
+
 impl Default for SharedString {
     fn default() -> Self {
         Self(ArcCow::Owned(Arc::default()))

crates/language/src/language.rs 🔗

@@ -139,11 +139,52 @@ pub trait ToLspPosition {
 
 /// A name of a language server.
 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
-pub struct LanguageServerName(pub Arc<str>);
+pub struct LanguageServerName(pub SharedString);
 
+impl std::fmt::Display for LanguageServerName {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        std::fmt::Display::fmt(&self.0, f)
+    }
+}
+
+impl AsRef<str> for LanguageServerName {
+    fn as_ref(&self) -> &str {
+        self.0.as_ref()
+    }
+}
+
+impl AsRef<OsStr> for LanguageServerName {
+    fn as_ref(&self) -> &OsStr {
+        self.0.as_ref().as_ref()
+    }
+}
+
+impl JsonSchema for LanguageServerName {
+    fn schema_name() -> String {
+        "LanguageServerName".into()
+    }
+
+    fn json_schema(_: &mut SchemaGenerator) -> Schema {
+        SchemaObject {
+            instance_type: Some(InstanceType::String.into()),
+            ..Default::default()
+        }
+        .into()
+    }
+}
 impl LanguageServerName {
+    pub const fn new_static(s: &'static str) -> Self {
+        Self(SharedString::new_static(s))
+    }
+
     pub fn from_proto(s: String) -> Self {
-        Self(Arc::from(s))
+        Self(s.into())
+    }
+}
+
+impl<'a> From<&'a str> for LanguageServerName {
+    fn from(str: &'a str) -> LanguageServerName {
+        LanguageServerName(str.to_string().into())
     }
 }
 
@@ -202,8 +243,8 @@ impl CachedLspAdapter {
         })
     }
 
-    pub fn name(&self) -> Arc<str> {
-        self.adapter.name().0.clone()
+    pub fn name(&self) -> LanguageServerName {
+        self.adapter.name().clone()
     }
 
     pub async fn get_language_server_command(
@@ -594,7 +635,7 @@ pub struct LanguageConfig {
     pub block_comment: Option<(Arc<str>, Arc<str>)>,
     /// A list of language servers that are allowed to run on subranges of a given language.
     #[serde(default)]
-    pub scope_opt_in_language_servers: Vec<String>,
+    pub scope_opt_in_language_servers: Vec<LanguageServerName>,
     #[serde(default)]
     pub overrides: HashMap<String, LanguageConfigOverride>,
     /// A list of characters that Zed should treat as word characters for the
@@ -658,7 +699,7 @@ pub struct LanguageConfigOverride {
     #[serde(default)]
     pub word_characters: Override<HashSet<char>>,
     #[serde(default)]
-    pub opt_into_language_servers: Vec<String>,
+    pub opt_into_language_servers: Vec<LanguageServerName>,
 }
 
 #[derive(Clone, Deserialize, Debug, Serialize, JsonSchema)]
@@ -1479,9 +1520,9 @@ impl LanguageScope {
     pub fn language_allowed(&self, name: &LanguageServerName) -> bool {
         let config = &self.language.config;
         let opt_in_servers = &config.scope_opt_in_language_servers;
-        if opt_in_servers.iter().any(|o| *o == *name.0) {
+        if opt_in_servers.iter().any(|o| *o == *name) {
             if let Some(over) = self.config_override() {
-                over.opt_into_language_servers.iter().any(|o| *o == *name.0)
+                over.opt_into_language_servers.iter().any(|o| *o == *name)
             } else {
                 false
             }

crates/language/src/language_settings.rs 🔗

@@ -99,7 +99,7 @@ pub struct LanguageSettings {
     /// special tokens:
     /// - `"!<language_server_id>"` - A language server ID prefixed with a `!` will be disabled.
     /// - `"..."` - A placeholder to refer to the **rest** of the registered language servers for this language.
-    pub language_servers: Vec<Arc<str>>,
+    pub language_servers: Vec<String>,
     /// Controls whether inline completions are shown immediately (true)
     /// or manually by triggering `editor::ShowInlineCompletion` (false).
     pub show_inline_completions: bool,
@@ -137,22 +137,24 @@ impl LanguageSettings {
     }
 
     pub(crate) fn resolve_language_servers(
-        configured_language_servers: &[Arc<str>],
+        configured_language_servers: &[String],
         available_language_servers: &[LanguageServerName],
     ) -> Vec<LanguageServerName> {
-        let (disabled_language_servers, enabled_language_servers): (Vec<Arc<str>>, Vec<Arc<str>>) =
-            configured_language_servers.iter().partition_map(
-                |language_server| match language_server.strip_prefix('!') {
-                    Some(disabled) => Either::Left(disabled.into()),
-                    None => Either::Right(language_server.clone()),
-                },
-            );
+        let (disabled_language_servers, enabled_language_servers): (
+            Vec<LanguageServerName>,
+            Vec<LanguageServerName>,
+        ) = configured_language_servers.iter().partition_map(
+            |language_server| match language_server.strip_prefix('!') {
+                Some(disabled) => Either::Left(LanguageServerName(disabled.to_string().into())),
+                None => Either::Right(LanguageServerName(language_server.clone().into())),
+            },
+        );
 
         let rest = available_language_servers
             .iter()
             .filter(|&available_language_server| {
-                !disabled_language_servers.contains(&available_language_server.0)
-                    && !enabled_language_servers.contains(&available_language_server.0)
+                !disabled_language_servers.contains(&available_language_server)
+                    && !enabled_language_servers.contains(&available_language_server)
             })
             .cloned()
             .collect::<Vec<_>>();
@@ -160,10 +162,10 @@ impl LanguageSettings {
         enabled_language_servers
             .into_iter()
             .flat_map(|language_server| {
-                if language_server.as_ref() == Self::REST_OF_LANGUAGE_SERVERS {
+                if language_server.0.as_ref() == Self::REST_OF_LANGUAGE_SERVERS {
                     rest.clone()
                 } else {
-                    vec![LanguageServerName(language_server.clone())]
+                    vec![language_server.clone()]
                 }
             })
             .collect::<Vec<_>>()
@@ -295,7 +297,7 @@ pub struct LanguageSettingsContent {
     ///
     /// Default: ["..."]
     #[serde(default)]
-    pub language_servers: Option<Vec<Arc<str>>>,
+    pub language_servers: Option<Vec<String>>,
     /// Controls whether inline completions are shown immediately (true)
     /// or manually by triggering `editor::ShowInlineCompletion` (false).
     ///
@@ -1165,7 +1167,7 @@ mod tests {
             names
                 .iter()
                 .copied()
-                .map(|name| LanguageServerName(name.into()))
+                .map(|name| LanguageServerName(name.to_string().into()))
                 .collect::<Vec<_>>()
         }
 

crates/language_tools/src/lsp_log.rs 🔗

@@ -236,7 +236,7 @@ impl LogStore {
                             ));
                         this.add_language_server(
                             LanguageServerKind::Global {
-                                name: LanguageServerName(Arc::from("copilot")),
+                                name: LanguageServerName::new_static("copilot"),
                             },
                             server.server_id(),
                             Some(server.clone()),

crates/languages/src/c.rs 🔗

@@ -13,13 +13,13 @@ use util::{fs::remove_matching, maybe, ResultExt};
 pub struct CLspAdapter;
 
 impl CLspAdapter {
-    const SERVER_NAME: &'static str = "clangd";
+    const SERVER_NAME: LanguageServerName = LanguageServerName::new_static("clangd");
 }
 
 #[async_trait(?Send)]
 impl super::LspAdapter for CLspAdapter {
     fn name(&self) -> LanguageServerName {
-        LanguageServerName(Self::SERVER_NAME.into())
+        Self::SERVER_NAME.clone()
     }
 
     async fn check_if_user_installed(
@@ -28,7 +28,8 @@ impl super::LspAdapter for CLspAdapter {
         cx: &AsyncAppContext,
     ) -> Option<LanguageServerBinary> {
         let configured_binary = cx.update(|cx| {
-            language_server_settings(delegate, Self::SERVER_NAME, cx).and_then(|s| s.binary.clone())
+            language_server_settings(delegate, &Self::SERVER_NAME, cx)
+                .and_then(|s| s.binary.clone())
         });
 
         match configured_binary {

crates/languages/src/go.rs 🔗

@@ -33,7 +33,7 @@ fn server_binary_arguments() -> Vec<OsString> {
 pub struct GoLspAdapter;
 
 impl GoLspAdapter {
-    const SERVER_NAME: &'static str = "gopls";
+    const SERVER_NAME: LanguageServerName = LanguageServerName::new_static("gopls");
 }
 
 static GOPLS_VERSION_REGEX: LazyLock<Regex> =
@@ -46,7 +46,7 @@ static GO_ESCAPE_SUBTEST_NAME_REGEX: LazyLock<Regex> = LazyLock::new(|| {
 #[async_trait(?Send)]
 impl super::LspAdapter for GoLspAdapter {
     fn name(&self) -> LanguageServerName {
-        LanguageServerName(Self::SERVER_NAME.into())
+        Self::SERVER_NAME.clone()
     }
 
     async fn fetch_latest_server_version(
@@ -71,7 +71,8 @@ impl super::LspAdapter for GoLspAdapter {
         cx: &AsyncAppContext,
     ) -> Option<LanguageServerBinary> {
         let configured_binary = cx.update(|cx| {
-            language_server_settings(delegate, Self::SERVER_NAME, cx).and_then(|s| s.binary.clone())
+            language_server_settings(delegate, &Self::SERVER_NAME, cx)
+                .and_then(|s| s.binary.clone())
         });
 
         match configured_binary {

crates/languages/src/python.rs 🔗

@@ -30,7 +30,7 @@ pub struct PythonLspAdapter {
 }
 
 impl PythonLspAdapter {
-    const SERVER_NAME: &'static str = "pyright";
+    const SERVER_NAME: LanguageServerName = LanguageServerName::new_static("pyright");
 
     pub fn new(node: Arc<dyn NodeRuntime>) -> Self {
         PythonLspAdapter { node }
@@ -40,7 +40,7 @@ impl PythonLspAdapter {
 #[async_trait(?Send)]
 impl LspAdapter for PythonLspAdapter {
     fn name(&self) -> LanguageServerName {
-        LanguageServerName(Self::SERVER_NAME.into())
+        Self::SERVER_NAME.clone()
     }
 
     async fn fetch_latest_server_version(
@@ -49,7 +49,7 @@ impl LspAdapter for PythonLspAdapter {
     ) -> Result<Box<dyn 'static + Any + Send>> {
         Ok(Box::new(
             self.node
-                .npm_package_latest_version(Self::SERVER_NAME)
+                .npm_package_latest_version(Self::SERVER_NAME.as_ref())
                 .await?,
         ) as Box<_>)
     }
@@ -62,16 +62,23 @@ impl LspAdapter for PythonLspAdapter {
     ) -> Result<LanguageServerBinary> {
         let latest_version = latest_version.downcast::<String>().unwrap();
         let server_path = container_dir.join(SERVER_PATH);
-        let package_name = Self::SERVER_NAME;
 
         let should_install_language_server = self
             .node
-            .should_install_npm_package(package_name, &server_path, &container_dir, &latest_version)
+            .should_install_npm_package(
+                Self::SERVER_NAME.as_ref(),
+                &server_path,
+                &container_dir,
+                &latest_version,
+            )
             .await;
 
         if should_install_language_server {
             self.node
-                .npm_install_packages(&container_dir, &[(package_name, latest_version.as_str())])
+                .npm_install_packages(
+                    &container_dir,
+                    &[(Self::SERVER_NAME.as_ref(), latest_version.as_str())],
+                )
                 .await?;
         }
 
@@ -182,7 +189,7 @@ impl LspAdapter for PythonLspAdapter {
         cx: &mut AsyncAppContext,
     ) -> Result<Value> {
         cx.update(|cx| {
-            language_server_settings(adapter.as_ref(), Self::SERVER_NAME, cx)
+            language_server_settings(adapter.as_ref(), &Self::SERVER_NAME, cx)
                 .and_then(|s| s.settings.clone())
                 .unwrap_or_default()
         })

crates/languages/src/rust.rs 🔗

@@ -25,13 +25,13 @@ use util::{fs::remove_matching, maybe, ResultExt};
 pub struct RustLspAdapter;
 
 impl RustLspAdapter {
-    const SERVER_NAME: &'static str = "rust-analyzer";
+    const SERVER_NAME: LanguageServerName = LanguageServerName::new_static("rust-analyzer");
 }
 
 #[async_trait(?Send)]
 impl LspAdapter for RustLspAdapter {
     fn name(&self) -> LanguageServerName {
-        LanguageServerName(Self::SERVER_NAME.into())
+        Self::SERVER_NAME.clone()
     }
 
     async fn check_if_user_installed(
@@ -41,7 +41,7 @@ impl LspAdapter for RustLspAdapter {
     ) -> Option<LanguageServerBinary> {
         let configured_binary = cx
             .update(|cx| {
-                language_server_settings(delegate, Self::SERVER_NAME, cx)
+                language_server_settings(delegate, &Self::SERVER_NAME, cx)
                     .and_then(|s| s.binary.clone())
             })
             .ok()?;
@@ -60,7 +60,7 @@ impl LspAdapter for RustLspAdapter {
                 path_lookup: None,
                 ..
             }) => {
-                let path = delegate.which(Self::SERVER_NAME.as_ref()).await;
+                let path = delegate.which("rust-analyzer".as_ref()).await;
                 let env = delegate.shell_env().await;
 
                 if let Some(path) = path {

crates/languages/src/tailwind.rs 🔗

@@ -32,7 +32,8 @@ pub struct TailwindLspAdapter {
 }
 
 impl TailwindLspAdapter {
-    const SERVER_NAME: &'static str = "tailwindcss-language-server";
+    const SERVER_NAME: LanguageServerName =
+        LanguageServerName::new_static("tailwindcss-language-server");
 
     pub fn new(node: Arc<dyn NodeRuntime>) -> Self {
         TailwindLspAdapter { node }
@@ -42,7 +43,7 @@ impl TailwindLspAdapter {
 #[async_trait(?Send)]
 impl LspAdapter for TailwindLspAdapter {
     fn name(&self) -> LanguageServerName {
-        LanguageServerName(Self::SERVER_NAME.into())
+        Self::SERVER_NAME.clone()
     }
 
     async fn check_if_user_installed(
@@ -52,7 +53,7 @@ impl LspAdapter for TailwindLspAdapter {
     ) -> Option<LanguageServerBinary> {
         let configured_binary = cx
             .update(|cx| {
-                language_server_settings(delegate, Self::SERVER_NAME, cx)
+                language_server_settings(delegate, &Self::SERVER_NAME, cx)
                     .and_then(|s| s.binary.clone())
             })
             .ok()??;
@@ -152,7 +153,7 @@ impl LspAdapter for TailwindLspAdapter {
         cx: &mut AsyncAppContext,
     ) -> Result<Value> {
         let tailwind_user_settings = cx.update(|cx| {
-            language_server_settings(delegate.as_ref(), Self::SERVER_NAME, cx)
+            language_server_settings(delegate.as_ref(), &Self::SERVER_NAME, cx)
                 .and_then(|s| s.settings.clone())
                 .unwrap_or_default()
         })?;

crates/languages/src/typescript.rs 🔗

@@ -71,7 +71,8 @@ pub struct TypeScriptLspAdapter {
 impl TypeScriptLspAdapter {
     const OLD_SERVER_PATH: &'static str = "node_modules/typescript-language-server/lib/cli.js";
     const NEW_SERVER_PATH: &'static str = "node_modules/typescript-language-server/lib/cli.mjs";
-    const SERVER_NAME: &'static str = "typescript-language-server";
+    const SERVER_NAME: LanguageServerName =
+        LanguageServerName::new_static("typescript-language-server");
     pub fn new(node: Arc<dyn NodeRuntime>) -> Self {
         TypeScriptLspAdapter { node }
     }
@@ -97,7 +98,7 @@ struct TypeScriptVersions {
 #[async_trait(?Send)]
 impl LspAdapter for TypeScriptLspAdapter {
     fn name(&self) -> LanguageServerName {
-        LanguageServerName(Self::SERVER_NAME.into())
+        Self::SERVER_NAME.clone()
     }
 
     async fn fetch_latest_server_version(
@@ -239,7 +240,7 @@ impl LspAdapter for TypeScriptLspAdapter {
         cx: &mut AsyncAppContext,
     ) -> Result<Value> {
         let override_options = cx.update(|cx| {
-            language_server_settings(delegate.as_ref(), Self::SERVER_NAME, cx)
+            language_server_settings(delegate.as_ref(), &Self::SERVER_NAME, cx)
                 .and_then(|s| s.settings.clone())
         })?;
         if let Some(options) = override_options {
@@ -304,7 +305,7 @@ impl EsLintLspAdapter {
     const GITHUB_ASSET_KIND: AssetKind = AssetKind::Zip;
 
     const SERVER_PATH: &'static str = "vscode-eslint/server/out/eslintServer.js";
-    const SERVER_NAME: &'static str = "eslint";
+    const SERVER_NAME: LanguageServerName = LanguageServerName::new_static("eslint");
 
     const FLAT_CONFIG_FILE_NAMES: &'static [&'static str] =
         &["eslint.config.js", "eslint.config.mjs", "eslint.config.cjs"];
@@ -331,7 +332,7 @@ impl LspAdapter for EsLintLspAdapter {
         let workspace_root = delegate.worktree_root_path();
 
         let eslint_user_settings = cx.update(|cx| {
-            language_server_settings(delegate.as_ref(), Self::SERVER_NAME, cx)
+            language_server_settings(delegate.as_ref(), &Self::SERVER_NAME, cx)
                 .and_then(|s| s.settings.clone())
                 .unwrap_or_default()
         })?;
@@ -403,7 +404,7 @@ impl LspAdapter for EsLintLspAdapter {
     }
 
     fn name(&self) -> LanguageServerName {
-        LanguageServerName(Self::SERVER_NAME.into())
+        Self::SERVER_NAME.clone()
     }
 
     async fn fetch_latest_server_version(

crates/languages/src/vtsls.rs 🔗

@@ -48,11 +48,11 @@ struct TypeScriptVersions {
     server_version: String,
 }
 
-const SERVER_NAME: &str = "vtsls";
+const SERVER_NAME: LanguageServerName = LanguageServerName::new_static("vtsls");
 #[async_trait(?Send)]
 impl LspAdapter for VtslsLspAdapter {
     fn name(&self) -> LanguageServerName {
-        LanguageServerName(SERVER_NAME.into())
+        SERVER_NAME.clone()
     }
 
     async fn fetch_latest_server_version(
@@ -74,7 +74,7 @@ impl LspAdapter for VtslsLspAdapter {
         cx: &AsyncAppContext,
     ) -> Option<LanguageServerBinary> {
         let configured_binary = cx.update(|cx| {
-            language_server_settings(delegate, SERVER_NAME, cx).and_then(|s| s.binary.clone())
+            language_server_settings(delegate, &SERVER_NAME, cx).and_then(|s| s.binary.clone())
         });
 
         match configured_binary {
@@ -267,7 +267,7 @@ impl LspAdapter for VtslsLspAdapter {
         cx: &mut AsyncAppContext,
     ) -> Result<Value> {
         let override_options = cx.update(|cx| {
-            language_server_settings(delegate.as_ref(), SERVER_NAME, cx)
+            language_server_settings(delegate.as_ref(), &SERVER_NAME, cx)
                 .and_then(|s| s.settings.clone())
         })?;
 

crates/languages/src/yaml.rs 🔗

@@ -30,7 +30,7 @@ pub struct YamlLspAdapter {
 }
 
 impl YamlLspAdapter {
-    const SERVER_NAME: &'static str = "yaml-language-server";
+    const SERVER_NAME: LanguageServerName = LanguageServerName::new_static("yaml-language-server");
     pub fn new(node: Arc<dyn NodeRuntime>) -> Self {
         YamlLspAdapter { node }
     }
@@ -39,7 +39,7 @@ impl YamlLspAdapter {
 #[async_trait(?Send)]
 impl LspAdapter for YamlLspAdapter {
     fn name(&self) -> LanguageServerName {
-        LanguageServerName(Self::SERVER_NAME.into())
+        Self::SERVER_NAME.clone()
     }
 
     async fn check_if_user_installed(
@@ -49,7 +49,7 @@ impl LspAdapter for YamlLspAdapter {
     ) -> Option<LanguageServerBinary> {
         let configured_binary = cx
             .update(|cx| {
-                language_server_settings(delegate, Self::SERVER_NAME, cx)
+                language_server_settings(delegate, &Self::SERVER_NAME, cx)
                     .and_then(|s| s.binary.clone())
             })
             .ok()??;
@@ -145,7 +145,7 @@ impl LspAdapter for YamlLspAdapter {
         let mut options = serde_json::json!({"[yaml]": {"editor.tabSize": tab_size}});
 
         let project_options = cx.update(|cx| {
-            language_server_settings(delegate.as_ref(), Self::SERVER_NAME, cx)
+            language_server_settings(delegate.as_ref(), &Self::SERVER_NAME, cx)
                 .and_then(|s| s.settings.clone())
         })?;
         if let Some(override_options) = project_options {

crates/project/src/lsp_store.rs 🔗

@@ -103,7 +103,7 @@ pub struct LocalLspStore {
     supplementary_language_servers:
         HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
     prettier_store: Model<PrettierStore>,
-    current_lsp_settings: HashMap<Arc<str>, LspSettings>,
+    current_lsp_settings: HashMap<LanguageServerName, LspSettings>,
     _subscription: gpui::Subscription,
 }
 
@@ -138,7 +138,7 @@ impl RemoteLspStore {}
 
 pub struct SshLspStore {
     upstream_client: AnyProtoClient,
-    current_lsp_settings: HashMap<Arc<str>, LspSettings>,
+    current_lsp_settings: HashMap<LanguageServerName, LspSettings>,
 }
 
 #[allow(clippy::large_enum_variant)]
@@ -316,8 +316,8 @@ impl LspStore {
 
     pub fn swap_current_lsp_settings(
         &mut self,
-        new_settings: HashMap<Arc<str>, LspSettings>,
-    ) -> Option<HashMap<Arc<str>, LspSettings>> {
+        new_settings: HashMap<LanguageServerName, LspSettings>,
+    ) -> Option<HashMap<LanguageServerName, LspSettings>> {
         match &mut self.mode {
             LspStoreMode::Ssh(SshLspStore {
                 current_lsp_settings,
@@ -933,7 +933,7 @@ impl LspStore {
                 if !language_settings(Some(language), file.as_ref(), cx).enable_language_server {
                     language_servers_to_stop.push((worktree_id, started_lsp_name.clone()));
                 } else if let Some(worktree) = worktree {
-                    let server_name = &adapter.name.0;
+                    let server_name = &adapter.name;
                     match (
                         current_lsp_settings.get(server_name),
                         new_lsp_settings.get(server_name),
@@ -4765,7 +4765,7 @@ impl LspStore {
         let project_id = self.project_id;
         let worktree_id = worktree.read(cx).id().to_proto();
         let upstream_client = ssh.upstream_client.clone();
-        let name = adapter.name().to_string();
+        let name = adapter.name();
 
         let Some(available_language) = self.languages.available_language_for_name(&language) else {
             log::error!("failed to find available language {language}");
@@ -4783,7 +4783,7 @@ impl LspStore {
                 }
             };
 
-            let name = adapter.name().to_string();
+            let name = adapter.name();
             let code_action_kinds = adapter
                 .adapter
                 .code_action_kinds()
@@ -4809,7 +4809,7 @@ impl LspStore {
                 .request(proto::CreateLanguageServer {
                     project_id,
                     worktree_id,
-                    name,
+                    name: name.0.to_string(),
                     binary: Some(language_server_command),
                     initialization_options,
                     code_action_kinds,
@@ -4892,7 +4892,7 @@ impl LspStore {
         );
 
         // We need some on the SSH client, and some on SSH host
-        let lsp = project_settings.lsp.get(&adapter.name.0);
+        let lsp = project_settings.lsp.get(&adapter.name);
         let override_options = lsp.and_then(|s| s.initialization_options.clone());
 
         let server_id = pending_server.server_id;
@@ -5078,7 +5078,7 @@ impl LspStore {
 
     async fn shutdown_language_server(
         server_state: Option<LanguageServerState>,
-        name: Arc<str>,
+        name: LanguageServerName,
         cx: AsyncAppContext,
     ) {
         let server = match server_state {
@@ -5123,7 +5123,7 @@ impl LspStore {
         let key = (worktree_id, adapter_name);
         if self.mode.is_local() {
             if let Some(server_id) = self.language_server_ids.remove(&key) {
-                let name = key.1 .0;
+                let name = key.1;
                 log::info!("stopping language server {name}");
 
                 // Remove other entries for this language server as well
@@ -7168,7 +7168,7 @@ impl LspAdapter for SshLspAdapter {
 }
 pub fn language_server_settings<'a, 'b: 'a>(
     delegate: &'a dyn LspAdapterDelegate,
-    language: &str,
+    language: &LanguageServerName,
     cx: &'b AppContext,
 ) -> Option<&'a LspSettings> {
     ProjectSettings::get(

crates/project/src/prettier_store.rs 🔗

@@ -338,7 +338,7 @@ impl PrettierStore {
             prettier_store
                 .update(cx, |prettier_store, cx| {
                     let name = if is_default {
-                        LanguageServerName(Arc::from("prettier (default)"))
+                        LanguageServerName("prettier (default)".to_string().into())
                     } else {
                         let worktree_path = worktree_id
                             .and_then(|id| {
@@ -366,7 +366,7 @@ impl PrettierStore {
                             }
                             None => format!("prettier ({})", prettier_dir.display()),
                         };
-                        LanguageServerName(Arc::from(name))
+                        LanguageServerName(name.into())
                     };
                     cx.emit(PrettierStoreEvent::LanguageServerAdded {
                         new_server_id,

crates/project/src/project_settings.rs 🔗

@@ -1,6 +1,7 @@
 use collections::HashMap;
 use fs::Fs;
 use gpui::{AppContext, AsyncAppContext, BorrowAppContext, EventEmitter, Model, ModelContext};
+use language::LanguageServerName;
 use paths::local_settings_file_relative_path;
 use rpc::{proto, AnyProtoClient, TypedEnvelope};
 use schemars::JsonSchema;
@@ -27,7 +28,7 @@ pub struct ProjectSettings {
     /// name to the lsp value.
     /// Default: null
     #[serde(default)]
-    pub lsp: HashMap<Arc<str>, LspSettings>,
+    pub lsp: HashMap<LanguageServerName, LspSettings>,
 
     /// Configuration for Git-related features
     #[serde(default)]

crates/remote_server/src/remote_editing_tests.rs 🔗

@@ -205,7 +205,7 @@ async fn test_remote_settings(cx: &mut TestAppContext, server_cx: &mut TestAppCo
             AllLanguageSettings::get_global(cx)
                 .language(Some(&"Rust".into()))
                 .language_servers,
-            ["custom-rust-analyzer".into()]
+            ["custom-rust-analyzer".to_string()]
         )
     });
 
@@ -264,7 +264,7 @@ async fn test_remote_settings(cx: &mut TestAppContext, server_cx: &mut TestAppCo
             )
             .language(Some(&"Rust".into()))
             .language_servers,
-            ["override-rust-analyzer".into()]
+            ["override-rust-analyzer".to_string()]
         )
     });
 
@@ -274,7 +274,7 @@ async fn test_remote_settings(cx: &mut TestAppContext, server_cx: &mut TestAppCo
             all_language_settings(file, cx)
                 .language(Some(&"Rust".into()))
                 .language_servers,
-            ["override-rust-analyzer".into()]
+            ["override-rust-analyzer".to_string()]
         )
     });
 }
@@ -357,7 +357,7 @@ async fn test_remote_lsp(cx: &mut TestAppContext, server_cx: &mut TestAppContext
             all_language_settings(file, cx)
                 .language(Some(&"Rust".into()))
                 .language_servers,
-            ["rust-analyzer".into()]
+            ["rust-analyzer".to_string()]
         )
     });