Skip to content

Commit 4a6fa8f

Browse files
committed
Rename AtomTextEdit -> Indel
1 parent 381cbc6 commit 4a6fa8f

File tree

11 files changed

+154
-163
lines changed

11 files changed

+154
-163
lines changed

crates/ra_assists/src/assist_ctx.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@ use ra_db::FileRange;
44
use ra_fmt::{leading_indent, reindent};
55
use ra_ide_db::RootDatabase;
66
use ra_syntax::{
7-
algo::{self, find_covering_element, find_node_at_offset},
7+
algo::{self, find_covering_element, find_node_at_offset, SyntaxRewriter},
88
AstNode, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextSize,
99
TokenAtOffset,
1010
};
1111
use ra_text_edit::TextEditBuilder;
1212

1313
use crate::{AssistAction, AssistFile, AssistId, AssistLabel, GroupLabel, ResolvedAssist};
14-
use algo::SyntaxRewriter;
1514

1615
#[derive(Clone, Debug)]
1716
pub(crate) struct Assist(pub(crate) Vec<AssistInfo>);
@@ -42,7 +41,6 @@ impl AssistInfo {
4241
}
4342
}
4443

45-
4644
/// `AssistCtx` allows to apply an assist or check if it could be applied.
4745
///
4846
/// Assists use a somewhat over-engineered approach, given the current needs. The

crates/ra_ide/src/completion/completion_context.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use ra_syntax::{
99
SyntaxKind::*,
1010
SyntaxNode, SyntaxToken, TextRange, TextSize,
1111
};
12-
use ra_text_edit::AtomTextEdit;
12+
use ra_text_edit::Indel;
1313

1414
use crate::{call_info::ActiveParameter, completion::CompletionConfig, FilePosition};
1515

@@ -76,7 +76,7 @@ impl<'a> CompletionContext<'a> {
7676
// actual completion.
7777
let file_with_fake_ident = {
7878
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());
8080
parse.reparse(&edit).tree()
8181
};
8282
let fake_ident_token =

crates/ra_ide/src/completion/completion_item.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ impl fmt::Debug for CompletionItem {
6262
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6363
let mut s = f.debug_struct("CompletionItem");
6464
s.field("label", &self.label()).field("source_range", &self.source_range());
65-
if self.text_edit().as_atoms().len() == 1 {
66-
let atom = &self.text_edit().as_atoms()[0];
65+
if self.text_edit().as_indels().len() == 1 {
66+
let atom = &self.text_edit().as_indels()[0];
6767
s.field("delete", &atom.delete);
6868
s.field("insert", &atom.insert);
6969
} else {

crates/ra_ide_db/src/line_index_utils.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
use std::convert::TryInto;
1111

1212
use ra_syntax::{TextRange, TextSize};
13-
use ra_text_edit::{AtomTextEdit, TextEdit};
13+
use ra_text_edit::{Indel, TextEdit};
1414

1515
use crate::line_index::{LineCol, LineIndex, Utf16Char};
1616

@@ -182,14 +182,14 @@ struct TranslatedEdit<'a> {
182182
}
183183

184184
struct Edits<'a> {
185-
edits: &'a [AtomTextEdit],
185+
edits: &'a [Indel],
186186
current: Option<TranslatedEdit<'a>>,
187187
acc_diff: i64,
188188
}
189189

190190
impl<'a> Edits<'a> {
191191
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 };
193193
x.advance_edit();
194194
x
195195
}

crates/ra_syntax/src/fuzz.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::{
55
str::{self, FromStr},
66
};
77

8-
use ra_text_edit::AtomTextEdit;
8+
use ra_text_edit::Indel;
99

1010
use crate::{validation, AstNode, SourceFile, TextRange};
1111

@@ -22,7 +22,7 @@ pub fn check_parser(text: &str) {
2222
#[derive(Debug, Clone)]
2323
pub struct CheckReparse {
2424
text: String,
25-
edit: AtomTextEdit,
25+
edit: Indel,
2626
edited_text: String,
2727
}
2828

@@ -43,7 +43,7 @@ impl CheckReparse {
4343
TextRange::at(delete_start.try_into().unwrap(), delete_len.try_into().unwrap());
4444
let edited_text =
4545
format!("{}{}{}", &text[..delete_start], &insert, &text[delete_start + delete_len..]);
46-
let edit = AtomTextEdit { delete, insert };
46+
let edit = Indel { delete, insert };
4747
Some(CheckReparse { text, edit, edited_text })
4848
}
4949

crates/ra_syntax/src/lib.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ pub mod fuzz;
3939

4040
use std::{marker::PhantomData, sync::Arc};
4141

42-
use ra_text_edit::AtomTextEdit;
42+
use ra_text_edit::Indel;
4343
use stdx::format_to;
4444

4545
use crate::syntax_node::GreenNode;
@@ -126,13 +126,13 @@ impl Parse<SourceFile> {
126126
buf
127127
}
128128

129-
pub fn reparse(&self, edit: &AtomTextEdit) -> Parse<SourceFile> {
130-
self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit))
129+
pub fn reparse(&self, indel: &Indel) -> Parse<SourceFile> {
130+
self.incremental_reparse(indel).unwrap_or_else(|| self.full_reparse(indel))
131131
}
132132

