floem_editor_core/buffer/
mod.rs

1use std::{
2    borrow::{Borrow, Cow},
3    cmp::Ordering,
4    collections::BTreeSet,
5    fmt::Display,
6    sync::{
7        atomic::{self, AtomicU64},
8        Arc,
9    },
10};
11
12use lapce_xi_rope::{
13    multiset::Subset,
14    tree::{Node, NodeInfo},
15    Delta, DeltaBuilder, DeltaElement, Interval, Rope, RopeDelta,
16};
17
18use crate::{
19    cursor::CursorMode,
20    editor::EditType,
21    indent::{auto_detect_indent_style, IndentStyle},
22    line_ending::{LineEnding, LineEndingDetermination},
23    mode::Mode,
24    selection::Selection,
25    word::WordCursor,
26};
27
28pub mod diff;
29pub mod rope_text;
30
31use rope_text::*;
32
33#[derive(Clone)]
34enum Contents {
35    Edit {
36        /// Groups related edits together so that they are undone and re-done
37        /// together. For example, an auto-indent insertion would be un-done
38        /// along with the newline that triggered it.
39        undo_group: usize,
40        /// The subset of the characters of the union string from after this
41        /// revision that were added by this revision.
42        inserts: Subset,
43        /// The subset of the characters of the union string from after this
44        /// revision that were deleted by this revision.
45        deletes: Subset,
46    },
47    Undo {
48        /// The set of groups toggled between undone and done.
49        /// Just the `symmetric_difference` (XOR) of the two sets.
50        toggled_groups: BTreeSet<usize>, // set of undo_group id's
51        /// Used to store a reversible difference between the old
52        /// and new `deletes_from_union`
53        deletes_bitxor: Subset,
54    },
55}
56
57#[derive(Clone)]
58struct Revision {
59    num: u64,
60    max_undo_so_far: usize,
61    edit: Contents,
62    cursor_before: Option<CursorMode>,
63    cursor_after: Option<CursorMode>,
64}
65
66#[derive(Debug, Clone)]
67pub struct InvalLines {
68    pub start_line: usize,
69    pub inval_count: usize,
70    pub new_count: usize,
71    pub old_text: Rope,
72}
73
74#[derive(Clone)]
75pub struct Buffer {
76    rev_counter: u64,
77    pristine_rev_id: u64,
78    atomic_rev: Arc<AtomicU64>,
79
80    text: Rope,
81    revs: Vec<Revision>,
82    cur_undo: usize,
83    undos: BTreeSet<usize>,
84    undo_group_id: usize,
85    live_undos: Vec<usize>,
86    deletes_from_union: Subset,
87    undone_groups: BTreeSet<usize>,
88    tombstones: Rope,
89    this_edit_type: EditType,
90    last_edit_type: EditType,
91
92    indent_style: IndentStyle,
93    line_ending: LineEnding,
94}
95
96impl Display for Buffer {
97    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98        f.write_str(&self.text().to_string())
99    }
100}
101
102impl Buffer {
103    pub fn new(text: impl Into<Rope>) -> Self {
104        let text = text.into();
105
106        // Determine the line ending of the text and adjust it if necessary
107        let line_ending = LineEndingDetermination::determine(&text);
108        let line_ending = line_ending.unwrap_or(LineEnding::Lf);
109
110        // Get rid of lone Cr's as Rope does not treat them as line endings
111        let text = line_ending.normalize_limited(&text);
112
113        let len = text.len();
114        Self {
115            text,
116
117            rev_counter: 1,
118            pristine_rev_id: 0,
119            atomic_rev: Arc::new(AtomicU64::new(0)),
120
121            revs: vec![Revision {
122                num: 0,
123                max_undo_so_far: 0,
124                edit: Contents::Undo {
125                    toggled_groups: BTreeSet::new(),
126                    deletes_bitxor: Subset::new(0),
127                },
128                cursor_before: None,
129                cursor_after: None,
130            }],
131            cur_undo: 1,
132            undos: BTreeSet::new(),
133            undo_group_id: 1,
134            live_undos: vec![0],
135            deletes_from_union: Subset::new(len),
136            undone_groups: BTreeSet::new(),
137            tombstones: Rope::default(),
138
139            this_edit_type: EditType::Other,
140            last_edit_type: EditType::Other,
141            indent_style: IndentStyle::DEFAULT_INDENT,
142            line_ending,
143        }
144    }
145
146    /// The current buffer revision
147    pub fn rev(&self) -> u64 {
148        self.revs.last().unwrap().num
149    }
150
151    /// Mark the buffer as pristine (aka 'saved')
152    pub fn set_pristine(&mut self) {
153        self.pristine_rev_id = self.rev();
154    }
155
156    pub fn is_pristine(&self) -> bool {
157        self.is_equivalent_revision(self.pristine_rev_id, self.rev())
158    }
159
160    pub fn set_cursor_before(&mut self, cursor: CursorMode) {
161        if let Some(rev) = self.revs.last_mut() {
162            rev.cursor_before = Some(cursor);
163        }
164    }
165
166    pub fn set_cursor_after(&mut self, cursor: CursorMode) {
167        if let Some(rev) = self.revs.last_mut() {
168            rev.cursor_after = Some(cursor);
169        }
170    }
171
172    fn is_equivalent_revision(&self, base_rev: u64, other_rev: u64) -> bool {
173        let base_subset = self
174            .find_rev(base_rev)
175            .map(|rev_index| self.deletes_from_cur_union_for_index(rev_index));
176        let other_subset = self
177            .find_rev(other_rev)
178            .map(|rev_index| self.deletes_from_cur_union_for_index(rev_index));
179
180        base_subset.is_some() && base_subset == other_subset
181    }
182
183    fn find_rev(&self, rev_id: u64) -> Option<usize> {
184        self.revs
185            .iter()
186            .enumerate()
187            .rev()
188            .find(|&(_, rev)| rev.num == rev_id)
189            .map(|(i, _)| i)
190    }
191
192    pub fn atomic_rev(&self) -> Arc<AtomicU64> {
193        self.atomic_rev.clone()
194    }
195
196    pub fn init_content(&mut self, content: Rope) {
197        if !content.is_empty() {
198            let line_ending = LineEndingDetermination::determine(&content);
199            self.line_ending = line_ending.unwrap_or(self.line_ending);
200
201            let content = self.line_ending.normalize_limited(&content);
202
203            let delta = Delta::simple_edit(Interval::new(0, 0), content, 0);
204            let (new_rev, new_text, new_tombstones, new_deletes_from_union) =
205                self.mk_new_rev(0, delta.clone());
206            self.apply_edit(
207                &delta,
208                new_rev,
209                new_text,
210                new_tombstones,
211                new_deletes_from_union,
212            );
213        }
214        self.set_pristine();
215    }
216
217    pub fn reload(&mut self, content: Rope, set_pristine: bool) -> (Rope, RopeDelta, InvalLines) {
218        // Determine the line ending of the new text
219        let line_ending = LineEndingDetermination::determine(&content);
220        self.line_ending = line_ending.unwrap_or(self.line_ending);
221
222        let content = self.line_ending.normalize_limited(&content);
223
224        let len = self.text.len();
225        let delta = Delta::simple_edit(Interval::new(0, len), content, len);
226        self.this_edit_type = EditType::Other;
227        let (text, delta, inval_lines) = self.add_delta(delta);
228        if set_pristine {
229            self.set_pristine();
230        }
231        (text, delta, inval_lines)
232    }
233
234    pub fn detect_indent(&mut self, default: impl FnOnce() -> IndentStyle) {
235        self.indent_style = auto_detect_indent_style(&self.text).unwrap_or_else(default);
236    }
237
238    pub fn indent_style(&self) -> IndentStyle {
239        self.indent_style
240    }
241
242    // TODO: users of this function should often be using Styling::indent_style instead!
243    pub fn indent_unit(&self) -> &'static str {
244        self.indent_style.as_str()
245    }
246
247    pub fn line_ending(&self) -> LineEnding {
248        self.line_ending
249    }
250
251    pub fn set_line_ending(&mut self, line_ending: LineEnding) {
252        self.line_ending = line_ending;
253    }
254
255    pub fn reset_edit_type(&mut self) {
256        self.last_edit_type = EditType::Other;
257    }
258
259    /// Apply edits, normalizes line endings before applying.
260    /// Returns `(Text before delta, delta, invalidated lines)`
261    pub fn edit<'a, I, E, S>(
262        &mut self,
263        edits: I,
264        edit_type: EditType,
265    ) -> (Rope, RopeDelta, InvalLines)
266    where
267        I: IntoIterator<Item = E>,
268        E: Borrow<(S, &'a str)>,
269        S: AsRef<Selection>,
270    {
271        let mut builder = DeltaBuilder::new(self.len());
272        let mut interval_rope = Vec::new();
273        for edit in edits {
274            let (selection, content) = edit.borrow();
275            let rope = Rope::from(content);
276            for region in selection.as_ref().regions() {
277                interval_rope.push((region.min(), region.max(), rope.clone()));
278            }
279        }
280        interval_rope.sort_by(|a, b| {
281            if a.0 == b.0 && a.1 == b.1 {
282                Ordering::Equal
283            } else if a.1 == b.0 {
284                Ordering::Less
285            } else {
286                a.1.cmp(&b.0)
287            }
288        });
289        for (start, end, rope) in interval_rope.into_iter() {
290            // TODO(minor): normalizing line endings here technically has an edge-case where it
291            // could be that we put a `\r` at the end of a replacement, then a `\n` at the start of
292            // a replacement right after it, and then it becomes a double newline.
293            // A possible alternative that might be better overall (?) would be to get the range of
294            // the delta and normalize that area after applying the delta.
295            builder.replace(start..end, self.line_ending.normalize(&rope));
296        }
297        let delta = builder.build();
298        self.this_edit_type = edit_type;
299        self.add_delta(delta)
300    }
301
302    pub fn normalize_line_endings(&mut self) -> Option<(Rope, RopeDelta, InvalLines)> {
303        let Some(delta) = self.line_ending.normalize_delta(&self.text) else {
304            // There were no changes needed
305            return None;
306        };
307        self.this_edit_type = EditType::NormalizeLineEndings;
308        Some(self.add_delta(delta))
309    }
310
311    // TODO: don't clone the delta and return it, if the caller needs it then they can clone it
312    /// Note: the delta's line-endings should be normalized.
313    fn add_delta(&mut self, delta: RopeDelta) -> (Rope, RopeDelta, InvalLines) {
314        let text = self.text.clone();
315
316        let undo_group = self.calculate_undo_group();
317        self.last_edit_type = self.this_edit_type;
318
319        let (new_rev, new_text, new_tombstones, new_deletes_from_union) =
320            self.mk_new_rev(undo_group, delta.clone());
321
322        let inval_lines = self.apply_edit(
323            &delta,
324            new_rev,
325            new_text,
326            new_tombstones,
327            new_deletes_from_union,
328        );
329
330        (text, delta, inval_lines)
331    }
332
333    fn apply_edit(
334        &mut self,
335        delta: &RopeDelta,
336        new_rev: Revision,
337        new_text: Rope,
338        new_tombstones: Rope,
339        new_deletes_from_union: Subset,
340    ) -> InvalLines {
341        self.rev_counter += 1;
342
343        let (iv, newlen) = delta.summary();
344        let old_logical_end_line = self.text.line_of_offset(iv.end) + 1;
345        let old_text = self.text.clone();
346
347        self.revs.push(new_rev);
348        self.text = new_text;
349        self.tombstones = new_tombstones;
350        self.deletes_from_union = new_deletes_from_union;
351
352        let logical_start_line = self.text.line_of_offset(iv.start);
353        let new_logical_end_line = self.text.line_of_offset(iv.start + newlen) + 1;
354        let old_hard_count = old_logical_end_line - logical_start_line;
355        let new_hard_count = new_logical_end_line - logical_start_line;
356
357        InvalLines {
358            start_line: logical_start_line,
359            inval_count: old_hard_count,
360            new_count: new_hard_count,
361            old_text,
362        }
363    }
364
365    fn calculate_undo_group(&mut self) -> usize {
366        let has_undos = !self.live_undos.is_empty();
367        let is_unbroken_group = !self.this_edit_type.breaks_undo_group(self.last_edit_type);
368
369        if has_undos && is_unbroken_group {
370            *self.live_undos.last().unwrap()
371        } else {
372            let undo_group = self.undo_group_id;
373            self.live_undos.truncate(self.cur_undo);
374            self.live_undos.push(undo_group);
375            self.cur_undo += 1;
376            self.undo_group_id += 1;
377            undo_group
378        }
379    }
380
381    /// Returns `(Revision, new text, new tombstones, new deletes from union)`
382    fn mk_new_rev(&self, undo_group: usize, delta: RopeDelta) -> (Revision, Rope, Rope, Subset) {
383        let (ins_delta, deletes) = delta.factor();
384
385        let deletes_at_rev = &self.deletes_from_union;
386
387        let union_ins_delta = ins_delta.transform_expand(deletes_at_rev, true);
388        let mut new_deletes = deletes.transform_expand(deletes_at_rev);
389
390        let new_inserts = union_ins_delta.inserted_subset();
391        if !new_inserts.is_empty() {
392            new_deletes = new_deletes.transform_expand(&new_inserts);
393        }
394        let cur_deletes_from_union = &self.deletes_from_union;
395        let text_ins_delta = union_ins_delta.transform_shrink(cur_deletes_from_union);
396        let text_with_inserts = text_ins_delta.apply(&self.text);
397        let rebased_deletes_from_union = cur_deletes_from_union.transform_expand(&new_inserts);
398
399        let undone = self.undone_groups.contains(&undo_group);
400        let new_deletes_from_union = {
401            let to_delete = if undone { &new_inserts } else { &new_deletes };
402            rebased_deletes_from_union.union(to_delete)
403        };
404
405        let (new_text, new_tombstones) = shuffle(
406            &text_with_inserts,
407            &self.tombstones,
408            &rebased_deletes_from_union,
409            &new_deletes_from_union,
410        );
411
412        let head_rev = self.revs.last().unwrap();
413        self.atomic_rev
414            .store(self.rev_counter, atomic::Ordering::Release);
415        (
416            Revision {
417                num: self.rev_counter,
418                max_undo_so_far: std::cmp::max(undo_group, head_rev.max_undo_so_far),
419                edit: Contents::Edit {
420                    undo_group,
421                    inserts: new_inserts,
422                    deletes: new_deletes,
423                },
424                cursor_before: None,
425                cursor_after: None,
426            },
427            new_text,
428            new_tombstones,
429            new_deletes_from_union,
430        )
431    }
432
433    fn deletes_from_union_for_index(&self, rev_index: usize) -> Cow<Subset> {
434        self.deletes_from_union_before_index(rev_index + 1, true)
435    }
436
437    fn deletes_from_cur_union_for_index(&self, rev_index: usize) -> Cow<Subset> {
438        let mut deletes_from_union = self.deletes_from_union_for_index(rev_index);
439        for rev in &self.revs[rev_index + 1..] {
440            if let Contents::Edit { ref inserts, .. } = rev.edit {
441                if !inserts.is_empty() {
442                    deletes_from_union = Cow::Owned(deletes_from_union.transform_union(inserts));
443                }
444            }
445        }
446        deletes_from_union
447    }
448
449    fn deletes_from_union_before_index(&self, rev_index: usize, invert_undos: bool) -> Cow<Subset> {
450        let mut deletes_from_union = Cow::Borrowed(&self.deletes_from_union);
451        let mut undone_groups = Cow::Borrowed(&self.undone_groups);
452
453        // invert the changes to deletes_from_union starting in the present and working backwards
454        for rev in self.revs[rev_index..].iter().rev() {
455            deletes_from_union = match rev.edit {
456                Contents::Edit {
457                    ref inserts,
458                    ref deletes,
459                    ref undo_group,
460                    ..
461                } => {
462                    if undone_groups.contains(undo_group) {
463                        // no need to un-delete undone inserts since we'll just shrink them out
464                        Cow::Owned(deletes_from_union.transform_shrink(inserts))
465                    } else {
466                        let un_deleted = deletes_from_union.subtract(deletes);
467                        Cow::Owned(un_deleted.transform_shrink(inserts))
468                    }
469                }
470                Contents::Undo {
471                    ref toggled_groups,
472                    ref deletes_bitxor,
473                } => {
474                    if invert_undos {
475                        let new_undone = undone_groups
476                            .symmetric_difference(toggled_groups)
477                            .cloned()
478                            .collect();
479                        undone_groups = Cow::Owned(new_undone);
480                        Cow::Owned(deletes_from_union.bitxor(deletes_bitxor))
481                    } else {
482                        deletes_from_union
483                    }
484                }
485            }
486        }
487        deletes_from_union
488    }
489
490    fn find_first_undo_candidate_index(&self, toggled_groups: &BTreeSet<usize>) -> usize {
491        // find the lowest toggled undo group number
492        if let Some(lowest_group) = toggled_groups.iter().cloned().next() {
493            for (i, rev) in self.revs.iter().enumerate().rev() {
494                if rev.max_undo_so_far < lowest_group {
495                    return i + 1; // +1 since we know the one we just found doesn't have it
496                }
497            }
498            0
499        } else {
500            // no toggled groups, return past end
501            self.revs.len()
502        }
503    }
504
505    fn compute_undo(&self, groups: &BTreeSet<usize>) -> (Revision, Subset) {
506        let toggled_groups = self
507            .undone_groups
508            .symmetric_difference(groups)
509            .cloned()
510            .collect();
511        let first_candidate = self.find_first_undo_candidate_index(&toggled_groups);
512        // the `false` below: don't invert undos since our first_candidate is based on the current undo set, not past
513        let mut deletes_from_union = self
514            .deletes_from_union_before_index(first_candidate, false)
515            .into_owned();
516
517        for rev in &self.revs[first_candidate..] {
518            if let Contents::Edit {
519                ref undo_group,
520                ref inserts,
521                ref deletes,
522                ..
523            } = rev.edit
524            {
525                if groups.contains(undo_group) {
526                    if !inserts.is_empty() {
527                        deletes_from_union = deletes_from_union.transform_union(inserts);
528                    }
529                } else {
530                    if !inserts.is_empty() {
531                        deletes_from_union = deletes_from_union.transform_expand(inserts);
532                    }
533                    if !deletes.is_empty() {
534                        deletes_from_union = deletes_from_union.union(deletes);
535                    }
536                }
537            }
538        }
539
540        let cursor_before = self
541            .revs
542            .get(first_candidate)
543            .and_then(|rev| rev.cursor_before.clone());
544
545        let cursor_after = self
546            .revs
547            .get(first_candidate)
548            .and_then(|rev| match &rev.edit {
549                Contents::Edit { undo_group, .. } => Some(undo_group),
550                Contents::Undo { .. } => None,
551            })
552            .and_then(|group| {
553                let mut cursor = None;
554                for rev in &self.revs[first_candidate..] {
555                    if let Contents::Edit { ref undo_group, .. } = rev.edit {
556                        if group == undo_group {
557                            cursor = rev.cursor_after.as_ref();
558                        } else {
559                            break;
560                        }
561                    }
562                }
563                cursor.cloned()
564            });
565
566        let deletes_bitxor = self.deletes_from_union.bitxor(&deletes_from_union);
567        let max_undo_so_far = self.revs.last().unwrap().max_undo_so_far;
568        self.atomic_rev
569            .store(self.rev_counter, atomic::Ordering::Release);
570        (
571            Revision {
572                num: self.rev_counter,
573                max_undo_so_far,
574                edit: Contents::Undo {
575                    toggled_groups,
576                    deletes_bitxor,
577                },
578                cursor_before,
579                cursor_after,
580            },
581            deletes_from_union,
582        )
583    }
584
585    fn undo(
586        &mut self,
587        groups: BTreeSet<usize>,
588    ) -> (
589        Rope,
590        RopeDelta,
591        InvalLines,
592        Option<CursorMode>,
593        Option<CursorMode>,
594    ) {
595        let text = self.text.clone();
596        let (new_rev, new_deletes_from_union) = self.compute_undo(&groups);
597        let delta = Delta::synthesize(
598            &self.tombstones,
599            &self.deletes_from_union,
600            &new_deletes_from_union,
601        );
602        let new_text = delta.apply(&self.text);
603        let new_tombstones = shuffle_tombstones(
604            &self.text,
605            &self.tombstones,
606            &self.deletes_from_union,
607            &new_deletes_from_union,
608        );
609        self.undone_groups = groups;
610
611        let cursor_before = new_rev.cursor_before.clone();
612        let cursor_after = new_rev.cursor_after.clone();
613
614        let inval_lines = self.apply_edit(
615            &delta,
616            new_rev,
617            new_text,
618            new_tombstones,
619            new_deletes_from_union,
620        );
621
622        (text, delta, inval_lines, cursor_before, cursor_after)
623    }
624
625    pub fn do_undo(&mut self) -> Option<(Rope, RopeDelta, InvalLines, Option<CursorMode>)> {
626        if self.cur_undo <= 1 {
627            return None;
628        }
629
630        self.cur_undo -= 1;
631        self.undos.insert(self.live_undos[self.cur_undo]);
632        self.last_edit_type = EditType::Undo;
633        let (text, delta, inval_lines, cursor_before, _cursor_after) =
634            self.undo(self.undos.clone());
635
636        Some((text, delta, inval_lines, cursor_before))
637    }
638
639    pub fn do_redo(&mut self) -> Option<(Rope, RopeDelta, InvalLines, Option<CursorMode>)> {
640        if self.cur_undo >= self.live_undos.len() {
641            return None;
642        }
643
644        self.undos.remove(&self.live_undos[self.cur_undo]);
645        self.cur_undo += 1;
646        self.last_edit_type = EditType::Redo;
647        let (text, delta, inval_lines, _cursor_before, cursor_after) =
648            self.undo(self.undos.clone());
649
650        Some((text, delta, inval_lines, cursor_after))
651    }
652
653    pub fn move_word_forward(&self, offset: usize) -> usize {
654        self.move_n_words_forward(offset, 1)
655    }
656
657    pub fn move_word_backward(&self, offset: usize, mode: Mode) -> usize {
658        self.move_n_words_backward(offset, 1, mode)
659    }
660
661    pub fn char_at_offset(&self, offset: usize) -> Option<char> {
662        if self.is_empty() {
663            return None;
664        }
665        let offset = offset.min(self.len());
666        WordCursor::new(&self.text, offset)
667            .inner
668            .peek_next_codepoint()
669    }
670}
671
672impl RopeText for Buffer {
673    fn text(&self) -> &Rope {
674        &self.text
675    }
676}
677
678fn shuffle_tombstones(
679    text: &Rope,
680    tombstones: &Rope,
681    old_deletes_from_union: &Subset,
682    new_deletes_from_union: &Subset,
683) -> Rope {
684    // Taking the complement of deletes_from_union leads to an interleaving valid for swapped text and tombstones,
685    // allowing us to use the same method to insert the text into the tombstones.
686    let inverse_tombstones_map = old_deletes_from_union.complement();
687    let move_delta = Delta::synthesize(
688        text,
689        &inverse_tombstones_map,
690        &new_deletes_from_union.complement(),
691    );
692    move_delta.apply(tombstones)
693}
694
695fn shuffle(
696    text: &Rope,
697    tombstones: &Rope,
698    old_deletes_from_union: &Subset,
699    new_deletes_from_union: &Subset,
700) -> (Rope, Rope) {
701    // Delta that deletes the right bits from the text
702    let del_delta = Delta::synthesize(tombstones, old_deletes_from_union, new_deletes_from_union);
703    let new_text = del_delta.apply(text);
704    (
705        new_text,
706        shuffle_tombstones(
707            text,
708            tombstones,
709            old_deletes_from_union,
710            new_deletes_from_union,
711        ),
712    )
713}
714
715pub struct DeltaValueRegion<'a, N: NodeInfo + 'a> {
716    pub old_offset: usize,
717    pub new_offset: usize,
718    pub len: usize,
719    pub node: &'a Node<N>,
720}
721
722/// Modified version of `xi_rope::delta::InsertsIter` which includes the node
723pub struct InsertsValueIter<'a, N: NodeInfo + 'a> {
724    pos: usize,
725    last_end: usize,
726    els_iter: std::slice::Iter<'a, DeltaElement<N>>,
727}
728impl<'a, N: NodeInfo + 'a> InsertsValueIter<'a, N> {
729    pub fn new(delta: &'a Delta<N>) -> InsertsValueIter<'a, N> {
730        InsertsValueIter {
731            pos: 0,
732            last_end: 0,
733            els_iter: delta.els.iter(),
734        }
735    }
736}
737impl<'a, N: NodeInfo> Iterator for InsertsValueIter<'a, N> {
738    type Item = DeltaValueRegion<'a, N>;
739
740    fn next(&mut self) -> Option<Self::Item> {
741        for elem in &mut self.els_iter {
742            match *elem {
743                DeltaElement::Copy(b, e) => {
744                    self.pos += e - b;
745                    self.last_end = e;
746                }
747                DeltaElement::Insert(ref n) => {
748                    let result = Some(DeltaValueRegion {
749                        old_offset: self.last_end,
750                        new_offset: self.pos,
751                        len: n.len(),
752                        node: n,
753                    });
754                    self.pos += n.len();
755                    self.last_end += n.len();
756                    return result;
757                }
758            }
759        }
760        None
761    }
762}
763
764#[cfg(test)]
765mod test;