use crate::{
error::OxiforgeError,
model::{LvglConfig, ToastDef, ToastPreset, UiDoc},
};
fn extract_spdx(yaml: &str) -> Option<String> {
for line in yaml.lines() {
let trimmed = line.trim();
if trimmed.is_empty() {
continue;
}
if !trimmed.starts_with('#') {
break;
}
if let Some(rest) = trimmed.strip_prefix("# SPDX-License-Identifier:") {
return Some(rest.trim().to_string());
}
}
None
}
pub fn parse_str(yaml: &str) -> Result<UiDoc, OxiforgeError> {
let spdx = extract_spdx(yaml);
let mut doc: UiDoc = serde_yaml::from_str(yaml)?;
doc.lvgl.spdx_license = spdx;
expand_toast_presets(&mut doc.lvgl);
Ok(doc)
}
fn expand_toast_presets(lvgl: &mut LvglConfig) {
let Some(presets) = lvgl.toast_presets.take() else { return };
let toasts = lvgl.toasts.get_or_insert_with(Vec::new);
for preset in presets {
toasts.push(preset_toast_def(preset));
}
}
fn preset_toast_def(preset: ToastPreset) -> ToastDef {
let yaml = format!(
"id: {id}\n\
duration_ms: 3000\n\
params: [msg]\n\
bg_color: 0x{bg:06x}\n\
bg_opa: 255\n\
radius: 6\n\
pad_all: 10\n\
widgets:\n\
\x20 - label:\n\
\x20 bind_text: msg\n\
\x20 text_color: 0xffffff\n\
\x20 align: center\n",
id = preset.id(),
bg = preset.bg(),
);
serde_yaml::from_str(&yaml).expect("preset toast template must be valid")
}
pub fn parse_file(path: &std::path::Path) -> Result<UiDoc, OxiforgeError> {
let content = std::fs::read_to_string(path)?;
parse_str(&content)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn extract_spdx_found() {
let yaml = "# SPDX-License-Identifier: GPL-3.0-only\nlvgl:\n pages: []\n";
assert_eq!(extract_spdx(yaml), Some("GPL-3.0-only".into()));
}
#[test]
fn extract_spdx_none() {
let yaml = "lvgl:\n pages: []\n";
assert_eq!(extract_spdx(yaml), None);
}
#[test]
fn extract_spdx_after_blank_comment() {
let yaml = "# some comment\n# SPDX-License-Identifier: MIT\nlvgl:\n pages: []\n";
assert_eq!(extract_spdx(yaml), Some("MIT".into()));
}
}