Skip to main content

ass_editor/commands/fonts_graphics_commands/
remove.rs

1//! Commands for removing embedded fonts and graphics from ASS documents
2
3use crate::commands::{CommandResult, EditorCommand};
4use crate::core::{EditorDocument, EditorError, Position, Range, Result};
5
6#[cfg(not(feature = "std"))]
7use alloc::{
8    format,
9    string::{String, ToString},
10};
11
12/// Command to remove an embedded font from the ASS document
13///
14/// Removes a font by filename from the `[Fonts]` section.
15#[derive(Debug, Clone, PartialEq, Eq)]
16pub struct RemoveFontCommand {
17    /// Font filename to remove
18    pub filename: String,
19}
20
21impl RemoveFontCommand {
22    /// Create a new remove font command
23    pub fn new(filename: String) -> Self {
24        Self { filename }
25    }
26}
27
28impl EditorCommand for RemoveFontCommand {
29    fn execute(&self, document: &mut EditorDocument) -> Result<CommandResult> {
30        let content = document.text().to_string();
31
32        // Find [Fonts] section
33        let fonts_section = content
34            .find("[Fonts]")
35            .ok_or_else(|| EditorError::command_failed("No [Fonts] section found"))?;
36
37        // Find the end of the Fonts section
38        let section_end = content[fonts_section..]
39            .find("\n[")
40            .map(|pos| fonts_section + pos)
41            .unwrap_or(content.len());
42
43        // Look for the font entry
44        let filename = &self.filename;
45        let search_pattern = format!("fontname: {filename}");
46        let section_content = &content[fonts_section..section_end];
47
48        if let Some(font_pos) = section_content.find(&search_pattern) {
49            let absolute_pos = fonts_section + font_pos;
50
51            // Find the end of this font's data (next fontname: or section end)
52            let font_end = content[absolute_pos..]
53                .find("\nfontname:")
54                .map(|pos| absolute_pos + pos)
55                .unwrap_or(section_end);
56
57            let range = Range::new(Position::new(absolute_pos), Position::new(font_end));
58            document.delete(range)?;
59
60            Ok(CommandResult::success_with_change(
61                Range::new(Position::new(absolute_pos), Position::new(absolute_pos)),
62                Position::new(absolute_pos),
63            ))
64        } else {
65            Ok(CommandResult::success())
66        }
67    }
68
69    fn description(&self) -> &str {
70        "Remove font"
71    }
72
73    fn memory_usage(&self) -> usize {
74        core::mem::size_of::<Self>() + self.filename.len()
75    }
76}
77
78/// Command to remove an embedded graphic from the ASS document
79///
80/// Removes a graphic by filename from the `[Graphics]` section.
81#[derive(Debug, Clone, PartialEq, Eq)]
82pub struct RemoveGraphicCommand {
83    /// Graphic filename to remove
84    pub filename: String,
85}
86
87impl RemoveGraphicCommand {
88    /// Create a new remove graphic command
89    pub fn new(filename: String) -> Self {
90        Self { filename }
91    }
92}
93
94impl EditorCommand for RemoveGraphicCommand {
95    fn execute(&self, document: &mut EditorDocument) -> Result<CommandResult> {
96        let content = document.text().to_string();
97
98        // Find [Graphics] section
99        let graphics_section = content
100            .find("[Graphics]")
101            .ok_or_else(|| EditorError::command_failed("No [Graphics] section found"))?;
102
103        // Find the end of the Graphics section
104        let section_end = content[graphics_section..]
105            .find("\n[")
106            .map(|pos| graphics_section + pos)
107            .unwrap_or(content.len());
108
109        // Look for the graphic entry
110        let filename = &self.filename;
111        let search_pattern = format!("filename: {filename}");
112        let section_content = &content[graphics_section..section_end];
113
114        if let Some(graphic_pos) = section_content.find(&search_pattern) {
115            let absolute_pos = graphics_section + graphic_pos;
116
117            // Find the end of this graphic's data (next filename: or section end)
118            let graphic_end = content[absolute_pos..]
119                .find("\nfilename:")
120                .map(|pos| absolute_pos + pos)
121                .unwrap_or(section_end);
122
123            let range = Range::new(Position::new(absolute_pos), Position::new(graphic_end));
124            document.delete(range)?;
125
126            Ok(CommandResult::success_with_change(
127                Range::new(Position::new(absolute_pos), Position::new(absolute_pos)),
128                Position::new(absolute_pos),
129            ))
130        } else {
131            Ok(CommandResult::success())
132        }
133    }
134
135    fn description(&self) -> &str {
136        "Remove graphic"
137    }
138
139    fn memory_usage(&self) -> usize {
140        core::mem::size_of::<Self>() + self.filename.len()
141    }
142}