diff options
Diffstat (limited to 'helix-core')
-rw-r--r-- | helix-core/src/lib.rs | 2 | ||||
-rw-r--r-- | helix-core/src/transaction.rs | 46 |
2 files changed, 47 insertions, 1 deletions
diff --git a/helix-core/src/lib.rs b/helix-core/src/lib.rs index b67e2c8a..14abf016 100644 --- a/helix-core/src/lib.rs +++ b/helix-core/src/lib.rs @@ -67,4 +67,4 @@ pub use syntax::Syntax; pub use diagnostic::Diagnostic; pub use line_ending::{LineEnding, DEFAULT_LINE_ENDING}; -pub use transaction::{Assoc, Change, ChangeSet, Operation, Transaction}; +pub use transaction::{Assoc, Change, ChangeSet, Deletion, Operation, Transaction}; diff --git a/helix-core/src/transaction.rs b/helix-core/src/transaction.rs index d8e581aa..06efe259 100644 --- a/helix-core/src/transaction.rs +++ b/helix-core/src/transaction.rs @@ -5,6 +5,7 @@ use std::borrow::Cow; /// (from, to, replacement) pub type Change = (usize, usize, Option<Tendril>); +pub type Deletion = (usize, usize); // TODO: pub(crate) #[derive(Debug, Clone, PartialEq, Eq)] @@ -534,6 +535,41 @@ impl Transaction { Self::from(changeset) } + /// Generate a transaction from a set of potentially overlapping deletions + /// by merging overlapping deletions together. + pub fn delete<I>(doc: &Rope, deletions: I) -> Self + where + I: Iterator<Item = Deletion>, + { + let len = doc.len_chars(); + + let (lower, upper) = deletions.size_hint(); + let size = upper.unwrap_or(lower); + let mut changeset = ChangeSet::with_capacity(2 * size + 1); // rough estimate + + let mut last = 0; + for (mut from, to) in deletions { + if last > to { + continue; + } + if last > from { + from = last + } + debug_assert!( + from <= to, + "Edit end must end before it starts (should {from} <= {to})" + ); + // Retain from last "to" to current "from" + changeset.retain(from - last); + changeset.delete(to - from); + last = to; + } + + changeset.retain(len - last); + + Self::from(changeset) + } + /// Generate a transaction with a change per selection range. pub fn change_by_selection<F>(doc: &Rope, selection: &Selection, f: F) -> Self where @@ -580,6 +616,16 @@ impl Transaction { ) } + /// Generate a transaction with a deletion per selection range. + /// Compared to using `change_by_selection` directly these ranges may overlap. + /// In that case they are merged + pub fn delete_by_selection<F>(doc: &Rope, selection: &Selection, f: F) -> Self + where + F: FnMut(&Range) -> Deletion, + { + Self::delete(doc, selection.iter().map(f)) + } + /// Insert text at each selection head. pub fn insert(doc: &Rope, selection: &Selection, text: Tendril) -> Self { Self::change_by_selection(doc, selection, |range| { |