Skip to content

Commit de3da46

Browse files
committed
Collect document symbols in arguments
1 parent 84d2e2c commit de3da46

File tree

2 files changed

+129
-38
lines changed

2 files changed

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

crates/ark/src/lsp/symbols.rs

Lines changed: 60 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -273,13 +273,13 @@ fn collect_call(
273273

274274
match fun_symbol.as_str() {
275275
"test_that" => collect_call_test_that(node, contents, symbols)?,
276-
_ => collect_call_methods(node, contents, symbols)?,
276+
_ => collect_call_arguments(node, contents, symbols)?,
277277
}
278278

279279
Ok(())
280280
}
281281

282-
fn collect_call_methods(
282+
fn collect_call_arguments(
283283
node: &Node,
284284
contents: &Rope,
285285
symbols: &mut Vec<DocumentSymbol>,
@@ -297,42 +297,57 @@ fn collect_call_methods(
297297
let Some(arg_value) = arg.child_by_field_name("value") else {
298298
continue;
299299
};
300-
if arg_value.kind() != "function_definition" {
301-
continue;
300+
301+
// Recurse into arguments. They might be a braced list, another call
302+
// that might contain functions, etc.
303+
collect_symbols(&arg_value, contents, 0, symbols)?;
304+
305+
if arg_value.kind() == "function_definition" {
306+
// Functions are not collected by `collect_symbols()` so we deal
307+
// with them here by processing the function body to extract child
308+
// symbols. We do this even if it's not a "method", i.e. if it's not
309+
// named.
310+
let body = arg_value.child_by_field_name("body").into_result()?;
311+
let mut children = Vec::new();
312+
collect_symbols(&body, contents, 0, &mut children)?;
313+
314+
// If there is a name node, collect it as a method
315+
if let Some(arg_fun) = arg.child_by_field_name("name") {
316+
collect_method(&arg_fun, &arg_value, contents, symbols)?;
317+
};
302318
}
319+
}
303320

304-
// Process the function body to extract child symbols.
305-
// We do this even if it's not a "method", i.e. if it's not named.
306-
let body = arg_value.child_by_field_name("body").into_result()?;
307-
let mut children = Vec::new();
308-
collect_symbols(&body, contents, 0, &mut children)?;
321+
Ok(())
322+
}
309323

310-
// There must be a name node, we're only collecting named functions as methods
311-
let Some(arg_name) = arg.child_by_field_name("name") else {
312-
continue;
313-
};
314-
if !arg_name.is_identifier_or_string() {
315-
continue;
316-
}
317-
let arg_name_str = contents.node_slice(&arg_name)?.to_string();
324+
fn collect_method(
325+
arg_fun: &Node,
326+
arg_value: &Node,
327+
contents: &Rope,
328+
symbols: &mut Vec<DocumentSymbol>,
329+
) -> anyhow::Result<()> {
330+
if !arg_fun.is_identifier_or_string() {
331+
return Ok(());
332+
}
333+
let arg_name_str = contents.node_slice(&arg_fun)?.to_string();
318334

319-
let start = convert_point_to_position(contents, arg_value.start_position());
320-
let end = convert_point_to_position(contents, arg_value.end_position());
335+
let start = convert_point_to_position(contents, arg_value.start_position());
336+
let end = convert_point_to_position(contents, arg_value.end_position());
321337

322-
let mut symbol = new_symbol_node(
323-
arg_name_str,
324-
SymbolKind::METHOD,
325-
Range { start, end },
326-
vec![],
327-
);
338+
let mut symbol = new_symbol_node(
339+
arg_name_str,
340+
SymbolKind::METHOD,
341+
Range { start, end },
342+
vec![],
343+
);
328344

329-
// Don't include whole function as detail as the body often doesn't
330-
// provide useful information and only make the outline more busy (with
331-
// curly braces, newline characters, etc).
332-
symbol.detail = Some(String::from("function()"));
345+
// Don't include whole function as detail as the body often doesn't
346+
// provide useful information and only make the outline more busy (with
347+
// curly braces, newline characters, etc).
348+
symbol.detail = Some(String::from("function()"));
333349

334-
symbols.push(symbol);
335-
}
350+
symbols.push(symbol);
336351

337352
Ok(())
338353
}
@@ -765,11 +780,18 @@ list(
765780
"
766781
));
767782
}
768-
}
769783

770-
// chat <- r6::r6class(
771-
// "chat",
772-
// public = list(
773-
// initialize = function() "initialize",
774-
// )
775-
// )
784+
#[test]
785+
fn test_symbol_call_arguments() {
786+
insta::assert_debug_snapshot!(test_symbol(
787+
"
788+
# section ----
789+
local({
790+
a <- function() {
791+
1
792+
}
793+
})
794+
"
795+
));
796+
}
797+
}

0 commit comments

Comments
 (0)