ass_editor/commands/style_commands/
edit.rs1use crate::commands::{CommandResult, EditorCommand};
7use crate::core::{EditorDocument, EditorError, Position, Range, Result};
8
9#[cfg(not(feature = "std"))]
10use alloc::{
11 format,
12 string::{String, ToString},
13 vec::Vec,
14};
15
16#[cfg(feature = "std")]
17use std::collections::HashMap;
18
19#[cfg(not(feature = "std"))]
20use alloc::collections::BTreeMap as HashMap;
21
22#[derive(Debug, Clone)]
24pub struct EditStyleCommand {
25 pub style_name: String,
26 pub field_updates: HashMap<String, String>,
27 pub description: Option<String>,
28}
29
30impl EditStyleCommand {
31 pub fn new(style_name: String) -> Self {
33 Self {
34 style_name,
35 field_updates: HashMap::new(),
36 description: None,
37 }
38 }
39
40 pub fn set_field(mut self, field: &str, value: String) -> Self {
42 self.field_updates.insert(field.to_string(), value);
43 self
44 }
45
46 pub fn set_font(self, font: &str) -> Self {
48 self.set_field("Fontname", font.to_string())
49 }
50
51 pub fn set_size(self, size: u32) -> Self {
53 self.set_field("Fontsize", size.to_string())
54 }
55
56 pub fn set_color(self, color: &str) -> Self {
58 self.set_field("PrimaryColour", color.to_string())
59 }
60
61 pub fn set_bold(self, bold: bool) -> Self {
63 self.set_field("Bold", if bold { "-1" } else { "0" }.to_string())
64 }
65
66 pub fn set_italic(self, italic: bool) -> Self {
68 self.set_field("Italic", if italic { "-1" } else { "0" }.to_string())
69 }
70
71 pub fn set_alignment(self, alignment: u32) -> Self {
73 self.set_field("Alignment", alignment.to_string())
74 }
75
76 #[must_use]
78 pub fn with_description(mut self, description: String) -> Self {
79 self.description = Some(description);
80 self
81 }
82}
83
84impl EditorCommand for EditStyleCommand {
85 fn execute(&self, document: &mut EditorDocument) -> Result<CommandResult> {
86 let content = document.text();
87 let style_pattern = format!("Style: {}", self.style_name);
88
89 if let Some(style_start) = content.find(&style_pattern) {
90 let line_start = content[..style_start]
92 .rfind('\n')
93 .map(|pos| pos + 1)
94 .unwrap_or(0);
95 let line_end = content[style_start..]
96 .find('\n')
97 .map(|pos| style_start + pos)
98 .unwrap_or(content.len());
99
100 let style_line = &content[line_start..line_end];
101 let fields: Vec<&str> = style_line.split(',').collect();
102
103 if fields.len() < 2 {
104 return Err(EditorError::command_failed("Invalid style format"));
105 }
106
107 let styles_section_start = content[..line_start]
109 .rfind("[V4+ Styles]")
110 .or_else(|| content[..line_start].rfind("[V4 Styles]"))
111 .or_else(|| content[..line_start].rfind("[Styles]"))
112 .ok_or_else(|| EditorError::command_failed("Could not find styles section"))?;
113
114 let format_line_start = content[styles_section_start..]
115 .find("Format:")
116 .map(|pos| styles_section_start + pos)
117 .ok_or_else(|| EditorError::command_failed("Could not find format line"))?;
118
119 let format_line_end = content[format_line_start..]
120 .find('\n')
121 .map(|pos| format_line_start + pos)
122 .unwrap_or(content.len());
123
124 let format_line = &content[format_line_start..format_line_end];
125 let format_fields: Vec<&str> = format_line
126 .strip_prefix("Format: ")
127 .unwrap_or(format_line)
128 .split(", ")
129 .collect();
130
131 let mut updated_fields = fields
133 .iter()
134 .map(|f| f.to_string())
135 .collect::<Vec<String>>();
136
137 for (field_name, new_value) in &self.field_updates {
138 if let Some(field_index) = format_fields.iter().position(|f| f == field_name) {
139 if field_index < updated_fields.len() {
140 updated_fields[field_index] = new_value.clone();
141 }
142 }
143 }
144
145 let new_style_line = updated_fields.join(",");
146 let range = Range::new(Position::new(line_start), Position::new(line_end));
147
148 document.replace(range, &new_style_line)?;
149
150 let end_pos = Position::new(line_start + new_style_line.len());
151 Ok(CommandResult::success_with_change(
152 Range::new(Position::new(line_start), end_pos),
153 end_pos,
154 )
155 .with_message(format!("Updated style '{}'", self.style_name)))
156 } else {
157 Err(EditorError::command_failed(format!(
158 "Style '{}' not found",
159 self.style_name
160 )))
161 }
162 }
163
164 fn description(&self) -> &str {
165 self.description.as_deref().unwrap_or("Edit style")
166 }
167
168 fn memory_usage(&self) -> usize {
169 core::mem::size_of::<Self>()
170 + self.style_name.len()
171 + self
172 .field_updates
173 .iter()
174 .map(|(k, v)| k.len() + v.len())
175 .sum::<usize>()
176 + self.description.as_ref().map_or(0, |d| d.len())
177 }
178}