11//! Utilities for LSP-related boilerplate code.
2- use std:: { ops:: Range , sync:: Arc } ;
2+ use std:: { mem , ops:: Range , sync:: Arc } ;
33
44use lsp_server:: Notification ;
55
@@ -133,11 +133,37 @@ impl GlobalState {
133133}
134134
135135pub ( 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+
139164 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) ) ,
141167 // We don't care about line endings or offset encoding here.
142168 endings : LineEndings :: Unix ,
143169 encoding : PositionEncoding :: Utf16 ,
@@ -148,38 +174,20 @@ pub(crate) fn apply_document_changes(
148174 // Some clients (e.g. Code) sort the ranges in reverse. As an optimization, we
149175 // remember the last valid line in the index and only rebuild it if needed.
150176 // 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 ;
166178 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) ;
176183 }
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 ) ;
180187 }
181188 }
182189 }
190+ text
183191}
184192
185193/// Checks that the edits inside the completion and the additional edits do not overlap.
@@ -242,51 +250,50 @@ mod tests {
242250 } ;
243251 }
244252
245- let mut text = String :: new ( ) ;
246- apply_document_changes ( & mut text, vec ! [ ] ) ;
253+ let text = apply_document_changes ( || String :: new ( ) , vec ! [ ] ) ;
247254 assert_eq ! ( text, "" ) ;
248- apply_document_changes (
249- & mut text,
255+ let text = apply_document_changes (
256+ || text,
250257 vec ! [ TextDocumentContentChangeEvent {
251258 range: None ,
252259 range_length: None ,
253260 text: String :: from( "the" ) ,
254261 } ] ,
255262 ) ;
256263 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" ] ) ;
258265 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" ] ) ;
260267 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" ] ) ;
262269 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 " ] ) ;
264271 assert_eq ! ( text, "quick foxes\n have dream" ) ;
265- apply_document_changes (
266- & mut text,
272+ let text = apply_document_changes (
273+ || text,
267274 c ! [ 0 , 0 ; 0 , 0 => "the " , 1 , 4 ; 1 , 4 => " quiet" , 1 , 16 ; 1 , 16 => "s\n " ] ,
268275 ) ;
269276 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 " ] ) ;
271278 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,
274281 c ! [ 1 , 0 ; 1 , 0 => "DREAM" , 2 , 0 ; 2 , 0 => "they " , 3 , 0 ; 3 , 0 => "DON'T THEY?" ] ,
275282 ) ;
276283 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 => "" ] ) ;
278285 assert_eq ! ( text, "the quick \n they have quiet dreams\n " ) ;
279286
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" ] ) ;
282289 assert_eq ! ( text, "a❤️" ) ;
283290
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" ] ) ;
286293 assert_eq ! ( text, "adcb" ) ;
287294
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" ] ) ;
290297 assert_eq ! ( text, "ațc\n cb" ) ;
291298 }
292299
0 commit comments