Skip to content

Commit 74dbe94

Browse files
committed
Fix ranges of comment sections
1 parent f529e53 commit 74dbe94

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

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

198-
let range = Range {
199-
start: convert_point_to_position(contents, child.start_position()),
200-
end: convert_point_to_position(contents, child.end_position()),
201-
};
202205
let section = Section {
203206
title,
204207
level: absolute_level,
205-
range,
208+
start_position: child.start_position(),
209+
end_position: None,
206210
children: Vec::new(),
207211
};
208212
active_sections.push(section);
@@ -235,7 +239,15 @@ fn collect_sections(
235239

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

241253
Ok(())
@@ -322,9 +334,18 @@ fn collect_assignment_with_function(
322334
fn finalize_section(
323335
active_sections: &mut Vec<Section>,
324336
symbols: &mut Vec<DocumentSymbol>,
337+
contents: &Rope,
325338
) -> anyhow::Result<()> {
326339
if let Some(section) = active_sections.pop() {
327-
let symbol = new_symbol(section.title, SymbolKind::STRING, section.range);
340+
let start_pos = section.start_position;
341+
let end_pos = section.end_position.unwrap_or(section.start_position);
342+
343+
let range = Range {
344+
start: convert_point_to_position(contents, start_pos),
345+
end: convert_point_to_position(contents, end_pos),
346+
};
347+
348+
let symbol = new_symbol(section.title, SymbolKind::STRING, range);
328349

329350
let mut final_symbol = symbol;
330351
final_symbol.children = Some(section.children);
@@ -505,4 +526,65 @@ foo <- function() {
505526

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

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)