use super::EditorDocument;
use crate::core::errors::{EditorError, Result};
use crate::core::position::{Position, Range};
use ass_core::parser::ast::Section;
#[cfg(not(feature = "std"))]
use alloc::string::ToString;
impl EditorDocument {
pub(super) fn insert_section_at(&mut self, index: usize, section_text: &str) -> Result<()> {
let section_count = self.parse_script_with(|script| script.sections().len())?;
if index >= section_count {
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()), section_text)?;
if !section_text.ends_with('\n') {
self.insert_raw(Position::new(self.len_bytes()), "\n")?;
}
return Ok(());
}
let content = self.text();
let insert_pos = self.parse_script_with(|script| -> Result<usize> {
if let Some(section) = script.sections().get(index) {
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) = content.find(header) {
Ok(pos)
} else {
Err(EditorError::SectionNotFound {
section: header.to_string(),
})
}
} else {
Ok(content.len())
}
})??;
let mut text_to_insert = section_text.to_string();
if !text_to_insert.ends_with('\n') {
text_to_insert.push('\n');
}
if insert_pos < content.len() {
text_to_insert.push('\n');
}
self.insert_raw(Position::new(insert_pos), &text_to_insert)?;
Ok(())
}
pub(super) fn replace_section(&mut self, index: usize, new_text: &str) -> Result<()> {
let content = self.text();
let section_info: Result<Option<&str>> = self.parse_script_with(|script| {
if let Some(section) = script.sections().get(index) {
let header = match section {
Section::ScriptInfo(_) => "[Script Info]",
Section::Styles(_) => "[V4+ Styles]",
Section::Events(_) => "[Events]",
Section::Fonts(_) => "[Fonts]",
Section::Graphics(_) => "[Graphics]",
};
Ok(Some(header))
} else {
Ok(None)
}
})?;
if let Some(header) = section_info? {
let start = self.find_section_start_by_header(&content, header)?;
let end = self.find_section_end_from_start(&content, start)?;
self.replace_raw(
Range::new(Position::new(start), Position::new(end)),
new_text,
)?;
}
Ok(())
}
pub(super) fn remove_last_section(&mut self) -> Result<()> {
let content = self.text();
let section_info: Result<Option<&str>> = self.parse_script_with(|script| {
if let Some(section) = script.sections().last() {
let header = match section {
Section::ScriptInfo(_) => "[Script Info]",
Section::Styles(_) => "[V4+ Styles]",
Section::Events(_) => "[Events]",
Section::Fonts(_) => "[Fonts]",
Section::Graphics(_) => "[Graphics]",
};
Ok(Some(header))
} else {
Ok(None)
}
})?;
if let Some(header) = section_info? {
let start = self.find_section_start_by_header(&content, header)?;
let end = self.find_section_end_from_start(&content, start)?;
self.delete_raw(Range::new(Position::new(start), Position::new(end)))?;
}
Ok(())
}
fn find_section_start_by_header(&self, content: &str, header: &str) -> Result<usize> {
content
.find(header)
.ok_or_else(|| EditorError::SectionNotFound {
section: header.to_string(),
})
}
fn find_section_end_from_start(&self, content: &str, start: usize) -> Result<usize> {
let section_headers = [
"[Script Info]",
"[V4+ Styles]",
"[Events]",
"[Fonts]",
"[Graphics]",
];
let mut end = content.len();
for header in §ion_headers {
if let Some(pos) = content[start + 1..].find(header) {
let actual_pos = start + 1 + pos;
if actual_pos < end {
end = actual_pos;
}
}
}
Ok(end)
}
}