Add config option to exclude locals from doc search
diff --git a/crates/ide/src/file_structure.rs b/crates/ide/src/file_structure.rs
index 6820f99..e0cd32b 100644
--- a/crates/ide/src/file_structure.rs
+++ b/crates/ide/src/file_structure.rs
@@ -23,6 +23,11 @@
Region,
}
+#[derive(Debug, Clone)]
+pub struct FileStructureConfig {
+ pub exclude_locals: bool,
+}
+
// Feature: File Structure
//
// Provides a tree of the symbols defined in the file. Can be used to
@@ -36,21 +41,24 @@
// | VS Code | <kbd>Ctrl+Shift+O</kbd> |
//
// 
-pub(crate) fn file_structure(file: &SourceFile) -> Vec<StructureNode> {
+pub(crate) fn file_structure(
+ file: &SourceFile,
+ config: &FileStructureConfig,
+) -> Vec<StructureNode> {
let mut res = Vec::new();
let mut stack = Vec::new();
for event in file.syntax().preorder_with_tokens() {
match event {
WalkEvent::Enter(NodeOrToken::Node(node)) => {
- if let Some(mut symbol) = structure_node(&node) {
+ if let Some(mut symbol) = structure_node(&node, config) {
symbol.parent = stack.last().copied();
stack.push(res.len());
res.push(symbol);
}
}
WalkEvent::Leave(NodeOrToken::Node(node)) => {
- if structure_node(&node).is_some() {
+ if structure_node(&node, config).is_some() {
stack.pop().unwrap();
}
}
@@ -71,7 +79,7 @@
res
}
-fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
+fn structure_node(node: &SyntaxNode, config: &FileStructureConfig) -> Option<StructureNode> {
fn decl<N: HasName + HasAttrs>(node: N, kind: StructureNodeKind) -> Option<StructureNode> {
decl_with_detail(&node, None, kind)
}
@@ -187,6 +195,10 @@
Some(node)
},
ast::LetStmt(it) => {
+ if config.exclude_locals {
+ return None;
+ }
+
let pat = it.pat()?;
let mut label = String::new();
@@ -254,9 +266,19 @@
use super::*;
+ const DEFAULT_CONFIG: FileStructureConfig = FileStructureConfig { exclude_locals: true };
+
fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
+ check_with_config(ra_fixture, &DEFAULT_CONFIG, expect);
+ }
+
+ fn check_with_config(
+ #[rust_analyzer::rust_fixture] ra_fixture: &str,
+ config: &FileStructureConfig,
+ expect: Expect,
+ ) {
let file = SourceFile::parse(ra_fixture, span::Edition::CURRENT).ok().unwrap();
- let structure = file_structure(&file);
+ let structure = file_structure(&file, config);
expect.assert_debug_eq(&structure)
}
@@ -701,13 +723,264 @@
),
deprecated: false,
},
+ ]
+ "#]],
+ );
+ }
+
+ #[test]
+ fn test_file_structure_include_locals() {
+ check_with_config(
+ r#"
+struct Foo {
+ x: i32
+}
+
+mod m {
+ fn bar1() {}
+ fn bar2<T>(t: T) -> T {}
+ fn bar3<A,
+ B>(a: A,
+ b: B) -> Vec<
+ u32
+ > {}
+}
+
+enum E { X, Y(i32) }
+type T = ();
+static S: i32 = 42;
+const C: i32 = 42;
+trait Tr {}
+trait Alias = Tr;
+
+macro_rules! mc {
+ () => {}
+}
+
+fn let_statements() {
+ let x = 42;
+ let mut y = x;
+ let Foo {
+ ..
+ } = Foo { x };
+ _ = ();
+ let _ = g();
+}
+"#,
+ &FileStructureConfig { exclude_locals: false },
+ expect![[r#"
+ [
+ StructureNode {
+ parent: None,
+ label: "Foo",
+ navigation_range: 8..11,
+ node_range: 1..26,
+ kind: SymbolKind(
+ Struct,
+ ),
+ detail: None,
+ deprecated: false,
+ },
StructureNode {
parent: Some(
- 27,
+ 0,
),
label: "x",
- navigation_range: 684..685,
- node_range: 680..691,
+ navigation_range: 18..19,
+ node_range: 18..24,
+ kind: SymbolKind(
+ Field,
+ ),
+ detail: Some(
+ "i32",
+ ),
+ deprecated: false,
+ },
+ StructureNode {
+ parent: None,
+ label: "m",
+ navigation_range: 32..33,
+ node_range: 28..158,
+ kind: SymbolKind(
+ Module,
+ ),
+ detail: None,
+ deprecated: false,
+ },
+ StructureNode {
+ parent: Some(
+ 2,
+ ),
+ label: "bar1",
+ navigation_range: 43..47,
+ node_range: 40..52,
+ kind: SymbolKind(
+ Function,
+ ),
+ detail: Some(
+ "fn()",
+ ),
+ deprecated: false,
+ },
+ StructureNode {
+ parent: Some(
+ 2,
+ ),
+ label: "bar2",
+ navigation_range: 60..64,
+ node_range: 57..81,
+ kind: SymbolKind(
+ Function,
+ ),
+ detail: Some(
+ "fn<T>(t: T) -> T",
+ ),
+ deprecated: false,
+ },
+ StructureNode {
+ parent: Some(
+ 2,
+ ),
+ label: "bar3",
+ navigation_range: 89..93,
+ node_range: 86..156,
+ kind: SymbolKind(
+ Function,
+ ),
+ detail: Some(
+ "fn<A, B>(a: A, b: B) -> Vec< u32 >",
+ ),
+ deprecated: false,
+ },
+ StructureNode {
+ parent: None,
+ label: "E",
+ navigation_range: 165..166,
+ node_range: 160..180,
+ kind: SymbolKind(
+ Enum,
+ ),
+ detail: None,
+ deprecated: false,
+ },
+ StructureNode {
+ parent: Some(
+ 6,
+ ),
+ label: "X",
+ navigation_range: 169..170,
+ node_range: 169..170,
+ kind: SymbolKind(
+ Variant,
+ ),
+ detail: None,
+ deprecated: false,
+ },
+ StructureNode {
+ parent: Some(
+ 6,
+ ),
+ label: "Y",
+ navigation_range: 172..173,
+ node_range: 172..178,
+ kind: SymbolKind(
+ Variant,
+ ),
+ detail: None,
+ deprecated: false,
+ },
+ StructureNode {
+ parent: None,
+ label: "T",
+ navigation_range: 186..187,
+ node_range: 181..193,
+ kind: SymbolKind(
+ TypeAlias,
+ ),
+ detail: Some(
+ "()",
+ ),
+ deprecated: false,
+ },
+ StructureNode {
+ parent: None,
+ label: "S",
+ navigation_range: 201..202,
+ node_range: 194..213,
+ kind: SymbolKind(
+ Static,
+ ),
+ detail: Some(
+ "i32",
+ ),
+ deprecated: false,
+ },
+ StructureNode {
+ parent: None,
+ label: "C",
+ navigation_range: 220..221,
+ node_range: 214..232,
+ kind: SymbolKind(
+ Const,
+ ),
+ detail: Some(
+ "i32",
+ ),
+ deprecated: false,
+ },
+ StructureNode {
+ parent: None,
+ label: "Tr",
+ navigation_range: 239..241,
+ node_range: 233..244,
+ kind: SymbolKind(
+ Trait,
+ ),
+ detail: None,
+ deprecated: false,
+ },
+ StructureNode {
+ parent: None,
+ label: "Alias",
+ navigation_range: 251..256,
+ node_range: 245..262,
+ kind: SymbolKind(
+ TraitAlias,
+ ),
+ detail: None,
+ deprecated: false,
+ },
+ StructureNode {
+ parent: None,
+ label: "mc",
+ navigation_range: 277..279,
+ node_range: 264..296,
+ kind: SymbolKind(
+ Macro,
+ ),
+ detail: None,
+ deprecated: false,
+ },
+ StructureNode {
+ parent: None,
+ label: "let_statements",
+ navigation_range: 301..315,
+ node_range: 298..429,
+ kind: SymbolKind(
+ Function,
+ ),
+ detail: Some(
+ "fn()",
+ ),
+ deprecated: false,
+ },
+ StructureNode {
+ parent: Some(
+ 15,
+ ),
+ label: "x",
+ navigation_range: 328..329,
+ node_range: 324..335,
kind: SymbolKind(
Local,
),
@@ -716,11 +989,11 @@
},
StructureNode {
parent: Some(
- 27,
+ 15,
),
label: "mut y",
- navigation_range: 700..705,
- node_range: 696..710,
+ navigation_range: 344..349,
+ node_range: 340..354,
kind: SymbolKind(
Local,
),
@@ -729,11 +1002,11 @@
},
StructureNode {
parent: Some(
- 27,
+ 15,
),
label: "Foo { .. }",
- navigation_range: 719..741,
- node_range: 715..754,
+ navigation_range: 363..385,
+ node_range: 359..398,
kind: SymbolKind(
Local,
),
@@ -742,11 +1015,11 @@
},
StructureNode {
parent: Some(
- 27,
+ 15,
),
label: "_",
- navigation_range: 804..805,
- node_range: 800..812,
+ navigation_range: 419..420,
+ node_range: 415..427,
kind: SymbolKind(
Local,
),
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 9887748..5349ebb 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -81,7 +81,7 @@
annotations::{Annotation, AnnotationConfig, AnnotationKind, AnnotationLocation},
call_hierarchy::{CallHierarchyConfig, CallItem},
expand_macro::ExpandedMacro,
- file_structure::{StructureNode, StructureNodeKind},
+ file_structure::{FileStructureConfig, StructureNode, StructureNodeKind},
folding_ranges::{Fold, FoldKind},
highlight_related::{HighlightRelatedConfig, HighlightedRange},
hover::{
@@ -430,12 +430,16 @@
/// Returns a tree representation of symbols in the file. Useful to draw a
/// file outline.
- pub fn file_structure(&self, file_id: FileId) -> Cancellable<Vec<StructureNode>> {
+ pub fn file_structure(
+ &self,
+ config: &FileStructureConfig,
+ file_id: FileId,
+ ) -> Cancellable<Vec<StructureNode>> {
// FIXME: Edition
self.with_db(|db| {
let editioned_file_id_wrapper = EditionedFileId::current_edition(&self.db, file_id);
-
- file_structure::file_structure(&db.parse(editioned_file_id_wrapper).tree())
+ let source_file = db.parse(editioned_file_id_wrapper).tree();
+ file_structure::file_structure(&source_file, config)
})
}
diff --git a/crates/rust-analyzer/src/cli/symbols.rs b/crates/rust-analyzer/src/cli/symbols.rs
index 9fad672..d7af56d 100644
--- a/crates/rust-analyzer/src/cli/symbols.rs
+++ b/crates/rust-analyzer/src/cli/symbols.rs
@@ -1,5 +1,5 @@
//! Read Rust code on stdin, print syntax tree on stdout.
-use ide::Analysis;
+use ide::{Analysis, FileStructureConfig};
use crate::cli::{flags, read_stdin};
@@ -7,7 +7,12 @@
pub fn run(self) -> anyhow::Result<()> {
let text = read_stdin()?;
let (analysis, file_id) = Analysis::from_single_file(text);
- let structure = analysis.file_structure(file_id).unwrap();
+ let structure = analysis
+ // The default setting in config.rs (document_symbol_search_excludeLocals) is to exclude
+ // locals because it is unlikely that users want document search to return the names of
+ // local variables, but here we include them deliberately.
+ .file_structure(&FileStructureConfig { exclude_locals: false }, file_id)
+ .unwrap();
for s in structure {
println!("{s:?}");
}
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 1a00295..77e5a8e 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -858,6 +858,9 @@
/// check will be performed.
check_workspace: bool = true,
+ /// Exclude all locals from document symbol search.
+ document_symbol_search_excludeLocals: bool = true,
+
/// These proc-macros will be ignored when trying to expand them.
///
/// This config takes a map of crate names with the exported proc-macro names to ignore as values.
@@ -1481,6 +1484,13 @@
Server,
}
+/// Configuration for document symbol search requests.
+#[derive(Debug, Clone)]
+pub struct DocumentSymbolConfig {
+ /// Should locals be excluded.
+ pub search_exclude_locals: bool,
+}
+
#[derive(Debug, Clone)]
pub struct NotificationsConfig {
pub cargo_toml_not_found: bool,
@@ -2438,6 +2448,12 @@
}
}
+ pub fn document_symbol(&self, source_root: Option<SourceRootId>) -> DocumentSymbolConfig {
+ DocumentSymbolConfig {
+ search_exclude_locals: *self.document_symbol_search_excludeLocals(source_root),
+ }
+ }
+
pub fn workspace_symbol(&self, source_root: Option<SourceRootId>) -> WorkspaceSymbolConfig {
WorkspaceSymbolConfig {
search_exclude_imports: *self.workspace_symbol_search_excludeImports(source_root),
diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs
index 25c0aac..74ed5e3 100644
--- a/crates/rust-analyzer/src/handlers/request.rs
+++ b/crates/rust-analyzer/src/handlers/request.rs
@@ -8,8 +8,9 @@
use base64::{Engine, prelude::BASE64_STANDARD};
use ide::{
AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, CompletionFieldsToResolve,
- FilePosition, FileRange, HoverAction, HoverGotoTypeData, InlayFieldsToResolve, Query,
- RangeInfo, ReferenceCategory, Runnable, RunnableKind, SingleResolve, SourceChange, TextEdit,
+ FilePosition, FileRange, FileStructureConfig, HoverAction, HoverGotoTypeData,
+ InlayFieldsToResolve, Query, RangeInfo, ReferenceCategory, Runnable, RunnableKind,
+ SingleResolve, SourceChange, TextEdit,
};
use ide_db::{FxHashMap, SymbolKind};
use itertools::Itertools;
@@ -568,7 +569,14 @@
let mut parents: Vec<(lsp_types::DocumentSymbol, Option<usize>)> = Vec::new();
- for symbol in snap.analysis.file_structure(file_id)? {
+ let config = snap.config.document_symbol(None);
+
+ let structure_nodes = snap.analysis.file_structure(
+ &FileStructureConfig { exclude_locals: config.search_exclude_locals },
+ file_id,
+ )?;
+
+ for symbol in structure_nodes {
let mut tags = Vec::new();
if symbol.deprecated {
tags.push(SymbolTag::DEPRECATED)
@@ -588,8 +596,7 @@
parents.push((doc_symbol, symbol.parent));
}
- // Builds hierarchy from a flat list, in reverse order (so that indices
- // makes sense)
+ // Builds hierarchy from a flat list, in reverse order (so that indices make sense)
let document_symbols = {
let mut acc = Vec::new();
while let Some((mut node, parent_idx)) = parents.pop() {
diff --git a/docs/book/src/configuration_generated.md b/docs/book/src/configuration_generated.md
index 99a30d8..6ee956f 100644
--- a/docs/book/src/configuration_generated.md
+++ b/docs/book/src/configuration_generated.md
@@ -610,6 +610,13 @@
the `Problems Panel`.
+## rust-analyzer.document.symbol.search.excludeLocals {#document.symbol.search.excludeLocals}
+
+Default: `true`
+
+Exclude all locals from document symbol search.
+
+
## rust-analyzer.files.exclude {#files.exclude}
Default: `[]`
diff --git a/editors/code/package.json b/editors/code/package.json
index 470db24..328eb50 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -1586,6 +1586,16 @@
}
},
{
+ "title": "Document",
+ "properties": {
+ "rust-analyzer.document.symbol.search.excludeLocals": {
+ "markdownDescription": "Exclude all locals from document symbol search.",
+ "default": true,
+ "type": "boolean"
+ }
+ }
+ },
+ {
"title": "Files",
"properties": {
"rust-analyzer.files.exclude": {