Skip to content

Commit ae5755f

Browse files
committed
Collect document symbols in arguments
1 parent 31da629 commit ae5755f

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

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

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

320-
let start = convert_point_to_position(contents, arg_value.start_position());
321-
let end = convert_point_to_position(contents, arg_value.end_position());
336+
let start = convert_point_to_position(contents, arg_value.start_position());
337+
let end = convert_point_to_position(contents, arg_value.end_position());
322338

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

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

335-
symbols.push(symbol);
336-
}
351+
symbols.push(symbol);
337352

338353
Ok(())
339354
}
@@ -766,11 +781,18 @@ list(
766781
"
767782
));
768783
}
769-
}
770784

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

0 commit comments

Comments
 (0)