Consolidate C and C++ LSP adapters

Antonio Scandurra and Max Brunsfeld created

Co-Authored-By: Max Brunsfeld <max@zed.dev>

Change summary

crates/zed/src/languages.rs     |   3 
crates/zed/src/languages/c.rs   | 136 ++++++++++++++++++++++++++++
crates/zed/src/languages/cpp.rs | 169 -----------------------------------
3 files changed, 137 insertions(+), 171 deletions(-)

Detailed changes

crates/zed/src/languages.rs 🔗

@@ -4,7 +4,6 @@ use rust_embed::RustEmbed;
 use std::{borrow::Cow, str, sync::Arc};
 
 mod c;
-mod cpp;
 mod installation;
 mod json;
 mod rust;
@@ -26,7 +25,7 @@ pub fn build_language_registry(login_shell_env_loaded: Task<()>) -> LanguageRegi
         (
             "cpp",
             tree_sitter_cpp::language(),
-            Some(Arc::new(cpp::CppLspAdapter) as Arc<dyn LspAdapter>),
+            Some(Arc::new(c::CLspAdapter) as Arc<dyn LspAdapter>),
         ),
         (
             "json",

crates/zed/src/languages/c.rs 🔗

@@ -105,4 +105,140 @@ impl super::LspAdapter for CLspAdapter {
         .log_err()
         .boxed()
     }
+
+    fn label_for_completion(
+        &self,
+        completion: &lsp::CompletionItem,
+        language: &Language,
+    ) -> Option<CodeLabel> {
+        let label = completion
+            .label
+            .strip_prefix("•")
+            .unwrap_or(&completion.label)
+            .trim();
+
+        match completion.kind {
+            Some(lsp::CompletionItemKind::FIELD) if completion.detail.is_some() => {
+                let detail = completion.detail.as_ref().unwrap();
+                let text = format!("{} {}", detail, label);
+                let source = Rope::from(format!("struct S {{ {} }}", text).as_str());
+                let runs = language.highlight_text(&source, 11..11 + text.len());
+                return Some(CodeLabel {
+                    filter_range: detail.len() + 1..text.len(),
+                    text,
+                    runs,
+                });
+            }
+            Some(lsp::CompletionItemKind::CONSTANT | lsp::CompletionItemKind::VARIABLE)
+                if completion.detail.is_some() =>
+            {
+                let detail = completion.detail.as_ref().unwrap();
+                let text = format!("{} {}", detail, label);
+                let runs = language.highlight_text(&Rope::from(text.as_str()), 0..text.len());
+                return Some(CodeLabel {
+                    filter_range: detail.len() + 1..text.len(),
+                    text,
+                    runs,
+                });
+            }
+            Some(lsp::CompletionItemKind::FUNCTION | lsp::CompletionItemKind::METHOD)
+                if completion.detail.is_some() =>
+            {
+                let detail = completion.detail.as_ref().unwrap();
+                let text = format!("{} {}", detail, label);
+                let runs = language.highlight_text(&Rope::from(text.as_str()), 0..text.len());
+                return Some(CodeLabel {
+                    filter_range: detail.len() + 1..text.rfind('(').unwrap_or(text.len()),
+                    text,
+                    runs,
+                });
+            }
+            Some(kind) => {
+                let highlight_name = match kind {
+                    lsp::CompletionItemKind::STRUCT
+                    | lsp::CompletionItemKind::INTERFACE
+                    | lsp::CompletionItemKind::CLASS
+                    | lsp::CompletionItemKind::ENUM => Some("type"),
+                    lsp::CompletionItemKind::ENUM_MEMBER => Some("variant"),
+                    lsp::CompletionItemKind::KEYWORD => Some("keyword"),
+                    lsp::CompletionItemKind::VALUE | lsp::CompletionItemKind::CONSTANT => {
+                        Some("constant")
+                    }
+                    _ => None,
+                };
+                if let Some(highlight_id) = language
+                    .grammar()
+                    .and_then(|g| g.highlight_id_for_name(highlight_name?))
+                {
+                    let mut label = CodeLabel::plain(label.to_string(), None);
+                    label.runs.push((
+                        0..label.text.rfind('(').unwrap_or(label.text.len()),
+                        highlight_id,
+                    ));
+                    return Some(label);
+                }
+            }
+            _ => {}
+        }
+        Some(CodeLabel::plain(label.to_string(), None))
+    }
+
+    fn label_for_symbol(
+        &self,
+        name: &str,
+        kind: lsp::SymbolKind,
+        language: &Language,
+    ) -> Option<CodeLabel> {
+        let (text, filter_range, display_range) = match kind {
+            lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => {
+                let text = format!("void {} () {{}}", name);
+                let filter_range = 0..name.len();
+                let display_range = 5..5 + name.len();
+                (text, filter_range, display_range)
+            }
+            lsp::SymbolKind::STRUCT => {
+                let text = format!("struct {} {{}}", name);
+                let filter_range = 7..7 + name.len();
+                let display_range = 0..filter_range.end;
+                (text, filter_range, display_range)
+            }
+            lsp::SymbolKind::ENUM => {
+                let text = format!("enum {} {{}}", name);
+                let filter_range = 5..5 + name.len();
+                let display_range = 0..filter_range.end;
+                (text, filter_range, display_range)
+            }
+            lsp::SymbolKind::INTERFACE | lsp::SymbolKind::CLASS => {
+                let text = format!("class {} {{}}", name);
+                let filter_range = 6..6 + name.len();
+                let display_range = 0..filter_range.end;
+                (text, filter_range, display_range)
+            }
+            lsp::SymbolKind::CONSTANT => {
+                let text = format!("const int {} = 0;", name);
+                let filter_range = 10..10 + name.len();
+                let display_range = 0..filter_range.end;
+                (text, filter_range, display_range)
+            }
+            lsp::SymbolKind::MODULE => {
+                let text = format!("namespace {} {{}}", name);
+                let filter_range = 10..10 + name.len();
+                let display_range = 0..filter_range.end;
+                (text, filter_range, display_range)
+            }
+            lsp::SymbolKind::TYPE_PARAMETER => {
+                let text = format!("typename {} {{}};", name);
+                let filter_range = 9..9 + name.len();
+                let display_range = 0..filter_range.end;
+                (text, filter_range, display_range)
+            }
+            _ => return None,
+        };
+
+        Some(CodeLabel {
+            runs: language.highlight_text(&text.as_str().into(), display_range.clone()),
+            text: text[display_range].to_string(),
+            filter_range,
+        })
+    }
 }

