From 4563b5ac4faefad152d2fc627f5d0d804a515d3c Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Thu, 5 Feb 2026 07:03:15 +0900 Subject: [PATCH] lsp: Add `container_name` to `lsp::Symbol` (#46822) Some language servers include local symbols (e.g., local variables, parameters) in workspace symbol results. Without the `containerName` information, these symbols lack context information, making it difficult to distinguish them from top-level definitions and hindering efficient symbol lookup. This change exposes the `container_name` field from LSP [`SymbolInformation`](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#symbolInformation) to the extension API, allowing language server extensions to access `symbol.container_name` in `label_for_symbol` and provide meaningful context when rendering symbol labels. Note: The `container_name `field is added to all extension API versions because they seem to share the same underlying Rust types via wasmtime bindgen. The field is optional, so existing extensions would remain compatible as far as I understand. Closes #ISSUE Release Notes: - Added `container_name` field to `lsp::Symbol`, accessible via the extension API's `label_for_symbol` function --------- Co-authored-by: MrSubidubi --- crates/extension/src/types/lsp.rs | 1 + crates/extension_api/wit/since_v0.8.0/lsp.wit | 1 + crates/extension_host/src/wasm_host/wit.rs | 20 ++-- .../src/wasm_host/wit/since_v0_2_0.rs | 4 +- .../src/wasm_host/wit/since_v0_3_0.rs | 4 +- .../src/wasm_host/wit/since_v0_4_0.rs | 4 +- .../src/wasm_host/wit/since_v0_5_0.rs | 4 +- .../src/wasm_host/wit/since_v0_6_0.rs | 110 +++++++++++++++++- .../src/wasm_host/wit/since_v0_8_0.rs | 1 + crates/language/src/language.rs | 20 ++-- .../src/extension_lsp_adapter.rs | 17 ++- crates/languages/src/c.rs | 6 +- crates/languages/src/go.rs | 6 +- crates/languages/src/python.rs | 20 ++-- crates/languages/src/rust.rs | 42 +++++-- crates/project/src/lsp_store.rs | 96 +++++++++------ crates/project/src/project.rs | 1 + crates/proto/proto/lsp.proto | 1 + 18 files changed, 268 insertions(+), 90 deletions(-) diff --git a/crates/extension/src/types/lsp.rs b/crates/extension/src/types/lsp.rs index 6e858211cd..4ccbc3944b 100644 --- a/crates/extension/src/types/lsp.rs +++ b/crates/extension/src/types/lsp.rs @@ -61,6 +61,7 @@ pub enum InsertTextFormat { pub struct Symbol { pub kind: SymbolKind, pub name: String, + pub container_name: Option, } /// The kind of an LSP symbol. diff --git a/crates/extension_api/wit/since_v0.8.0/lsp.wit b/crates/extension_api/wit/since_v0.8.0/lsp.wit index 91a36c93a6..47ec9728ad 100644 --- a/crates/extension_api/wit/since_v0.8.0/lsp.wit +++ b/crates/extension_api/wit/since_v0.8.0/lsp.wit @@ -55,6 +55,7 @@ interface lsp { record symbol { kind: symbol-kind, name: string, + container-name: option, } /// The kind of an LSP symbol. diff --git a/crates/extension_host/src/wasm_host/wit.rs b/crates/extension_host/src/wasm_host/wit.rs index e080915b4f..d2334681b4 100644 --- a/crates/extension_host/src/wasm_host/wit.rs +++ b/crates/extension_host/src/wasm_host/wit.rs @@ -586,7 +586,7 @@ impl Extension { .call_labels_for_completions( store, &language_server_id.0, - &completions.into_iter().collect::>(), + &completions.into_iter().map(Into::into).collect::>(), ) .await? .map(|labels| { @@ -599,7 +599,7 @@ impl Extension { .call_labels_for_completions( store, &language_server_id.0, - &completions.into_iter().collect::>(), + &completions.into_iter().map(Into::into).collect::>(), ) .await? .map(|labels| { @@ -612,7 +612,7 @@ impl Extension { .call_labels_for_completions( store, &language_server_id.0, - &completions.into_iter().collect::>(), + &completions.into_iter().map(Into::into).collect::>(), ) .await? .map(|labels| { @@ -625,7 +625,7 @@ impl Extension { .call_labels_for_completions( store, &language_server_id.0, - &completions.into_iter().collect::>(), + &completions.into_iter().map(Into::into).collect::>(), ) .await? .map(|labels| { @@ -638,7 +638,7 @@ impl Extension { .call_labels_for_completions( store, &language_server_id.0, - &completions.into_iter().collect::>(), + &completions.into_iter().map(Into::into).collect::>(), ) .await? .map(|labels| { @@ -692,7 +692,7 @@ impl Extension { .call_labels_for_symbols( store, &language_server_id.0, - &symbols.into_iter().collect::>(), + &symbols.into_iter().map(Into::into).collect::>(), ) .await? .map(|labels| { @@ -705,7 +705,7 @@ impl Extension { .call_labels_for_symbols( store, &language_server_id.0, - &symbols.into_iter().collect::>(), + &symbols.into_iter().map(Into::into).collect::>(), ) .await? .map(|labels| { @@ -718,7 +718,7 @@ impl Extension { .call_labels_for_symbols( store, &language_server_id.0, - &symbols.into_iter().collect::>(), + &symbols.into_iter().map(Into::into).collect::>(), ) .await? .map(|labels| { @@ -731,7 +731,7 @@ impl Extension { .call_labels_for_symbols( store, &language_server_id.0, - &symbols.into_iter().collect::>(), + &symbols.into_iter().map(Into::into).collect::>(), ) .await? .map(|labels| { @@ -744,7 +744,7 @@ impl Extension { .call_labels_for_symbols( store, &language_server_id.0, - &symbols.into_iter().collect::>(), + &symbols.into_iter().map(Into::into).collect::>(), ) .await? .map(|labels| { diff --git a/crates/extension_host/src/wasm_host/wit/since_v0_2_0.rs b/crates/extension_host/src/wasm_host/wit/since_v0_2_0.rs index 05e3f5a4e7..316648d9f2 100644 --- a/crates/extension_host/src/wasm_host/wit/since_v0_2_0.rs +++ b/crates/extension_host/src/wasm_host/wit/since_v0_2_0.rs @@ -6,7 +6,7 @@ use semver::Version; use std::sync::{Arc, OnceLock}; use wasmtime::component::{Linker, Resource}; -use super::latest; +use super::{latest, since_v0_6_0}; pub const MIN_VERSION: Version = Version::new(0, 2, 0); @@ -20,7 +20,7 @@ wasmtime::component::bindgen!({ "key-value-store": ExtensionKeyValueStore, "zed:extension/github": latest::zed::extension::github, "zed:extension/http-client": latest::zed::extension::http_client, - "zed:extension/lsp": latest::zed::extension::lsp, + "zed:extension/lsp": since_v0_6_0::zed::extension::lsp, "zed:extension/nodejs": latest::zed::extension::nodejs, "zed:extension/platform": latest::zed::extension::platform, "zed:extension/slash-command": latest::zed::extension::slash_command, diff --git a/crates/extension_host/src/wasm_host/wit/since_v0_3_0.rs b/crates/extension_host/src/wasm_host/wit/since_v0_3_0.rs index 08393934fe..6078c85c4d 100644 --- a/crates/extension_host/src/wasm_host/wit/since_v0_3_0.rs +++ b/crates/extension_host/src/wasm_host/wit/since_v0_3_0.rs @@ -6,7 +6,7 @@ use semver::Version; use std::sync::{Arc, OnceLock}; use wasmtime::component::{Linker, Resource}; -use super::latest; +use super::{latest, since_v0_6_0}; pub const MIN_VERSION: Version = Version::new(0, 3, 0); @@ -21,7 +21,7 @@ wasmtime::component::bindgen!({ "zed:extension/common": latest::zed::extension::common, "zed:extension/github": latest::zed::extension::github, "zed:extension/http-client": latest::zed::extension::http_client, - "zed:extension/lsp": latest::zed::extension::lsp, + "zed:extension/lsp": since_v0_6_0::zed::extension::lsp, "zed:extension/nodejs": latest::zed::extension::nodejs, "zed:extension/platform": latest::zed::extension::platform, "zed:extension/process": latest::zed::extension::process, diff --git a/crates/extension_host/src/wasm_host/wit/since_v0_4_0.rs b/crates/extension_host/src/wasm_host/wit/since_v0_4_0.rs index 1b2a95023b..ea2e07473b 100644 --- a/crates/extension_host/src/wasm_host/wit/since_v0_4_0.rs +++ b/crates/extension_host/src/wasm_host/wit/since_v0_4_0.rs @@ -6,7 +6,7 @@ use semver::Version; use std::sync::{Arc, OnceLock}; use wasmtime::component::{Linker, Resource}; -use super::latest; +use super::{latest, since_v0_6_0}; pub const MIN_VERSION: Version = Version::new(0, 4, 0); @@ -21,7 +21,7 @@ wasmtime::component::bindgen!({ "zed:extension/common": latest::zed::extension::common, "zed:extension/github": latest::zed::extension::github, "zed:extension/http-client": latest::zed::extension::http_client, - "zed:extension/lsp": latest::zed::extension::lsp, + "zed:extension/lsp": since_v0_6_0::zed::extension::lsp, "zed:extension/nodejs": latest::zed::extension::nodejs, "zed:extension/platform": latest::zed::extension::platform, "zed:extension/process": latest::zed::extension::process, diff --git a/crates/extension_host/src/wasm_host/wit/since_v0_5_0.rs b/crates/extension_host/src/wasm_host/wit/since_v0_5_0.rs index 23701c9d03..e5ad91368d 100644 --- a/crates/extension_host/src/wasm_host/wit/since_v0_5_0.rs +++ b/crates/extension_host/src/wasm_host/wit/since_v0_5_0.rs @@ -6,7 +6,7 @@ use semver::Version; use std::sync::{Arc, OnceLock}; use wasmtime::component::{Linker, Resource}; -use super::latest; +use super::{latest, since_v0_6_0}; pub const MIN_VERSION: Version = Version::new(0, 5, 0); @@ -21,7 +21,7 @@ wasmtime::component::bindgen!({ "zed:extension/common": latest::zed::extension::common, "zed:extension/github": latest::zed::extension::github, "zed:extension/http-client": latest::zed::extension::http_client, - "zed:extension/lsp": latest::zed::extension::lsp, + "zed:extension/lsp": since_v0_6_0::zed::extension::lsp, "zed:extension/nodejs": latest::zed::extension::nodejs, "zed:extension/platform": latest::zed::extension::platform, "zed:extension/process": latest::zed::extension::process, diff --git a/crates/extension_host/src/wasm_host/wit/since_v0_6_0.rs b/crates/extension_host/src/wasm_host/wit/since_v0_6_0.rs index 8595c278b9..2ffe86128b 100644 --- a/crates/extension_host/src/wasm_host/wit/since_v0_6_0.rs +++ b/crates/extension_host/src/wasm_host/wit/since_v0_6_0.rs @@ -22,7 +22,6 @@ wasmtime::component::bindgen!({ "zed:extension/common": latest::zed::extension::common, "zed:extension/github": latest::zed::extension::github, "zed:extension/http-client": latest::zed::extension::http_client, - "zed:extension/lsp": latest::zed::extension::lsp, "zed:extension/nodejs": latest::zed::extension::nodejs, "zed:extension/platform": latest::zed::extension::platform, "zed:extension/process": latest::zed::extension::process, @@ -107,6 +106,115 @@ impl From for latest::DownloadedFileType { } } +impl From for lsp::Symbol { + fn from(value: latest::lsp::Symbol) -> Self { + Self { + name: value.name, + kind: value.kind.into(), + } + } +} + +impl From for lsp::Completion { + fn from(value: latest::lsp::Completion) -> Self { + Self { + label: value.label, + label_details: value.label_details.map(Into::into), + detail: value.detail, + kind: value.kind.map(Into::into), + insert_text_format: value.insert_text_format.map(Into::into), + } + } +} + +impl From for lsp::CompletionLabelDetails { + fn from(value: latest::lsp::CompletionLabelDetails) -> Self { + Self { + detail: value.detail, + description: value.description, + } + } +} + +impl From for lsp::CompletionKind { + fn from(value: latest::lsp::CompletionKind) -> Self { + match value { + latest::lsp::CompletionKind::Text => Self::Text, + latest::lsp::CompletionKind::Method => Self::Method, + latest::lsp::CompletionKind::Function => Self::Function, + latest::lsp::CompletionKind::Constructor => Self::Constructor, + latest::lsp::CompletionKind::Field => Self::Field, + latest::lsp::CompletionKind::Variable => Self::Variable, + latest::lsp::CompletionKind::Class => Self::Class, + latest::lsp::CompletionKind::Interface => Self::Interface, + latest::lsp::CompletionKind::Module => Self::Module, + latest::lsp::CompletionKind::Property => Self::Property, + latest::lsp::CompletionKind::Unit => Self::Unit, + latest::lsp::CompletionKind::Value => Self::Value, + latest::lsp::CompletionKind::Enum => Self::Enum, + latest::lsp::CompletionKind::Keyword => Self::Keyword, + latest::lsp::CompletionKind::Snippet => Self::Snippet, + latest::lsp::CompletionKind::Color => Self::Color, + latest::lsp::CompletionKind::File => Self::File, + latest::lsp::CompletionKind::Reference => Self::Reference, + latest::lsp::CompletionKind::Folder => Self::Folder, + latest::lsp::CompletionKind::EnumMember => Self::EnumMember, + latest::lsp::CompletionKind::Constant => Self::Constant, + latest::lsp::CompletionKind::Struct => Self::Struct, + latest::lsp::CompletionKind::Event => Self::Event, + latest::lsp::CompletionKind::Operator => Self::Operator, + latest::lsp::CompletionKind::TypeParameter => Self::TypeParameter, + latest::lsp::CompletionKind::Other(kind) => Self::Other(kind), + } + } +} + +impl From for lsp::InsertTextFormat { + fn from(value: latest::lsp::InsertTextFormat) -> Self { + match value { + latest::lsp::InsertTextFormat::PlainText => Self::PlainText, + latest::lsp::InsertTextFormat::Snippet => Self::Snippet, + latest::lsp::InsertTextFormat::Other(value) => Self::Other(value), + } + } +} + +impl From for lsp::SymbolKind { + fn from(value: latest::lsp::SymbolKind) -> Self { + match value { + latest::lsp::SymbolKind::File => Self::File, + latest::lsp::SymbolKind::Module => Self::Module, + latest::lsp::SymbolKind::Namespace => Self::Namespace, + latest::lsp::SymbolKind::Package => Self::Package, + latest::lsp::SymbolKind::Class => Self::Class, + latest::lsp::SymbolKind::Method => Self::Method, + latest::lsp::SymbolKind::Property => Self::Property, + latest::lsp::SymbolKind::Field => Self::Field, + latest::lsp::SymbolKind::Constructor => Self::Constructor, + latest::lsp::SymbolKind::Enum => Self::Enum, + latest::lsp::SymbolKind::Interface => Self::Interface, + latest::lsp::SymbolKind::Function => Self::Function, + latest::lsp::SymbolKind::Variable => Self::Variable, + latest::lsp::SymbolKind::Constant => Self::Constant, + latest::lsp::SymbolKind::String => Self::String, + latest::lsp::SymbolKind::Number => Self::Number, + latest::lsp::SymbolKind::Boolean => Self::Boolean, + latest::lsp::SymbolKind::Array => Self::Array, + latest::lsp::SymbolKind::Object => Self::Object, + latest::lsp::SymbolKind::Key => Self::Key, + latest::lsp::SymbolKind::Null => Self::Null, + latest::lsp::SymbolKind::EnumMember => Self::EnumMember, + latest::lsp::SymbolKind::Struct => Self::Struct, + latest::lsp::SymbolKind::Event => Self::Event, + latest::lsp::SymbolKind::Operator => Self::Operator, + latest::lsp::SymbolKind::TypeParameter => Self::TypeParameter, + latest::lsp::SymbolKind::Other(kind) => Self::Other(kind), + } + } +} + +impl lsp::Host for WasmState {} + impl HostKeyValueStore for WasmState { async fn insert( &mut self, diff --git a/crates/extension_host/src/wasm_host/wit/since_v0_8_0.rs b/crates/extension_host/src/wasm_host/wit/since_v0_8_0.rs index 9fd1cd7936..55e24d3723 100644 --- a/crates/extension_host/src/wasm_host/wit/since_v0_8_0.rs +++ b/crates/extension_host/src/wasm_host/wit/since_v0_8_0.rs @@ -421,6 +421,7 @@ impl From for Symbol { Self { kind: value.kind.into(), name: value.name, + container_name: value.container_name, } } } diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index 9332df9a3f..0ae17bdc30 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -197,6 +197,13 @@ pub struct Location { pub range: Range, } +#[derive(Debug, Clone)] +pub struct Symbol { + pub name: String, + pub kind: lsp::SymbolKind, + pub container_name: Option, +} + type ServerBinaryCache = futures::lock::Mutex>; type DownloadableLanguageServerBinary = LocalBoxFuture<'static, Result>; pub type LanguageServerBinaryLocations = LocalBoxFuture< @@ -316,7 +323,7 @@ impl CachedLspAdapter { pub async fn labels_for_symbols( &self, - symbols: &[(String, lsp::SymbolKind)], + symbols: &[Symbol], language: &Arc, ) -> Result>> { self.adapter @@ -446,12 +453,12 @@ pub trait LspAdapter: 'static + Send + Sync + DynLspInstaller { async fn labels_for_symbols( self: Arc, - symbols: &[(String, lsp::SymbolKind)], + symbols: &[Symbol], language: &Arc, ) -> Result>> { let mut labels = Vec::new(); - for (ix, (name, kind)) in symbols.iter().enumerate() { - let label = self.label_for_symbol(name, *kind, language).await; + for (ix, symbol) in symbols.iter().enumerate() { + let label = self.label_for_symbol(symbol, language).await; if let Some(label) = label { labels.resize(ix + 1, None); *labels.last_mut().unwrap() = Some(label); @@ -462,9 +469,8 @@ pub trait LspAdapter: 'static + Send + Sync + DynLspInstaller { async fn label_for_symbol( &self, - _: &str, - _: lsp::SymbolKind, - _: &Arc, + _symbol: &Symbol, + _language: &Arc, ) -> Option { None } diff --git a/crates/language_extension/src/extension_lsp_adapter.rs b/crates/language_extension/src/extension_lsp_adapter.rs index 269aac1f2a..c2062a294d 100644 --- a/crates/language_extension/src/extension_lsp_adapter.rs +++ b/crates/language_extension/src/extension_lsp_adapter.rs @@ -421,16 +421,23 @@ impl LspAdapter for ExtensionLspAdapter { async fn labels_for_symbols( self: Arc, - symbols: &[(String, lsp::SymbolKind)], + symbols: &[language::Symbol], language: &Arc, ) -> Result>> { let symbols = symbols .iter() .cloned() - .map(|(name, kind)| extension::Symbol { - name, - kind: lsp_symbol_kind_to_extension(kind), - }) + .map( + |language::Symbol { + name, + kind, + container_name, + }| extension::Symbol { + name, + kind: lsp_symbol_kind_to_extension(kind), + container_name, + }, + ) .collect::>(); let labels = self diff --git a/crates/languages/src/c.rs b/crates/languages/src/c.rs index 76a0674eda..3a9207329d 100644 --- a/crates/languages/src/c.rs +++ b/crates/languages/src/c.rs @@ -287,11 +287,11 @@ impl super::LspAdapter for CLspAdapter { async fn label_for_symbol( &self, - name: &str, - kind: lsp::SymbolKind, + symbol: &language::Symbol, language: &Arc, ) -> Option { - let (text, filter_range, display_range) = match kind { + let name = &symbol.name; + let (text, filter_range, display_range) = match symbol.kind { lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => { let text = format!("void {} () {{}}", name); let filter_range = 0..name.len(); diff --git a/crates/languages/src/go.rs b/crates/languages/src/go.rs index 84ca4bafda..917c07cb92 100644 --- a/crates/languages/src/go.rs +++ b/crates/languages/src/go.rs @@ -334,11 +334,11 @@ impl LspAdapter for GoLspAdapter { async fn label_for_symbol( &self, - name: &str, - kind: lsp::SymbolKind, + symbol: &language::Symbol, language: &Arc, ) -> Option { - let (text, filter_range, display_range) = match kind { + let name = &symbol.name; + let (text, filter_range, display_range) = match symbol.kind { lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => { let text = format!("func {} () {{}}", name); let filter_range = 5..5 + name.len(); diff --git a/crates/languages/src/python.rs b/crates/languages/src/python.rs index 0efaa3f096..9f9d31ac86 100644 --- a/crates/languages/src/python.rs +++ b/crates/languages/src/python.rs @@ -8,7 +8,7 @@ use futures::{AsyncBufReadExt, StreamExt as _}; use gpui::{App, AsyncApp, SharedString, Task}; use http_client::github::{AssetKind, GitHubLspBinaryVersion, latest_github_release}; use language::language_settings::language_settings; -use language::{ContextLocation, DynLspInstaller, LanguageToolchainStore, LspInstaller}; +use language::{ContextLocation, DynLspInstaller, LanguageToolchainStore, LspInstaller, Symbol}; use language::{ContextProvider, LspAdapter, LspAdapterDelegate}; use language::{LanguageName, ManifestName, ManifestProvider, ManifestQuery}; use language::{Toolchain, ToolchainList, ToolchainLister, ToolchainMetadata}; @@ -550,11 +550,11 @@ impl LspAdapter for PyrightLspAdapter { async fn label_for_symbol( &self, - name: &str, - kind: lsp::SymbolKind, + symbol: &language::Symbol, language: &Arc, ) -> Option { - let (text, filter_range, display_range) = match kind { + let name = &symbol.name; + let (text, filter_range, display_range) = match symbol.kind { lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => { let text = format!("def {}():\n", name); let filter_range = 4..4 + name.len(); @@ -1708,11 +1708,11 @@ impl LspAdapter for PyLspAdapter { async fn label_for_symbol( &self, - name: &str, - kind: lsp::SymbolKind, + symbol: &language::Symbol, language: &Arc, ) -> Option { - let (text, filter_range, display_range) = match kind { + let name = &symbol.name; + let (text, filter_range, display_range) = match symbol.kind { lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => { let text = format!("def {}():\n", name); let filter_range = 4..4 + name.len(); @@ -2000,11 +2000,11 @@ impl LspAdapter for BasedPyrightLspAdapter { async fn label_for_symbol( &self, - name: &str, - kind: lsp::SymbolKind, + symbol: &Symbol, language: &Arc, ) -> Option { - let (text, filter_range, display_range) = match kind { + let name = &symbol.name; + let (text, filter_range, display_range) = match symbol.kind { lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => { let text = format!("def {}():\n", name); let filter_range = 4..4 + name.len(); diff --git a/crates/languages/src/rust.rs b/crates/languages/src/rust.rs index 3d1b7f951b..f79fea7798 100644 --- a/crates/languages/src/rust.rs +++ b/crates/languages/src/rust.rs @@ -572,11 +572,11 @@ impl LspAdapter for RustLspAdapter { async fn label_for_symbol( &self, - name: &str, - kind: lsp::SymbolKind, + symbol: &language::Symbol, language: &Arc, ) -> Option { - let (prefix, suffix) = match kind { + let name = &symbol.name; + let (prefix, suffix) = match symbol.kind { lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => ("fn ", "();"), lsp::SymbolKind::STRUCT => ("struct ", ";"), lsp::SymbolKind::ENUM => ("enum ", "{}"), @@ -1826,7 +1826,14 @@ mod tests { assert_eq!( adapter - .label_for_symbol("hello", lsp::SymbolKind::FUNCTION, &language) + .label_for_symbol( + &language::Symbol { + name: "hello".to_string(), + kind: lsp::SymbolKind::FUNCTION, + container_name: None, + }, + &language + ) .await, Some(CodeLabel::new( "fn hello".to_string(), @@ -1837,7 +1844,14 @@ mod tests { assert_eq!( adapter - .label_for_symbol("World", lsp::SymbolKind::TYPE_PARAMETER, &language) + .label_for_symbol( + &language::Symbol { + name: "World".to_string(), + kind: lsp::SymbolKind::TYPE_PARAMETER, + container_name: None, + }, + &language + ) .await, Some(CodeLabel::new( "type World".to_string(), @@ -1848,7 +1862,14 @@ mod tests { assert_eq!( adapter - .label_for_symbol("zed", lsp::SymbolKind::PACKAGE, &language) + .label_for_symbol( + &language::Symbol { + name: "zed".to_string(), + kind: lsp::SymbolKind::PACKAGE, + container_name: None, + }, + &language + ) .await, Some(CodeLabel::new( "extern crate zed".to_string(), @@ -1859,7 +1880,14 @@ mod tests { assert_eq!( adapter - .label_for_symbol("Variant", lsp::SymbolKind::ENUM_MEMBER, &language) + .label_for_symbol( + &language::Symbol { + name: "Variant".to_string(), + kind: lsp::SymbolKind::ENUM_MEMBER, + container_name: None, + }, + &language + ) .await, Some(CodeLabel::new( "Variant".to_string(), diff --git a/crates/project/src/lsp_store.rs b/crates/project/src/lsp_store.rs index fff28b012e..9b4be5a6be 100644 --- a/crates/project/src/lsp_store.rs +++ b/crates/project/src/lsp_store.rs @@ -3993,6 +3993,7 @@ struct CoreSymbol { pub name: String, pub kind: lsp::SymbolKind, pub range: Range>, + pub container_name: Option, } #[derive(Clone, Debug, PartialEq, Eq)] @@ -7947,7 +7948,7 @@ impl LspStore { server_id: LanguageServerId, lsp_adapter: Arc, worktree: WeakEntity, - lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>, + lsp_symbols: Vec<(String, SymbolKind, lsp::Location, Option)>, } let mut requests = Vec::new(); @@ -8010,6 +8011,7 @@ impl LspStore { lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location, + lsp_symbol.container_name, ) }) .collect::>() @@ -8029,7 +8031,12 @@ impl LspStore { return None; } }; - Some((lsp_symbol.name, lsp_symbol.kind, location)) + Some(( + lsp_symbol.name, + lsp_symbol.kind, + location, + lsp_symbol.container_name, + )) }) .collect::>() } @@ -8059,36 +8066,39 @@ impl LspStore { result .lsp_symbols .into_iter() - .filter_map(|(symbol_name, symbol_kind, symbol_location)| { - let abs_path = symbol_location.uri.to_file_path().ok()?; - let source_worktree = result.worktree.upgrade()?; - let source_worktree_id = source_worktree.read(cx).id(); + .filter_map( + |(symbol_name, symbol_kind, symbol_location, container_name)| { + let abs_path = symbol_location.uri.to_file_path().ok()?; + let source_worktree = result.worktree.upgrade()?; + let source_worktree_id = source_worktree.read(cx).id(); - let path = if let Some((tree, rel_path)) = - this.worktree_store.read(cx).find_worktree(&abs_path, cx) - { - let worktree_id = tree.read(cx).id(); - SymbolLocation::InProject(ProjectPath { - worktree_id, - path: rel_path, + let path = if let Some((tree, rel_path)) = + this.worktree_store.read(cx).find_worktree(&abs_path, cx) + { + let worktree_id = tree.read(cx).id(); + SymbolLocation::InProject(ProjectPath { + worktree_id, + path: rel_path, + }) + } else { + SymbolLocation::OutsideProject { + signature: this.symbol_signature(&abs_path), + abs_path: abs_path.into(), + } + }; + + Some(CoreSymbol { + source_language_server_id: result.server_id, + language_server_name: result.lsp_adapter.name.clone(), + source_worktree_id, + path, + kind: symbol_kind, + name: symbol_name, + range: range_from_lsp(symbol_location.range), + container_name, }) - } else { - SymbolLocation::OutsideProject { - signature: this.symbol_signature(&abs_path), - abs_path: abs_path.into(), - } - }; - - Some(CoreSymbol { - source_language_server_id: result.server_id, - language_server_name: result.lsp_adapter.name.clone(), - source_worktree_id, - path, - kind: symbol_kind, - name: symbol_name, - range: range_from_lsp(symbol_location.range), - }) - }) + }, + ) .collect::>() }); @@ -10713,6 +10723,7 @@ impl LspStore { kind: symbol.kind, range: symbol.range, label: CodeLabel::default(), + container_name: symbol.container_name, }, cx, ) @@ -12213,6 +12224,7 @@ impl LspStore { worktree_id: Default::default(), path: Default::default(), signature: Default::default(), + container_name: symbol.container_name.clone(), }; match &symbol.path { SymbolLocation::InProject(path) => { @@ -12264,6 +12276,7 @@ impl LspStore { range: Unclipped(PointUtf16::new(start.row, start.column)) ..Unclipped(PointUtf16::new(end.row, end.column)), kind, + container_name: serialized_symbol.container_name, }) } @@ -14703,11 +14716,11 @@ async fn populate_labels_for_symbols( let mut label_params = Vec::new(); for (language, mut symbols) in symbols_by_language { label_params.clear(); - label_params.extend( - symbols - .iter_mut() - .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)), - ); + label_params.extend(symbols.iter_mut().map(|symbol| language::Symbol { + name: mem::take(&mut symbol.name), + kind: symbol.kind, + container_name: symbol.container_name.take(), + })); let mut labels = Vec::new(); if let Some(language) = language { @@ -14726,7 +14739,17 @@ async fn populate_labels_for_symbols( } } - for ((symbol, (name, _)), label) in symbols + for ( + ( + symbol, + language::Symbol { + name, + container_name, + .. + }, + ), + label, + ) in symbols .into_iter() .zip(label_params.drain(..)) .zip(labels.into_iter().chain(iter::repeat(None))) @@ -14740,6 +14763,7 @@ async fn populate_labels_for_symbols( name, kind: symbol.kind, range: symbol.range, + container_name, }); } } diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index c5f0a2e53a..fa6315518b 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -833,6 +833,7 @@ pub struct Symbol { pub name: String, pub kind: lsp::SymbolKind, pub range: Range>, + pub container_name: Option, } #[derive(Clone, Debug)] diff --git a/crates/proto/proto/lsp.proto b/crates/proto/proto/lsp.proto index d95801190d..59fa367736 100644 --- a/crates/proto/proto/lsp.proto +++ b/crates/proto/proto/lsp.proto @@ -109,6 +109,7 @@ message Symbol { PointUtf16 end = 8; bytes signature = 9; uint64 language_server_id = 10; + optional string container_name = 11; } message GetDocumentSymbols {