Skip to main content

ass_editor/core/document/
editing.rs

1//! Undo-aware text editing operations
2//!
3//! Public `insert`, `delete`, and `replace` methods that run the matching
4//! command, record the operation in the undo history, invalidate the
5//! validation cache, and emit document events.
6
7use super::EditorDocument;
8use crate::core::errors::Result;
9use crate::core::position::{Position, Range};
10
11#[cfg(feature = "std")]
12use crate::events::DocumentEvent;
13
14#[cfg(not(feature = "std"))]
15use alloc::string::ToString;
16
17impl EditorDocument {
18    /// Insert text at position with undo support
19    ///
20    /// Inserts text at the given position, automatically updating the underlying
21    /// text representation and recording the operation in the undo history.
22    ///
23    /// # Examples
24    ///
25    /// ```
26    /// use ass_editor::{EditorDocument, Position};
27    ///
28    /// let mut doc = EditorDocument::from_content("Hello World").unwrap();
29    /// let pos = Position::new(5); // Insert after "Hello"
30    /// doc.insert(pos, " there").unwrap();
31    ///
32    /// assert_eq!(doc.text(), "Hello there World");
33    ///
34    /// // Can undo the operation
35    /// doc.undo().unwrap();
36    /// assert_eq!(doc.text(), "Hello World");
37    /// ```
38    ///
39    /// # Errors
40    ///
41    /// Returns `Err` if the position is beyond the document bounds.
42    pub fn insert(&mut self, pos: Position, text: &str) -> Result<()> {
43        use crate::commands::{EditorCommand, InsertTextCommand};
44        use crate::core::history::Operation;
45
46        let command = InsertTextCommand::new(pos, text.to_string());
47        let result = command.execute(self)?;
48
49        // Record the operation in history
50        let operation = Operation::Insert {
51            position: pos,
52            text: text.to_string(),
53        };
54        self.history
55            .record_operation(operation, command.description().to_string(), &result);
56
57        // Clear validation cache since content changed
58        self.validator.clear_cache();
59
60        // Emit event
61        #[cfg(feature = "std")]
62        self.emit(DocumentEvent::TextInserted {
63            position: pos,
64            text: text.to_string(),
65            length: text.len(),
66        });
67
68        Ok(())
69    }
70
71    /// Delete text in range with undo support
72    pub fn delete(&mut self, range: Range) -> Result<()> {
73        use crate::commands::{DeleteTextCommand, EditorCommand};
74        use crate::core::history::Operation;
75
76        // Capture the text that will be deleted BEFORE deletion
77        let deleted_text = self.text_range(range)?;
78
79        let command = DeleteTextCommand::new(range);
80        let result = command.execute(self)?;
81
82        // Record the operation in history
83        let operation = Operation::Delete {
84            range,
85            deleted_text: deleted_text.clone(),
86        };
87        self.history
88            .record_operation(operation, command.description().to_string(), &result);
89
90        // Clear validation cache since content changed
91        self.validator.clear_cache();
92
93        // Emit event
94        #[cfg(feature = "std")]
95        self.emit(DocumentEvent::TextDeleted {
96            range,
97            deleted_text,
98        });
99
100        Ok(())
101    }
102
103    /// Replace text in range with undo support
104    pub fn replace(&mut self, range: Range, text: &str) -> Result<()> {
105        use crate::commands::{EditorCommand, ReplaceTextCommand};
106        use crate::core::history::Operation;
107
108        // Capture the old text BEFORE replacement
109        let old_text = self.text_range(range)?;
110
111        let command = ReplaceTextCommand::new(range, text.to_string());
112        let result = command.execute(self)?;
113
114        // Record the operation in history
115        let operation = Operation::Replace {
116            range,
117            old_text: old_text.clone(),
118            new_text: text.to_string(),
119        };
120        self.history
121            .record_operation(operation, command.description().to_string(), &result);
122
123        // Clear validation cache since content changed
124        self.validator.clear_cache();
125
126        // Emit event
127        #[cfg(feature = "std")]
128        self.emit(DocumentEvent::TextReplaced {
129            range,
130            old_text,
131            new_text: text.to_string(),
132        });
133
134        Ok(())
135    }
136}