use crate::Snapshot;
use std::collections::VecDeque;
const MAX_HISTORY_DEPTH: usize = 100;
#[derive(Debug)]
pub struct HistoryManager {
undo_stack: VecDeque<Snapshot>,
redo_stack: VecDeque<Snapshot>,
suppress_capture: bool,
}
impl HistoryManager {
pub fn new() -> Self {
Self {
undo_stack: VecDeque::new(),
redo_stack: VecDeque::new(),
suppress_capture: false,
}
}
pub fn capture_before_command(&mut self, snapshot: Snapshot) {
if self.suppress_capture {
return;
}
self.undo_stack.push_back(snapshot);
if self.undo_stack.len() > MAX_HISTORY_DEPTH {
self.undo_stack.pop_front();
}
self.redo_stack.clear();
}
pub fn pop_undo(&mut self) -> Option<Snapshot> {
self.undo_stack.pop_back()
}
pub fn pop_redo(&mut self) -> Option<Snapshot> {
self.redo_stack.pop_back()
}
pub fn push_redo(&mut self, snapshot: Snapshot) {
self.redo_stack.push_back(snapshot);
}
pub fn push_undo(&mut self, snapshot: Snapshot) {
self.undo_stack.push_back(snapshot);
if self.undo_stack.len() > MAX_HISTORY_DEPTH {
self.undo_stack.pop_front();
}
}
pub fn can_undo(&self) -> bool {
!self.undo_stack.is_empty()
}
pub fn can_redo(&self) -> bool {
!self.redo_stack.is_empty()
}
pub fn clear(&mut self) {
self.undo_stack.clear();
self.redo_stack.clear();
}
pub fn suppress(&mut self) {
self.suppress_capture = true;
}
pub fn unsuppress(&mut self) {
self.suppress_capture = false;
}
pub fn undo_depth(&self) -> usize {
self.undo_stack.len()
}
pub fn redo_depth(&self) -> usize {
self.redo_stack.len()
}
}
impl Default for HistoryManager {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::DependencyGraph;
fn create_test_snapshot() -> Snapshot {
Snapshot {
boards: vec![],
columns: vec![],
cards: vec![],
archived_cards: vec![],
sprints: vec![],
graph: DependencyGraph::new(),
}
}
#[test]
fn test_basic_undo() {
let mut history = HistoryManager::new();
let snap = create_test_snapshot();
history.capture_before_command(snap);
assert!(history.can_undo());
assert!(!history.can_redo());
let restored = history.pop_undo();
assert!(restored.is_some());
assert!(!history.can_undo());
}
#[test]
fn test_basic_redo() {
let mut history = HistoryManager::new();
let snap = create_test_snapshot();
history.push_redo(snap);
assert!(history.can_redo());
let restored = history.pop_redo();
assert!(restored.is_some());
assert!(!history.can_redo());
}
#[test]
fn test_redo_cleared_on_new_action() {
let mut history = HistoryManager::new();
let snap1 = create_test_snapshot();
let snap2 = create_test_snapshot();
history.capture_before_command(snap1.clone());
history.push_redo(snap2);
assert!(history.can_redo());
history.capture_before_command(snap1);
assert!(!history.can_redo());
}
#[test]
fn test_suppress() {
let mut history = HistoryManager::new();
let snap = create_test_snapshot();
history.suppress();
history.capture_before_command(snap);
assert!(!history.can_undo());
history.unsuppress();
history.capture_before_command(create_test_snapshot());
assert!(history.can_undo());
}
#[test]
fn test_clear() {
let mut history = HistoryManager::new();
let snap = create_test_snapshot();
history.capture_before_command(snap.clone());
history.push_redo(snap);
assert!(history.can_undo());
assert!(history.can_redo());
history.clear();
assert!(!history.can_undo());
assert!(!history.can_redo());
}
#[test]
fn test_undo_stack_is_bounded() {
let mut history = HistoryManager::new();
for _ in 0..MAX_HISTORY_DEPTH + 50 {
history.capture_before_command(create_test_snapshot());
}
assert_eq!(history.undo_depth(), MAX_HISTORY_DEPTH);
}
#[test]
fn test_depth() {
let mut history = HistoryManager::new();
assert_eq!(history.undo_depth(), 0);
assert_eq!(history.redo_depth(), 0);
history.capture_before_command(create_test_snapshot());
history.capture_before_command(create_test_snapshot());
assert_eq!(history.undo_depth(), 2);
history.push_redo(create_test_snapshot());
assert_eq!(history.redo_depth(), 1);
}
}