@@ -94,8 +94,14 @@ impl ChangeSet {
94 head_b = b;
94 head_b = b;
96 // insertion in B
96 // insertion in B
97− (a, Some(change @ Insert(..))) => {
97+ (a, Some(Insert(current))) => {
98+ // merge onto previous insert if possible
99+ // TODO: do these as operations on a changeset
100+ if let Some(Insert(prev)) = changes.last_mut() {
101+ prev.push_tendril(¤t);
98− changes.push(change);
103+ changes.push(Insert(current));
99 head_a = a;
105 head_a = a;
100 head_b = changes_b.next();
106 head_b = changes_b.next();
@@ -422,7 +428,9 @@ impl Transaction {
422 let mut last = 0;
428 let mut last = 0;
423 for (from, to, tendril) in changes {
429 for (from, to, tendril) in changes {
424 // Retain from last "to" to current "from"
430 // Retain from last "to" to current "from"
431+ if from - last > 0 {
425− acc.push(Operation::Retain(from - last));
432+ acc.push(Operation::Retain(from - last));
426 let span = to - from;
434 let span = to - from;
427 match tendril {
435 match tendril {
428 Some(text) => {
436 Some(text) => {
@@ -581,4 +589,36 @@ mod test {
581 transaction.apply(&mut state);
589 transaction.apply(&mut state);
582 assert_eq!(state.doc, Rope::from_str("hello void! 123"));
590 assert_eq!(state.doc, Rope::from_str("hello void! 123"));
594+ fn insert_composition() {
595+ let mut state = State::new("".into());
596+ let t1 = Transaction::insert(&state, Tendril::from_char('h'));
597+ t1.apply(&mut state);
598+ let t2 = Transaction::insert(&state, Tendril::from_char('e'));
599+ t2.apply(&mut state);
600+ let t3 = Transaction::insert(&state, Tendril::from_char('l'));
601+ t3.apply(&mut state);
602+ let t4 = Transaction::insert(&state, Tendril::from_char('l'));
603+ t4.apply(&mut state);
604+ let t5 = Transaction::insert(&state, Tendril::from_char('o'));
605+ t5.apply(&mut state);
607+ assert_eq!(state.doc, Rope::from_str("hello"));
609+ // changesets as follows:
614+ let mut changes = t1
616+ .compose(t2.changes)
617+ .compose(t3.changes)
618+ .compose(t4.changes)
619+ .compose(t5.changes);
622+ assert_eq!(changes.changes, &[Insert("hello".into())]);