@@ -25,6 +25,16 @@ const MAX_WARNING_REPEAT: Duration = Duration::from_secs(3_600);
25
25
const NAME : & str = "llm-ls" ;
26
26
const VERSION : & str = env ! ( "CARGO_PKG_VERSION" ) ;
27
27
28
+ fn get_position_idx ( rope : & Rope , row : usize , col : usize ) -> Result < usize > {
29
+ Ok ( rope. try_line_to_char ( row) . map_err ( internal_error) ?
30
+ + col. min (
31
+ rope. get_line ( row. min ( rope. len_lines ( ) - 1 ) )
32
+ . ok_or_else ( || internal_error ( format ! ( "failed to find line at {row}" ) ) ) ?
33
+ . len_chars ( )
34
+ - 1 ,
35
+ ) )
36
+ }
37
+
28
38
#[ derive( Debug , PartialEq , Eq , Serialize , Deserialize ) ]
29
39
enum CompletionType {
30
40
Empty ,
@@ -42,45 +52,71 @@ impl Display for CompletionType {
42
52
}
43
53
}
44
54
45
- fn should_complete ( document : & Document , position : Position ) -> CompletionType {
55
+ fn should_complete ( document : & Document , position : Position ) -> Result < CompletionType > {
46
56
let row = position. line as usize ;
47
57
let column = position. character as usize ;
48
58
if let Some ( tree) = & document. tree {
49
59
let current_node = tree. root_node ( ) . descendant_for_point_range (
50
60
tree_sitter:: Point { row, column } ,
51
- tree_sitter:: Point { row, column } ,
61
+ tree_sitter:: Point {
62
+ row,
63
+ column : column + 1 ,
64
+ } ,
52
65
) ;
53
66
if let Some ( node) = current_node {
54
67
if node == tree. root_node ( ) {
55
- return CompletionType :: MultiLine ;
68
+ return Ok ( CompletionType :: MultiLine ) ;
56
69
}
57
70
let start = node. start_position ( ) ;
58
71
let end = node. end_position ( ) ;
59
- let mut start_offset = document. text . line_to_char ( start. row ) + start. column ;
60
- let mut end_offset = document. text . line_to_char ( end. row ) + end. column - 1 ;
61
- let start_char = document. text . char ( start_offset) ;
72
+ let mut start_offset = get_position_idx ( & document. text , start. row , start. column ) ?;
73
+ let mut end_offset = get_position_idx ( & document. text , end. row , end. column ) ? - 1 ;
74
+ let start_char = document
75
+ . text
76
+ . get_char ( start_offset. min ( document. text . len_chars ( ) - 1 ) )
77
+ . ok_or_else ( || {
78
+ internal_error ( format ! ( "failed to find start char at {start_offset}" ) )
79
+ } ) ?;
80
+ let end_char = document
81
+ . text
82
+ . get_char ( end_offset. min ( document. text . len_chars ( ) - 1 ) )
83
+ . ok_or_else ( || {
84
+ internal_error ( format ! ( "failed to find end char at {end_offset}" ) )
85
+ } ) ?;
62
86
if !start_char. is_whitespace ( ) {
63
87
start_offset += 1 ;
64
88
}
65
- let end_char = document. text . char ( end_offset) ;
66
89
if !end_char. is_whitespace ( ) {
67
90
end_offset -= 1 ;
68
91
}
69
92
if start_offset >= end_offset {
70
- return CompletionType :: SingleLine ;
93
+ return Ok ( CompletionType :: SingleLine ) ;
71
94
}
72
- let slice = document. text . slice ( start_offset..end_offset) ;
95
+ let slice = document
96
+ . text
97
+ . get_slice ( start_offset..end_offset)
98
+ . ok_or_else ( || {
99
+ internal_error ( format ! (
100
+ "failed to find slice at {start_offset}..{end_offset}"
101
+ ) )
102
+ } ) ?;
73
103
if slice. to_string ( ) . trim ( ) . is_empty ( ) {
74
- return CompletionType :: MultiLine ;
104
+ return Ok ( CompletionType :: MultiLine ) ;
75
105
}
76
106
}
77
107
}
78
- let start_idx = document. text . line_to_char ( row) ;
79
- let next_char = document. text . char ( start_idx + column) ;
108
+ let start_idx = document
109
+ . text
110
+ . try_line_to_char ( row)
111
+ . map_err ( internal_error) ?;
112
+ let next_char = document
113
+ . text
114
+ . get_char ( start_idx + column)
115
+ . ok_or_else ( || internal_error ( format ! ( "failed to find char at {}" , start_idx + column) ) ) ?;
80
116
if next_char. is_whitespace ( ) {
81
- CompletionType :: SingleLine
117
+ Ok ( CompletionType :: SingleLine )
82
118
} else {
83
- CompletionType :: Empty
119
+ Ok ( CompletionType :: Empty )
84
120
}
85
121
}
86
122
@@ -271,12 +307,12 @@ fn build_prompt(
271
307
let mut after_iter = text. lines_at ( pos. line as usize ) ;
272
308
let mut before_line = before_iter. next ( ) ;
273
309
if let Some ( line) = before_line {
274
- let col = ( pos. character as usize ) . clamp ( 0 , line. len_chars ( ) ) ;
310
+ let col = ( pos. character as usize ) . clamp ( 0 , line. len_chars ( ) - 1 ) ;
275
311
before_line = Some ( line. slice ( 0 ..col) ) ;
276
312
}
277
313
let mut after_line = after_iter. next ( ) ;
278
314
if let Some ( line) = after_line {
279
- let col = ( pos. character as usize ) . clamp ( 0 , line. len_chars ( ) ) ;
315
+ let col = ( pos. character as usize ) . clamp ( 0 , line. len_chars ( ) - 1 ) ;
280
316
after_line = Some ( line. slice ( col..) ) ;
281
317
}
282
318
let mut before = vec ! [ ] ;
@@ -334,7 +370,7 @@ fn build_prompt(
334
370
let mut first = true ;
335
371
for mut line in text. lines_at ( pos. line as usize + 1 ) . reversed ( ) {
336
372
if first {
337
- let col = ( pos. character as usize ) . clamp ( 0 , line. len_chars ( ) ) ;
373
+ let col = ( pos. character as usize ) . clamp ( 0 , line. len_chars ( ) - 1 ) ;
338
374
line = line. slice ( 0 ..col) ;
339
375
first = false ;
340
376
}
@@ -582,7 +618,7 @@ impl Backend {
582
618
* unauthenticated_warn_at = Instant :: now ( ) ;
583
619
}
584
620
}
585
- let completion_type = should_complete ( document, params. text_document_position . position ) ;
621
+ let completion_type = should_complete ( document, params. text_document_position . position ) ? ;
586
622
info ! ( %completion_type, "completion type: {completion_type:?}" ) ;
587
623
if completion_type == CompletionType :: Empty {
588
624
return Ok ( CompletionResult { request_id, completions : vec ! [ ] } ) ;
@@ -658,7 +694,7 @@ impl LanguageServer for Backend {
658
694
} ) ,
659
695
capabilities : ServerCapabilities {
660
696
text_document_sync : Some ( TextDocumentSyncCapability :: Kind (
661
- TextDocumentSyncKind :: FULL ,
697
+ TextDocumentSyncKind :: INCREMENTAL ,
662
698
) ) ,
663
699
..Default :: default ( )
664
700
} ,
@@ -702,9 +738,15 @@ impl LanguageServer for Backend {
702
738
let mut document_map = self . document_map . write ( ) . await ;
703
739
let doc = document_map. get_mut ( & uri) ;
704
740
if let Some ( doc) = doc {
705
- match doc. change ( & params. content_changes [ 0 ] . text ) . await {
706
- Ok ( ( ) ) => info ! ( "{uri} changed" ) ,
707
- Err ( err) => error ! ( "error when changing {uri}: {err}" ) ,
741
+ for change in & params. content_changes {
742
+ if let Some ( range) = change. range {
743
+ match doc. change ( range, & change. text ) . await {
744
+ Ok ( ( ) ) => info ! ( "{uri} changed" ) ,
745
+ Err ( err) => error ! ( "error when changing {uri}: {err}" ) ,
746
+ }
747
+ } else {
748
+ warn ! ( "Could not update document, got change request with missing range" ) ;
749
+ }
708
750
}
709
751
} else {
710
752
warn ! ( "textDocument/didChange {uri}: document not found" ) ;
0 commit comments