@@ -27,6 +27,7 @@ use crate::lsp::indexer::IndexEntryData;
27
27
use crate :: lsp:: state:: WorldState ;
28
28
use crate :: lsp:: traits:: rope:: RopeExt ;
29
29
use crate :: lsp:: traits:: string:: StringExt ;
30
+ use crate :: treesitter:: point_end_of_previous_row;
30
31
use crate :: treesitter:: BinaryOperatorType ;
31
32
use crate :: treesitter:: NodeType ;
32
33
use crate :: treesitter:: NodeTypeExt ;
@@ -116,7 +117,8 @@ pub fn symbols(params: &WorkspaceSymbolParams) -> anyhow::Result<Vec<SymbolInfor
116
117
struct Section {
117
118
title : String ,
118
119
level : usize ,
119
- range : Range ,
120
+ start_position : tree_sitter:: Point ,
121
+ end_position : Option < tree_sitter:: Point > ,
120
122
children : Vec < DocumentSymbol > ,
121
123
}
122
124
@@ -192,17 +194,19 @@ fn collect_sections(
192
194
while !active_sections. is_empty ( ) &&
193
195
active_sections. last ( ) . unwrap ( ) . level >= absolute_level
194
196
{
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) ?;
196
203
}
197
204
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
- } ;
202
205
let section = Section {
203
206
title,
204
207
level : absolute_level,
205
- range,
208
+ start_position : child. start_position ( ) ,
209
+ end_position : None ,
206
210
children : Vec :: new ( ) ,
207
211
} ;
208
212
active_sections. push ( section) ;
@@ -235,7 +239,15 @@ fn collect_sections(
235
239
236
240
// Close any remaining active sections
237
241
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) ?;
239
251
}
240
252
241
253
Ok ( ( ) )
@@ -322,9 +334,18 @@ fn collect_assignment_with_function(
322
334
fn finalize_section (
323
335
active_sections : & mut Vec < Section > ,
324
336
symbols : & mut Vec < DocumentSymbol > ,
337
+ contents : & Rope ,
325
338
) -> anyhow:: Result < ( ) > {
326
339
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) ;
328
349
329
350
let mut final_symbol = symbol;
330
351
final_symbol. children = Some ( section. children ) ;
@@ -505,4 +526,65 @@ foo <- function() {
505
526
506
527
assert_eq ! ( test_symbol( "{ foo <- 1 }" ) , vec![ foo] ) ;
507
528
}
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
+ }
508
590
}
0 commit comments