use ui::history::SnapshotHistory;
use markdown::{Cursor, Doc, Selection};
use crate::{comment::Anchor, editor::Mode};
pub const DEFAULT_UNDO_LIMIT: usize = 100;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EditKind {
Insert,
Delete,
Structure,
}
#[derive(Clone)]
struct Snapshot {
doc: Doc,
mode: Mode,
selection: Selection,
anchors: Vec<Anchor>,
}
pub struct History {
snapshots: SnapshotHistory<Snapshot>,
last: Option<(EditKind, Cursor)>,
}
impl Default for History {
fn default() -> Self {
Self {
snapshots: SnapshotHistory::new(DEFAULT_UNDO_LIMIT),
last: None,
}
}
}
impl History {
pub fn with_limit(limit: usize) -> Self {
Self {
snapshots: SnapshotHistory::new(limit),
last: None,
}
}
pub fn record(
&mut self,
kind: EditKind,
mode: Mode,
doc: &Doc,
selection: Selection,
anchors: &[Anchor],
) {
let joins = self.joins(kind, selection);
self.snapshots.record((!joins).then(|| Snapshot {
doc: doc.clone(),
mode,
selection,
anchors: anchors.to_vec(),
}));
if !joins {
self.last = None;
}
}
pub fn landed(&mut self, kind: EditKind, selection: Selection) {
self.last = (kind != EditKind::Structure).then_some((kind, selection.head));
}
fn joins(&self, kind: EditKind, selection: Selection) -> bool {
if kind == EditKind::Structure || !self.snapshots.can_undo() {
return false;
}
self.last == Some((kind, selection.head)) && selection.is_collapsed()
}
pub fn interrupt(&mut self) {
self.last = None;
}
pub fn undo(
&mut self,
mode: Mode,
doc: &Doc,
selection: Selection,
anchors: &[Anchor],
) -> Option<Step> {
let previous = self.snapshots.undo(|| Snapshot {
doc: doc.clone(),
mode,
selection,
anchors: anchors.to_vec(),
})?;
self.last = None;
Some(previous.into())
}
pub fn redo(
&mut self,
mode: Mode,
doc: &Doc,
selection: Selection,
anchors: &[Anchor],
) -> Option<Step> {
let next = self.snapshots.redo(|| Snapshot {
doc: doc.clone(),
mode,
selection,
anchors: anchors.to_vec(),
})?;
self.last = None;
Some(next.into())
}
}
pub struct Step {
pub doc: Doc,
pub mode: Mode,
pub selection: Selection,
pub anchors: Vec<Anchor>,
}
impl From<Snapshot> for Step {
fn from(snapshot: Snapshot) -> Self {
Self {
doc: snapshot.doc,
mode: snapshot.mode,
selection: snapshot.selection,
anchors: snapshot.anchors,
}
}
}