Skip to main content

ass_editor/commands/event_commands/
batch_delete.rs

1//! Command to delete multiple events from an ASS document.
2
3use super::helpers::collect_event_lines;
4use crate::commands::{CommandResult, EditorCommand};
5use crate::core::{EditorDocument, Position, Range, Result};
6
7#[cfg(not(feature = "std"))]
8use alloc::{string::ToString, vec::Vec};
9
10/// Command to delete multiple events from the ASS document
11///
12/// Removes multiple events (Dialogue or Comment) at the specified indices from the `[Events]` section.
13/// Indices are automatically sorted and processed in reverse order to maintain correctness.
14/// All indices are 0-based and include both Dialogue and Comment events.
15#[derive(Debug, Clone, PartialEq, Eq)]
16pub struct BatchDeleteEventsCommand {
17    /// Indices of events to delete (will be sorted and deduplicated)
18    pub event_indices: Vec<usize>,
19}
20
21impl BatchDeleteEventsCommand {
22    /// Create a new batch delete events command
23    pub fn new(event_indices: Vec<usize>) -> Self {
24        Self { event_indices }
25    }
26}
27
28impl EditorCommand for BatchDeleteEventsCommand {
29    fn execute(&self, document: &mut EditorDocument) -> Result<CommandResult> {
30        if self.event_indices.is_empty() {
31            return Ok(CommandResult::success());
32        }
33
34        // Sort indices in descending order to delete from end to start
35        // This prevents index shifting issues
36        let mut sorted_indices = self.event_indices.clone();
37        sorted_indices.sort_unstable_by(|a, b| b.cmp(a));
38        sorted_indices.dedup();
39
40        let content = document.text();
41        let event_positions = collect_event_lines(&content)?;
42
43        // Delete events in reverse order to avoid index shifting
44        let mut total_deleted = 0;
45        let mut first_delete_pos = Position::new(content.len());
46
47        for index in &sorted_indices {
48            if let Some(event_line) = event_positions
49                .iter()
50                .find(|event_line| event_line.index == *index)
51            {
52                let range = Range::new(
53                    Position::new(event_line.start),
54                    Position::new(event_line.end_with_newline),
55                );
56                document.delete(range)?;
57                total_deleted += 1;
58
59                // Track the earliest deletion position
60                if range.start.offset < first_delete_pos.offset {
61                    first_delete_pos = range.start;
62                }
63            }
64        }
65
66        if total_deleted > 0 {
67            Ok(CommandResult::success_with_change(
68                Range::new(first_delete_pos, first_delete_pos),
69                first_delete_pos,
70            ))
71        } else {
72            Ok(CommandResult::success())
73        }
74    }
75
76    fn description(&self) -> &str {
77        "Delete multiple events"
78    }
79
80    fn memory_usage(&self) -> usize {
81        core::mem::size_of::<Self>() + self.event_indices.len() * core::mem::size_of::<usize>()
82    }
83}