diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_assists/src/assist_ctx.rs | 4 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/completion_context.rs | 4 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/completion_item.rs | 4 | ||||
-rw-r--r-- | crates/ra_ide_db/src/line_index_utils.rs | 6 | ||||
-rw-r--r-- | crates/ra_syntax/src/fuzz.rs | 6 | ||||
-rw-r--r-- | crates/ra_syntax/src/lib.rs | 14 | ||||
-rw-r--r-- | crates/ra_syntax/src/parsing/reparsing.rs | 16 | ||||
-rw-r--r-- | crates/ra_text_edit/src/lib.rs | 131 | ||||
-rw-r--r-- | crates/ra_text_edit/src/text_edit.rs | 102 | ||||
-rw-r--r-- | crates/rust-analyzer/src/conv.rs | 29 |
10 files changed, 154 insertions, 162 deletions
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs index 89547ce03..83dd270c6 100644 --- a/crates/ra_assists/src/assist_ctx.rs +++ b/crates/ra_assists/src/assist_ctx.rs | |||
@@ -4,14 +4,13 @@ use ra_db::FileRange; | |||
4 | use ra_fmt::{leading_indent, reindent}; | 4 | use ra_fmt::{leading_indent, reindent}; |
5 | use ra_ide_db::RootDatabase; | 5 | use ra_ide_db::RootDatabase; |
6 | use ra_syntax::{ | 6 | use ra_syntax::{ |
7 | algo::{self, find_covering_element, find_node_at_offset}, | 7 | algo::{self, find_covering_element, find_node_at_offset, SyntaxRewriter}, |
8 | AstNode, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextSize, | 8 | AstNode, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextSize, |
9 | TokenAtOffset, | 9 | TokenAtOffset, |
10 | }; | 10 | }; |
11 | use ra_text_edit::TextEditBuilder; | 11 | use ra_text_edit::TextEditBuilder; |
12 | 12 | ||
13 | use crate::{AssistAction, AssistFile, AssistId, AssistLabel, GroupLabel, ResolvedAssist}; | 13 | use crate::{AssistAction, AssistFile, AssistId, AssistLabel, GroupLabel, ResolvedAssist}; |
14 | use algo::SyntaxRewriter; | ||
15 | 14 | ||
16 | #[derive(Clone, Debug)] | 15 | #[derive(Clone, Debug)] |
17 | pub(crate) struct Assist(pub(crate) Vec<AssistInfo>); | 16 | pub(crate) struct Assist(pub(crate) Vec<AssistInfo>); |
@@ -42,7 +41,6 @@ impl AssistInfo { | |||
42 | } | 41 | } |
43 | } | 42 | } |
44 | 43 | ||
45 | |||
46 | /// `AssistCtx` allows to apply an assist or check if it could be applied. | 44 | /// `AssistCtx` allows to apply an assist or check if it could be applied. |
47 | /// | 45 | /// |
48 | /// Assists use a somewhat over-engineered approach, given the current needs. The | 46 | /// Assists use a somewhat over-engineered approach, given the current needs. The |
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs index dd87bd119..b6b9627de 100644 --- a/crates/ra_ide/src/completion/completion_context.rs +++ b/crates/ra_ide/src/completion/completion_context.rs | |||
@@ -9,7 +9,7 @@ use ra_syntax::{ | |||
9 | SyntaxKind::*, | 9 | SyntaxKind::*, |
10 | SyntaxNode, SyntaxToken, TextRange, TextSize, | 10 | SyntaxNode, SyntaxToken, TextRange, TextSize, |
11 | }; | 11 | }; |
12 | use ra_text_edit::AtomTextEdit; | 12 | use ra_text_edit::Indel; |
13 | 13 | ||
14 | use crate::{call_info::ActiveParameter, completion::CompletionConfig, FilePosition}; | 14 | use crate::{call_info::ActiveParameter, completion::CompletionConfig, FilePosition}; |
15 | 15 | ||
@@ -76,7 +76,7 @@ impl<'a> CompletionContext<'a> { | |||
76 | // actual completion. | 76 | // actual completion. |
77 | let file_with_fake_ident = { | 77 | let file_with_fake_ident = { |
78 | let parse = db.parse(position.file_id); | 78 | let parse = db.parse(position.file_id); |
79 | let edit = AtomTextEdit::insert(position.offset, "intellijRulezz".to_string()); | 79 | let edit = Indel::insert(position.offset, "intellijRulezz".to_string()); |
80 | parse.reparse(&edit).tree() | 80 | parse.reparse(&edit).tree() |
81 | }; | 81 | }; |
82 | let fake_ident_token = | 82 | let fake_ident_token = |
diff --git a/crates/ra_ide/src/completion/completion_item.rs b/crates/ra_ide/src/completion/completion_item.rs index 5936fb8f7..383b23ac4 100644 --- a/crates/ra_ide/src/completion/completion_item.rs +++ b/crates/ra_ide/src/completion/completion_item.rs | |||
@@ -62,8 +62,8 @@ impl fmt::Debug for CompletionItem { | |||
62 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | 62 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
63 | let mut s = f.debug_struct("CompletionItem"); | 63 | let mut s = f.debug_struct("CompletionItem"); |
64 | s.field("label", &self.label()).field("source_range", &self.source_range()); | 64 | s.field("label", &self.label()).field("source_range", &self.source_range()); |
65 | if self.text_edit().as_atoms().len() == 1 { | 65 | if self.text_edit().as_indels().len() == 1 { |
66 | let atom = &self.text_edit().as_atoms()[0]; | 66 | let atom = &self.text_edit().as_indels()[0]; |
67 | s.field("delete", &atom.delete); | 67 | s.field("delete", &atom.delete); |
68 | s.field("insert", &atom.insert); | 68 | s.field("insert", &atom.insert); |
69 | } else { | 69 | } else { |
diff --git a/crates/ra_ide_db/src/line_index_utils.rs b/crates/ra_ide_db/src/line_index_utils.rs index 039a12c0d..7fa6fc448 100644 --- a/crates/ra_ide_db/src/line_index_utils.rs +++ b/crates/ra_ide_db/src/line_index_utils.rs | |||
@@ -10,7 +10,7 @@ | |||
10 | use std::convert::TryInto; | 10 | use std::convert::TryInto; |
11 | 11 | ||
12 | use ra_syntax::{TextRange, TextSize}; | 12 | use ra_syntax::{TextRange, TextSize}; |
13 | use ra_text_edit::{AtomTextEdit, TextEdit}; | 13 | use ra_text_edit::{Indel, TextEdit}; |
14 | 14 | ||
15 | use crate::line_index::{LineCol, LineIndex, Utf16Char}; | 15 | use crate::line_index::{LineCol, LineIndex, Utf16Char}; |
16 | 16 | ||
@@ -182,14 +182,14 @@ struct TranslatedEdit<'a> { | |||
182 | } | 182 | } |
183 | 183 | ||
184 | struct Edits<'a> { | 184 | struct Edits<'a> { |
185 | edits: &'a [AtomTextEdit], | 185 | edits: &'a [Indel], |
186 | current: Option<TranslatedEdit<'a>>, | 186 | current: Option<TranslatedEdit<'a>>, |
187 | acc_diff: i64, | 187 | acc_diff: i64, |
188 | } | 188 | } |
189 | 189 | ||
190 | impl<'a> Edits<'a> { | 190 | impl<'a> Edits<'a> { |
191 | fn from_text_edit(text_edit: &'a TextEdit) -> Edits<'a> { | 191 | fn from_text_edit(text_edit: &'a TextEdit) -> Edits<'a> { |
192 | let mut x = Edits { edits: text_edit.as_atoms(), current: None, acc_diff: 0 }; | 192 | let mut x = Edits { edits: text_edit.as_indels(), current: None, acc_diff: 0 }; |
193 | x.advance_edit(); | 193 | x.advance_edit(); |
194 | x | 194 | x |
195 | } | 195 | } |
diff --git a/crates/ra_syntax/src/fuzz.rs b/crates/ra_syntax/src/fuzz.rs index 10fbe3176..39f9b12ab 100644 --- a/crates/ra_syntax/src/fuzz.rs +++ b/crates/ra_syntax/src/fuzz.rs | |||
@@ -5,7 +5,7 @@ use std::{ | |||
5 | str::{self, FromStr}, | 5 | str::{self, FromStr}, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use ra_text_edit::AtomTextEdit; | 8 | use ra_text_edit::Indel; |
9 | 9 | ||
10 | use crate::{validation, AstNode, SourceFile, TextRange}; | 10 | use crate::{validation, AstNode, SourceFile, TextRange}; |
11 | 11 | ||
@@ -22,7 +22,7 @@ pub fn check_parser(text: &str) { | |||
22 | #[derive(Debug, Clone)] | 22 | #[derive(Debug, Clone)] |
23 | pub struct CheckReparse { | 23 | pub struct CheckReparse { |
24 | text: String, | 24 | text: String, |
25 | edit: AtomTextEdit, | 25 | edit: Indel, |
26 | edited_text: String, | 26 | edited_text: String, |
27 | } | 27 | } |
28 | 28 | ||
@@ -43,7 +43,7 @@ impl CheckReparse { | |||
43 | TextRange::at(delete_start.try_into().unwrap(), delete_len.try_into().unwrap()); | 43 | TextRange::at(delete_start.try_into().unwrap(), delete_len.try_into().unwrap()); |
44 | let edited_text = | 44 | let edited_text = |
45 | format!("{}{}{}", &text[..delete_start], &insert, &text[delete_start + delete_len..]); | 45 | format!("{}{}{}", &text[..delete_start], &insert, &text[delete_start + delete_len..]); |
46 | let edit = AtomTextEdit { delete, insert }; | 46 | let edit = Indel { delete, insert }; |
47 | Some(CheckReparse { text, edit, edited_text }) | 47 | Some(CheckReparse { text, edit, edited_text }) |
48 | } | 48 | } |
49 | 49 | ||
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs index d0234cada..1a7348dac 100644 --- a/crates/ra_syntax/src/lib.rs +++ b/crates/ra_syntax/src/lib.rs | |||
@@ -39,7 +39,7 @@ pub mod fuzz; | |||
39 | 39 | ||
40 | use std::{marker::PhantomData, sync::Arc}; | 40 | use std::{marker::PhantomData, sync::Arc}; |
41 | 41 | ||
42 | use ra_text_edit::AtomTextEdit; | 42 | use ra_text_edit::Indel; |
43 | use stdx::format_to; | 43 | use stdx::format_to; |
44 | 44 | ||
45 | use crate::syntax_node::GreenNode; | 45 | use crate::syntax_node::GreenNode; |
@@ -126,13 +126,13 @@ impl Parse<SourceFile> { | |||
126 | buf | 126 | buf |
127 | } | 127 | } |
128 | 128 | ||
129 | pub fn reparse(&self, edit: &AtomTextEdit) -> Parse<SourceFile> { | 129 | pub fn reparse(&self, indel: &Indel) -> Parse<SourceFile> { |
130 | self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit)) | 130 | self.incremental_reparse(indel).unwrap_or_else(|| self.full_reparse(indel)) |
131 | } | 131 | } |
132 | 132 | ||
133 | fn incremental_reparse(&self, edit: &AtomTextEdit) -> Option<Parse<SourceFile>> { | 133 | fn incremental_reparse(&self, indel: &Indel) -> Option<Parse<SourceFile>> { |
134 | // FIXME: validation errors are not handled here | 134 | // FIXME: validation errors are not handled here |
135 | parsing::incremental_reparse(self.tree().syntax(), edit, self.errors.to_vec()).map( | 135 | parsing::incremental_reparse(self.tree().syntax(), indel, self.errors.to_vec()).map( |
136 | |(green_node, errors, _reparsed_range)| Parse { | 136 | |(green_node, errors, _reparsed_range)| Parse { |
137 | green: green_node, | 137 | green: green_node, |
138 | errors: Arc::new(errors), | 138 | errors: Arc::new(errors), |
@@ -141,8 +141,8 @@ impl Parse<SourceFile> { | |||
141 | ) | 141 | ) |
142 | } | 142 | } |
143 | 143 | ||
144 | fn full_reparse(&self, edit: &AtomTextEdit) -> Parse<SourceFile> { | 144 | fn full_reparse(&self, indel: &Indel) -> Parse<SourceFile> { |
145 | let text = edit.apply(self.tree().syntax().text().to_string()); | 145 | let text = indel.apply(self.tree().syntax().text().to_string()); |
146 | SourceFile::parse(&text) | 146 | SourceFile::parse(&text) |
147 | } | 147 | } |
148 | } | 148 | } |
diff --git a/crates/ra_syntax/src/parsing/reparsing.rs b/crates/ra_syntax/src/parsing/reparsing.rs index ffff0a7b2..6257e3f33 100644 --- a/crates/ra_syntax/src/parsing/reparsing.rs +++ b/crates/ra_syntax/src/parsing/reparsing.rs | |||
@@ -7,7 +7,7 @@ | |||
7 | //! and try to parse only this block. | 7 | //! and try to parse only this block. |
8 | 8 | ||
9 | use ra_parser::Reparser; | 9 | use ra_parser::Reparser; |
10 | use ra_text_edit::AtomTextEdit; | 10 | use ra_text_edit::Indel; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | algo, | 13 | algo, |
@@ -24,7 +24,7 @@ use crate::{ | |||
24 | 24 | ||
25 | pub(crate) fn incremental_reparse( | 25 | pub(crate) fn incremental_reparse( |
26 | node: &SyntaxNode, | 26 | node: &SyntaxNode, |
27 | edit: &AtomTextEdit, | 27 | edit: &Indel, |
28 | errors: Vec<SyntaxError>, | 28 | errors: Vec<SyntaxError>, |
29 | ) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> { | 29 | ) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> { |
30 | if let Some((green, new_errors, old_range)) = reparse_token(node, &edit) { | 30 | if let Some((green, new_errors, old_range)) = reparse_token(node, &edit) { |
@@ -39,7 +39,7 @@ pub(crate) fn incremental_reparse( | |||
39 | 39 | ||
40 | fn reparse_token<'node>( | 40 | fn reparse_token<'node>( |
41 | root: &'node SyntaxNode, | 41 | root: &'node SyntaxNode, |
42 | edit: &AtomTextEdit, | 42 | edit: &Indel, |
43 | ) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> { | 43 | ) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> { |
44 | let prev_token = algo::find_covering_element(root, edit.delete).as_token()?.clone(); | 44 | let prev_token = algo::find_covering_element(root, edit.delete).as_token()?.clone(); |
45 | let prev_token_kind = prev_token.kind(); | 45 | let prev_token_kind = prev_token.kind(); |
@@ -88,7 +88,7 @@ fn reparse_token<'node>( | |||
88 | 88 | ||
89 | fn reparse_block<'node>( | 89 | fn reparse_block<'node>( |
90 | root: &'node SyntaxNode, | 90 | root: &'node SyntaxNode, |
91 | edit: &AtomTextEdit, | 91 | edit: &Indel, |
92 | ) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> { | 92 | ) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> { |
93 | let (node, reparser) = find_reparsable_node(root, edit.delete)?; | 93 | let (node, reparser) = find_reparsable_node(root, edit.delete)?; |
94 | let text = get_text_after_edit(node.clone().into(), edit); | 94 | let text = get_text_after_edit(node.clone().into(), edit); |
@@ -108,9 +108,9 @@ fn reparse_block<'node>( | |||
108 | Some((node.replace_with(green), new_parser_errors, node.text_range())) | 108 | Some((node.replace_with(green), new_parser_errors, node.text_range())) |
109 | } | 109 | } |
110 | 110 | ||
111 | fn get_text_after_edit(element: SyntaxElement, edit: &AtomTextEdit) -> String { | 111 | fn get_text_after_edit(element: SyntaxElement, edit: &Indel) -> String { |
112 | let edit = | 112 | let edit = |
113 | AtomTextEdit::replace(edit.delete - element.text_range().start(), edit.insert.clone()); | 113 | Indel::replace(edit.delete - element.text_range().start(), edit.insert.clone()); |
114 | 114 | ||
115 | let text = match element { | 115 | let text = match element { |
116 | NodeOrToken::Token(token) => token.text().to_string(), | 116 | NodeOrToken::Token(token) => token.text().to_string(), |
@@ -167,7 +167,7 @@ fn merge_errors( | |||
167 | old_errors: Vec<SyntaxError>, | 167 | old_errors: Vec<SyntaxError>, |
168 | new_errors: Vec<SyntaxError>, | 168 | new_errors: Vec<SyntaxError>, |
169 | range_before_reparse: TextRange, | 169 | range_before_reparse: TextRange, |
170 | edit: &AtomTextEdit, | 170 | edit: &Indel, |
171 | ) -> Vec<SyntaxError> { | 171 | ) -> Vec<SyntaxError> { |
172 | let mut res = Vec::new(); | 172 | let mut res = Vec::new(); |
173 | 173 | ||
@@ -198,7 +198,7 @@ mod tests { | |||
198 | 198 | ||
199 | fn do_check(before: &str, replace_with: &str, reparsed_len: u32) { | 199 | fn do_check(before: &str, replace_with: &str, reparsed_len: u32) { |
200 | let (range, before) = extract_range(before); | 200 | let (range, before) = extract_range(before); |
201 | let edit = AtomTextEdit::replace(range, replace_with.to_owned()); | 201 | let edit = Indel::replace(range, replace_with.to_owned()); |
202 | let after = edit.apply(before.clone()); | 202 | let after = edit.apply(before.clone()); |
203 | 203 | ||
204 | let fully_reparsed = SourceFile::parse(&after); | 204 | let fully_reparsed = SourceFile::parse(&after); |
diff --git a/crates/ra_text_edit/src/lib.rs b/crates/ra_text_edit/src/lib.rs index e656260c7..c41bf324b 100644 --- a/crates/ra_text_edit/src/lib.rs +++ b/crates/ra_text_edit/src/lib.rs | |||
@@ -1,30 +1,40 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! Representation of a `TextEdit`. |
2 | 2 | //! | |
3 | mod text_edit; | 3 | //! `rust-analyzer` never mutates text itself and only sends diffs to clients, |
4 | //! so `TextEdit` is the ultimate representation of the work done by | ||
5 | //! rust-analyzer. | ||
4 | 6 | ||
5 | use text_size::{TextRange, TextSize}; | 7 | use text_size::{TextRange, TextSize}; |
6 | 8 | ||
7 | pub use crate::text_edit::{TextEdit, TextEditBuilder}; | 9 | /// `InsertDelete` -- a single "atomic" change to text |
8 | 10 | /// | |
9 | /// Must not overlap with other `AtomTextEdit`s | 11 | /// Must not overlap with other `InDel`s |
10 | #[derive(Debug, Clone)] | 12 | #[derive(Debug, Clone)] |
11 | pub struct AtomTextEdit { | 13 | pub struct Indel { |
14 | pub insert: String, | ||
12 | /// Refers to offsets in the original text | 15 | /// Refers to offsets in the original text |
13 | pub delete: TextRange, | 16 | pub delete: TextRange, |
14 | pub insert: String, | ||
15 | } | 17 | } |
16 | 18 | ||
17 | impl AtomTextEdit { | 19 | #[derive(Debug, Clone)] |
18 | pub fn replace(range: TextRange, replace_with: String) -> AtomTextEdit { | 20 | pub struct TextEdit { |
19 | AtomTextEdit { delete: range, insert: replace_with } | 21 | indels: Vec<Indel>, |
20 | } | 22 | } |
21 | 23 | ||
22 | pub fn delete(range: TextRange) -> AtomTextEdit { | 24 | #[derive(Debug, Default)] |
23 | AtomTextEdit::replace(range, String::new()) | 25 | pub struct TextEditBuilder { |
24 | } | 26 | indels: Vec<Indel>, |
27 | } | ||
25 | 28 | ||
26 | pub fn insert(offset: TextSize, text: String) -> AtomTextEdit { | 29 | impl Indel { |
27 | AtomTextEdit::replace(TextRange::empty(offset), text) | 30 | pub fn insert(offset: TextSize, text: String) -> Indel { |
31 | Indel::replace(TextRange::empty(offset), text) | ||
32 | } | ||
33 | pub fn delete(range: TextRange) -> Indel { | ||
34 | Indel::replace(range, String::new()) | ||
35 | } | ||
36 | pub fn replace(range: TextRange, replace_with: String) -> Indel { | ||
37 | Indel { delete: range, insert: replace_with } | ||
28 | } | 38 | } |
29 | 39 | ||
30 | pub fn apply(&self, mut text: String) -> String { | 40 | pub fn apply(&self, mut text: String) -> String { |
@@ -34,3 +44,90 @@ impl AtomTextEdit { | |||
34 | text | 44 | text |
35 | } | 45 | } |
36 | } | 46 | } |
47 | |||
48 | impl TextEdit { | ||
49 | pub fn insert(offset: TextSize, text: String) -> TextEdit { | ||
50 | let mut builder = TextEditBuilder::default(); | ||
51 | builder.insert(offset, text); | ||
52 | builder.finish() | ||
53 | } | ||
54 | |||
55 | pub fn delete(range: TextRange) -> TextEdit { | ||
56 | let mut builder = TextEditBuilder::default(); | ||
57 | builder.delete(range); | ||
58 | builder.finish() | ||
59 | } | ||
60 | |||
61 | pub fn replace(range: TextRange, replace_with: String) -> TextEdit { | ||
62 | let mut builder = TextEditBuilder::default(); | ||
63 | builder.replace(range, replace_with); | ||
64 | builder.finish() | ||
65 | } | ||
66 | |||
67 | pub(crate) fn from_indels(mut indels: Vec<Indel>) -> TextEdit { | ||
68 | indels.sort_by_key(|a| (a.delete.start(), a.delete.end())); | ||
69 | for (a1, a2) in indels.iter().zip(indels.iter().skip(1)) { | ||
70 | assert!(a1.delete.end() <= a2.delete.start()) | ||
71 | } | ||
72 | TextEdit { indels } | ||
73 | } | ||
74 | |||
75 | pub fn as_indels(&self) -> &[Indel] { | ||
76 | &self.indels | ||
77 | } | ||
78 | |||
79 | pub fn apply(&self, text: &str) -> String { | ||
80 | let mut total_len = TextSize::of(text); | ||
81 | for indel in self.indels.iter() { | ||
82 | total_len += TextSize::of(&indel.insert); | ||
83 | total_len -= indel.delete.end() - indel.delete.start(); | ||
84 | } | ||
85 | let mut buf = String::with_capacity(total_len.into()); | ||
86 | let mut prev = 0; | ||
87 | for indel in self.indels.iter() { | ||
88 | let start: usize = indel.delete.start().into(); | ||
89 | let end: usize = indel.delete.end().into(); | ||
90 | if start > prev { | ||
91 | buf.push_str(&text[prev..start]); | ||
92 | } | ||
93 | buf.push_str(&indel.insert); | ||
94 | prev = end; | ||
95 | } | ||
96 | buf.push_str(&text[prev..text.len()]); | ||
97 | assert_eq!(TextSize::of(&buf), total_len); | ||
98 | buf | ||
99 | } | ||
100 | |||
101 | pub fn apply_to_offset(&self, offset: TextSize) -> Option<TextSize> { | ||
102 | let mut res = offset; | ||
103 | for indel in self.indels.iter() { | ||
104 | if indel.delete.start() >= offset { | ||
105 | break; | ||
106 | } | ||
107 | if offset < indel.delete.end() { | ||
108 | return None; | ||
109 | } | ||
110 | res += TextSize::of(&indel.insert); | ||
111 | res -= indel.delete.len(); | ||
112 | } | ||
113 | Some(res) | ||
114 | } | ||
115 | } | ||
116 | |||
117 | impl TextEditBuilder { | ||
118 | pub fn replace(&mut self, range: TextRange, replace_with: String) { | ||
119 | self.indels.push(Indel::replace(range, replace_with)) | ||
120 | } | ||
121 | pub fn delete(&mut self, range: TextRange) { | ||
122 | self.indels.push(Indel::delete(range)) | ||
123 | } | ||
124 | pub fn insert(&mut self, offset: TextSize, text: String) { | ||
125 | self.indels.push(Indel::insert(offset, text)) | ||
126 | } | ||
127 | pub fn finish(self) -> TextEdit { | ||
128 | TextEdit::from_indels(self.indels) | ||
129 | } | ||
130 | pub fn invalidates_offset(&self, offset: TextSize) -> bool { | ||
131 | self.indels.iter().any(|indel| indel.delete.contains_inclusive(offset)) | ||
132 | } | ||
133 | } | ||
diff --git a/crates/ra_text_edit/src/text_edit.rs b/crates/ra_text_edit/src/text_edit.rs deleted file mode 100644 index eabab4b4d..000000000 --- a/crates/ra_text_edit/src/text_edit.rs +++ /dev/null | |||
@@ -1,102 +0,0 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use crate::AtomTextEdit; | ||
4 | |||
5 | use text_size::{TextRange, TextSize}; | ||
6 | |||
7 | #[derive(Debug, Clone)] | ||
8 | pub struct TextEdit { | ||
9 | atoms: Vec<AtomTextEdit>, | ||
10 | } | ||
11 | |||
12 | #[derive(Debug, Default)] | ||
13 | pub struct TextEditBuilder { | ||
14 | atoms: Vec<AtomTextEdit>, | ||
15 | } | ||
16 | |||
17 | impl TextEditBuilder { | ||
18 | pub fn replace(&mut self, range: TextRange, replace_with: String) { | ||
19 | self.atoms.push(AtomTextEdit::replace(range, replace_with)) | ||
20 | } | ||
21 | pub fn delete(&mut self, range: TextRange) { | ||
22 | self.atoms.push(AtomTextEdit::delete(range)) | ||
23 | } | ||
24 | pub fn insert(&mut self, offset: TextSize, text: String) { | ||
25 | self.atoms.push(AtomTextEdit::insert(offset, text)) | ||
26 | } | ||
27 | pub fn finish(self) -> TextEdit { | ||
28 | TextEdit::from_atoms(self.atoms) | ||
29 | } | ||
30 | pub fn invalidates_offset(&self, offset: TextSize) -> bool { | ||
31 | self.atoms.iter().any(|atom| atom.delete.contains_inclusive(offset)) | ||
32 | } | ||
33 | } | ||
34 | |||
35 | impl TextEdit { | ||
36 | pub fn insert(offset: TextSize, text: String) -> TextEdit { | ||
37 | let mut builder = TextEditBuilder::default(); | ||
38 | builder.insert(offset, text); | ||
39 | builder.finish() | ||
40 | } | ||
41 | |||
42 | pub fn delete(range: TextRange) -> TextEdit { | ||
43 | let mut builder = TextEditBuilder::default(); | ||
44 | builder.delete(range); | ||
45 | builder.finish() | ||
46 | } | ||
47 | |||
48 | pub fn replace(range: TextRange, replace_with: String) -> TextEdit { | ||
49 | let mut builder = TextEditBuilder::default(); | ||
50 | builder.replace(range, replace_with); | ||
51 | builder.finish() | ||
52 | } | ||
53 | |||
54 | pub(crate) fn from_atoms(mut atoms: Vec<AtomTextEdit>) -> TextEdit { | ||
55 | atoms.sort_by_key(|a| (a.delete.start(), a.delete.end())); | ||
56 | for (a1, a2) in atoms.iter().zip(atoms.iter().skip(1)) { | ||
57 | assert!(a1.delete.end() <= a2.delete.start()) | ||
58 | } | ||
59 | TextEdit { atoms } | ||
60 | } | ||
61 | |||
62 | pub fn as_atoms(&self) -> &[AtomTextEdit] { | ||
63 | &self.atoms | ||
64 | } | ||
65 | |||
66 | pub fn apply(&self, text: &str) -> String { | ||
67 | let mut total_len = TextSize::of(text); | ||
68 | for atom in self.atoms.iter() { | ||
69 | total_len += TextSize::of(&atom.insert); | ||
70 | total_len -= atom.delete.end() - atom.delete.start(); | ||
71 | } | ||
72 | let mut buf = String::with_capacity(total_len.into()); | ||
73 | let mut prev = 0; | ||
74 | for atom in self.atoms.iter() { | ||
75 | let start: usize = atom.delete.start().into(); | ||
76 | let end: usize = atom.delete.end().into(); | ||
77 | if start > prev { | ||
78 | buf.push_str(&text[prev..start]); | ||
79 | } | ||
80 | buf.push_str(&atom.insert); | ||
81 | prev = end; | ||
82 | } | ||
83 | buf.push_str(&text[prev..text.len()]); | ||
84 | assert_eq!(TextSize::of(&buf), total_len); | ||
85 | buf | ||
86 | } | ||
87 | |||
88 | pub fn apply_to_offset(&self, offset: TextSize) -> Option<TextSize> { | ||
89 | let mut res = offset; | ||
90 | for atom in self.atoms.iter() { | ||
91 | if atom.delete.start() >= offset { | ||
92 | break; | ||
93 | } | ||
94 | if offset < atom.delete.end() { | ||
95 | return None; | ||
96 | } | ||
97 | res += TextSize::of(&atom.insert); | ||
98 | res -= atom.delete.len(); | ||
99 | } | ||
100 | Some(res) | ||
101 | } | ||
102 | } | ||
diff --git a/crates/rust-analyzer/src/conv.rs b/crates/rust-analyzer/src/conv.rs index 7be5ebcdb..f64c90b5b 100644 --- a/crates/rust-analyzer/src/conv.rs +++ b/crates/rust-analyzer/src/conv.rs | |||
@@ -15,7 +15,7 @@ use ra_ide::{ | |||
15 | ReferenceAccess, Severity, SourceChange, SourceFileEdit, | 15 | ReferenceAccess, Severity, SourceChange, SourceFileEdit, |
16 | }; | 16 | }; |
17 | use ra_syntax::{SyntaxKind, TextRange, TextSize}; | 17 | use ra_syntax::{SyntaxKind, TextRange, TextSize}; |
18 | use ra_text_edit::{AtomTextEdit, TextEdit}; | 18 | use ra_text_edit::{Indel, TextEdit}; |
19 | use ra_vfs::LineEndings; | 19 | use ra_vfs::LineEndings; |
20 | 20 | ||
21 | use crate::{ | 21 | use crate::{ |
@@ -124,23 +124,22 @@ impl ConvWith<(&LineIndex, LineEndings)> for CompletionItem { | |||
124 | let mut text_edit = None; | 124 | let mut text_edit = None; |
125 | // LSP does not allow arbitrary edits in completion, so we have to do a | 125 | // LSP does not allow arbitrary edits in completion, so we have to do a |
126 | // non-trivial mapping here. | 126 | // non-trivial mapping here. |
127 | for atom_edit in self.text_edit().as_atoms() { | 127 | for indel in self.text_edit().as_indels() { |
128 | if atom_edit.delete.contains_range(self.source_range()) { | 128 | if indel.delete.contains_range(self.source_range()) { |
129 | text_edit = Some(if atom_edit.delete == self.source_range() { | 129 | text_edit = Some(if indel.delete == self.source_range() { |
130 | atom_edit.conv_with((ctx.0, ctx.1)) | 130 | indel.conv_with((ctx.0, ctx.1)) |
131 | } else { | 131 | } else { |
132 | assert!(self.source_range().end() == atom_edit.delete.end()); | 132 | assert!(self.source_range().end() == indel.delete.end()); |
133 | let range1 = | 133 | let range1 = TextRange::new(indel.delete.start(), self.source_range().start()); |
134 | TextRange::new(atom_edit.delete.start(), self.source_range().start()); | ||
135 | let range2 = self.source_range(); | 134 | let range2 = self.source_range(); |
136 | let edit1 = AtomTextEdit::replace(range1, String::new()); | 135 | let edit1 = Indel::replace(range1, String::new()); |
137 | let edit2 = AtomTextEdit::replace(range2, atom_edit.insert.clone()); | 136 | let edit2 = Indel::replace(range2, indel.insert.clone()); |
138 | additional_text_edits.push(edit1.conv_with((ctx.0, ctx.1))); | 137 | additional_text_edits.push(edit1.conv_with((ctx.0, ctx.1))); |
139 | edit2.conv_with((ctx.0, ctx.1)) | 138 | edit2.conv_with((ctx.0, ctx.1)) |
140 | }) | 139 | }) |
141 | } else { | 140 | } else { |
142 | assert!(self.source_range().intersect(atom_edit.delete).is_none()); | 141 | assert!(self.source_range().intersect(indel.delete).is_none()); |
143 | additional_text_edits.push(atom_edit.conv_with((ctx.0, ctx.1))); | 142 | additional_text_edits.push(indel.conv_with((ctx.0, ctx.1))); |
144 | } | 143 | } |
145 | } | 144 | } |
146 | let text_edit = text_edit.unwrap(); | 145 | let text_edit = text_edit.unwrap(); |
@@ -257,11 +256,11 @@ impl ConvWith<(&LineIndex, LineEndings)> for TextEdit { | |||
257 | type Output = Vec<lsp_types::TextEdit>; | 256 | type Output = Vec<lsp_types::TextEdit>; |
258 | 257 | ||
259 | fn conv_with(self, ctx: (&LineIndex, LineEndings)) -> Vec<lsp_types::TextEdit> { | 258 | fn conv_with(self, ctx: (&LineIndex, LineEndings)) -> Vec<lsp_types::TextEdit> { |
260 | self.as_atoms().iter().map_conv_with(ctx).collect() | 259 | self.as_indels().iter().map_conv_with(ctx).collect() |
261 | } | 260 | } |
262 | } | 261 | } |
263 | 262 | ||
264 | impl ConvWith<(&LineIndex, LineEndings)> for &AtomTextEdit { | 263 | impl ConvWith<(&LineIndex, LineEndings)> for &Indel { |
265 | type Output = lsp_types::TextEdit; | 264 | type Output = lsp_types::TextEdit; |
266 | 265 | ||
267 | fn conv_with( | 266 | fn conv_with( |
@@ -522,7 +521,7 @@ impl TryConvWith<&WorldSnapshot> for SourceFileEdit { | |||
522 | let line_index = world.analysis().file_line_index(self.file_id)?; | 521 | let line_index = world.analysis().file_line_index(self.file_id)?; |
523 | let line_endings = world.file_line_endings(self.file_id); | 522 | let line_endings = world.file_line_endings(self.file_id); |
524 | let edits = | 523 | let edits = |
525 | self.edit.as_atoms().iter().map_conv_with((&line_index, line_endings)).collect(); | 524 | self.edit.as_indels().iter().map_conv_with((&line_index, line_endings)).collect(); |
526 | Ok(TextDocumentEdit { text_document, edits }) | 525 | Ok(TextDocumentEdit { text_document, edits }) |
527 | } | 526 | } |
528 | } | 527 | } |