From 7344d28768c43d8955bf23c183d606be08f27c64 Mon Sep 17 00:00:00 2001 From: Bernardo Date: Mon, 10 Dec 2018 22:09:12 +0100 Subject: extract AtomEdit and Edit into new ra_text_edit crate --- crates/ra_text_edit/Cargo.toml | 12 +++++ crates/ra_text_edit/src/edit.rs | 84 +++++++++++++++++++++++++++++++++++ crates/ra_text_edit/src/lib.rs | 29 ++++++++++++ crates/ra_text_edit/src/text_utils.rs | 5 +++ 4 files changed, 130 insertions(+) create mode 100644 crates/ra_text_edit/Cargo.toml create mode 100644 crates/ra_text_edit/src/edit.rs create mode 100644 crates/ra_text_edit/src/lib.rs create mode 100644 crates/ra_text_edit/src/text_utils.rs (limited to 'crates/ra_text_edit') diff --git a/crates/ra_text_edit/Cargo.toml b/crates/ra_text_edit/Cargo.toml new file mode 100644 index 000000000..3c4157a4e --- /dev/null +++ b/crates/ra_text_edit/Cargo.toml @@ -0,0 +1,12 @@ +[package] +edition = "2018" +name = "ra_text_edit" +version = "0.1.0" +authors = ["Aleksey Kladov "] +publish = false + +[dependencies] +text_unit = "0.1.5" + +[dev-dependencies] +test_utils = { path = "../test_utils" } diff --git a/crates/ra_text_edit/src/edit.rs b/crates/ra_text_edit/src/edit.rs new file mode 100644 index 000000000..560cf2bbc --- /dev/null +++ b/crates/ra_text_edit/src/edit.rs @@ -0,0 +1,84 @@ +use crate::AtomEdit; +use crate::text_utils::contains_offset_nonstrict; +use text_unit::{TextRange, TextUnit}; + +#[derive(Debug, Clone)] +pub struct Edit { + atoms: Vec, +} + +#[derive(Debug)] +pub struct EditBuilder { + atoms: Vec, +} + +impl EditBuilder { + pub fn new() -> EditBuilder { + EditBuilder { atoms: Vec::new() } + } + pub fn replace(&mut self, range: TextRange, replace_with: String) { + self.atoms.push(AtomEdit::replace(range, replace_with)) + } + pub fn delete(&mut self, range: TextRange) { + self.atoms.push(AtomEdit::delete(range)) + } + pub fn insert(&mut self, offset: TextUnit, text: String) { + self.atoms.push(AtomEdit::insert(offset, text)) + } + pub fn finish(self) -> Edit { + let mut atoms = self.atoms; + 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()) + } + Edit { atoms } + } + pub fn invalidates_offset(&self, offset: TextUnit) -> bool { + self.atoms + .iter() + .any(|atom| contains_offset_nonstrict(atom.delete, offset)) + } +} + +impl Edit { + pub fn into_atoms(self) -> Vec { + self.atoms + } + + pub fn apply(&self, text: &str) -> String { + let mut total_len = text.len(); + for atom in self.atoms.iter() { + total_len += atom.insert.len(); + total_len -= u32::from(atom.delete.end() - atom.delete.start()) as usize; + } + let mut buf = String::with_capacity(total_len); + let mut prev = 0; + for atom in self.atoms.iter() { + let start = u32::from(atom.delete.start()) as usize; + let end = u32::from(atom.delete.end()) as usize; + 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!(buf.len(), total_len); + buf + } + + pub fn apply_to_offset(&self, offset: TextUnit) -> 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 += TextUnit::of_str(&atom.insert); + res -= atom.delete.len(); + } + Some(res) + } +} diff --git a/crates/ra_text_edit/src/lib.rs b/crates/ra_text_edit/src/lib.rs new file mode 100644 index 000000000..789471e8a --- /dev/null +++ b/crates/ra_text_edit/src/lib.rs @@ -0,0 +1,29 @@ +mod edit; +pub mod text_utils; + +pub use crate::edit::{Edit, EditBuilder}; + +use text_unit::{TextRange, TextUnit}; + +#[derive(Debug, Clone)] +pub struct AtomEdit { + pub delete: TextRange, + pub insert: String, +} + +impl AtomEdit { + pub fn replace(range: TextRange, replace_with: String) -> AtomEdit { + AtomEdit { + delete: range, + insert: replace_with, + } + } + + pub fn delete(range: TextRange) -> AtomEdit { + AtomEdit::replace(range, String::new()) + } + + pub fn insert(offset: TextUnit, text: String) -> AtomEdit { + AtomEdit::replace(TextRange::offset_len(offset, 0.into()), text) + } +} diff --git a/crates/ra_text_edit/src/text_utils.rs b/crates/ra_text_edit/src/text_utils.rs new file mode 100644 index 000000000..e3b4dc4fe --- /dev/null +++ b/crates/ra_text_edit/src/text_utils.rs @@ -0,0 +1,5 @@ +use text_unit::{TextRange, TextUnit}; + +pub fn contains_offset_nonstrict(range: TextRange, offset: TextUnit) -> bool { + range.start() <= offset && offset <= range.end() +} -- cgit v1.2.3