ass_editor/commands/
batch_command.rs1use crate::core::{EditorDocument, Position, Range, Result};
4
5use super::{CommandResult, EditorCommand};
6
7#[cfg(not(feature = "std"))]
8use alloc::{boxed::Box, format, string::String, vec::Vec};
9
10#[derive(Debug)]
12pub struct BatchCommand {
13 pub commands: Vec<Box<dyn EditorCommand>>,
15 pub description: String,
17}
18
19impl BatchCommand {
20 pub fn new(description: String) -> Self {
38 Self {
39 commands: Vec::new(),
40 description,
41 }
42 }
43
44 pub fn add_command(mut self, command: Box<dyn EditorCommand>) -> Self {
46 self.commands.push(command);
47 self
48 }
49
50 pub fn add_commands(mut self, commands: Vec<Box<dyn EditorCommand>>) -> Self {
52 self.commands.extend(commands);
53 self
54 }
55}
56
57impl EditorCommand for BatchCommand {
58 fn execute(&self, document: &mut EditorDocument) -> Result<CommandResult> {
59 let mut overall_result = CommandResult::success();
60 let mut first_range: Option<Range> = None;
61 let mut last_cursor: Option<Position> = None;
62
63 for command in &self.commands {
64 let result = command.execute(document)?;
65
66 if !result.success {
67 return Ok(CommandResult::failure(format!(
68 "Batch command failed at: {}",
69 command.description()
70 )));
71 }
72
73 if let Some(range) = result.modified_range {
75 first_range = Some(match first_range {
76 Some(existing) => existing.union(&range),
77 None => range,
78 });
79 }
80
81 if result.new_cursor.is_some() {
82 last_cursor = result.new_cursor;
83 }
84
85 if result.content_changed {
86 overall_result.content_changed = true;
87 }
88 }
89
90 overall_result.modified_range = first_range;
91 overall_result.new_cursor = last_cursor;
92
93 Ok(overall_result)
94 }
95
96 fn description(&self) -> &str {
97 &self.description
98 }
99
100 fn memory_usage(&self) -> usize {
101 core::mem::size_of::<Self>()
102 + self.description.len()
103 + self
104 .commands
105 .iter()
106 .map(|c| c.memory_usage())
107 .sum::<usize>()
108 }
109}