diff --git a/crates/ide_db/src/symbol_index.rs b/crates/ide_db/src/symbol_index.rs index da427d6868..0f5c4abc4b 100644 --- a/crates/ide_db/src/symbol_index.rs +++ b/crates/ide_db/src/symbol_index.rs @@ -161,6 +161,11 @@ impl Clone for Snap> { // That is, `#` switches from "types" to all symbols, `*` switches from the current // workspace to dependencies. // +// Note that filtering does not currently work in VSCode due to the editor never +// sending the special symbols to the language server. Instead, you can configure +// the filtering via the `rust-analyzer.workspace.symbol.search.scope` and +// `rust-analyzer.workspace.symbol.search.kind` settings. +// // |=== // | Editor | Shortcut // diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index a3866c1baf..339014fd31 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -24,7 +24,8 @@ use vfs::AbsPathBuf; use crate::{ caps::completion_item_edit_resolve, diagnostics::DiagnosticsMapConfig, - line_index::OffsetEncoding, lsp_ext::supports_utf8, + line_index::OffsetEncoding, lsp_ext::supports_utf8, lsp_ext::WorkspaceSymbolSearchKind, + lsp_ext::WorkspaceSymbolSearchScope, }; // Defines the server-side configuration of the rust-analyzer. We generate @@ -215,6 +216,11 @@ config_data! { /// Advanced option, fully override the command rust-analyzer uses for /// formatting. rustfmt_overrideCommand: Option> = "null", + + /// Workspace symbol search scope. + workspace_symbol_search_scope: WorskpaceSymbolSearchScopeDef = "\"workspace\"", + /// Workspace symbol search kind. + workspace_symbol_search_kind: WorskpaceSymbolSearchKindDef = "\"only_types\"", } } @@ -309,6 +315,15 @@ pub struct RunnablesConfig { pub cargo_extra_args: Vec, } +/// Configuration for workspace symbol search requests. +#[derive(Debug, Clone)] +pub struct WorkspaceSymbolConfig { + /// In what scope should the symbol be searched in. + pub search_scope: WorkspaceSymbolSearchScope, + /// What kind of symbol is being search for. + pub search_kind: WorkspaceSymbolSearchKind, +} + impl Config { pub fn new(root_path: AbsPathBuf, caps: ClientCapabilities) -> Self { Config { caps, data: ConfigData::default(), discovered_projects: None, root_path } @@ -687,6 +702,22 @@ impl Config { .contains(&MarkupKind::Markdown), } } + + pub fn workspace_symbol(&self) -> WorkspaceSymbolConfig { + WorkspaceSymbolConfig { + search_scope: match self.data.workspace_symbol_search_scope { + WorskpaceSymbolSearchScopeDef::Workspace => WorkspaceSymbolSearchScope::Workspace, + WorskpaceSymbolSearchScopeDef::WorkspaceAndDependencies => { + WorkspaceSymbolSearchScope::WorkspaceAndDependencies + } + }, + search_kind: match self.data.workspace_symbol_search_kind { + WorskpaceSymbolSearchKindDef::OnlyTypes => WorkspaceSymbolSearchKind::OnlyTypes, + WorskpaceSymbolSearchKindDef::AllSymbols => WorkspaceSymbolSearchKind::AllSymbols, + }, + } + } + pub fn semantic_tokens_refresh(&self) -> bool { try_or!(self.caps.workspace.as_ref()?.semantic_tokens.as_ref()?.refresh_support?, false) } @@ -733,6 +764,20 @@ enum ImportPrefixDef { ByCrate, } +#[derive(Deserialize, Debug, Clone)] +#[serde(rename_all = "snake_case")] +enum WorskpaceSymbolSearchScopeDef { + Workspace, + WorkspaceAndDependencies, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(rename_all = "snake_case")] +enum WorskpaceSymbolSearchKindDef { + OnlyTypes, + AllSymbols, +} + macro_rules! _config_data { (struct $name:ident { $( @@ -903,6 +948,22 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json "type": "array", "items": { "type": ["string", "object"] }, }, + "WorskpaceSymbolSearchScopeDef" => set! { + "type": "string", + "enum": ["workspace", "workspace_and_dependencies"], + "enumDescriptions": [ + "Search in current workspace only", + "Search in current workspace and dependencies" + ], + }, + "WorskpaceSymbolSearchKindDef" => set! { + "type": "string", + "enum": ["only_types", "all_symbols"], + "enumDescriptions": [ + "Search for types only", + "Search for all symbols kinds" + ], + }, _ => panic!("{}: {}", ty, default), } diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 8fe97fd7c3..51041d7a0c 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -38,7 +38,7 @@ use crate::{ from_proto, global_state::{GlobalState, GlobalStateSnapshot}, line_index::LineEndings, - lsp_ext::{self, InlayHint, InlayHintsParams}, + lsp_ext::{self, InlayHint, InlayHintsParams, WorkspaceSymbolParams}, lsp_utils::all_edits_are_disjoint, to_proto, LspError, Result, }; @@ -380,11 +380,12 @@ pub(crate) fn handle_document_symbol( pub(crate) fn handle_workspace_symbol( snap: GlobalStateSnapshot, - params: lsp_types::WorkspaceSymbolParams, + params: WorkspaceSymbolParams, ) -> Result>> { let _p = profile::span("handle_workspace_symbol"); - let all_symbols = params.query.contains('#'); - let libs = params.query.contains('*'); + + let (all_symbols, libs) = decide_search_scope_and_kind(¶ms, &snap); + let query = { let query: String = params.query.chars().filter(|&c| c != '#' && c != '*').collect(); let mut q = Query::new(query); @@ -406,6 +407,45 @@ pub(crate) fn handle_workspace_symbol( return Ok(Some(res)); + fn decide_search_scope_and_kind( + params: &WorkspaceSymbolParams, + snap: &GlobalStateSnapshot, + ) -> (bool, bool) { + // Support old-style parsing of markers in the query. + let mut all_symbols = params.query.contains('#'); + let mut libs = params.query.contains('*'); + + let config = snap.config.workspace_symbol(); + + // If no explicit marker was set, check request params. If that's also empty + // use global config. + if !all_symbols { + let search_kind = if let Some(ref search_kind) = params.search_kind { + search_kind + } else { + &config.search_kind + }; + all_symbols = match search_kind { + lsp_ext::WorkspaceSymbolSearchKind::OnlyTypes => false, + lsp_ext::WorkspaceSymbolSearchKind::AllSymbols => true, + } + } + + if !libs { + let search_scope = if let Some(ref search_scope) = params.search_scope { + search_scope + } else { + &config.search_scope + }; + libs = match search_scope { + lsp_ext::WorkspaceSymbolSearchScope::Workspace => false, + lsp_ext::WorkspaceSymbolSearchScope::WorkspaceAndDependencies => true, + } + } + + (all_symbols, libs) + } + fn exec_query(snap: &GlobalStateSnapshot, query: Query) -> Result> { let mut res = Vec::new(); for nav in snap.analysis.symbol_search(query)? { diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 3bd0980580..34b53a7a80 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -4,7 +4,8 @@ use std::{collections::HashMap, path::PathBuf}; use lsp_types::request::Request; use lsp_types::{ - notification::Notification, CodeActionKind, Position, Range, TextDocumentIdentifier, + notification::Notification, CodeActionKind, PartialResultParams, Position, Range, + TextDocumentIdentifier, WorkDoneProgressParams, }; use serde::{Deserialize, Serialize}; @@ -438,3 +439,42 @@ pub enum MoveItemDirection { Up, Down, } + +#[derive(Debug)] +pub enum WorkspaceSymbol {} + +impl Request for WorkspaceSymbol { + type Params = WorkspaceSymbolParams; + type Result = Option>; + const METHOD: &'static str = "workspace/symbol"; +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct WorkspaceSymbolParams { + #[serde(flatten)] + pub partial_result_params: PartialResultParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + /// A non-empty query string + pub query: String, + + pub search_scope: Option, + + pub search_kind: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] +#[serde(rename_all = "camelCase")] +pub enum WorkspaceSymbolSearchScope { + Workspace, + WorkspaceAndDependencies, +} + +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] +#[serde(rename_all = "camelCase")] +pub enum WorkspaceSymbolSearchKind { + OnlyTypes, + AllSymbols, +} diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index c7bd7eee1a..4e07916113 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -525,9 +525,9 @@ impl GlobalState { .on::(handlers::handle_open_docs) .on::(handlers::handle_open_cargo_toml) .on::(handlers::handle_move_item) + .on::(handlers::handle_workspace_symbol) .on::(handlers::handle_on_type_formatting) .on::(handlers::handle_document_symbol) - .on::(handlers::handle_workspace_symbol) .on::(handlers::handle_goto_definition) .on::(handlers::handle_goto_implementation) .on::(handlers::handle_goto_type_definition) diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index 8fcd72d5d5..2d3787d0fe 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md @@ -1,5 +1,5 @@