1
1
//! Utilities for LSP-related boilerplate code.
2
- use std:: { ops:: Range , sync:: Arc } ;
2
+ use std:: { mem , ops:: Range , sync:: Arc } ;
3
3
4
4
use lsp_server:: Notification ;
5
5
@@ -133,11 +133,37 @@ impl GlobalState {
133
133
}
134
134
135
135
pub ( crate ) fn apply_document_changes (
136
- old_text : & mut String ,
137
- content_changes : Vec < lsp_types:: TextDocumentContentChangeEvent > ,
138
- ) {
136
+ file_contents : impl FnOnce ( ) -> String ,
137
+ mut content_changes : Vec < lsp_types:: TextDocumentContentChangeEvent > ,
138
+ ) -> String {
139
+ // Skip to the last full document change, as it invalidates all previous changes anyways.
140
+ let mut start = content_changes
141
+ . iter ( )
142
+ . rev ( )
143
+ . position ( |change| change. range . is_none ( ) )
144
+ . map ( |idx| content_changes. len ( ) - idx - 1 )
145
+ . unwrap_or ( 0 ) ;
146
+
147
+ let mut text: String = match content_changes. get_mut ( start) {
148
+ // peek at the first content change as an optimization
149
+ Some ( lsp_types:: TextDocumentContentChangeEvent { range : None , text, .. } ) => {
150
+ let text = mem:: take ( text) ;
151
+ start += 1 ;
152
+
153
+ // The only change is a full document update
154
+ if start == content_changes. len ( ) {
155
+ return text;
156
+ }
157
+ text
158
+ }
159
+ Some ( _) => file_contents ( ) ,
160
+ // we received no content changes
161
+ None => return file_contents ( ) ,
162
+ } ;
163
+
139
164
let mut line_index = LineIndex {
140
- index : Arc :: new ( ide:: LineIndex :: new ( old_text) ) ,
165
+ // the index will be overwritten in the bottom loop's first iteration
166
+ index : Arc :: new ( ide:: LineIndex :: new ( & text) ) ,
141
167
// We don't care about line endings or offset encoding here.
142
168
endings : LineEndings :: Unix ,
143
169
encoding : PositionEncoding :: Utf16 ,
@@ -148,38 +174,20 @@ pub(crate) fn apply_document_changes(
148
174
// Some clients (e.g. Code) sort the ranges in reverse. As an optimization, we
149
175
// remember the last valid line in the index and only rebuild it if needed.
150
176
// The VFS will normalize the end of lines to `\n`.
151
- enum IndexValid {
152
- All ,
153
- UpToLineExclusive ( u32 ) ,
154
- }
155
-
156
- impl IndexValid {
157
- fn covers ( & self , line : u32 ) -> bool {
158
- match * self {
159
- IndexValid :: UpToLineExclusive ( to) => to > line,
160
- _ => true ,
161
- }
162
- }
163
- }
164
-
165
- let mut index_valid = IndexValid :: All ;
177
+ let mut index_valid = !0u32 ;
166
178
for change in content_changes {
167
- match change. range {
168
- Some ( range) => {
169
- if !index_valid. covers ( range. end . line ) {
170
- line_index. index = Arc :: new ( ide:: LineIndex :: new ( old_text) ) ;
171
- }
172
- index_valid = IndexValid :: UpToLineExclusive ( range. start . line ) ;
173
- if let Ok ( range) = from_proto:: text_range ( & line_index, range) {
174
- old_text. replace_range ( Range :: < usize > :: from ( range) , & change. text ) ;
175
- }
179
+ // The None case can't happen as we have handled it above already
180
+ if let Some ( range) = change. range {
181
+ if index_valid <= range. end . line {
182
+ * Arc :: make_mut ( & mut line_index. index ) = ide:: LineIndex :: new ( & text) ;
176
183
}
177
- None => {
178
- * old_text = change . text ;
179
- index_valid = IndexValid :: UpToLineExclusive ( 0 ) ;
184
+ index_valid = range . start . line ;
185
+ if let Ok ( range ) = from_proto :: text_range ( & line_index , range ) {
186
+ text . replace_range ( Range :: < usize > :: from ( range ) , & change . text ) ;
180
187
}
181
188
}
182
189
}
190
+ text
183
191
}
184
192
185
193
/// Checks that the edits inside the completion and the additional edits do not overlap.
@@ -242,51 +250,50 @@ mod tests {
242
250
} ;
243
251
}
244
252
245
- let mut text = String :: new ( ) ;
246
- apply_document_changes ( & mut text, vec ! [ ] ) ;
253
+ let text = apply_document_changes ( || String :: new ( ) , vec ! [ ] ) ;
247
254
assert_eq ! ( text, "" ) ;
248
- apply_document_changes (
249
- & mut text,
255
+ let text = apply_document_changes (
256
+ || text,
250
257
vec ! [ TextDocumentContentChangeEvent {
251
258
range: None ,
252
259
range_length: None ,
253
260
text: String :: from( "the" ) ,
254
261
} ] ,
255
262
) ;
256
263
assert_eq ! ( text, "the" ) ;
257
- apply_document_changes ( & mut text, c ! [ 0 , 3 ; 0 , 3 => " quick" ] ) ;
264
+ let text = apply_document_changes ( || text, c ! [ 0 , 3 ; 0 , 3 => " quick" ] ) ;
258
265
assert_eq ! ( text, "the quick" ) ;
259
- apply_document_changes ( & mut text, c ! [ 0 , 0 ; 0 , 4 => "" , 0 , 5 ; 0 , 5 => " foxes" ] ) ;
266
+ let text = apply_document_changes ( || text, c ! [ 0 , 0 ; 0 , 4 => "" , 0 , 5 ; 0 , 5 => " foxes" ] ) ;
260
267
assert_eq ! ( text, "quick foxes" ) ;
261
- apply_document_changes ( & mut text, c ! [ 0 , 11 ; 0 , 11 => "\n dream" ] ) ;
268
+ let text = apply_document_changes ( || text, c ! [ 0 , 11 ; 0 , 11 => "\n dream" ] ) ;
262
269
assert_eq ! ( text, "quick foxes\n dream" ) ;
263
- apply_document_changes ( & mut text, c ! [ 1 , 0 ; 1 , 0 => "have " ] ) ;
270
+ let text = apply_document_changes ( || text, c ! [ 1 , 0 ; 1 , 0 => "have " ] ) ;
264
271
assert_eq ! ( text, "quick foxes\n have dream" ) ;
265
- apply_document_changes (
266
- & mut text,
272
+ let text = apply_document_changes (
273
+ || text,
267
274
c ! [ 0 , 0 ; 0 , 0 => "the " , 1 , 4 ; 1 , 4 => " quiet" , 1 , 16 ; 1 , 16 => "s\n " ] ,
268
275
) ;
269
276
assert_eq ! ( text, "the quick foxes\n have quiet dreams\n " ) ;
270
- apply_document_changes ( & mut text, c ! [ 0 , 15 ; 0 , 15 => "\n " , 2 , 17 ; 2 , 17 => "\n " ] ) ;
277
+ let text = apply_document_changes ( || text, c ! [ 0 , 15 ; 0 , 15 => "\n " , 2 , 17 ; 2 , 17 => "\n " ] ) ;
271
278
assert_eq ! ( text, "the quick foxes\n \n have quiet dreams\n \n " ) ;
272
- apply_document_changes (
273
- & mut text,
279
+ let text = apply_document_changes (
280
+ || text,
274
281
c ! [ 1 , 0 ; 1 , 0 => "DREAM" , 2 , 0 ; 2 , 0 => "they " , 3 , 0 ; 3 , 0 => "DON'T THEY?" ] ,
275
282
) ;
276
283
assert_eq ! ( text, "the quick foxes\n DREAM\n they have quiet dreams\n DON'T THEY?\n " ) ;
277
- apply_document_changes ( & mut text, c ! [ 0 , 10 ; 1 , 5 => "" , 2 , 0 ; 2 , 12 => "" ] ) ;
284
+ let text = apply_document_changes ( || text, c ! [ 0 , 10 ; 1 , 5 => "" , 2 , 0 ; 2 , 12 => "" ] ) ;
278
285
assert_eq ! ( text, "the quick \n they have quiet dreams\n " ) ;
279
286
280
- text = String :: from ( "❤️" ) ;
281
- apply_document_changes ( & mut text, c ! [ 0 , 0 ; 0 , 0 => "a" ] ) ;
287
+ let text = String :: from ( "❤️" ) ;
288
+ let text = apply_document_changes ( || text, c ! [ 0 , 0 ; 0 , 0 => "a" ] ) ;
282
289
assert_eq ! ( text, "a❤️" ) ;
283
290
284
- text = String :: from ( "a\n b" ) ;
285
- apply_document_changes ( & mut text, c ! [ 0 , 1 ; 1 , 0 => "\n țc" , 0 , 1 ; 1 , 1 => "d" ] ) ;
291
+ let text = String :: from ( "a\n b" ) ;
292
+ let text = apply_document_changes ( || text, c ! [ 0 , 1 ; 1 , 0 => "\n țc" , 0 , 1 ; 1 , 1 => "d" ] ) ;
286
293
assert_eq ! ( text, "adcb" ) ;
287
294
288
- text = String :: from ( "a\n b" ) ;
289
- apply_document_changes ( & mut text, c ! [ 0 , 1 ; 1 , 0 => "ț\n c" , 0 , 2 ; 0 , 2 => "c" ] ) ;
295
+ let text = String :: from ( "a\n b" ) ;
296
+ let text = apply_document_changes ( || text, c ! [ 0 , 1 ; 1 , 0 => "ț\n c" , 0 , 2 ; 0 , 2 => "c" ] ) ;
290
297
assert_eq ! ( text, "ațc\n cb" ) ;
291
298
}
292
299
0 commit comments