mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 04:53:34 +00:00
Add new LSP extension for workspace symbol lookup
The new extension allows filtering of workspace symbool lookup results by search scope or search kind. Filtering can be configured in 3 different ways: - The '#' or '*' markers can be added inline with the symbol lookup query. The '#' marker means symbols should be looked up in the current workspace and any dependencies. If not specified, only current workspace is considered. The '*' marker means all kinds of symbols should be looked up (types, functions, etc). If not specified, only type symbols are returned. - Each LSP request can take an optional search_scope or search_kind argument query parameter. - Finally there are 2 global config options that can be set for all requests served by the active RA instance. Add support for setting the global config options to the VSCode extension. The extension does not use the per-request way, but it's useful for other IDEs. The latest version of VSCode filters out the inline markers, so currently the only reasonable way to use the new functionality is via the global config.
This commit is contained in:
parent
c04eaa1f37
commit
1f7d2a6c22
8 changed files with 220 additions and 8 deletions
|
@ -161,6 +161,11 @@ impl<DB: ParallelDatabase> Clone for Snap<salsa::Snapshot<DB>> {
|
||||||
// That is, `#` switches from "types" to all symbols, `*` switches from the current
|
// That is, `#` switches from "types" to all symbols, `*` switches from the current
|
||||||
// workspace to dependencies.
|
// 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
|
// | Editor | Shortcut
|
||||||
//
|
//
|
||||||
|
|
|
@ -24,7 +24,8 @@ use vfs::AbsPathBuf;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
caps::completion_item_edit_resolve, diagnostics::DiagnosticsMapConfig,
|
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
|
// 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
|
/// Advanced option, fully override the command rust-analyzer uses for
|
||||||
/// formatting.
|
/// formatting.
|
||||||
rustfmt_overrideCommand: Option<Vec<String>> = "null",
|
rustfmt_overrideCommand: Option<Vec<String>> = "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<String>,
|
pub cargo_extra_args: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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 {
|
impl Config {
|
||||||
pub fn new(root_path: AbsPathBuf, caps: ClientCapabilities) -> Self {
|
pub fn new(root_path: AbsPathBuf, caps: ClientCapabilities) -> Self {
|
||||||
Config { caps, data: ConfigData::default(), discovered_projects: None, root_path }
|
Config { caps, data: ConfigData::default(), discovered_projects: None, root_path }
|
||||||
|
@ -687,6 +702,22 @@ impl Config {
|
||||||
.contains(&MarkupKind::Markdown),
|
.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 {
|
pub fn semantic_tokens_refresh(&self) -> bool {
|
||||||
try_or!(self.caps.workspace.as_ref()?.semantic_tokens.as_ref()?.refresh_support?, false)
|
try_or!(self.caps.workspace.as_ref()?.semantic_tokens.as_ref()?.refresh_support?, false)
|
||||||
}
|
}
|
||||||
|
@ -733,6 +764,20 @@ enum ImportPrefixDef {
|
||||||
ByCrate,
|
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 {
|
macro_rules! _config_data {
|
||||||
(struct $name:ident {
|
(struct $name:ident {
|
||||||
$(
|
$(
|
||||||
|
@ -903,6 +948,22 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": { "type": ["string", "object"] },
|
"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),
|
_ => panic!("{}: {}", ty, default),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ use crate::{
|
||||||
from_proto,
|
from_proto,
|
||||||
global_state::{GlobalState, GlobalStateSnapshot},
|
global_state::{GlobalState, GlobalStateSnapshot},
|
||||||
line_index::LineEndings,
|
line_index::LineEndings,
|
||||||
lsp_ext::{self, InlayHint, InlayHintsParams},
|
lsp_ext::{self, InlayHint, InlayHintsParams, WorkspaceSymbolParams},
|
||||||
lsp_utils::all_edits_are_disjoint,
|
lsp_utils::all_edits_are_disjoint,
|
||||||
to_proto, LspError, Result,
|
to_proto, LspError, Result,
|
||||||
};
|
};
|
||||||
|
@ -380,11 +380,12 @@ pub(crate) fn handle_document_symbol(
|
||||||
|
|
||||||
pub(crate) fn handle_workspace_symbol(
|
pub(crate) fn handle_workspace_symbol(
|
||||||
snap: GlobalStateSnapshot,
|
snap: GlobalStateSnapshot,
|
||||||
params: lsp_types::WorkspaceSymbolParams,
|
params: WorkspaceSymbolParams,
|
||||||
) -> Result<Option<Vec<SymbolInformation>>> {
|
) -> Result<Option<Vec<SymbolInformation>>> {
|
||||||
let _p = profile::span("handle_workspace_symbol");
|
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 = {
|
||||||
let query: String = params.query.chars().filter(|&c| c != '#' && c != '*').collect();
|
let query: String = params.query.chars().filter(|&c| c != '#' && c != '*').collect();
|
||||||
let mut q = Query::new(query);
|
let mut q = Query::new(query);
|
||||||
|
@ -406,6 +407,45 @@ pub(crate) fn handle_workspace_symbol(
|
||||||
|
|
||||||
return Ok(Some(res));
|
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<Vec<SymbolInformation>> {
|
fn exec_query(snap: &GlobalStateSnapshot, query: Query) -> Result<Vec<SymbolInformation>> {
|
||||||
let mut res = Vec::new();
|
let mut res = Vec::new();
|
||||||
for nav in snap.analysis.symbol_search(query)? {
|
for nav in snap.analysis.symbol_search(query)? {
|
||||||
|
|
|
@ -4,7 +4,8 @@ use std::{collections::HashMap, path::PathBuf};
|
||||||
|
|
||||||
use lsp_types::request::Request;
|
use lsp_types::request::Request;
|
||||||
use lsp_types::{
|
use lsp_types::{
|
||||||
notification::Notification, CodeActionKind, Position, Range, TextDocumentIdentifier,
|
notification::Notification, CodeActionKind, PartialResultParams, Position, Range,
|
||||||
|
TextDocumentIdentifier, WorkDoneProgressParams,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
@ -438,3 +439,42 @@ pub enum MoveItemDirection {
|
||||||
Up,
|
Up,
|
||||||
Down,
|
Down,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum WorkspaceSymbol {}
|
||||||
|
|
||||||
|
impl Request for WorkspaceSymbol {
|
||||||
|
type Params = WorkspaceSymbolParams;
|
||||||
|
type Result = Option<Vec<lsp_types::SymbolInformation>>;
|
||||||
|
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<WorkspaceSymbolSearchScope>,
|
||||||
|
|
||||||
|
pub search_kind: Option<WorkspaceSymbolSearchKind>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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,
|
||||||
|
}
|
||||||
|
|
|
@ -525,9 +525,9 @@ impl GlobalState {
|
||||||
.on::<lsp_ext::ExternalDocs>(handlers::handle_open_docs)
|
.on::<lsp_ext::ExternalDocs>(handlers::handle_open_docs)
|
||||||
.on::<lsp_ext::OpenCargoToml>(handlers::handle_open_cargo_toml)
|
.on::<lsp_ext::OpenCargoToml>(handlers::handle_open_cargo_toml)
|
||||||
.on::<lsp_ext::MoveItem>(handlers::handle_move_item)
|
.on::<lsp_ext::MoveItem>(handlers::handle_move_item)
|
||||||
|
.on::<lsp_ext::WorkspaceSymbol>(handlers::handle_workspace_symbol)
|
||||||
.on::<lsp_types::request::OnTypeFormatting>(handlers::handle_on_type_formatting)
|
.on::<lsp_types::request::OnTypeFormatting>(handlers::handle_on_type_formatting)
|
||||||
.on::<lsp_types::request::DocumentSymbolRequest>(handlers::handle_document_symbol)
|
.on::<lsp_types::request::DocumentSymbolRequest>(handlers::handle_document_symbol)
|
||||||
.on::<lsp_types::request::WorkspaceSymbol>(handlers::handle_workspace_symbol)
|
|
||||||
.on::<lsp_types::request::GotoDefinition>(handlers::handle_goto_definition)
|
.on::<lsp_types::request::GotoDefinition>(handlers::handle_goto_definition)
|
||||||
.on::<lsp_types::request::GotoImplementation>(handlers::handle_goto_implementation)
|
.on::<lsp_types::request::GotoImplementation>(handlers::handle_goto_implementation)
|
||||||
.on::<lsp_types::request::GotoTypeDefinition>(handlers::handle_goto_type_definition)
|
.on::<lsp_types::request::GotoTypeDefinition>(handlers::handle_goto_type_definition)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<!---
|
<!---
|
||||||
lsp_ext.rs hash: 6e57fc1b345b00e9
|
lsp_ext.rs hash: 10a8988e6893e6b2
|
||||||
|
|
||||||
If you need to change the above hash to make the test pass, please check if you
|
If you need to change the above hash to make the test pass, please check if you
|
||||||
need to adjust this doc as well and ping this issue:
|
need to adjust this doc as well and ping this issue:
|
||||||
|
@ -650,3 +650,33 @@ export const enum Direction {
|
||||||
Down = "Down"
|
Down = "Down"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Lookup workspace symbol search scope and kind
|
||||||
|
|
||||||
|
**Issue:** https://github.com/rust-analyzer/rust-analyzer/pull/7698
|
||||||
|
|
||||||
|
This request is sent from client to server to search for workspace symbols filtered by an
|
||||||
|
optional search scope and / or an optional symbol kind.
|
||||||
|
|
||||||
|
**Method:** `workspace/symbol`
|
||||||
|
|
||||||
|
**Request:** `WorkspaceSymbolParams`
|
||||||
|
|
||||||
|
**Response:** `SymbolInformation[] | null`
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface lsp_ext.WorkspaceSymbolParams extends WorkspaceSymbolParams {
|
||||||
|
searchScope?: WorkspaceSymbolSearchScope;
|
||||||
|
searchKind?: WorkspaceSymbolSearchKind;
|
||||||
|
}
|
||||||
|
|
||||||
|
const enum WorkspaceSymbolSearchScope {
|
||||||
|
Workspace = "Workspace",
|
||||||
|
WorkspaceAndDependencies = "WorkspaceAndDependencies"
|
||||||
|
}
|
||||||
|
|
||||||
|
const enum WorkspaceSymbolSearchKind {
|
||||||
|
OnlyTypes = "OnlyTypes",
|
||||||
|
AllSymbols = "AllSymbols"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
|
@ -341,3 +341,13 @@ Additional arguments to `rustfmt`.
|
||||||
Advanced option, fully override the command rust-analyzer uses for
|
Advanced option, fully override the command rust-analyzer uses for
|
||||||
formatting.
|
formatting.
|
||||||
--
|
--
|
||||||
|
[[rust-analyzer.workspace.symbol.search.scope]]rust-analyzer.workspace.symbol.search.scope (default: `"workspace"`)::
|
||||||
|
+
|
||||||
|
--
|
||||||
|
Workspace symbol search scope.
|
||||||
|
--
|
||||||
|
[[rust-analyzer.workspace.symbol.search.kind]]rust-analyzer.workspace.symbol.search.kind (default: `"only_types"`)::
|
||||||
|
+
|
||||||
|
--
|
||||||
|
Workspace symbol search kind.
|
||||||
|
--
|
||||||
|
|
|
@ -783,6 +783,32 @@
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"rust-analyzer.workspace.symbol.search.scope": {
|
||||||
|
"markdownDescription": "Workspace symbol search scope.",
|
||||||
|
"default": "workspace",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"workspace",
|
||||||
|
"workspace_and_dependencies"
|
||||||
|
],
|
||||||
|
"enumDescriptions": [
|
||||||
|
"Search in current workspace only",
|
||||||
|
"Search in current workspace and dependencies"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"rust-analyzer.workspace.symbol.search.kind": {
|
||||||
|
"markdownDescription": "Workspace symbol search kind.",
|
||||||
|
"default": "only_types",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"only_types",
|
||||||
|
"all_symbols"
|
||||||
|
],
|
||||||
|
"enumDescriptions": [
|
||||||
|
"Search for types only",
|
||||||
|
"Search for all symbols kinds"
|
||||||
|
]
|
||||||
|
},
|
||||||
"$generated-end": false
|
"$generated-end": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue