Skip to main content

ass_editor/commands/
fluent_builder.rs

1//! Fluent builder API (`TextCommand`) and the `DocumentCommandExt` trait.
2
3use crate::core::{EditorDocument, EditorError, Position, Range, Result};
4
5use super::{
6    CommandResult, DeleteTextCommand, EditorCommand, InsertTextCommand, ReplaceTextCommand,
7};
8
9#[cfg(not(feature = "std"))]
10use alloc::string::ToString;
11
12/// Fluent API builder for creating and executing commands
13///
14/// Provides an ergonomic way to build and execute commands:
15/// ```
16/// use ass_editor::{EditorDocument, Position, TextCommand};
17///
18/// let mut doc = EditorDocument::from_content("Hello world!").unwrap();
19/// let position = Position::new(5);
20///
21/// let result = TextCommand::new(&mut doc)
22///     .at(position)
23///     .insert(" beautiful")
24///     .unwrap();
25///
26/// assert_eq!(doc.text(), "Hello beautiful world!");
27/// ```
28pub struct TextCommand<'a> {
29    document: &'a mut EditorDocument,
30    position: Option<Position>,
31    range: Option<Range>,
32}
33
34impl<'a> TextCommand<'a> {
35    /// Create a new text command builder
36    pub fn new(document: &'a mut EditorDocument) -> Self {
37        Self {
38            document,
39            position: None,
40            range: None,
41        }
42    }
43
44    /// Set the position for the operation
45    #[must_use]
46    pub fn at(mut self, position: Position) -> Self {
47        self.position = Some(position);
48        self
49    }
50
51    /// Set the range for the operation
52    #[must_use]
53    pub fn range(mut self, range: Range) -> Self {
54        self.range = Some(range);
55        self
56    }
57
58    /// Insert text at the current position
59    pub fn insert(self, text: &str) -> Result<CommandResult> {
60        let position = self
61            .position
62            .ok_or_else(|| EditorError::command_failed("Position not set for insert operation"))?;
63
64        let command = InsertTextCommand::new(position, text.to_string());
65        command.execute(self.document)
66    }
67
68    /// Delete text in the current range
69    pub fn delete(self) -> Result<CommandResult> {
70        let range = self
71            .range
72            .ok_or_else(|| EditorError::command_failed("Range not set for delete operation"))?;
73
74        let command = DeleteTextCommand::new(range);
75        command.execute(self.document)
76    }
77
78    /// Replace text in the current range
79    pub fn replace(self, new_text: &str) -> Result<CommandResult> {
80        let range = self
81            .range
82            .ok_or_else(|| EditorError::command_failed("Range not set for replace operation"))?;
83
84        let command = ReplaceTextCommand::new(range, new_text.to_string());
85        command.execute(self.document)
86    }
87}
88
89// Extension trait to add fluent command methods to EditorDocument
90pub trait DocumentCommandExt {
91    /// Start a fluent command chain
92    fn command(&mut self) -> TextCommand<'_>;
93
94    /// Quick insert at position
95    fn insert_at(&mut self, position: Position, text: &str) -> Result<CommandResult>;
96
97    /// Quick delete range
98    fn delete_range(&mut self, range: Range) -> Result<CommandResult>;
99
100    /// Quick replace range
101    fn replace_range(&mut self, range: Range, text: &str) -> Result<CommandResult>;
102}
103
104impl DocumentCommandExt for EditorDocument {
105    fn command(&mut self) -> TextCommand<'_> {
106        TextCommand::new(self)
107    }
108
109    fn insert_at(&mut self, position: Position, text: &str) -> Result<CommandResult> {
110        let command = InsertTextCommand::new(position, text.to_string());
111        command.execute(self)
112    }
113
114    fn delete_range(&mut self, range: Range) -> Result<CommandResult> {
115        let command = DeleteTextCommand::new(range);
116        command.execute(self)
117    }
118
119    fn replace_range(&mut self, range: Range, text: &str) -> Result<CommandResult> {
120        let command = ReplaceTextCommand::new(range, text.to_string());
121        command.execute(self)
122    }
123}