// SPDX-FileCopyrightText: 2024 Topola contributors // // SPDX-License-Identifier: MIT //! Manages command history operations, allowing for undoing and redoing commands. //! Handles error scenarios related to command history, maintaining lists of executed //! and undone commands for easy navigation. use derive_getters::{Dissolve, Getters}; use serde::{Deserialize, Serialize}; use thiserror::Error; use crate::{autorouter::execution::Command, board::edit::BoardEdit}; #[derive(Error, Debug, Clone)] pub enum HistoryError { #[error("no previous command")] NoPreviousCommand, #[error("no next command")] NoNextCommand, } #[derive(Debug, Clone, Getters, Serialize, Deserialize)] #[serde(transparent)] pub struct HistoryEntry { command: Command, #[serde(skip)] edit: Option, } #[derive(Debug, Default, Clone, Getters, Dissolve, Serialize, Deserialize)] pub struct History { done: Vec, undone: Vec, } impl History { pub fn new() -> Self { Self::default() } pub fn do_(&mut self, command: Command, edit: Option) { self.done.push(HistoryEntry { command, edit }); } pub fn undo(&mut self) -> Result<(), HistoryError> { let Some(command) = self.done.pop() else { return Err(HistoryError::NoPreviousCommand); }; self.undone.push(command); Ok(()) } pub fn redo(&mut self) -> Result<(), HistoryError> { let Some(command) = self.undone.pop() else { return Err(HistoryError::NoNextCommand); }; self.done.push(command); Ok(()) } pub fn set_undone(&mut self, iter: impl IntoIterator) { self.undone = Vec::from_iter(iter); } pub fn last_done(&self) -> Result<&HistoryEntry, HistoryError> { self.done.last().ok_or(HistoryError::NoPreviousCommand) } pub fn last_undone(&self) -> Result<&HistoryEntry, HistoryError> { self.undone.last().ok_or(HistoryError::NoNextCommand) } }