Skip to content

Commit 8ab7f56

Browse files
committed
Fix ranges of comment sections
1 parent ba2bf62 commit 8ab7f56

File tree

3 files changed

+118
-17
lines changed

3 files changed

+118
-17
lines changed

crates/ark/src/lsp/snapshots/ark__lsp__symbols__tests__symbol_assignment_function_nested_section.snap

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ expression: "test_symbol(\"\n## title0 ----\nfoo <- function() {\n # title1 ---
1515
character: 0,
1616
},
1717
end: Position {
18-
line: 1,
19-
character: 14,
18+
line: 7,
19+
character: 1,
2020
},
2121
},
2222
selection_range: Range {
@@ -25,8 +25,8 @@ expression: "test_symbol(\"\n## title0 ----\nfoo <- function() {\n # title1 ---
2525
character: 0,
2626
},
2727
end: Position {
28-
line: 1,
29-
character: 14,
28+
line: 7,
29+
character: 1,
3030
},
3131
},
3232
children: Some(
@@ -73,8 +73,8 @@ expression: "test_symbol(\"\n## title0 ----\nfoo <- function() {\n # title1 ---
7373
character: 2,
7474
},
7575
end: Position {
76-
line: 3,
77-
character: 15,
76+
line: 5,
77+
character: 16,
7878
},
7979
},
8080
selection_range: Range {
@@ -83,8 +83,8 @@ expression: "test_symbol(\"\n## title0 ----\nfoo <- function() {\n # title1 ---
8383
character: 2,
8484
},
8585
end: Position {
86-
line: 3,
87-
character: 15,
86+
line: 5,
87+
character: 16,
8888
},
8989
},
9090
children: Some(

crates/ark/src/lsp/symbols.rs

Lines changed: 91 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use crate::lsp::indexer::IndexEntryData;
2727
use crate::lsp::state::WorldState;
2828
use crate::lsp::traits::rope::RopeExt;
2929
use crate::lsp::traits::string::StringExt;
30+
use crate::treesitter::point_end_of_previous_row;
3031
use crate::treesitter::BinaryOperatorType;
3132
use crate::treesitter::NodeType;
3233
use crate::treesitter::NodeTypeExt;
@@ -116,7 +117,8 @@ pub fn symbols(params: &WorkspaceSymbolParams) -> anyhow::Result<Vec<SymbolInfor
116117
struct Section {
117118
title: String,
118119
level: usize,
119-
range: Range,
120+
start_position: tree_sitter::Point,
121+
end_position: Option<tree_sitter::Point>,
120122
children: Vec<DocumentSymbol>,
121123
}
122124

@@ -193,17 +195,19 @@ fn collect_sections(
193195
while !active_sections.is_empty() &&
194196
active_sections.last().unwrap().level >= absolute_level
195197
{
196-
finalize_section(&mut active_sections, symbols)?;
198+
// Set end position for the section being closed
199+
if let Some(section) = active_sections.last_mut() {
200+
let pos = point_end_of_previous_row(child.start_position(), contents);
201+
section.end_position = Some(pos);
202+
}
203+
finalize_section(&mut active_sections, symbols, contents)?;
197204
}
198205

199-
let range = Range {
200-
start: convert_point_to_position(contents, child.start_position()),
201-
end: convert_point_to_position(contents, child.end_position()),
202-
};
203206
let section = Section {
204207
title,
205208
level: absolute_level,
206-
range,
209+
start_position: child.start_position(),
210+
end_position: None,
207211
children: Vec::new(),
208212
};
209213
active_sections.push(section);
@@ -236,7 +240,15 @@ fn collect_sections(
236240

237241
// Close any remaining active sections
238242
while !active_sections.is_empty() {
239-
finalize_section(&mut active_sections, symbols)?;
243+
// Set end position to the parent node's end for remaining sections
244+
if let Some(section) = active_sections.last_mut() {
245+
let mut pos = node.end_position();
246+
if pos.row > section.start_position.row {
247+
pos = point_end_of_previous_row(pos, contents);
248+
}
249+
section.end_position = Some(pos);
250+
}
251+
finalize_section(&mut active_sections, symbols, contents)?;
240252
}
241253

242254
Ok(())
@@ -323,9 +335,18 @@ fn collect_assignment_with_function(
323335
fn finalize_section(
324336
active_sections: &mut Vec<Section>,
325337
symbols: &mut Vec<DocumentSymbol>,
338+
contents: &Rope,
326339
) -> anyhow::Result<()> {
327340
if let Some(section) = active_sections.pop() {
328-
let symbol = new_symbol(section.title, SymbolKind::STRING, section.range);
341+
let start_pos = section.start_position;
342+
let end_pos = section.end_position.unwrap_or(section.start_position);
343+
344+
let range = Range {
345+
start: convert_point_to_position(contents, start_pos),
346+
end: convert_point_to_position(contents, end_pos),
347+
};
348+
349+
let symbol = new_symbol(section.title, SymbolKind::STRING, range);
329350

330351
let mut final_symbol = symbol;
331352
final_symbol.children = Some(section.children);
@@ -507,4 +528,65 @@ foo <- function() {
507528

508529
assert_eq!(test_symbol("{ foo <- 1 }"), vec![foo]);
509530
}
531+
532+
#[test]
533+
fn test_symbol_section_ranges_extend() {
534+
let symbols = test_symbol(
535+
"# Section 1 ----
536+
x <- 1
537+
y <- 2
538+
# Section 2 ----
539+
z <- 3",
540+
);
541+
542+
assert_eq!(symbols.len(), 2);
543+
544+
// First section should extend from line 0 to line 2 (start of next section)
545+
let section1 = &symbols[0];
546+
assert_eq!(section1.name, "Section 1");
547+
assert_eq!(section1.range.start.line, 0);
548+
assert_eq!(section1.range.end.line, 2);
549+
550+
// Second section should extend from line 3 to end of file
551+
let section2 = &symbols[1];
552+
assert_eq!(section2.name, "Section 2");
553+
assert_eq!(section2.range.start.line, 3);
554+
assert_eq!(section2.range.end.line, 3);
555+
}
556+
557+
#[test]
558+
fn test_symbol_section_ranges_in_function() {
559+
let symbols = test_symbol(
560+
"foo <- function() {
561+
# Section A ----
562+
x <- 1
563+
y <- 2
564+
# Section B ----
565+
z <- 3
566+
}",
567+
);
568+
569+
assert_eq!(symbols.len(), 1);
570+
571+
// Should have one function symbol
572+
let function = &symbols[0];
573+
assert_eq!(function.name, "foo");
574+
assert_eq!(function.kind, SymbolKind::FUNCTION);
575+
576+
// Function should have two section children
577+
let children = function.children.as_ref().unwrap();
578+
assert_eq!(children.len(), 2);
579+
580+
// First section should extend from line 1 to line 3 (start of next section)
581+
let section_a = &children[0];
582+
assert_eq!(section_a.name, "Section A");
583+
assert_eq!(section_a.range.start.line, 1);
584+
assert_eq!(section_a.range.end.line, 3);
585+
586+
// Second section should extend from line 4 to end of function body
587+
let section_b = &children[1];
588+
assert_eq!(section_b.name, "Section B");
589+
assert_eq!(section_b.range.start.line, 4);
590+
assert_eq!(section_b.range.end.line, 5); // End of function body
591+
}
510592
}

crates/ark/src/treesitter.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,3 +571,22 @@ pub(crate) fn node_find_containing_call<'tree>(node: Node<'tree>) -> Option<Node
571571

572572
None
573573
}
574+
575+
pub(crate) fn point_end_of_previous_row(
576+
mut point: tree_sitter::Point,
577+
contents: &ropey::Rope,
578+
) -> tree_sitter::Point {
579+
if point.row > 0 {
580+
let prev_row = point.row - 1;
581+
let line = contents.line(prev_row as usize);
582+
let line_len = line.len_chars().saturating_sub(1); // Subtract 1 for newline
583+
tree_sitter::Point {
584+
row: prev_row,
585+
column: line_len,
586+
}
587+
} else {
588+
// We're at the very beginning of the document, can't go back further
589+
point.column = 0;
590+
point
591+
}
592+
}

0 commit comments

Comments
 (0)