use super::EditorDocument;
use crate::commands::CommandResult;
use crate::core::errors::{EditorError, Result};
use crate::core::position::{Position, Range};
use ass_core::parser::ast::Section;
use ass_core::parser::script::ScriptDeltaOwned;
use ass_core::parser::Script;
#[cfg(not(feature = "std"))]
use alloc::string::ToString;
impl EditorDocument {
pub fn apply_script_delta(&mut self, delta: ScriptDeltaOwned) -> Result<()> {
use crate::core::history::Operation;
let undo_data = self.capture_delta_undo_data(&delta)?;
self.apply_script_delta_internal(delta.clone())?;
let operation = Operation::Delta {
forward: delta,
undo_data,
};
let result = CommandResult::success();
self.history
.record_operation(operation, "Apply delta".to_string(), &result);
Ok(())
}
fn apply_script_delta_internal(&mut self, delta: ScriptDeltaOwned) -> Result<()> {
let current_content = self.text();
let script = Script::parse(¤t_content).map_err(EditorError::from)?;
let mut removed_indices = delta.removed.clone();
removed_indices.sort_by(|a, b| b.cmp(a));
for index in removed_indices {
if index < script.sections().len() {
let section = &script.sections()[index];
let start_offset = self.find_section_start(section)?;
let end_offset = self.find_section_end(section)?;
self.delete_raw(Range::new(
Position::new(start_offset),
Position::new(end_offset),
))?;
}
}
for (index, new_section_text) in delta.modified {
if index < script.sections().len() {
let section = &script.sections()[index];
let start_offset = self.find_section_start(section)?;
let end_offset = self.find_section_end(section)?;
self.replace_raw(
Range::new(Position::new(start_offset), Position::new(end_offset)),
&new_section_text,
)?;
}
}
for section_text in delta.added {
let end_pos = Position::new(self.len_bytes());
if self.len_bytes() > 0 && !self.text().ends_with('\n') {
self.insert_raw(end_pos, "\n")?;
}
self.insert_raw(Position::new(self.len_bytes()), §ion_text)?;
if !section_text.ends_with('\n') {
self.insert_raw(Position::new(self.len_bytes()), "\n")?;
}
}
let _ = Script::parse(&self.text()).map_err(EditorError::from)?;
Ok(())
}
fn find_section_start(&self, section: &Section) -> Result<usize> {
let header = match section {
Section::ScriptInfo(_) => "[Script Info]",
Section::Styles(_) => "[V4+ Styles]",
Section::Events(_) => "[Events]",
Section::Fonts(_) => "[Fonts]",
Section::Graphics(_) => "[Graphics]",
};
if let Some(pos) = self.text().find(header) {
Ok(pos)
} else {
Err(EditorError::SectionNotFound {
section: header.to_string(),
})
}
}
fn find_section_end(&self, section: &Section) -> Result<usize> {
let start = self.find_section_start(section)?;
let content = &self.text()[start..];
let section_headers = [
"[Script Info]",
"[V4+ Styles]",
"[Events]",
"[Fonts]",
"[Graphics]",
];
let mut end_offset = content.len();
for header in §ion_headers {
if let Some(pos) = content.find(header) {
if pos > 0 {
end_offset = end_offset.min(pos);
}
}
}
Ok(start + end_offset)
}
}