Skip to main content

ass_editor/commands/script_info_commands/
get.rs

1//! Read commands for retrieving `[Script Info]` properties.
2
3use crate::core::{EditorDocument, EditorError, Result};
4
5#[cfg(not(feature = "std"))]
6use alloc::{
7    format,
8    string::{String, ToString},
9    vec::Vec,
10};
11
12/// Command to get a script info property from the ASS document
13///
14/// Retrieves the value of a specific property from the `[Script Info]` section.
15/// Returns an error if the property doesn't exist. value
16#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct GetScriptInfoCommand {
18    /// Property name to retrieve
19    pub property: String,
20}
21
22impl GetScriptInfoCommand {
23    /// Create a new get script info command
24    pub fn new(property: String) -> Self {
25        Self { property }
26    }
27
28    /// Execute and return the property value
29    pub fn get_value(&self, document: &EditorDocument) -> Result<Option<String>> {
30        let content = document.text();
31
32        // Find [Script Info] section
33        let script_info_start = content
34            .find("[Script Info]")
35            .ok_or_else(|| EditorError::command_failed("No [Script Info] section found"))?;
36
37        // Find the end of Script Info section
38        let script_info_end = content[script_info_start..]
39            .find("\n[")
40            .map(|pos| script_info_start + pos)
41            .unwrap_or(content.len());
42
43        // Look for the property
44        let property_pattern = format!("{}: ", self.property);
45        let search_range = &content[script_info_start..script_info_end];
46
47        if let Some(prop_pos) = search_range.find(&property_pattern) {
48            let value_start = prop_pos + property_pattern.len();
49            let value_end = search_range[value_start..]
50                .find('\n')
51                .map(|pos| value_start + pos)
52                .unwrap_or(search_range.len());
53
54            let value = search_range[value_start..value_end].trim().to_string();
55            Ok(Some(value))
56        } else {
57            Ok(None)
58        }
59    }
60}
61
62/// Command to get all script info properties from the ASS document
63///
64/// Returns all properties in the `[Script Info]` section as key-value pairs.
65/// Returns an empty vector if the section doesn't exist.
66#[derive(Debug, Clone, PartialEq, Eq)]
67pub struct GetAllScriptInfoCommand;
68
69impl GetAllScriptInfoCommand {
70    /// Create a new get all script info command
71    pub fn new() -> Self {
72        Self
73    }
74
75    /// Execute and return all properties as key-value pairs
76    pub fn get_all(&self, document: &EditorDocument) -> Result<Vec<(String, String)>> {
77        let content = document.text();
78
79        // Find [Script Info] section
80        let script_info_start = content
81            .find("[Script Info]")
82            .ok_or_else(|| EditorError::command_failed("No [Script Info] section found"))?;
83
84        // Find the end of Script Info section
85        let script_info_end = content[script_info_start..]
86            .find("\n[")
87            .map(|pos| script_info_start + pos)
88            .unwrap_or(content.len());
89
90        let search_range = &content[script_info_start..script_info_end];
91        let mut properties = Vec::new();
92
93        for line in search_range.lines() {
94            // Skip the section header and empty lines
95            if line.starts_with('[') || line.trim().is_empty() {
96                continue;
97            }
98
99            // Parse property: value pairs
100            if let Some(colon_pos) = line.find(':') {
101                let property = line[..colon_pos].trim().to_string();
102                let value = line[colon_pos + 1..].trim().to_string();
103                properties.push((property, value));
104            }
105        }
106
107        Ok(properties)
108    }
109}
110
111impl Default for GetAllScriptInfoCommand {
112    fn default() -> Self {
113        Self::new()
114    }
115}