Skip to content

Commit 5e3988d

Browse files
committed
Don't emit assigned objects in nested contexts as document symbols
1 parent 9318e7c commit 5e3988d

File tree

3 files changed

+206
-59
lines changed

3 files changed

+206
-59
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
---
2+
source: crates/ark/src/lsp/symbols.rs
3+
expression: "test_symbol(\"foo <- function() { bar <- function() 1 }\")"
4+
---
5+
[
6+
DocumentSymbol {
7+
name: "foo",
8+
detail: Some(
9+
"function()",
10+
),
11+
kind: Function,
12+
tags: None,
13+
deprecated: None,
14+
range: Range {
15+
start: Position {
16+
line: 0,
17+
character: 0,
18+
},
19+
end: Position {
20+
line: 0,
21+
character: 41,
22+
},
23+
},
24+
selection_range: Range {
25+
start: Position {
26+
line: 0,
27+
character: 0,
28+
},
29+
end: Position {
30+
line: 0,
31+
character: 41,
32+
},
33+
},
34+
children: Some(
35+
[
36+
DocumentSymbol {
37+
name: "bar",
38+
detail: Some(
39+
"function()",
40+
),
41+
kind: Function,
42+
tags: None,
43+
deprecated: None,
44+
range: Range {
45+
start: Position {
46+
line: 0,
47+
character: 20,
48+
},
49+
end: Position {
50+
line: 0,
51+
character: 39,
52+
},
53+
},
54+
selection_range: Range {
55+
start: Position {
56+
line: 0,
57+
character: 20,
58+
},
59+
end: Position {
60+
line: 0,
61+
character: 39,
62+
},
63+
},
64+
children: Some(
65+
[],
66+
),
67+
},
68+
],
69+
),
70+
},
71+
]
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
---
2+
source: crates/ark/src/lsp/symbols.rs
3+
expression: "test_symbol(\"\nlocal({\n inner1 <- 1 # Not a symbol\n})\na <- function() {\n inner2 <- 2 # Not a symbol\n inner3 <- function() 3 # Symbol\n}\n\")"
4+
---
5+
[
6+
DocumentSymbol {
7+
name: "a",
8+
detail: Some(
9+
"function()",
10+
),
11+
kind: Function,
12+
tags: None,
13+
deprecated: None,
14+
range: Range {
15+
start: Position {
16+
line: 4,
17+
character: 0,
18+
},
19+
end: Position {
20+
line: 7,
21+
character: 1,
22+
},
23+
},
24+
selection_range: Range {
25+
start: Position {
26+
line: 4,
27+
character: 0,
28+
},
29+
end: Position {
30+
line: 7,
31+
character: 1,
32+
},
33+
},
34+
children: Some(
35+
[
36+
DocumentSymbol {
37+
name: "inner3",
38+
detail: Some(
39+
"function()",
40+
),
41+
kind: Function,
42+
tags: None,
43+
deprecated: None,
44+
range: Range {
45+
start: Position {
46+
line: 6,
47+
character: 2,
48+
},
49+
end: Position {
50+
line: 6,
51+
character: 24,
52+
},
53+
},
54+
selection_range: Range {
55+
start: Position {
56+
line: 6,
57+
character: 2,
58+
},
59+
end: Position {
60+
line: 6,
61+
character: 24,
62+
},
63+
},
64+
children: Some(
65+
[],
66+
),
67+
},
68+
],
69+
),
70+
},
71+
]

crates/ark/src/lsp/symbols.rs

Lines changed: 64 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,15 @@ struct Section {
122122
children: Vec<DocumentSymbol>,
123123
}
124124

125-
struct CollectContext;
125+
struct CollectContext {
126+
top_level: bool,
127+
}
128+
129+
impl CollectContext {
130+
fn new() -> Self {
131+
Self { top_level: true }
132+
}
133+
}
126134

