Push the current state onto the undo stack before an edit. `kind` controls grouping: consecutive edits of the same kind are merged (only InsertChar, Backspace, and Delete are grouped).
(&mut self, kind: UndoActionKind)
| 398 | /// `kind` controls grouping: consecutive edits of the same kind are merged |
| 399 | /// (only InsertChar, Backspace, and Delete are grouped). |
| 400 | pub fn push_undo(&mut self, kind: UndoActionKind) { |
| 401 | // Grouping: if the last undo entry has the same kind and it's a groupable kind, |
| 402 | // don't push a new entry (the original pre-group state is already saved). |
| 403 | let should_group = matches!(kind, UndoActionKind::InsertChar | UndoActionKind::Backspace | UndoActionKind::Delete); |
| 404 | if should_group { |
| 405 | if let Some(last) = self.undo_stack.last() { |
| 406 | if last.action_kind == kind { |
| 407 | // Same groupable action — skip push, keep the original entry |
| 408 | // Clear redo stack since we're making a new edit |
| 409 | self.redo_stack.clear(); |
| 410 | return; |
| 411 | } |
| 412 | } |
| 413 | } |
| 414 | |
| 415 | self.undo_stack.push(UndoEntry { |
| 416 | text: self.text.clone(), |
| 417 | cursor_pos: self.cursor_pos, |
| 418 | selection_anchor: self.selection_anchor, |
| 419 | action_kind: kind, |
| 420 | }); |
| 421 | // Limit stack size |
| 422 | if self.undo_stack.len() > MAX_UNDO_STACK { |
| 423 | self.undo_stack.remove(0); |
| 424 | } |
| 425 | // Any new edit clears the redo stack |
| 426 | self.redo_stack.clear(); |
| 427 | } |
| 428 | |
| 429 | /// Undo the last edit. Returns true if undo was performed. |
| 430 | pub fn undo(&mut self) -> bool { |