diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-07-27 10:49:45 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-07-27 10:49:45 +0100 |
commit | bc9fab156596d05ddb6b3fa57acd0fbd0755f2a0 (patch) | |
tree | 41661d408beb5cb5332f68f6c9a4cdfa6a43adc0 | |
parent | edcd0b1f62da19c9a7a197fa982c9b19dcfd62f2 (diff) | |
parent | 83a87fcd11298d8de32801ac6496ddf8b4e9c0e1 (diff) |
Merge #5532
5532: Restore line index optimization for edits r=matklad a=lnicola
Co-authored-by: Laurențiu Nicola <[email protected]>
-rw-r--r-- | crates/rust-analyzer/src/lsp_utils.rs | 40 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop.rs | 14 |
2 files changed, 31 insertions, 23 deletions
diff --git a/crates/rust-analyzer/src/lsp_utils.rs b/crates/rust-analyzer/src/lsp_utils.rs index 0bc3ff115..d4cc9dd04 100644 --- a/crates/rust-analyzer/src/lsp_utils.rs +++ b/crates/rust-analyzer/src/lsp_utils.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | //! Utilities for LSP-related boilerplate code. | 1 | //! Utilities for LSP-related boilerplate code. |
2 | use std::{error::Error, ops::Range}; | 2 | use std::{borrow::Cow, error::Error, ops::Range}; |
3 | 3 | ||
4 | use lsp_server::Notification; | 4 | use lsp_server::Notification; |
5 | use ra_db::Canceled; | 5 | use ra_db::Canceled; |
@@ -84,8 +84,8 @@ impl GlobalState { | |||
84 | pub(crate) fn apply_document_changes( | 84 | pub(crate) fn apply_document_changes( |
85 | old_text: &mut String, | 85 | old_text: &mut String, |
86 | content_changes: Vec<lsp_types::TextDocumentContentChangeEvent>, | 86 | content_changes: Vec<lsp_types::TextDocumentContentChangeEvent>, |
87 | mut line_index: Cow<'_, LineIndex>, | ||
87 | ) { | 88 | ) { |
88 | let mut line_index = LineIndex::new(old_text); | ||
89 | // The changes we got must be applied sequentially, but can cross lines so we | 89 | // The changes we got must be applied sequentially, but can cross lines so we |
90 | // have to keep our line index updated. | 90 | // have to keep our line index updated. |
91 | // Some clients (e.g. Code) sort the ranges in reverse. As an optimization, we | 91 | // Some clients (e.g. Code) sort the ranges in reverse. As an optimization, we |
@@ -110,7 +110,7 @@ pub(crate) fn apply_document_changes( | |||
110 | match change.range { | 110 | match change.range { |
111 | Some(range) => { | 111 | Some(range) => { |
112 | if !index_valid.covers(range.end.line) { | 112 | if !index_valid.covers(range.end.line) { |
113 | line_index = LineIndex::new(&old_text); | 113 | line_index = Cow::Owned(LineIndex::new(old_text)); |
114 | } | 114 | } |
115 | index_valid = IndexValid::UpToLineExclusive(range.start.line); | 115 | index_valid = IndexValid::UpToLineExclusive(range.start.line); |
116 | let range = from_proto::text_range(&line_index, range); | 116 | let range = from_proto::text_range(&line_index, range); |
@@ -145,10 +145,15 @@ mod tests { | |||
145 | }; | 145 | }; |
146 | } | 146 | } |
147 | 147 | ||
148 | fn run(text: &mut String, changes: Vec<TextDocumentContentChangeEvent>) { | ||
149 | let line_index = Cow::Owned(LineIndex::new(&text)); | ||
150 | super::apply_document_changes(text, changes, line_index); | ||
151 | } | ||
152 | |||
148 | let mut text = String::new(); | 153 | let mut text = String::new(); |
149 | apply_document_changes(&mut text, vec![]); | 154 | run(&mut text, vec![]); |
150 | assert_eq!(text, ""); | 155 | assert_eq!(text, ""); |
151 | apply_document_changes( | 156 | run( |
152 | &mut text, | 157 | &mut text, |
153 | vec![TextDocumentContentChangeEvent { | 158 | vec![TextDocumentContentChangeEvent { |
154 | range: None, | 159 | range: None, |
@@ -157,39 +162,36 @@ mod tests { | |||
157 | }], | 162 | }], |
158 | ); | 163 | ); |
159 | assert_eq!(text, "the"); | 164 | assert_eq!(text, "the"); |
160 | apply_document_changes(&mut text, c![0, 3; 0, 3 => " quick"]); | 165 | run(&mut text, c![0, 3; 0, 3 => " quick"]); |
161 | assert_eq!(text, "the quick"); | 166 | assert_eq!(text, "the quick"); |
162 | apply_document_changes(&mut text, c![0, 0; 0, 4 => "", 0, 5; 0, 5 => " foxes"]); | 167 | run(&mut text, c![0, 0; 0, 4 => "", 0, 5; 0, 5 => " foxes"]); |
163 | assert_eq!(text, "quick foxes"); | 168 | assert_eq!(text, "quick foxes"); |
164 | apply_document_changes(&mut text, c![0, 11; 0, 11 => "\ndream"]); | 169 | run(&mut text, c![0, 11; 0, 11 => "\ndream"]); |
165 | assert_eq!(text, "quick foxes\ndream"); | 170 | assert_eq!(text, "quick foxes\ndream"); |
166 | apply_document_changes(&mut text, c![1, 0; 1, 0 => "have "]); | 171 | run(&mut text, c![1, 0; 1, 0 => "have "]); |
167 | assert_eq!(text, "quick foxes\nhave dream"); | 172 | assert_eq!(text, "quick foxes\nhave dream"); |
168 | apply_document_changes( | 173 | run(&mut text, c![0, 0; 0, 0 => "the ", 1, 4; 1, 4 => " quiet", 1, 16; 1, 16 => "s\n"]); |
169 | &mut text, | ||
170 | c![0, 0; 0, 0 => "the ", 1, 4; 1, 4 => " quiet", 1, 16; 1, 16 => "s\n"], | ||
171 | ); | ||
172 | assert_eq!(text, "the quick foxes\nhave quiet dreams\n"); | 174 | assert_eq!(text, "the quick foxes\nhave quiet dreams\n"); |
173 | apply_document_changes(&mut text, c![0, 15; 0, 15 => "\n", 2, 17; 2, 17 => "\n"]); | 175 | run(&mut text, c![0, 15; 0, 15 => "\n", 2, 17; 2, 17 => "\n"]); |
174 | assert_eq!(text, "the quick foxes\n\nhave quiet dreams\n\n"); | 176 | assert_eq!(text, "the quick foxes\n\nhave quiet dreams\n\n"); |
175 | apply_document_changes( | 177 | run( |
176 | &mut text, | 178 | &mut text, |
177 | c![1, 0; 1, 0 => "DREAM", 2, 0; 2, 0 => "they ", 3, 0; 3, 0 => "DON'T THEY?"], | 179 | c![1, 0; 1, 0 => "DREAM", 2, 0; 2, 0 => "they ", 3, 0; 3, 0 => "DON'T THEY?"], |
178 | ); | 180 | ); |
179 | assert_eq!(text, "the quick foxes\nDREAM\nthey have quiet dreams\nDON'T THEY?\n"); | 181 | assert_eq!(text, "the quick foxes\nDREAM\nthey have quiet dreams\nDON'T THEY?\n"); |
180 | apply_document_changes(&mut text, c![0, 10; 1, 5 => "", 2, 0; 2, 12 => ""]); | 182 | run(&mut text, c![0, 10; 1, 5 => "", 2, 0; 2, 12 => ""]); |
181 | assert_eq!(text, "the quick \nthey have quiet dreams\n"); | 183 | assert_eq!(text, "the quick \nthey have quiet dreams\n"); |
182 | 184 | ||
183 | text = String::from("❤️"); | 185 | text = String::from("❤️"); |
184 | apply_document_changes(&mut text, c![0, 0; 0, 0 => "a"]); | 186 | run(&mut text, c![0, 0; 0, 0 => "a"]); |
185 | assert_eq!(text, "a❤️"); | 187 | assert_eq!(text, "a❤️"); |
186 | 188 | ||
187 | text = String::from("a\nb"); | 189 | text = String::from("a\nb"); |
188 | apply_document_changes(&mut text, c![0, 1; 1, 0 => "\nțc", 0, 1; 1, 1 => "d"]); | 190 | run(&mut text, c![0, 1; 1, 0 => "\nțc", 0, 1; 1, 1 => "d"]); |
189 | assert_eq!(text, "adcb"); | 191 | assert_eq!(text, "adcb"); |
190 | 192 | ||
191 | text = String::from("a\nb"); | 193 | text = String::from("a\nb"); |
192 | apply_document_changes(&mut text, c![0, 1; 1, 0 => "ț\nc", 0, 2; 0, 2 => "c"]); | 194 | run(&mut text, c![0, 1; 1, 0 => "ț\nc", 0, 2; 0, 2 => "c"]); |
193 | assert_eq!(text, "ațc\ncb"); | 195 | assert_eq!(text, "ațc\ncb"); |
194 | } | 196 | } |
195 | } | 197 | } |
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 51626fcd5..0ace4cb45 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -1,13 +1,14 @@ | |||
1 | //! The main loop of `rust-analyzer` responsible for dispatching LSP | 1 | //! The main loop of `rust-analyzer` responsible for dispatching LSP |
2 | //! requests/replies and notifications back to the client. | 2 | //! requests/replies and notifications back to the client. |
3 | use std::{ | 3 | use std::{ |
4 | borrow::Cow, | ||
4 | env, fmt, panic, | 5 | env, fmt, panic, |
5 | time::{Duration, Instant}, | 6 | time::{Duration, Instant}, |
6 | }; | 7 | }; |
7 | 8 | ||
8 | use crossbeam_channel::{select, Receiver}; | 9 | use crossbeam_channel::{select, Receiver}; |
9 | use lsp_server::{Connection, Notification, Request, Response}; | 10 | use lsp_server::{Connection, Notification, Request, Response}; |
10 | use lsp_types::notification::Notification as _; | 11 | use lsp_types::{notification::Notification as _, DidChangeTextDocumentParams}; |
11 | use ra_db::VfsPath; | 12 | use ra_db::VfsPath; |
12 | use ra_ide::{Canceled, FileId}; | 13 | use ra_ide::{Canceled, FileId}; |
13 | use ra_prof::profile; | 14 | use ra_prof::profile; |
@@ -421,15 +422,20 @@ impl GlobalState { | |||
421 | })? | 422 | })? |
422 | .on::<lsp_types::notification::DidChangeTextDocument>(|this, params| { | 423 | .on::<lsp_types::notification::DidChangeTextDocument>(|this, params| { |
423 | if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { | 424 | if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { |
424 | let doc = this.mem_docs.get_mut(&path).unwrap(); | 425 | let DidChangeTextDocumentParams { text_document, content_changes } = params; |
425 | let vfs = &mut this.vfs.write().0; | 426 | let vfs = &mut this.vfs.write().0; |
427 | let world = this.snapshot(); | ||
426 | let file_id = vfs.file_id(&path).unwrap(); | 428 | let file_id = vfs.file_id(&path).unwrap(); |
429 | |||
430 | // let file_id = vfs.file_id(&path).unwrap(); | ||
427 | let mut text = String::from_utf8(vfs.file_contents(file_id).to_vec()).unwrap(); | 431 | let mut text = String::from_utf8(vfs.file_contents(file_id).to_vec()).unwrap(); |
428 | apply_document_changes(&mut text, params.content_changes); | 432 | let line_index = world.analysis.file_line_index(file_id)?; |
433 | apply_document_changes(&mut text, content_changes, Cow::Borrowed(&line_index)); | ||
429 | 434 | ||
430 | // The version passed in DidChangeTextDocument is the version after all edits are applied | 435 | // The version passed in DidChangeTextDocument is the version after all edits are applied |
431 | // so we should apply it before the vfs is notified. | 436 | // so we should apply it before the vfs is notified. |
432 | doc.version = params.text_document.version; | 437 | let doc = this.mem_docs.get_mut(&path).unwrap(); |
438 | doc.version = text_document.version; | ||
433 | 439 | ||
434 | vfs.set_file_contents(path.clone(), Some(text.into_bytes())); | 440 | vfs.set_file_contents(path.clone(), Some(text.into_bytes())); |
435 | } | 441 | } |