diff options
author | Blaž Hrastnik | 2020-09-07 08:08:28 +0000 |
---|---|---|
committer | Blaž Hrastnik | 2020-09-07 08:08:28 +0000 |
commit | dd749bb2846584aa20078cfa2aea4fe18678c12c (patch) | |
tree | 8ae7048e4247a9f11087230dabe16c4b45914a85 /helix-core/src/transaction.rs | |
parent | 4e349add60db745ebf459bb97b77031d3d9b6678 (diff) |
Expand transaction API.
Diffstat (limited to 'helix-core/src/transaction.rs')
-rw-r--r-- | helix-core/src/transaction.rs | 77 |
1 files changed, 61 insertions, 16 deletions
diff --git a/helix-core/src/transaction.rs b/helix-core/src/transaction.rs index d078679c..2f40be76 100644 --- a/helix-core/src/transaction.rs +++ b/helix-core/src/transaction.rs @@ -1,4 +1,4 @@ -use crate::{Rope, Selection, Tendril}; +use crate::{Rope, Selection, SelectionRange, State, Tendril}; // TODO: divided into three different operations, I sort of like having just // Splice { extent, Option<text>, distance } better. @@ -47,18 +47,6 @@ impl ChangeSet { } } - pub fn insert(doc: &Rope, pos: usize, c: char) -> Self { - let len = doc.len_chars(); - Self { - changes: vec![ - Change::Retain(pos), - Change::Insert(Tendril::from_char(c)), - Change::Retain(len - pos), - ], - len, - } - } - // TODO: from iter /// Combine two changesets together. @@ -210,8 +198,11 @@ impl ChangeSet { unimplemented!() } - pub fn apply(&self, text: &mut Rope) { - // TODO: validate text.chars() == self.len + /// Returns true if applied successfully. + pub fn apply(&self, text: &mut Rope) -> bool { + if text.len_chars() != self.len { + return false; + } let mut pos = 0; @@ -231,6 +222,7 @@ impl ChangeSet { } } } + true } /// `true` when the set is empty. @@ -332,7 +324,60 @@ pub struct Transaction { // scroll_into_view } -impl Transaction {} +impl Transaction { + /// Returns true if applied successfully. + pub fn apply(&self, state: &mut State) -> bool { + // apply changes to the document + if !self.changes.apply(&mut state.doc) { + return false; + } + + // update the selection: either take the selection specified in the transaction, or map the + // current selection through changes. + state.selection = self + .selection + .clone() + .unwrap_or_else(|| state.selection.clone().map(&self.changes)); + + true + } + + pub fn insert(state: &State, text: Tendril) -> Self { + let len = state.doc.len_chars(); + let ranges = state.selection.ranges(); + let mut changes = Vec::with_capacity(2 * ranges.len() + 1); + let mut last = 0; + + for range in state.selection.ranges() { + let cur = range.head; + changes.push(Change::Retain(cur)); + changes.push(Change::Insert(text.clone())); + last = cur; + } + changes.push(Change::Retain(len - last)); + + Self::from(ChangeSet { changes, len }) + } + + pub fn change_selection<F>(selection: Selection, f: F) -> Self + where + F: Fn(SelectionRange) -> ChangeSet, + { + selection.ranges().iter().map(|range| true); + // TODO: most idiomatic would be to return a + // Change { from: x, to: y, insert: "str" } + unimplemented!() + } +} + +impl From<ChangeSet> for Transaction { + fn from(changes: ChangeSet) -> Self { + Self { + changes, + selection: None, + } + } +} #[cfg(test)] mod test { |