ftui_runtime/undo/mod.rs
1#![forbid(unsafe_code)]
2
3//! Undo/Redo command history framework.
4//!
5//! This module provides infrastructure for reversible operations in FrankenTUI
6//! applications. It implements the Command Pattern with support for:
7//!
8//! - **Reversibility**: Every command can be undone and redone
9//! - **Merging**: Consecutive similar commands batch together (e.g., typing)
10//! - **Memory management**: Commands report size for bounded history
11//! - **Batching**: Multiple commands group into atomic operations
12//!
13//! # Architecture
14//!
15//! ```text
16//! ┌─────────────────────────────────────────────────────────────────┐
17//! │ UndoStack │
18//! │ ┌──────────────────┐ ┌──────────────────┐ │
19//! │ │ Undo Stack │ │ Redo Stack │ │
20//! │ │ ┌────────────┐ │ │ ┌────────────┐ │ │
21//! │ │ │ CommandN │ │ undo() │ │ Command1 │ │ │
22//! │ │ ├────────────┤ │ ──────► │ ├────────────┤ │ │
23//! │ │ │ Command2 │ │ │ │ Command2 │ │ │
24//! │ │ ├────────────┤ │ ◄────── │ ├────────────┤ │ │
25//! │ │ │ Command1 │ │ redo() │ │ CommandN │ │ │
26//! │ │ └────────────┘ │ │ └────────────┘ │ │
27//! │ └──────────────────┘ └──────────────────┘ │
28//! └─────────────────────────────────────────────────────────────────┘
29//! ```
30//!
31//! # Quick Start
32//!
33//! ```ignore
34//! use ftui_runtime::undo::{UndoableCmd, CommandMetadata, TextInsertCmd, WidgetId};
35//!
36//! // Create a command
37//! let cmd = TextInsertCmd::new(WidgetId::new(1), 0, "Hello")
38//! .with_apply(|id, pos, text| {
39//! // Apply the insertion
40//! Ok(())
41//! })
42//! .with_remove(|id, pos, len| {
43//! // Remove the insertion
44//! Ok(())
45//! });
46//!
47//! // Execute the command
48//! cmd.execute()?;
49//!
50//! // Later, undo it
51//! cmd.undo()?;
52//! ```
53//!
54//! # Module Structure
55//!
56//! - [`command`]: Core `UndoableCmd` trait and built-in commands
57//!
58//! # Design Notes
59//!
60//! ## Why Commands Store Callbacks
61//!
62//! Commands need to interact with widget state, but we can't store references
63//! to widgets (lifetime issues). Instead, commands store callbacks that are
64//! set by the widget when the command is created. This allows:
65//!
66//! 1. Commands to be stored in history (owned, not borrowed)
67//! 2. Widgets to control how operations are applied
68//! 3. Commands to work with any widget implementation
69//!
70//! ## Merge Strategy
71//!
72//! Command merging reduces memory usage and makes undo more natural:
73//!
74//! - Typing "hello" creates 5 insert commands
75//! - Merged, they become 1 command that inserts "hello"
76//! - Undo removes "hello" in one step (more intuitive)
77//!
78//! Merge decisions use:
79//! - Time window (500ms default)
80//! - Word boundaries (optional)
81//! - Size limits (prevent unbounded growth)
82//!
83//! ## Memory Budget
84//!
85//! Every command reports its size via `size_bytes()`. The undo stack uses
86//! this to enforce memory limits:
87//!
88//! - Default: 10MB history
89//! - Oldest commands evicted when limit exceeded
90//! - Commands can estimate or measure their size
91
92pub mod command;
93pub mod history;
94pub mod transaction;
95
96// Re-export commonly used types
97pub use command::{
98 CommandBatch, CommandError, CommandMetadata, CommandResult, CommandSource, MergeConfig,
99 TextDeleteCmd, TextInsertCmd, TextReplaceCmd, UndoableCmd, WidgetId,
100};
101pub use history::{HistoryConfig, HistoryManager};
102pub use transaction::{Transaction, TransactionScope};