Skip to main content

ass_editor/commands/
text_commands.rs

1//! Primitive text-editing commands: insert, delete, and replace.
2
3use crate::core::{EditorDocument, Position, Range, Result};
4
5use super::{CommandResult, EditorCommand};
6
7#[cfg(not(feature = "std"))]
8use alloc::string::String;
9
10/// Text insertion command
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct InsertTextCommand {
13    /// Position to insert text at
14    pub position: Position,
15    /// Text to insert
16    pub text: String,
17    /// Optional description override
18    pub description: Option<String>,
19}
20
21impl InsertTextCommand {
22    /// Create a new insert text command
23    ///
24    /// # Examples
25    ///
26    /// ```
27    /// use ass_editor::{InsertTextCommand, EditorDocument, Position, EditorCommand};
28    ///
29    /// let mut doc = EditorDocument::new();
30    /// let command = InsertTextCommand::new(Position::new(0), "Hello World".to_string());
31    ///
32    /// let result = command.execute(&mut doc).unwrap();
33    /// assert!(result.success);
34    /// assert_eq!(doc.text(), "Hello World");
35    /// ```
36    pub fn new(position: Position, text: String) -> Self {
37        Self {
38            position,
39            text,
40            description: None,
41        }
42    }
43
44    /// Set a custom description for this command
45    #[must_use]
46    pub fn with_description(mut self, description: String) -> Self {
47        self.description = Some(description);
48        self
49    }
50}
51
52impl EditorCommand for InsertTextCommand {
53    fn execute(&self, document: &mut EditorDocument) -> Result<CommandResult> {
54        document.insert_raw(self.position, &self.text)?;
55
56        let end_pos = Position::new(self.position.offset + self.text.len());
57        let range = Range::new(self.position, end_pos);
58
59        Ok(CommandResult::success_with_change(range, end_pos))
60    }
61
62    fn description(&self) -> &str {
63        self.description.as_deref().unwrap_or("Insert text")
64    }
65
66    fn memory_usage(&self) -> usize {
67        core::mem::size_of::<Self>()
68            + self.text.len()
69            + self.description.as_ref().map_or(0, |d| d.len())
70    }
71}
72
73/// Text deletion command
74#[derive(Debug, Clone, PartialEq, Eq)]
75pub struct DeleteTextCommand {
76    /// Range of text to delete
77    pub range: Range,
78    /// Optional description override
79    pub description: Option<String>,
80}
81
82impl DeleteTextCommand {
83    /// Create a new delete text command
84    pub fn new(range: Range) -> Self {
85        Self {
86            range,
87            description: None,
88        }
89    }
90
91    /// Set a custom description for this command
92    #[must_use]
93    pub fn with_description(mut self, description: String) -> Self {
94        self.description = Some(description);
95        self
96    }
97}
98
99impl EditorCommand for DeleteTextCommand {
100    fn execute(&self, document: &mut EditorDocument) -> Result<CommandResult> {
101        document.delete_raw(self.range)?;
102
103        let cursor_pos = self.range.start;
104        let range = Range::new(self.range.start, self.range.start);
105
106        Ok(CommandResult::success_with_change(range, cursor_pos))
107    }
108
109    fn description(&self) -> &str {
110        self.description.as_deref().unwrap_or("Delete text")
111    }
112}
113
114/// Text replacement command
115#[derive(Debug, Clone, PartialEq, Eq)]
116pub struct ReplaceTextCommand {
117    /// Range of text to replace
118    pub range: Range,
119    /// New text to insert
120    pub new_text: String,
121    /// Optional description override
122    pub description: Option<String>,
123}
124
125impl ReplaceTextCommand {
126    /// Create a new replace text command
127    pub fn new(range: Range, new_text: String) -> Self {
128        Self {
129            range,
130            new_text,
131            description: None,
132        }
133    }
134
135    /// Set a custom description for this command
136    #[must_use]
137    pub fn with_description(mut self, description: String) -> Self {
138        self.description = Some(description);
139        self
140    }
141}
142
143impl EditorCommand for ReplaceTextCommand {
144    fn execute(&self, document: &mut EditorDocument) -> Result<CommandResult> {
145        document.replace_raw(self.range, &self.new_text)?;
146
147        let end_pos = Position::new(self.range.start.offset + self.new_text.len());
148        let range = Range::new(self.range.start, end_pos);
149
150        Ok(CommandResult::success_with_change(range, end_pos))
151    }
152
153    fn description(&self) -> &str {
154        self.description.as_deref().unwrap_or("Replace text")
155    }
156
157    fn memory_usage(&self) -> usize {
158        core::mem::size_of::<Self>()
159            + self.new_text.len()
160            + self.description.as_ref().map_or(0, |d| d.len())
161    }
162}