use ui::history::SnapshotHistory;
use markdown::{Cursor, Doc, Selection};
use crate::{anchor::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>,
}
impl Default for History {
fn default() -> Self {
Self::with_limit(DEFAULT_UNDO_LIMIT)
}
}
impl History {
pub fn with_limit(limit: usize) -> Self {
Self {
snapshots: SnapshotHistory::new(limit),
}
}
pub fn clear(&mut self) {
self.snapshots.clear();
}
pub fn can_undo(&self) -> bool {
self.snapshots.can_undo()
}
pub fn record(
&mut self,
joins: bool,
mode: Mode,
doc: &Doc,
selection: Selection,
anchors: &[Anchor],
) {
self.snapshots.record((!joins).then(|| Snapshot {
doc: doc.clone(),
mode,
selection,
anchors: anchors.to_vec(),
}));
}
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(),
})?;
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(),
})?;
Some(next.into())
}
}
#[derive(Default)]
pub struct Run {
last: Option<(EditKind, Cursor)>,
}
impl Run {
pub fn joins(&self, kind: EditKind, selection: Selection) -> bool {
kind != EditKind::Structure
&& self.last == Some((kind, selection.head))
&& selection.is_collapsed()
}
pub fn landed(&mut self, kind: EditKind, selection: Selection) {
self.last = (kind != EditKind::Structure).then_some((kind, selection.head));
}
pub fn interrupt(&mut self) {
self.last = None;
}
}
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,
}
}
}