From 1984410ac998ac5561f4a3de87d3d125f2f61178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Thu, 28 May 2020 14:59:50 +0900 Subject: [PATCH] Selection mapping over changesets. --- helix-core/src/lib.rs | 2 +- helix-core/src/selection.rs | 30 +++++++++++++++++++++++++++++- helix-core/src/transaction.rs | 7 +++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/helix-core/src/lib.rs b/helix-core/src/lib.rs index e027f9434..421d8f3cb 100644 --- a/helix-core/src/lib.rs +++ b/helix-core/src/lib.rs @@ -13,4 +13,4 @@ pub use selection::Selection; pub use state::State; -pub use transaction::{Change, ChangeSet, Transaction}; +pub use transaction::{Assoc, Change, ChangeSet, Transaction}; diff --git a/helix-core/src/selection.rs b/helix-core/src/selection.rs index 0b2cd5a3b..98bbdb7fa 100644 --- a/helix-core/src/selection.rs +++ b/helix-core/src/selection.rs @@ -2,6 +2,7 @@ //! single selection range. //! //! All positioning is done via `char` offsets into the buffer. +use crate::{Assoc, ChangeSet}; use smallvec::{smallvec, SmallVec}; #[inline] @@ -59,7 +60,18 @@ impl Range { } } - // TODO: map + /// Map a range through a set of changes. Returns a new range representing the same position + /// after the changes are applied. + pub fn map(self, changes: &ChangeSet) -> Self { + let anchor = changes.map_pos(self.anchor, Assoc::Before); + let head = changes.map_pos(self.head, Assoc::Before); + + // TODO: possibly unnecessary + if self.anchor == anchor && self.head == head { + return self; + } + Self { anchor, head } + } /// Extend the range to cover at least `from` `to`. #[must_use] @@ -115,6 +127,22 @@ impl Selection { // add_range // push // replace_range + /// Map selections over a set of changes. Useful for adjusting the selection position after + /// applying changes to a document. + pub fn map(self, changes: &ChangeSet) -> Self { + if changes.is_empty() { + return self; + } + + Self::new( + self.ranges + .into_iter() + .map(|range| range.map(changes)) + .collect(), + self.primary_index, + ) + } + #[must_use] /// Constructs a selection holding a single range. pub fn single(anchor: usize, head: usize) -> Self { diff --git a/helix-core/src/transaction.rs b/helix-core/src/transaction.rs index c6be89ac8..8da01c099 100644 --- a/helix-core/src/transaction.rs +++ b/helix-core/src/transaction.rs @@ -242,6 +242,13 @@ impl ChangeSet { } } + /// `true` when the set is empty. + #[inline] + pub fn is_empty(&self) -> bool { + let len = self.changes.len(); + len == 0 || (len == 1 && self.changes[0] == Change::Retain(self.len)) + } + /// Map a position through the changes. /// /// `assoc` indicates which size to associate the position with. `Before` will keep the