ass_editor/commands/karaoke_commands/
split.rs1use crate::commands::{CommandResult, EditorCommand};
4use crate::core::{EditorDocument, Position, Range, Result};
5
6#[cfg(not(feature = "std"))]
7use alloc::{format, string::String, vec::Vec};
8
9#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct SplitKaraokeCommand {
12 pub range: Range,
14 pub split_positions: Vec<usize>,
16 pub new_duration: Option<u32>,
18}
19
20impl SplitKaraokeCommand {
21 pub fn new(range: Range, split_positions: Vec<usize>) -> Self {
23 Self {
24 range,
25 split_positions,
26 new_duration: None,
27 }
28 }
29
30 #[must_use]
32 pub fn duration(mut self, duration: u32) -> Self {
33 self.new_duration = Some(duration);
34 self
35 }
36}
37
38impl EditorCommand for SplitKaraokeCommand {
39 fn execute(&self, document: &mut EditorDocument) -> Result<CommandResult> {
40 let original_text = document.text_range(self.range)?;
41 let processed_text = self.split_karaoke_text(&original_text)?;
42
43 document.replace_raw(self.range, &processed_text)?;
44
45 let end_pos = Position::new(self.range.start.offset + processed_text.len());
46 let range = Range::new(self.range.start, end_pos);
47
48 Ok(CommandResult::success_with_change(range, end_pos))
49 }
50
51 fn description(&self) -> &str {
52 "Split karaoke timing"
53 }
54
55 fn memory_usage(&self) -> usize {
56 core::mem::size_of::<Self>() + self.split_positions.len() * core::mem::size_of::<usize>()
57 }
58}
59
60impl SplitKaraokeCommand {
61 fn split_karaoke_text(&self, text: &str) -> Result<String> {
63 let mut result = String::new();
66 let mut last_pos = 0;
67
68 for &pos in &self.split_positions {
69 if pos <= last_pos || pos >= text.len() {
70 continue;
71 }
72
73 let segment = &text[last_pos..pos];
74 if !segment.is_empty() {
75 let duration = self.new_duration.unwrap_or(50);
76 result.push_str(&format!("{{\\k{duration}}}{segment}"));
77 }
78 last_pos = pos;
79 }
80
81 if last_pos < text.len() {
83 let segment = &text[last_pos..];
84 if !segment.is_empty() {
85 let duration = self.new_duration.unwrap_or(50);
86 result.push_str(&format!("{{\\k{duration}}}{segment}"));
87 }
88 }
89
90 Ok(result)
91 }
92}