@@ -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
@@ -193,17 +195,19 @@ fn collect_sections(
193
195
while !active_sections. is_empty ( ) &&
194
196
active_sections. last ( ) . unwrap ( ) . level >= absolute_level
195
197
{
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) ?;
197
204
}
198
205
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
- } ;
203
206
let section = Section {
204
207
title,
205
208
level : absolute_level,
206
- range,
209
+ start_position : child. start_position ( ) ,
210
+ end_position : None ,
207
211
children : Vec :: new ( ) ,
208
212
} ;
209
213
active_sections. push ( section) ;
@@ -236,7 +240,15 @@ fn collect_sections(
236
240
237
241
// Close any remaining active sections
238
242
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) ?;
240
252
}
241
253
242
254
Ok ( ( ) )
@@ -323,9 +335,18 @@ fn collect_assignment_with_function(
323
335
fn finalize_section (
324
336
active_sections : & mut Vec < Section > ,
325
337
symbols : & mut Vec < DocumentSymbol > ,
338
+ contents : & Rope ,
326
339
) -> anyhow:: Result < ( ) > {
327
340
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) ;
329
350
330
351
let mut final_symbol = symbol;
331
352
final_symbol. children = Some ( section. children ) ;
@@ -507,4 +528,65 @@ foo <- function() {
507
528
508
529
assert_eq ! ( test_symbol( "{ foo <- 1 }" ) , vec![ foo] ) ;
509
530
}
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
+ }
510
592
}
0 commit comments