From 4a6fa8f0dfcebbb4ea80394e5e4ca21f076f58f2 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 5 May 2020 23:15:49 +0200 Subject: Rename AtomTextEdit -> Indel --- crates/ra_assists/src/assist_ctx.rs | 4 +- crates/ra_ide/src/completion/completion_context.rs | 4 +- crates/ra_ide/src/completion/completion_item.rs | 4 +- crates/ra_ide_db/src/line_index_utils.rs | 6 +- crates/ra_syntax/src/fuzz.rs | 6 +- crates/ra_syntax/src/lib.rs | 14 +-- crates/ra_syntax/src/parsing/reparsing.rs | 16 +-- crates/ra_text_edit/src/lib.rs | 131 ++++++++++++++++++--- crates/ra_text_edit/src/text_edit.rs | 102 ---------------- crates/rust-analyzer/src/conv.rs | 29 +++-- 10 files changed, 154 insertions(+), 162 deletions(-) delete mode 100644 crates/ra_text_edit/src/text_edit.rs (limited to 'crates') 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; use ra_fmt::{leading_indent, reindent}; use ra_ide_db::RootDatabase; use ra_syntax::{ - algo::{self, find_covering_element, find_node_at_offset}, + algo::{self, find_covering_element, find_node_at_offset, SyntaxRewriter}, AstNode, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, }; use ra_text_edit::TextEditBuilder; use crate::{AssistAction, AssistFile, AssistId, AssistLabel, GroupLabel, ResolvedAssist}; -use algo::SyntaxRewriter; #[derive(Clone, Debug)] pub(crate) struct Assist(pub(crate) Vec); @@ -42,7 +41,6 @@ impl AssistInfo { } } - /// `AssistCtx` allows to apply an assist or check if it could be applied. /// /// 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::{ SyntaxKind::*, SyntaxNode, SyntaxToken, TextRange, TextSize, }; -use ra_text_edit::AtomTextEdit; +use ra_text_edit::Indel; use crate::{call_info::ActiveParameter, completion::CompletionConfig, FilePosition}; @@ -76,7 +76,7 @@ impl<'a> CompletionContext<'a> { // actual completion. let file_with_fake_ident = { let parse = db.parse(position.file_id); - let edit = AtomTextEdit::insert(position.offset, "intellijRulezz".to_string()); + let edit = Indel::insert(position.offset, "intellijRulezz".to_string()); parse.reparse(&edit).tree() }; 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 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut s = f.debug_struct("CompletionItem"); s.field("label", &self.label()).field("source_range", &self.source_range()); - if self.text_edit().as_atoms().len() == 1 { - let atom = &self.text_edit().as_atoms()[0]; + if self.text_edit().as_indels().len() == 1 { + let atom = &self.text_edit().as_indels()[0]; s.field("delete", &atom.delete); s.field("insert", &atom.insert); } 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 @@ use std::convert::TryInto; use ra_syntax::{TextRange, TextSize}; -use ra_text_edit::{AtomTextEdit, TextEdit}; +use ra_text_edit::{Indel, TextEdit}; use crate::line_index::{LineCol, LineIndex, Utf16Char}; @@ -182,14 +182,14 @@ struct TranslatedEdit<'a> { } struct Edits<'a> { - edits: &'a [AtomTextEdit], + edits: &'a [Indel], current: Option>, acc_diff: i64, } impl<'a> Edits<'a> { fn from_text_edit(text_edit: &'a TextEdit) -> Edits<'a> { - let mut x = Edits { edits: text_edit.as_atoms(), current: None, acc_diff: 0 }; + let mut x = Edits { edits: text_edit.as_indels(), current: None, acc_diff: 0 }; x.advance_edit(); x } 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::{ str::{self, FromStr}, }; -use ra_text_edit::AtomTextEdit; +use ra_text_edit::Indel; use crate::{validation, AstNode, SourceFile, TextRange}; @@ -22,7 +22,7 @@ pub fn check_parser(text: &str) { #[derive(Debug, Clone)] pub struct CheckReparse { text: String, - edit: AtomTextEdit, + edit: Indel, edited_text: String, } @@ -43,7 +43,7 @@ impl CheckReparse { TextRange::at(delete_start.try_into().unwrap(), delete_len.try_into().unwrap()); let edited_text = format!("{}{}{}", &text[..delete_start], &insert, &text[delete_start + delete_len..]); - let edit = AtomTextEdit { delete, insert }; + let edit = Indel { delete, insert }; Some(CheckReparse { text, edit, edited_text }) } 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; use std::{marker::PhantomData, sync::Arc}; -use ra_text_edit::AtomTextEdit; +use ra_text_edit::Indel; use stdx::format_to; use crate::syntax_node::GreenNode; @@ -126,13 +126,13 @@ impl Parse { buf } - pub fn reparse(&self, edit: &AtomTextEdit) -> Parse { - self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit)) + pub fn reparse(&self, indel: &Indel) -> Parse { + self.incremental_reparse(indel).unwrap_or_else(|| self.full_reparse(indel)) } - fn incremental_reparse(&self, edit: &AtomTextEdit) -> Option> { + fn incremental_reparse(&self, indel: &Indel) -> Option> { // FIXME: validation errors are not handled here - parsing::incremental_reparse(self.tree().syntax(), edit, self.errors.to_vec()).map( + parsing::incremental_reparse(self.tree().syntax(), indel, self.errors.to_vec()).map( |(green_node, errors, _reparsed_range)| Parse { green: green_node, errors: Arc::new(errors), @@ -141,8 +141,8 @@ impl Parse { ) } - fn full_reparse(&self, edit: &AtomTextEdit) -> Parse { - let text = edit.apply(self.tree().syntax().text().to_string()); + fn full_reparse(&self, indel: &Indel) -> Parse { + let text = indel.apply(self.tree().syntax().text().to_string()); SourceFile::parse(&text) } } 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 @@ //! and try to parse only this block. use ra_parser::Reparser; -use ra_text_edit::AtomTextEdit; +use ra_text_edit::Indel; use crate::{ algo, @@ -24,7 +24,7 @@ use crate::{ pub(crate) fn incremental_reparse( node: &SyntaxNode, - edit: &AtomTextEdit, + edit: &Indel, errors: Vec, ) -> Option<(GreenNode, Vec, TextRange)> { if let Some((green, new_errors, old_range)) = reparse_token(node, &edit) { @@ -39,7 +39,7 @@ pub(crate) fn incremental_reparse( fn reparse_token<'node>( root: &'node SyntaxNode, - edit: &AtomTextEdit, + edit: &Indel, ) -> Option<(GreenNode, Vec, TextRange)> { let prev_token = algo::find_covering_element(root, edit.delete).as_token()?.clone(); let prev_token_kind = prev_token.kind(); @@ -88,7 +88,7 @@ fn reparse_token<'node>( fn reparse_block<'node>( root: &'node SyntaxNode, - edit: &AtomTextEdit, + edit: &Indel, ) -> Option<(GreenNode, Vec, TextRange)> { let (node, reparser) = find_reparsable_node(root, edit.delete)?; let text = get_text_after_edit(node.clone().into(), edit); @@ -108,9 +108,9 @@ fn reparse_block<'node>( Some((node.replace_with(green), new_parser_errors, node.text_range())) } -fn get_text_after_edit(element: SyntaxElement, edit: &AtomTextEdit) -> String { +fn get_text_after_edit(element: SyntaxElement, edit: &Indel) -> String { let edit = - AtomTextEdit::replace(edit.delete - element.text_range().start(), edit.insert.clone()); + Indel::replace(edit.delete - element.text_range().start(), edit.insert.clone()); let text = match element { NodeOrToken::Token(token) => token.text().to_string(), @@ -167,7 +167,7 @@ fn merge_errors( old_errors: Vec, new_errors: Vec, range_before_reparse: TextRange, - edit: &AtomTextEdit, + edit: &Indel, ) -> Vec { let mut res = Vec::new(); @@ -198,7 +198,7 @@ mod tests { fn do_check(before: &str, replace_with: &str, reparsed_len: u32) { let (range, before) = extract_range(before); - let edit = AtomTextEdit::replace(range, replace_with.to_owned()); + let edit = Indel::replace(range, replace_with.to_owned()); let after = edit.apply(before.clone()); 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 @@ -//! FIXME: write short doc here - -mod text_edit; +//! Representation of a `TextEdit`. +//! +//! `rust-analyzer` never mutates text itself and only sends diffs to clients, +//! so `TextEdit` is the ultimate representation of the work done by +//! rust-analyzer. use text_size::{TextRange, TextSize}; -pub use crate::text_edit::{TextEdit, TextEditBuilder}; - -/// Must not overlap with other `AtomTextEdit`s +/// `InsertDelete` -- a single "atomic" change to text +/// +/// Must not overlap with other `InDel`s #[derive(Debug, Clone)] -pub struct AtomTextEdit { +pub struct Indel { + pub insert: String, /// Refers to offsets in the original text pub delete: TextRange, - pub insert: String, } -impl AtomTextEdit { - pub fn replace(range: TextRange, replace_with: String) -> AtomTextEdit { - AtomTextEdit { delete: range, insert: replace_with } - } +#[derive(Debug, Clone)] +pub struct TextEdit { + indels: Vec, +} - pub fn delete(range: TextRange) -> AtomTextEdit { - AtomTextEdit::replace(range, String::new()) - } +#[derive(Debug, Default)] +pub struct TextEditBuilder { + indels: Vec, +} - pub fn insert(offset: TextSize, text: String) -> AtomTextEdit { - AtomTextEdit::replace(TextRange::empty(offset), text) +impl Indel { + pub fn insert(offset: TextSize, text: String) -> Indel { + Indel::replace(TextRange::empty(offset), text) + } + pub fn delete(range: TextRange) -> Indel { + Indel::replace(range, String::new()) + } + pub fn replace(range: TextRange, replace_with: String) -> Indel { + Indel { delete: range, insert: replace_with } } pub fn apply(&self, mut text: String) -> String { @@ -34,3 +44,90 @@ impl AtomTextEdit { text } } + +impl TextEdit { + pub fn insert(offset: TextSize, text: String) -> TextEdit { + let mut builder = TextEditBuilder::default(); + builder.insert(offset, text); + builder.finish() + } + + pub fn delete(range: TextRange) -> TextEdit { + let mut builder = TextEditBuilder::default(); + builder.delete(range); + builder.finish() + } + + pub fn replace(range: TextRange, replace_with: String) -> TextEdit { + let mut builder = TextEditBuilder::default(); + builder.replace(range, replace_with); + builder.finish() + } + + pub(crate) fn from_indels(mut indels: Vec) -> TextEdit { + indels.sort_by_key(|a| (a.delete.start(), a.delete.end())); + for (a1, a2) in indels.iter().zip(indels.iter().skip(1)) { + assert!(a1.delete.end() <= a2.delete.start()) + } + TextEdit { indels } + } + + pub fn as_indels(&self) -> &[Indel] { + &self.indels + } + + pub fn apply(&self, text: &str) -> String { + let mut total_len = TextSize::of(text); + for indel in self.indels.iter() { + total_len += TextSize::of(&indel.insert); + total_len -= indel.delete.end() - indel.delete.start(); + } + let mut buf = String::with_capacity(total_len.into()); + let mut prev = 0; + for indel in self.indels.iter() { + let start: usize = indel.delete.start().into(); + let end: usize = indel.delete.end().into(); + if start > prev { + buf.push_str(&text[prev..start]); + } + buf.push_str(&indel.insert); + prev = end; + } + buf.push_str(&text[prev..text.len()]); + assert_eq!(TextSize::of(&buf), total_len); + buf + } + + pub fn apply_to_offset(&self, offset: TextSize) -> Option { + let mut res = offset; + for indel in self.indels.iter() { + if indel.delete.start() >= offset { + break; + } + if offset < indel.delete.end() { + return None; + } + res += TextSize::of(&indel.insert); + res -= indel.delete.len(); + } + Some(res) + } +} + +impl TextEditBuilder { + pub fn replace(&mut self, range: TextRange, replace_with: String) { + self.indels.push(Indel::replace(range, replace_with)) + } + pub fn delete(&mut self, range: TextRange) { + self.indels.push(Indel::delete(range)) + } + pub fn insert(&mut self, offset: TextSize, text: String) { + self.indels.push(Indel::insert(offset, text)) + } + pub fn finish(self) -> TextEdit { + TextEdit::from_indels(self.indels) + } + pub fn invalidates_offset(&self, offset: TextSize) -> bool { + self.indels.iter().any(|indel| indel.delete.contains_inclusive(offset)) + } +} 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 @@ -//! FIXME: write short doc here - -use crate::AtomTextEdit; - -use text_size::{TextRange, TextSize}; - -#[derive(Debug, Clone)] -pub struct TextEdit { - atoms: Vec, -} - -#[derive(Debug, Default)] -pub struct TextEditBuilder { - atoms: Vec, -} - -impl TextEditBuilder { - pub fn replace(&mut self, range: TextRange, replace_with: String) { - self.atoms.push(AtomTextEdit::replace(range, replace_with)) - } - pub fn delete(&mut self, range: TextRange) { - self.atoms.push(AtomTextEdit::delete(range)) - } - pub fn insert(&mut self, offset: TextSize, text: String) { - self.atoms.push(AtomTextEdit::insert(offset, text)) - } - pub fn finish(self) -> TextEdit { - TextEdit::from_atoms(self.atoms) - } - pub fn invalidates_offset(&self, offset: TextSize) -> bool { - self.atoms.iter().any(|atom| atom.delete.contains_inclusive(offset)) - } -} - -impl TextEdit { - pub fn insert(offset: TextSize, text: String) -> TextEdit { - let mut builder = TextEditBuilder::default(); - builder.insert(offset, text); - builder.finish() - } - - pub fn delete(range: TextRange) -> TextEdit { - let mut builder = TextEditBuilder::default(); - builder.delete(range); - builder.finish() - } - - pub fn replace(range: TextRange, replace_with: String) -> TextEdit { - let mut builder = TextEditBuilder::default(); - builder.replace(range, replace_with); - builder.finish() - } - - pub(crate) fn from_atoms(mut atoms: Vec) -> TextEdit { - atoms.sort_by_key(|a| (a.delete.start(), a.delete.end())); - for (a1, a2) in atoms.iter().zip(atoms.iter().skip(1)) { - assert!(a1.delete.end() <= a2.delete.start()) - } - TextEdit { atoms } - } - - pub fn as_atoms(&self) -> &[AtomTextEdit] { - &self.atoms - } - - pub fn apply(&self, text: &str) -> String { - let mut total_len = TextSize::of(text); - for atom in self.atoms.iter() { - total_len += TextSize::of(&atom.insert); - total_len -= atom.delete.end() - atom.delete.start(); - } - let mut buf = String::with_capacity(total_len.into()); - let mut prev = 0; - for atom in self.atoms.iter() { - let start: usize = atom.delete.start().into(); - let end: usize = atom.delete.end().into(); - if start > prev { - buf.push_str(&text[prev..start]); - } - buf.push_str(&atom.insert); - prev = end; - } - buf.push_str(&text[prev..text.len()]); - assert_eq!(TextSize::of(&buf), total_len); - buf - } - - pub fn apply_to_offset(&self, offset: TextSize) -> Option { - let mut res = offset; - for atom in self.atoms.iter() { - if atom.delete.start() >= offset { - break; - } - if offset < atom.delete.end() { - return None; - } - res += TextSize::of(&atom.insert); - res -= atom.delete.len(); - } - Some(res) - } -} 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::{ ReferenceAccess, Severity, SourceChange, SourceFileEdit, }; use ra_syntax::{SyntaxKind, TextRange, TextSize}; -use ra_text_edit::{AtomTextEdit, TextEdit}; +use ra_text_edit::{Indel, TextEdit}; use ra_vfs::LineEndings; use crate::{ @@ -124,23 +124,22 @@ impl ConvWith<(&LineIndex, LineEndings)> for CompletionItem { let mut text_edit = None; // LSP does not allow arbitrary edits in completion, so we have to do a // non-trivial mapping here. - for atom_edit in self.text_edit().as_atoms() { - if atom_edit.delete.contains_range(self.source_range()) { - text_edit = Some(if atom_edit.delete == self.source_range() { - atom_edit.conv_with((ctx.0, ctx.1)) + for indel in self.text_edit().as_indels() { + if indel.delete.contains_range(self.source_range()) { + text_edit = Some(if indel.delete == self.source_range() { + indel.conv_with((ctx.0, ctx.1)) } else { - assert!(self.source_range().end() == atom_edit.delete.end()); - let range1 = - TextRange::new(atom_edit.delete.start(), self.source_range().start()); + assert!(self.source_range().end() == indel.delete.end()); + let range1 = TextRange::new(indel.delete.start(), self.source_range().start()); let range2 = self.source_range(); - let edit1 = AtomTextEdit::replace(range1, String::new()); - let edit2 = AtomTextEdit::replace(range2, atom_edit.insert.clone()); + let edit1 = Indel::replace(range1, String::new()); + let edit2 = Indel::replace(range2, indel.insert.clone()); additional_text_edits.push(edit1.conv_with((ctx.0, ctx.1))); edit2.conv_with((ctx.0, ctx.1)) }) } else { - assert!(self.source_range().intersect(atom_edit.delete).is_none()); - additional_text_edits.push(atom_edit.conv_with((ctx.0, ctx.1))); + assert!(self.source_range().intersect(indel.delete).is_none()); + additional_text_edits.push(indel.conv_with((ctx.0, ctx.1))); } } let text_edit = text_edit.unwrap(); @@ -257,11 +256,11 @@ impl ConvWith<(&LineIndex, LineEndings)> for TextEdit { type Output = Vec; fn conv_with(self, ctx: (&LineIndex, LineEndings)) -> Vec { - self.as_atoms().iter().map_conv_with(ctx).collect() + self.as_indels().iter().map_conv_with(ctx).collect() } } -impl ConvWith<(&LineIndex, LineEndings)> for &AtomTextEdit { +impl ConvWith<(&LineIndex, LineEndings)> for &Indel { type Output = lsp_types::TextEdit; fn conv_with( @@ -522,7 +521,7 @@ impl TryConvWith<&WorldSnapshot> for SourceFileEdit { let line_index = world.analysis().file_line_index(self.file_id)?; let line_endings = world.file_line_endings(self.file_id); let edits = - self.edit.as_atoms().iter().map_conv_with((&line_index, line_endings)).collect(); + self.edit.as_indels().iter().map_conv_with((&line_index, line_endings)).collect(); Ok(TextDocumentEdit { text_document, edits }) } } -- cgit v1.2.3