@@ -1,5 +1,9 @@
11use crate::{Rope, Selection, SelectionRange, State, Tendril};
22
3+// TODO: make Change enum internal and export this as the public Change type
4+/// (from, to, replacement)
5+type Change2 = (usize, usize, Option<Tendril>);
6+
37// TODO: divided into three different operations, I sort of like having just
48// Splice { extent, Option<text>, distance } better.
59// insert: Splice { extent: 0, text: Some("a"), distance: 2 }
@@ -342,15 +346,11 @@ impl Transaction {
342346 true
343347 }
344348
345− pub fn change_by_selection<F>(state: &State, f: F) -> Self
346− where
347− F: Fn(&SelectionRange) -> (usize, usize, Option<Tendril>),
348− {
349+ /// Generate a transaction from a set of changes.
350+ // TODO: take an owned iter instead of Vec
351+ pub fn change(state: &State, changes: Vec<Change2>) -> Self {
349352 let len = state.doc.len_chars();
350− let ranges = state.selection.ranges();
351− let mut acc = Vec::with_capacity(2 * ranges.len() + 1);
352−
353− let changes = ranges.iter().map(f);
353+ let mut acc = Vec::with_capacity(2 * changes.len() + 1);
354354
355355 // TODO: verify ranges are ordered and not overlapping.
356356
@@ -370,6 +370,14 @@ impl Transaction {
370370 Self::from(ChangeSet { changes: acc, len })
371371 }
372372
373+ /// Generate a transaction with a change per selection range.
374+ pub fn change_by_selection<F>(state: &State, f: F) -> Self
375+ where
376+ F: Fn(&SelectionRange) -> Change2,
377+ {
378+ Self::change(state, state.selection.ranges.iter().map(f).collect())
379+ }
380+
373381 /// Insert text at each selection head.
374382 pub fn insert(state: &State, text: Tendril) -> Self {
375383 Self::change_by_selection(state, |range| (range.head, range.head, Some(text.clone())))