aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/rust-analyzer/src/lsp_utils.rs40
-rw-r--r--crates/rust-analyzer/src/main_loop.rs14
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.
2use std::{error::Error, ops::Range}; 2use std::{borrow::Cow, error::Error, ops::Range};
3 3
4use lsp_server::Notification; 4use lsp_server::Notification;
5use ra_db::Canceled; 5use ra_db::Canceled;
@@ -84,8 +84,8 @@ impl GlobalState {
84pub(crate) fn apply_document_changes( 84pub(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.
3use std::{ 3use std::{
4 borrow::Cow,
4 env, fmt, panic, 5 env, fmt, panic,
5 time::{Duration, Instant}, 6 time::{Duration, Instant},
6}; 7};
7 8
8use crossbeam_channel::{select, Receiver}; 9use crossbeam_channel::{select, Receiver};
9use lsp_server::{Connection, Notification, Request, Response}; 10use lsp_server::{Connection, Notification, Request, Response};
10use lsp_types::notification::Notification as _; 11use lsp_types::{notification::Notification as _, DidChangeTextDocumentParams};
11use ra_db::VfsPath; 12use ra_db::VfsPath;
12use ra_ide::{Canceled, FileId}; 13use ra_ide::{Canceled, FileId};
13use ra_prof::profile; 14use 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(&params.text_document.uri) { 424 if let Ok(path) = from_proto::vfs_path(&params.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 }