]> git.lizzy.rs Git - rust.git/blob - crates/rust-analyzer/src/diff.rs
Merge #7777
[rust.git] / crates / rust-analyzer / src / diff.rs
1 //! Generate minimal `TextEdit`s from different text versions
2 use dissimilar::Chunk;
3 use ide::{TextEdit, TextRange, TextSize};
4
5 pub(crate) fn diff(left: &str, right: &str) -> TextEdit {
6     let chunks = dissimilar::diff(left, right);
7     textedit_from_chunks(chunks)
8 }
9
10 fn 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)]
42 mod 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 }