7698: Add new LSP extension for workspace symbol lookup r=matklad a=alcroito

As well as all symbol types (functions, modules).

Remove outdated documentation regarding symbol lookup filtering.

Closes #4881

Co-authored-by: alcroito <placinta@gmail.com>
This commit is contained in:
bors[bot] 2021-05-18 19:20:51 +00:00 committed by GitHub
commit 49a5d6a8d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 220 additions and 8 deletions

View File

@ -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
// 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
//

View File

@ -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<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>,
}
/// 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),
}

View File

@ -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<Option<Vec<SymbolInformation>>> {
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(&params, &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<Vec<SymbolInformation>> {
let mut res = Vec::new();
for nav in snap.analysis.symbol_search(query)? {

View File

@ -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<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,
}

View File

@ -525,9 +525,9 @@ impl GlobalState {
.on::<lsp_ext::ExternalDocs>(handlers::handle_open_docs)
.on::<lsp_ext::OpenCargoToml>(handlers::handle_open_cargo_toml)
.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::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::GotoImplementation>(handlers::handle_goto_implementation)
.on::<lsp_types::request::GotoTypeDefinition>(handlers::handle_goto_type_definition)

View File

@ -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
need to adjust this doc as well and ping this issue:
@ -650,3 +650,33 @@ export const enum Direction {
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"
}
```

View File

@ -341,3 +341,13 @@ Additional arguments to `rustfmt`.
Advanced option, fully override the command rust-analyzer uses for
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.
--

View File

@ -783,6 +783,32 @@
"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
}
},