aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock7
-rw-r--r--crates/rust-analyzer/Cargo.toml1
-rw-r--r--crates/rust-analyzer/src/diff.rs53
-rw-r--r--crates/rust-analyzer/src/handlers.rs12
-rw-r--r--crates/rust-analyzer/src/lib.rs1
-rw-r--r--crates/rust-analyzer/tests/rust-analyzer/main.rs31
6 files changed, 82 insertions, 23 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 9ddbeac47..1aa0c072d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -349,6 +349,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
349checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" 349checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
350 350
351[[package]] 351[[package]]
352name = "dissimilar"
353version = "1.0.2"
354source = "registry+https://github.com/rust-lang/crates.io-index"
355checksum = "fc4b29f4b9bb94bf267d57269fd0706d343a160937108e9619fe380645428abb"
356
357[[package]]
352name = "drop_bomb" 358name = "drop_bomb"
353version = "0.1.5" 359version = "0.1.5"
354source = "registry+https://github.com/rust-lang/crates.io-index" 360source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1343,6 +1349,7 @@ dependencies = [
1343 "anyhow", 1349 "anyhow",
1344 "cfg", 1350 "cfg",
1345 "crossbeam-channel 0.5.0", 1351 "crossbeam-channel 0.5.0",
1352 "dissimilar",
1346 "env_logger", 1353 "env_logger",
1347 "expect-test", 1354 "expect-test",
1348 "flycheck", 1355 "flycheck",
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 0a002337b..0a63593fb 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -17,6 +17,7 @@ path = "src/bin/main.rs"
17[dependencies] 17[dependencies]
18anyhow = "1.0.26" 18anyhow = "1.0.26"
19crossbeam-channel = "0.5.0" 19crossbeam-channel = "0.5.0"
20dissimilar = "1.0.2"
20env_logger = { version = "0.8.1", default-features = false } 21env_logger = { version = "0.8.1", default-features = false }
21itertools = "0.10.0" 22itertools = "0.10.0"
22jod-thread = "0.1.0" 23jod-thread = "0.1.0"
diff --git a/crates/rust-analyzer/src/diff.rs b/crates/rust-analyzer/src/diff.rs
new file mode 100644
index 000000000..231be5807
--- /dev/null
+++ b/crates/rust-analyzer/src/diff.rs
@@ -0,0 +1,53 @@
1//! Generate minimal `TextEdit`s from different text versions
2use dissimilar::Chunk;
3use ide::{TextEdit, TextRange, TextSize};
4
5pub(crate) fn diff(left: &str, right: &str) -> TextEdit {
6 let chunks = dissimilar::diff(left, right);
7 textedit_from_chunks(chunks)
8}
9
10fn textedit_from_chunks(chunks: Vec<dissimilar::Chunk>) -> TextEdit {
11 let mut builder = TextEdit::builder();
12 let mut pos = TextSize::default();
13
14 let mut chunks = chunks.into_iter().peekable();
15 while let Some(chunk) = chunks.next() {
16 if let (Chunk::Delete(deleted), Some(&Chunk::Insert(inserted))) = (chunk, chunks.peek()) {
17 chunks.next().unwrap();
18 let deleted_len = TextSize::of(deleted);
19 builder.replace(TextRange::at(pos, deleted_len), inserted.into());
20 pos += deleted_len;
21 continue;
22 }
23
24 match chunk {
25 Chunk::Equal(text) => {
26 pos += TextSize::of(text);
27 }
28 Chunk::Delete(deleted) => {
29 let deleted_len = TextSize::of(deleted);
30 builder.delete(TextRange::at(pos, deleted_len));
31 pos += deleted_len;
32 }
33 Chunk::Insert(inserted) => {
34 builder.insert(pos, inserted.into());
35 }
36 }
37 }
38 builder.finish()
39}
40
41#[cfg(test)]
42mod tests {
43 use super::*;
44
45 #[test]
46 fn diff_applies() {
47 let mut original = String::from("fn foo(a:u32){\n}");
48 let result = "fn foo(a: u32) {}";
49 let edit = diff(&original, result);
50 edit.apply(&mut original);
51 assert_eq!(original, result);
52 }
53}
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 78411f6c0..948cfc17c 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -31,6 +31,7 @@ use serde_json::to_value;
31use stdx::{format_to, split_once}; 31use stdx::{format_to, split_once};
32use syntax::{algo, ast, AstNode, TextRange, TextSize}; 32use syntax::{algo, ast, AstNode, TextRange, TextSize};
33 33
34use crate::diff::diff;
34use crate::{ 35use crate::{
35 cargo_target_spec::CargoTargetSpec, 36 cargo_target_spec::CargoTargetSpec,
36 config::RustfmtConfig, 37 config::RustfmtConfig,
@@ -840,7 +841,7 @@ pub(crate) fn handle_formatting(
840 let crate_ids = snap.analysis.crate_for(file_id)?; 841 let crate_ids = snap.analysis.crate_for(file_id)?;
841 842
842 let file_line_index = snap.analysis.file_line_index(file_id)?; 843 let file_line_index = snap.analysis.file_line_index(file_id)?;
843 let end_position = to_proto::position(&file_line_index, TextSize::of(file.as_str())); 844 let file_line_endings = snap.file_line_endings(file_id);
844 845
845 let mut rustfmt = match &snap.config.rustfmt { 846 let mut rustfmt = match &snap.config.rustfmt {
846 RustfmtConfig::Rustfmt { extra_args } => { 847 RustfmtConfig::Rustfmt { extra_args } => {
@@ -902,10 +903,11 @@ pub(crate) fn handle_formatting(
902 // The document is already formatted correctly -- no edits needed. 903 // The document is already formatted correctly -- no edits needed.
903 Ok(None) 904 Ok(None)
904 } else { 905 } else {
905 Ok(Some(vec![lsp_types::TextEdit { 906 Ok(Some(to_proto::text_edit_vec(
906 range: Range::new(Position::new(0, 0), end_position), 907 &file_line_index,
907 new_text: captured_stdout, 908 file_line_endings,
908 }])) 909 diff(&file, &captured_stdout),
910 )))
909 } 911 }
910} 912}
911 913
diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs
index d538ad69a..c9494e300 100644
--- a/crates/rust-analyzer/src/lib.rs
+++ b/crates/rust-analyzer/src/lib.rs
@@ -34,6 +34,7 @@ mod request_metrics;
34mod lsp_utils; 34mod lsp_utils;
35mod thread_pool; 35mod thread_pool;
36mod document; 36mod document;
37mod diff;
37pub mod lsp_ext; 38pub mod lsp_ext;
38pub mod config; 39pub mod config;
39 40
diff --git a/crates/rust-analyzer/tests/rust-analyzer/main.rs b/crates/rust-analyzer/tests/rust-analyzer/main.rs
index e51eb2626..84db0856d 100644
--- a/crates/rust-analyzer/tests/rust-analyzer/main.rs
+++ b/crates/rust-analyzer/tests/rust-analyzer/main.rs
@@ -190,15 +190,10 @@ pub use std::collections::HashMap;
190 }, 190 },
191 json!([ 191 json!([
192 { 192 {
193 "newText": r#"mod bar; 193 "newText": "",
194
195fn main() {}
196
197pub use std::collections::HashMap;
198"#,
199 "range": { 194 "range": {
200 "end": { "character": 0, "line": 6 }, 195 "end": { "character": 0, "line": 3 },
201 "start": { "character": 0, "line": 0 } 196 "start": { "character": 11, "line": 2 }
202 } 197 }
203 } 198 }
204 ]), 199 ]),
@@ -248,17 +243,17 @@ pub use std::collections::HashMap;
248 }, 243 },
249 json!([ 244 json!([
250 { 245 {
251 "newText": r#"mod bar; 246 "newText": "",
252 247 "range": {
253async fn test() {} 248 "end": { "character": 0, "line": 3 },
254 249 "start": { "character": 17, "line": 2 }
255fn main() {} 250 }
256 251 },
257pub use std::collections::HashMap; 252 {
258"#, 253 "newText": "",
259 "range": { 254 "range": {
260 "end": { "character": 0, "line": 9 }, 255 "end": { "character": 0, "line": 6 },
261 "start": { "character": 0, "line": 0 } 256 "start": { "character": 11, "line": 5 }
262 } 257 }
263 } 258 }
264 ]), 259 ]),