ass_editor/commands/fonts_graphics_commands/
add.rs1use super::uuencode_data;
4use crate::commands::{CommandResult, EditorCommand};
5use crate::core::{EditorDocument, Position, Range, Result};
6
7#[cfg(not(feature = "std"))]
8use alloc::{
9 format,
10 string::{String, ToString},
11 vec::Vec,
12};
13
14#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct AddFontCommand {
20 pub filename: String,
22 pub data_lines: Vec<String>,
24}
25
26impl AddFontCommand {
27 pub fn new(filename: String, data_lines: Vec<String>) -> Self {
29 Self {
30 filename,
31 data_lines,
32 }
33 }
34
35 pub fn from_binary(filename: String, data: &[u8]) -> Self {
37 let encoded = uuencode_data(&filename, data);
38 Self {
39 filename,
40 data_lines: encoded,
41 }
42 }
43}
44
45impl EditorCommand for AddFontCommand {
46 fn execute(&self, document: &mut EditorDocument) -> Result<CommandResult> {
47 let content = document.text().to_string();
48
49 let fonts_section = content.find("[Fonts]");
51
52 let insert_pos = if let Some(section_start) = fonts_section {
53 content[section_start..]
55 .find("\n[")
56 .map(|pos| section_start + pos)
57 .unwrap_or(content.len())
58 } else {
59 let mut insert_pos = content.len();
61
62 if !content.ends_with('\n') {
64 document.insert_raw(Position::new(insert_pos), "\n")?;
65 insert_pos += 1;
66 }
67
68 document.insert_raw(Position::new(insert_pos), "[Fonts]\n")?;
70 insert_pos + "[Fonts]\n".len()
71 };
72
73 let filename = &self.filename;
75 let mut font_entry = format!("fontname: {filename}\n");
76 for line in &self.data_lines {
77 font_entry.push_str(line);
78 font_entry.push('\n');
79 }
80
81 document.insert_raw(Position::new(insert_pos), &font_entry)?;
83
84 Ok(CommandResult::success_with_change(
85 Range::new(
86 Position::new(insert_pos),
87 Position::new(insert_pos + font_entry.len()),
88 ),
89 Position::new(insert_pos + font_entry.len()),
90 ))
91 }
92
93 fn description(&self) -> &str {
94 "Add font"
95 }
96
97 fn memory_usage(&self) -> usize {
98 core::mem::size_of::<Self>()
99 + self.filename.len()
100 + self.data_lines.iter().map(|l| l.len()).sum::<usize>()
101 }
102}
103
104#[derive(Debug, Clone, PartialEq, Eq)]
109pub struct AddGraphicCommand {
110 pub filename: String,
112 pub data_lines: Vec<String>,
114}
115
116impl AddGraphicCommand {
117 pub fn new(filename: String, data_lines: Vec<String>) -> Self {
119 Self {
120 filename,
121 data_lines,
122 }
123 }
124
125 pub fn from_binary(filename: String, data: &[u8]) -> Self {
127 let encoded = uuencode_data(&filename, data);
128 Self {
129 filename,
130 data_lines: encoded,
131 }
132 }
133}
134
135impl EditorCommand for AddGraphicCommand {
136 fn execute(&self, document: &mut EditorDocument) -> Result<CommandResult> {
137 let content = document.text().to_string();
138
139 let graphics_section = content.find("[Graphics]");
141
142 let insert_pos = if let Some(section_start) = graphics_section {
143 content[section_start..]
145 .find("\n[")
146 .map(|pos| section_start + pos)
147 .unwrap_or(content.len())
148 } else {
149 let mut insert_pos = content.len();
151
152 if !content.ends_with('\n') {
154 document.insert_raw(Position::new(insert_pos), "\n")?;
155 insert_pos += 1;
156 }
157
158 document.insert_raw(Position::new(insert_pos), "[Graphics]\n")?;
160 insert_pos + "[Graphics]\n".len()
161 };
162
163 let filename = &self.filename;
165 let mut graphic_entry = format!("filename: {filename}\n");
166 for line in &self.data_lines {
167 graphic_entry.push_str(line);
168 graphic_entry.push('\n');
169 }
170
171 document.insert_raw(Position::new(insert_pos), &graphic_entry)?;
173
174 Ok(CommandResult::success_with_change(
175 Range::new(
176 Position::new(insert_pos),
177 Position::new(insert_pos + graphic_entry.len()),
178 ),
179 Position::new(insert_pos + graphic_entry.len()),
180 ))
181 }
182
183 fn description(&self) -> &str {
184 "Add graphic"
185 }
186
187 fn memory_usage(&self) -> usize {
188 core::mem::size_of::<Self>()
189 + self.filename.len()
190 + self.data_lines.iter().map(|l| l.len()).sum::<usize>()
191 }
192}