-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathundo_manager.py
More file actions
158 lines (122 loc) · 5.32 KB
/
undo_manager.py
File metadata and controls
158 lines (122 loc) · 5.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
"""
Undo/Redo stack manager for text operations.
Provides full history management with state restoration.
"""
from typing import List, Optional, Any, Dict
from dataclasses import dataclass
from copy import deepcopy
@dataclass
class HistoryState:
"""Represents a state in the undo/redo history."""
text: str
operation_description: str
timestamp: float
metadata: dict = None
def __post_init__(self):
if self.metadata is None:
self.metadata = {}
class UndoRedoManager:
"""Manages undo/redo functionality for text operations."""
def __init__(self, max_history: int = 100):
self.max_history = max_history
self.undo_stack: List[HistoryState] = []
self.redo_stack: List[HistoryState] = []
self.current_state: Optional[HistoryState] = None
def push_state(self, text: str, description: str = "", metadata: dict = None):
"""Push a new state onto the undo stack."""
import time
state = HistoryState(
text=text,
operation_description=description,
timestamp=time.time(),
metadata=metadata or {}
)
if self.current_state is not None:
self.undo_stack.append(self.current_state)
# Limit stack size
if len(self.undo_stack) > self.max_history:
self.undo_stack.pop(0)
self.current_state = state
self.redo_stack.clear() # Clear redo stack when new state is pushed
def can_undo(self) -> bool:
"""Check if undo is available."""
return len(self.undo_stack) > 0
def can_redo(self) -> bool:
"""Check if redo is available."""
return len(self.redo_stack) > 0
def undo(self) -> Optional[HistoryState]:
"""Undo to the previous state."""
if not self.can_undo():
return None
if self.current_state is not None:
self.redo_stack.append(self.current_state)
self.current_state = self.undo_stack.pop()
return self.current_state
def redo(self) -> Optional[HistoryState]:
"""Redo to the next state."""
if not self.can_redo():
return None
if self.current_state is not None:
self.undo_stack.append(self.current_state)
self.current_state = self.redo_stack.pop()
return self.current_state
def get_current_state(self) -> Optional[HistoryState]:
"""Get the current state."""
return self.current_state
def clear(self):
"""Clear all history."""
self.undo_stack.clear()
self.redo_stack.clear()
self.current_state = None
def get_undo_history(self) -> List[str]:
"""Get list of undo descriptions."""
return [state.operation_description for state in reversed(self.undo_stack)]
def get_redo_history(self) -> List[str]:
"""Get list of redo descriptions."""
return [state.operation_description for state in reversed(self.redo_stack)]
def get_history_size(self) -> int:
"""Get total number of states in history."""
return len(self.undo_stack) + len(self.redo_stack) + (1 if self.current_state else 0)
class MultiFileHistoryManager:
"""Manages undo/redo for multiple files."""
def __init__(self, max_history: int = 100):
self.max_history = max_history
self.file_managers: Dict[str, UndoRedoManager] = {}
def get_manager(self, file_path: str) -> UndoRedoManager:
"""Get or create an undo/redo manager for a specific file."""
if file_path not in self.file_managers:
self.file_managers[file_path] = UndoRedoManager(self.max_history)
return self.file_managers[file_path]
def push_state(self, file_path: str, text: str, description: str = "", metadata: dict = None):
"""Push a state for a specific file."""
manager = self.get_manager(file_path)
manager.push_state(text, description, metadata)
def undo(self, file_path: str) -> Optional[HistoryState]:
"""Undo for a specific file."""
if file_path in self.file_managers:
return self.file_managers[file_path].undo()
return None
def redo(self, file_path: str) -> Optional[HistoryState]:
"""Redo for a specific file."""
if file_path in self.file_managers:
return self.file_managers[file_path].redo()
return None
def can_undo(self, file_path: str) -> bool:
"""Check if undo is available for a file."""
if file_path in self.file_managers:
return self.file_managers[file_path].can_undo()
return False
def can_redo(self, file_path: str) -> bool:
"""Check if redo is available for a file."""
if file_path in self.file_managers:
return self.file_managers[file_path].can_redo()
return False
def clear_file(self, file_path: str):
"""Clear history for a specific file."""
if file_path in self.file_managers:
self.file_managers[file_path].clear()
def clear_all(self):
"""Clear all file histories."""
for manager in self.file_managers.values():
manager.clear()
self.file_managers.clear()