133-
fn incremental_reparse(&self, edit: &AtomTextEdit) -> Option<Parse<SourceFile>> {
133+
fn incremental_reparse(&self, indel: &Indel) -> Option<Parse<SourceFile>> {
134134
// 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(
136136
|(green_node, errors, _reparsed_range)| Parse {
137137
green: green_node,
138138
errors: Arc::new(errors),
@@ -141,8 +141,8 @@ impl Parse<SourceFile> {
141141
)
142142
}
143143

144-
fn full_reparse(&self, edit: &AtomTextEdit) -> Parse<SourceFile> {
145-
let text = edit.apply(self.tree().syntax().text().to_string());
144+
fn full_reparse(&self, indel: &Indel) -> Parse<SourceFile> {
145+
let text = indel.apply(self.tree().syntax().text().to_string());
146146
SourceFile::parse(&text)
147147
}
148148
}

crates/ra_syntax/src/parsing/reparsing.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//! and try to parse only this block.
88
99
use ra_parser::Reparser;
10-
use ra_text_edit::AtomTextEdit;
10+
use ra_text_edit::Indel;
1111

1212
use crate::{
1313
algo,
@@ -24,7 +24,7 @@ use crate::{
2424

2525
pub(crate) fn incremental_reparse(
2626
node: &SyntaxNode,
27-
edit: &AtomTextEdit,
27+
edit: &Indel,
2828
errors: Vec<SyntaxError>,
2929
) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
3030
if let Some((green, new_errors, old_range)) = reparse_token(node, &edit) {
@@ -39,7 +39,7 @@ pub(crate) fn incremental_reparse(
3939

4040
fn reparse_token<'node>(
4141
root: &'node SyntaxNode,
42-
edit: &AtomTextEdit,
42+
edit: &Indel,
4343
) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
4444
let prev_token = algo::find_covering_element(root, edit.delete).as_token()?.clone();
4545
let prev_token_kind = prev_token.kind();
@@ -88,7 +88,7 @@ fn reparse_token<'node>(
8888

8989
fn reparse_block<'node>(
9090
root: &'node SyntaxNode,
91-
edit: &AtomTextEdit,
91+
edit: &Indel,
9292
) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
9393
let (node, reparser) = find_reparsable_node(root, edit.delete)?;
9494
let text = get_text_after_edit(node.clone().into(), edit);
@@ -108,9 +108,9 @@ fn reparse_block<'node>(
108108
Some((node.replace_with(green), new_parser_errors, node.text_range()))
109109
}
110110

111-
fn get_text_after_edit(element: SyntaxElement, edit: &AtomTextEdit) -> String {
111+
fn get_text_after_edit(element: SyntaxElement, edit: &Indel) -> String {
112112
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());
114114

115115
let text = match element {
116116
NodeOrToken::Token(token) => token.text().to_string(),
@@ -167,7 +167,7 @@ fn merge_errors(
167167
old_errors: Vec<SyntaxError>,
168168
new_errors: Vec<SyntaxError>,
169169
range_before_reparse: TextRange,
170-
edit: &AtomTextEdit,
170+
edit: &Indel,
171171
) -> Vec<SyntaxError> {
172172
let mut res = Vec::new();
173173

@@ -198,7 +198,7 @@ mod tests {
198198

199199
fn do_check(before: &str, replace_with: &str, reparsed_len: u32) {
200200
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());
202202
let after = edit.apply(before.clone());
203203

204204
let fully_reparsed = SourceFile::parse(&after);

crates/ra_text_edit/src/lib.rs

Lines changed: 114 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,40 @@
1-
//! FIXME: write short doc here
2-
3-
mod text_edit;
1+
//! Representation of a `TextEdit`.
2+
//!
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.
46
57
use text_size::{TextRange, TextSize};
68

7-
pub use crate::text_edit::{TextEdit, TextEditBuilder};
8-
9-
/// Must not overlap with other `AtomTextEdit`s
9+
/// `InsertDelete` -- a single "atomic" change to text
10+
///
11+
/// Must not overlap with other `InDel`s
1012
#[derive(Debug, Clone)]
11-
pub struct AtomTextEdit {
13+
pub struct Indel {
14+
pub insert: String,
1215
/// Refers to offsets in the original text
1316
pub delete: TextRange,
14-
pub insert: String,
1517
}
1618

17-
impl AtomTextEdit {
18-
pub fn replace(range: TextRange, replace_with: String) -> AtomTextEdit {
19-
AtomTextEdit { delete: range, insert: replace_with }
20-
}
19+
#[derive(Debug, Clone)]
20+
pub struct TextEdit {
21+
indels: Vec<Indel>,
22+
}
2123

22-
pub fn delete(range: TextRange) -> AtomTextEdit {
23-
AtomTextEdit::replace(range, String::new())
24-
}
24+
#[derive(Debug, Default)]
25+
pub struct TextEditBuilder {
26+
indels: Vec<Indel>,
27+
}
2528

26-
pub fn insert(offset: TextSize, text: String) -> AtomTextEdit {
27-
AtomTextEdit::replace(TextRange::empty(offset), text)
29+
impl Indel {
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 }
2838
}
2939

3040
pub fn apply(&self, mut text: String) -> String {
@@ -34,3 +44,90 @@ impl AtomTextEdit {
3444
text
3545
}
3646
}
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+
}

0 commit comments

Comments
 (0)