127135
pub(crate) fn document_symbols(
128136
state: &WorldState,
@@ -138,8 +146,13 @@ pub(crate) fn document_symbols(
138146
let mut result = Vec::new();
139147

140148
// Extract and process all symbols from the AST
141-
let mut ctx = CollectContext;
142-
if let Err(err) = collect_symbols(&mut ctx, &root_node, contents, 0, &mut result) {
149+
if let Err(err) = collect_symbols(
150+
&mut CollectContext::new(),
151+
&root_node,
152+
contents,
153+
0,
154+
&mut result,
155+
) {
143156
log::error!("Failed to collect symbols: {err:?}");
144157
return Ok(Vec::new());
145158
}
@@ -156,7 +169,12 @@ fn collect_symbols(
156169
symbols: &mut Vec<DocumentSymbol>,
157170
) -> anyhow::Result<()> {
158171
match node.node_type() {
159-
NodeType::Program | NodeType::BracedExpression => {
172+
NodeType::Program => {
173+
collect_sections(ctx, node, contents, current_level, symbols)?;
174+
},
175+
176+
NodeType::BracedExpression => {
177+
ctx.top_level = false;
160178
collect_sections(ctx, node, contents, current_level, symbols)?;
161179
},
162180

@@ -425,18 +443,25 @@ fn collect_assignment(
425443
return collect_assignment_with_function(ctx, node, contents, symbols);
426444
}
427445

428-
// Otherwise, collect as generic object
429-
let name = contents.node_slice(&lhs)?.to_string();
446+
if ctx.top_level {
447+
// Collect as generic object, but only if we're at top-level. Assigned
448+
// objects in nested functions and blocks cause the outline to become
449+
// too busy.
450+
let name = contents.node_slice(&lhs)?.to_string();
430451

431-
let start = convert_point_to_position(contents, lhs.start_position());
432-
let end = convert_point_to_position(contents, lhs.end_position());
452+
let start = convert_point_to_position(contents, lhs.start_position());
453+
let end = convert_point_to_position(contents, lhs.end_position());
433454

434-
// Now recurse into RHS
435-
let mut children = Vec::new();
436-
collect_symbols(ctx, &rhs, contents, 0, &mut children)?;
455+
// Now recurse into RHS
456+
let mut children = Vec::new();
457+
collect_symbols(ctx, &rhs, contents, 0, &mut children)?;
437458

438-
let symbol = new_symbol_node(name, SymbolKind::VARIABLE, Range { start, end }, children);
439-
symbols.push(symbol);
459+
let symbol = new_symbol_node(name, SymbolKind::VARIABLE, Range { start, end }, children);
460+
symbols.push(symbol);
461+
} else {
462+
// Recurse into RHS
463+
collect_symbols(ctx, &rhs, contents, 0, symbols)?;
464+
}
440465

441466
Ok(())
442467
}
@@ -541,8 +566,14 @@ mod tests {
541566
let node = doc.ast.root_node();
542567

543568
let mut symbols = Vec::new();
544-
let mut ctx = CollectContext;
545-
collect_symbols(&mut ctx, &node, &doc.contents, 0, &mut symbols).unwrap();
569+
collect_symbols(
570+
&mut CollectContext::new(),
571+
&node,
572+
&doc.contents,
573+
0,
574+
&mut symbols,
575+
)
576+
.unwrap();
546577
symbols
547578
}
548579

@@ -620,33 +651,7 @@ mod tests {
620651

621652
#[test]
622653
fn test_symbol_assignment_function_nested() {
623-
let range = Range {
624-
start: Position {
625-
line: 0,
626-
character: 20,
627-
},
628-
end: Position {
629-
line: 0,
630-
character: 23,
631-
},
632-
};
633-
let bar = new_symbol(String::from("bar"), SymbolKind::VARIABLE, range);
634-
635-
let range = Range {
636-
start: Position {
637-
line: 0,
638-
character: 0,
639-
},
640-
end: Position {
641-
line: 0,
642-
character: 30,
643-
},
644-
};
645-
let mut foo = new_symbol(String::from("foo"), SymbolKind::FUNCTION, range);
646-
foo.children = Some(vec![bar]);
647-
foo.detail = Some(String::from("function()"));
648-
649-
assert_eq!(test_symbol("foo <- function() { bar <- 1 }"), vec![foo]);
654+
insta::assert_debug_snapshot!(test_symbol("foo <- function() { bar <- function() 1 }"));
650655
}
651656

652657
#[test]
@@ -664,23 +669,6 @@ foo <- function() {
664669
));
665670
}
666671

667-
#[test]
668-
fn test_symbol_braced_list() {
669-
let range = Range {
670-
start: Position {
671-
line: 0,
672-
character: 2,
673-
},
674-
end: Position {
675-
line: 0,
676-
character: 5,
677-
},
678-
};
679-
let foo = new_symbol(String::from("foo"), SymbolKind::VARIABLE, range);
680-
681-
assert_eq!(test_symbol("{ foo <- 1 }"), vec![foo]);
682-
}
683-
684672
#[test]
685673
fn test_symbol_section_ranges_extend() {
686674
let symbols = test_symbol(
@@ -840,4 +828,21 @@ class <- r6::r6class(
840828
"
841829
));
842830
}
831+
832+
#[test]
833+
// Assigned variables in nested contexts are not emitted as symbols
834+
fn test_symbol_nested_assignments() {
835+
insta::assert_debug_snapshot!(test_symbol(
836+
"
837+
local({
838+
inner1 <- 1 # Not a symbol
839+
})
840+
a <- function() {
841+
inner2 <- 2 # Not a symbol
842+
inner3 <- function() 3 # Symbol
843+
}
844+
"
845+
));
846+
assert_eq!(test_symbol("{ foo <- 1 }"), vec![]);
847+
}
843848
}

0 commit comments

Comments
 (0)