crates/zed/src/languages/cpp.rs 🔗

@@ -1,169 +0,0 @@
-use anyhow::Result;
-use client::http::HttpClient;
-use futures::future::BoxFuture;
-pub use language::*;
-use std::{any::Any, path::PathBuf, sync::Arc};
-
-pub struct CppLspAdapter;
-
-impl super::LspAdapter for CppLspAdapter {
-    fn name(&self) -> LanguageServerName {
-        super::c::CLspAdapter.name()
-    }
-
-    fn fetch_latest_server_version(
-        &self,
-        http: Arc<dyn HttpClient>,
-    ) -> BoxFuture<'static, Result<Box<dyn 'static + Send + Any>>> {
-        super::c::CLspAdapter.fetch_latest_server_version(http)
-    }
-
-    fn fetch_server_binary(
-        &self,
-        version: Box<dyn 'static + Send + Any>,
-        http: Arc<dyn HttpClient>,
-        container_dir: PathBuf,
-    ) -> BoxFuture<'static, Result<PathBuf>> {
-        super::c::CLspAdapter.fetch_server_binary(version, http, container_dir)
-    }
-
-    fn cached_server_binary(&self, container_dir: PathBuf) -> BoxFuture<'static, Option<PathBuf>> {
-        super::c::CLspAdapter.cached_server_binary(container_dir)
-    }
-
-    fn label_for_completion(
-        &self,
-        completion: &lsp::CompletionItem,
-        language: &Language,
-    ) -> Option<CodeLabel> {
-        let label = completion
-            .label
-            .strip_prefix("•")
-            .unwrap_or(&completion.label)
-            .trim();
-
-        match completion.kind {
-            Some(lsp::CompletionItemKind::FIELD) if completion.detail.is_some() => {
-                let detail = completion.detail.as_ref().unwrap();
-                let text = format!("{} {}", detail, label);
-                let source = Rope::from(format!("struct S {{ {} }}", text).as_str());
-                let runs = language.highlight_text(&source, 11..11 + text.len());
-                return Some(CodeLabel {
-                    filter_range: detail.len() + 1..text.len(),
-                    text,
-                    runs,
-                });
-            }
-            Some(lsp::CompletionItemKind::CONSTANT | lsp::CompletionItemKind::VARIABLE)
-                if completion.detail.is_some() =>
-            {
-                let detail = completion.detail.as_ref().unwrap();
-                let text = format!("{} {}", detail, label);
-                let runs = language.highlight_text(&Rope::from(text.as_str()), 0..text.len());
-                return Some(CodeLabel {
-                    filter_range: detail.len() + 1..text.len(),
-                    text,
-                    runs,
-                });
-            }
-            Some(lsp::CompletionItemKind::FUNCTION | lsp::CompletionItemKind::METHOD)
-                if completion.detail.is_some() =>
-            {
-                let detail = completion.detail.as_ref().unwrap();
-                let text = format!("{} {}", detail, label);
-                let runs = language.highlight_text(&Rope::from(text.as_str()), 0..text.len());
-                return Some(CodeLabel {
-                    filter_range: detail.len() + 1..text.rfind('(').unwrap_or(text.len()),
-                    text,
-                    runs,
-                });
-            }
-            Some(kind) => {
-                let highlight_name = match kind {
-                    lsp::CompletionItemKind::STRUCT
-                    | lsp::CompletionItemKind::INTERFACE
-                    | lsp::CompletionItemKind::CLASS
-                    | lsp::CompletionItemKind::ENUM => Some("type"),
-                    lsp::CompletionItemKind::ENUM_MEMBER => Some("variant"),
-                    lsp::CompletionItemKind::KEYWORD => Some("keyword"),
-                    lsp::CompletionItemKind::VALUE | lsp::CompletionItemKind::CONSTANT => {
-                        Some("constant")
-                    }
-                    _ => None,
-                };
-                if let Some(highlight_id) = language
-                    .grammar()
-                    .and_then(|g| g.highlight_id_for_name(highlight_name?))
-                {
-                    let mut label = CodeLabel::plain(label.to_string(), None);
-                    label.runs.push((
-                        0..label.text.rfind('(').unwrap_or(label.text.len()),
-                        highlight_id,
-                    ));
-                    return Some(label);
-                }
-            }
-            _ => {}
-        }
-        Some(CodeLabel::plain(label.to_string(), None))
-    }
-
-    fn label_for_symbol(
-        &self,
-        name: &str,
-        kind: lsp::SymbolKind,
-        language: &Language,
-    ) -> Option<CodeLabel> {
-        let (text, filter_range, display_range) = match kind {
-            lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => {
-                let text = format!("void {} () {{}}", name);
-                let filter_range = 0..name.len();
-                let display_range = 5..5 + name.len();
-                (text, filter_range, display_range)
-            }
-            lsp::SymbolKind::STRUCT => {
-                let text = format!("struct {} {{}}", name);
-                let filter_range = 7..7 + name.len();
-                let display_range = 0..filter_range.end;
-                (text, filter_range, display_range)
-            }
-            lsp::SymbolKind::ENUM => {
-                let text = format!("enum {} {{}}", name);
-                let filter_range = 5..5 + name.len();
-                let display_range = 0..filter_range.end;
-                (text, filter_range, display_range)
-            }
-            lsp::SymbolKind::INTERFACE | lsp::SymbolKind::CLASS => {
-                let text = format!("class {} {{}}", name);
-                let filter_range = 6..6 + name.len();
-                let display_range = 0..filter_range.end;
-                (text, filter_range, display_range)
-            }
-            lsp::SymbolKind::CONSTANT => {
-                let text = format!("const int {} = 0;", name);
-                let filter_range = 10..10 + name.len();
-                let display_range = 0..filter_range.end;
-                (text, filter_range, display_range)
-            }
-            lsp::SymbolKind::MODULE => {
-                let text = format!("namespace {} {{}}", name);
-                let filter_range = 10..10 + name.len();
-                let display_range = 0..filter_range.end;
-                (text, filter_range, display_range)
-            }
-            lsp::SymbolKind::TYPE_PARAMETER => {
-                let text = format!("typename {} {{}};", name);
-                let filter_range = 9..9 + name.len();
-                let display_range = 0..filter_range.end;
-                (text, filter_range, display_range)
-            }
-            _ => return None,
-        };
-
-        Some(CodeLabel {
-            runs: language.highlight_text(&text.as_str().into(), display_range.clone()),
-            text: text[display_range].to_string(),
-            filter_range,
-        })
-    }
-}