use crate::utils::Loc;
use quick_error::quick_error;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Event {
Insert(Loc, String),
Delete(Loc, String),
InsertLine(usize, String),
DeleteLine(usize, String),
SplitDown(Loc),
SpliceUp(Loc),
}
impl Event {
#[must_use]
pub fn reverse(self) -> Event {
match self {
Event::Insert(loc, ch) => Event::Delete(loc, ch),
Event::Delete(loc, ch) => Event::Insert(loc, ch),
Event::InsertLine(loc, st) => Event::DeleteLine(loc, st),
Event::DeleteLine(loc, st) => Event::InsertLine(loc, st),
Event::SplitDown(loc) => Event::SpliceUp(loc),
Event::SpliceUp(loc) => Event::SplitDown(loc),
}
}
#[must_use]
pub fn loc(self) -> Loc {
match self {
Event::Insert(loc, _) => loc,
Event::Delete(loc, _) => loc,
Event::InsertLine(loc, _) => Loc { x: 0, y: loc },
Event::DeleteLine(loc, _) => Loc { x: 0, y: loc },
Event::SplitDown(loc) => loc,
Event::SpliceUp(loc) => loc,
}
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum Status {
StartOfFile,
EndOfFile,
StartOfLine,
EndOfLine,
None,
}
pub type Result<T> = std::result::Result<T, Error>;
quick_error! {
#[derive(Debug)]
pub enum Error {
Io(err: std::io::Error) {
from()
display("I/O error: {}", err)
source(err)
}
Rope(err: ropey::Error) {
from()
display("Rope error: {}", err)
source(err)
}
NoFileName
OutOfRange
ReadOnlyFile
}
}
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct EventMgmt {
pub patch: Vec<Event>,
pub undo: Vec<Vec<Event>>,
pub redo: Vec<Vec<Event>>,
}
impl EventMgmt {
pub fn register(&mut self, ev: Event) {
self.redo.clear();
self.patch.push(ev);
}
pub fn commit(&mut self) {
if !self.patch.is_empty() {
let mut patch = vec![];
std::mem::swap(&mut self.patch, &mut patch);
self.undo.push(patch);
}
}
pub fn undo(&mut self) -> Option<Vec<Event>> {
self.commit();
let mut ev = self.undo.pop()?;
self.redo.push(ev.clone());
ev.reverse();
Some(ev)
}
pub fn redo(&mut self) -> Option<Vec<Event>> {
self.commit();
let ev = self.redo.pop()?;
self.undo.push(ev.clone());
Some(ev)
}
#[must_use]
pub fn is_undo_empty(&self) -> bool {
self.undo.is_empty()
}
#[must_use]
pub fn is_redo_empty(&self) -> bool {
self.redo.is_empty()
}
#[must_use]
pub fn is_patch_empty(&self) -> bool {
self.patch.is_empty()
}
#[must_use]
pub fn last(&self) -> Option<&Event> {
if self.patch.is_empty() {
self.undo.last().and_then(|u| u.last())
} else {
self.patch.last()
}
}
}