@@ -63,6 +63,56 @@ impl ChangeSet {
66+ // Changeset builder operations: delete/insert/retain
67+ fn delete(&mut self, n: usize) {
73+ if let Some(Delete(count)) = self.changes.last_mut() {
76+ self.changes.push(Delete(n));
80+ fn insert(&mut self, fragment: Tendril) {
83+ if fragment.is_empty() {
87+ let new_last = match self.changes.as_mut_slice() {
88+ [.., Insert(prev)] => {
89+ prev.push_tendril(&fragment);
92+ [.., Insert(prev), Delete(_)] => {
93+ prev.push_tendril(&fragment);
96+ [.., last @ Delete(_)] => std::mem::replace(last, Insert(fragment)),
97+ _ => Insert(fragment),
100+ self.changes.push(new_last);
103+ fn retain(&mut self, n: usize) {
109+ if let Some(Retain(count)) = self.changes.last_mut() {
112+ self.changes.push(Retain(n));
66 /// Combine two changesets together.
116 /// Combine two changesets together.
67 /// In other words, If `this` goes `docA` → `docB` and `other` represents `docB` → `docC`, the
117 /// In other words, If `this` goes `docA` → `docB` and `other` represents `docB` → `docC`, the
68 /// returned value will represent the change `docA` → `docC`.
118 /// returned value will represent the change `docA` → `docC`.
@@ -77,7 +127,10 @@ impl ChangeSet {
77 let mut head_a = changes_a.next();
127 let mut head_a = changes_a.next();
78 let mut head_b = changes_b.next();
128 let mut head_b = changes_b.next();
130+ let mut changes = Self {
80− let mut changes: Vec<Operation> = Vec::with_capacity(len); // TODO: max(a, b), shrink_to_fit() afterwards
132+ changes: Vec::with_capacity(len), // TODO: max(a, b), shrink_to_fit() afterwards
83 use std::cmp::Ordering;
136 use std::cmp::Ordering;
@@ -88,37 +141,31 @@ impl ChangeSet {
90 // deletion in A
143 // deletion in A
91− (Some(change @ Delete(..)), b) => {
144+ (Some(Delete(i)), b) => {
92− changes.push(change);
145+ changes.delete(i);
93 head_a = changes_a.next();
146 head_a = changes_a.next();
94 head_b = b;
147 head_b = b;
96 // insertion in B
149 // insertion in B
97 (a, Some(Insert(current))) => {
150 (a, Some(Insert(current))) => {
98− // merge onto previous insert if possible
151+ changes.insert(current);
99− // TODO: do these as operations on a changeset
100− if let Some(Insert(prev)) = changes.last_mut() {
101− prev.push_tendril(¤t);
103− changes.push(Insert(current));
105 head_a = a;
152 head_a = a;
106 head_b = changes_b.next();
153 head_b = changes_b.next();
108 (None, _) | (_, None) => return unreachable!(),
155 (None, _) | (_, None) => return unreachable!(),
109 (Some(Retain(i)), Some(Retain(j))) => match i.cmp(&j) {
156 (Some(Retain(i)), Some(Retain(j))) => match i.cmp(&j) {
110 Ordering::Less => {
157 Ordering::Less => {
111− changes.push(Retain(i));
158+ changes.retain(i);
112 head_a = changes_a.next();
159 head_a = changes_a.next();
113 head_b = Some(Retain(j - i));
160 head_b = Some(Retain(j - i));
115 Ordering::Equal => {
162 Ordering::Equal => {
116− changes.push(Retain(i));
163+ changes.retain(i);
117 head_a = changes_a.next();
164 head_a = changes_a.next();
118 head_b = changes_b.next();
165 head_b = changes_b.next();
120 Ordering::Greater => {
167 Ordering::Greater => {
121− changes.push(Retain(j));
168+ changes.retain(j);
122 head_a = Some(Retain(i - j));
169 head_a = Some(Retain(i - j));
123 head_b = changes_b.next();
170 head_b = changes_b.next();
@@ -147,12 +194,12 @@ impl ChangeSet {
147 let len = s.chars().count();
194 let len = s.chars().count();
148 match len.cmp(&j) {
195 match len.cmp(&j) {
149 Ordering::Less => {
196 Ordering::Less => {
150− changes.push(Insert(s));
197+ changes.insert(s);
151 head_a = changes_a.next();
198 head_a = changes_a.next();
152 head_b = Some(Retain(j - len));
199 head_b = Some(Retain(j - len));
154 Ordering::Equal => {
201 Ordering::Equal => {
155− changes.push(Insert(s));
202+ changes.insert(s);
156 head_a = changes_a.next();
203 head_a = changes_a.next();
157 head_b = changes_b.next();
204 head_b = changes_b.next();
@@ -160,7 +207,7 @@ impl ChangeSet {
160 // figure out the byte index of the truncated string end
207 // figure out the byte index of the truncated string end
161 let (pos, _) = s.char_indices().nth(j).unwrap();
208 let (pos, _) = s.char_indices().nth(j).unwrap();
162 let pos = pos as u32;
209 let pos = pos as u32;
163− changes.push(Insert(s.subtendril(0, pos)));
210+ changes.insert(s.subtendril(0, pos));
164 head_a = Some(Insert(s.subtendril(pos, s.len() as u32 - pos)));
211 head_a = Some(Insert(s.subtendril(pos, s.len() as u32 - pos)));
165 head_b = changes_b.next();
212 head_b = changes_b.next();
@@ -168,17 +215,17 @@ impl ChangeSet {
169 (Some(Retain(i)), Some(Delete(j))) => match i.cmp(&j) {
216 (Some(Retain(i)), Some(Delete(j))) => match i.cmp(&j) {
170 Ordering::Less => {
217 Ordering::Less => {
171− changes.push(Delete(i));
218+ changes.delete(i);
172 head_a = changes_a.next();
219 head_a = changes_a.next();
173 head_b = Some(Delete(j - i));
220 head_b = Some(Delete(j - i));
175 Ordering::Equal => {
222 Ordering::Equal => {
176− changes.push(Delete(j));
223+ changes.delete(j);
177 head_a = changes_a.next();
224 head_a = changes_a.next();
178 head_b = changes_b.next();
225 head_b = changes_b.next();
180 Ordering::Greater => {
227 Ordering::Greater => {
181− changes.push(Delete(j));
228+ changes.delete(j);
182 head_a = Some(Retain(i - j));
229 head_a = Some(Retain(i - j));
183 head_b = changes_b.next();
230 head_b = changes_b.next();
@@ -186,10 +233,7 @@ impl ChangeSet {
191− changes,
236+ changes
195 /// Given another change set starting in the same document, maps this
239 /// Given another change set starting in the same document, maps this
@@ -421,37 +465,29 @@ impl Transaction {
421 I: IntoIterator<Item = Change> + ExactSizeIterator,
465 I: IntoIterator<Item = Change> + ExactSizeIterator,
423 let len = state.doc.len_chars();
467 let len = state.doc.len_chars();
424− let mut acc = Vec::with_capacity(2 * changes.len() + 1);
468+ let acc = Vec::with_capacity(2 * changes.len() + 1);
469+ let mut changeset = ChangeSet { changes: acc, len };
426 // TODO: verify ranges are ordered and not overlapping or change will panic.
471 // TODO: verify ranges are ordered and not overlapping or change will panic.
428 let mut last = 0;
473 let mut last = 0;
429 for (from, to, tendril) in changes {
474 for (from, to, tendril) in changes {
430 // Retain from last "to" to current "from"
475 // Retain from last "to" to current "from"
431− if from - last > 0 {
476+ changeset.retain(from - last);
432− acc.push(Operation::Retain(from - last));
434 let span = to - from;
477 let span = to - from;
435 match tendril {
478 match tendril {
436 Some(text) => {
479 Some(text) => {
437− if span > 0 {
480+ changeset.delete(span);
438− acc.push(Operation::Delete(span));
481+ changeset.insert(text);
440− acc.push(Operation::Insert(text));
442− None if span > 0 => acc.push(Operation::Delete(span)),
483+ None => changeset.delete(span),
443− // empty delete is useless
446 last = to;
485 last = to;
449− let span = len - last;
488+ changeset.retain(len - last);
451− acc.push(Operation::Retain(span));
454− Self::from(ChangeSet { changes: acc, len })
490+ Self::from(changeset)
457 /// Generate a transaction with a change per selection range.
493 /// Generate a transaction with a change per selection range.
@@ -591,7 +627,7 @@ mod test {
594− fn insert_composition() {
630+ fn optimized_composition() {
595 let mut state = State::new("".into());
631 let mut state = State::new("".into());
596 let t1 = Transaction::insert(&state, Tendril::from_char('h'));
632 let t1 = Transaction::insert(&state, Tendril::from_char('h'));
597 t1.apply(&mut state);
633 t1.apply(&mut state);
@@ -620,5 +656,6 @@ mod test {
621 use Operation::*;
657 use Operation::*;
622 assert_eq!(changes.changes, &[Insert("hello".into())]);
658 assert_eq!(changes.changes, &[Insert("hello".into())]);
659+ // instead of insert h, insert e, insert l, insert l, insert o