hjkl_buffer/undo.rs
1//! Undo/redo entry type for per-buffer undo history.
2//!
3//! Lives in `hjkl-buffer` so that [`crate::Buffer`] can own the undo stack
4//! directly, keeping per-buffer state co-located with the rope.
5
6use std::collections::BTreeMap;
7use std::time::SystemTime;
8
9/// A single entry in the undo or redo stack.
10///
11/// The `timestamp` records the wall-clock time at which the snapshot was
12/// taken (i.e. when `push_undo` was called), enabling the `:earlier` /
13/// `:later` time-travel ex commands to walk the stack by duration rather
14/// than by step count.
15///
16/// Stored as a `ropey::Rope` (O(1) Arc-clone) rather than a `String` so
17/// snapshot cost is negligible even on multi-MB buffers.
18#[derive(Debug, Clone)]
19pub struct UndoEntry {
20 pub rope: ropey::Rope,
21 pub cursor: (usize, usize),
22 pub timestamp: SystemTime,
23 /// Local marks / jumplist / changelist / this-buffer's-global-marks
24 /// snapshot, so undo/redo restore mark-ish positions alongside the
25 /// text instead of leaving them shifted by the edit being undone
26 /// (audit-r2 fix 2). `Default::default()` (all empty) for callers
27 /// that don't populate it — restoring an all-empty snapshot is a
28 /// no-op against a freshly-constructed buffer's own empty state, so
29 /// existing fixtures that only care about text/cursor stay valid.
30 pub marks: MarkSnapshot,
31}
32
33/// Buffer-scoped "edit coherence" state snapshotted alongside a
34/// [`UndoEntry`]'s rope so undo/redo can restore marks, not just text.
35///
36/// Positions are plain `(row, col)` (or `(row, col)` values keyed by
37/// mark char) — no buffer-id tagging needed here even for
38/// `global_marks`, because a `MarkSnapshot` always belongs to exactly
39/// one buffer's undo stack; the engine is responsible for reattaching
40/// its own `buffer_id` when writing entries back into the session-global
41/// marks map (see `Editor::restore_marks`).
42#[derive(Debug, Clone, Default, PartialEq, Eq)]
43pub struct MarkSnapshot {
44 /// `ma`-`mz` local marks (`View::marks_cloned`).
45 pub local_marks: BTreeMap<char, (usize, usize)>,
46 /// Back-jumplist (`Ctrl-o` stack), newest at the back.
47 pub jump_back: Vec<(usize, usize)>,
48 /// Forward-jumplist (`Ctrl-i` stack), newest at the back.
49 pub jump_fwd: Vec<(usize, usize)>,
50 /// `` `. `` / `'.` — position of the most recent change.
51 pub change_last_edit: Option<(usize, usize)>,
52 /// Changelist ring (`g;` / `g,`).
53 pub change_list: Vec<(usize, usize)>,
54 /// Walk cursor into `change_list`; `None` outside a walk.
55 pub change_cursor: Option<usize>,
56 /// `mA`-`mZ` global marks that belong to THIS buffer (bare
57 /// `(row, col)` — the buffer-id is implicit, this buffer).
58 pub global_marks: BTreeMap<char, (usize, usize)>,
59}