pinel 0.8.0

A lightweight editor built with rust
use std::{fs, io::Write, path::PathBuf};

#[derive(Debug, Clone)]
pub struct ThemeColors {
    pub rosewater: String,
    pub flamingo: String,
    pub pink: String,
    pub mauve: String,
    pub red: String,
    pub maroon: String,
    pub peach: String,
    pub yellow: String,
    pub green: String,
    pub teal: String,
    pub sky: String,
    pub sapphire: String,
    pub blue: String,
    pub lavender: String,
    pub text: String,
    pub subtext1: String,
    pub subtext0: String,
    pub overlay2: String,
    pub overlay1: String,
    pub overlay0: String,
    pub surface2: String,
    pub surface1: String,
    pub surface0: String,
    pub base: String,
    pub mantle: String,
    pub crust: String,
}

impl Default for ThemeColors {
    fn default() -> Self {
        Self {
            rosewater: "#f5e0dc".to_string(),
            flamingo: "#f2cdcd".to_string(),
            pink: "#f5c2e7".to_string(),
            mauve: "#cba6f7".to_string(),
            red: "#f38ba8".to_string(),
            maroon: "#eba0ac".to_string(),
            peach: "#fab387".to_string(),
            yellow: "#f9e2af".to_string(),
            green: "#a6e3a1".to_string(),
            teal: "#94e2d5".to_string(),
            sky: "#89dceb".to_string(),
            sapphire: "#74c7ec".to_string(),
            blue: "#89b4fa".to_string(),
            lavender: "#b4befe".to_string(),
            text: "#cdd6f4".to_string(),
            subtext1: "#bac2de".to_string(),
            subtext0: "#a6adc8".to_string(),
            overlay2: "#9399b2".to_string(),
            overlay1: "#7f849c".to_string(),
            overlay0: "#6c7086".to_string(),
            surface2: "#585b70".to_string(),
            surface1: "#45475a".to_string(),
            surface0: "#313244".to_string(),
            base: "#1e1e2e".to_string(),
            mantle: "#181825".to_string(),
            crust: "#11111b".to_string(),
        }
    }
}

#[allow(dead_code)]
impl ThemeColors {
    pub fn to_lua(&self) -> String {
        format!(
            r#"-- Pinel Theme Configuration
-- Edit these hex color values to customize your theme

return {{
    rosewater = "{}",
    flamingo = "{}",
    pink = "{}",
    mauve = "{}",
    red = "{}",
    maroon = "{}",
    peach = "{}",
    yellow = "{}",
    green = "{}",
    teal = "{}",
    sky = "{}",
    sapphire = "{}",
    blue = "{}",
    lavender = "{}",
    text = "{}",
    subtext1 = "{}",
    subtext0 = "{}",
    overlay2 = "{}",
    overlay1 = "{}",
    overlay0 = "{}",
    surface2 = "{}",
    surface1 = "{}",
    surface0 = "{}",
    base = "{}",
    mantle = "{}",
    crust = "{}",
}}
"#,
            self.rosewater,
            self.flamingo,
            self.pink,
            self.mauve,
            self.red,
            self.maroon,
            self.peach,
            self.yellow,
            self.green,
            self.teal,
            self.sky,
            self.sapphire,
            self.blue,
            self.lavender,
            self.text,
            self.subtext1,
            self.subtext0,
            self.overlay2,
            self.overlay1,
            self.overlay0,
            self.surface2,
            self.surface1,
            self.surface0,
            self.base,
            self.mantle,
            self.crust,
        )
    }

    pub fn from_lua(content: &str) -> Result<Self, String> {
        let mut theme = Self::default();

        for line in content.lines() {
            let line = line.trim();
            if line.is_empty() || line.starts_with("--") || line == "return {" || line == "}" {
                continue;
            }

            if let Some((key, value)) = line.split_once('=') {
                let key = key.trim();
                let value = value
                    .trim()
                    .trim_end_matches(',')
                    .trim_matches('"')
                    .trim_matches('\'')
                    .to_string();

                match key {
                    "rosewater" => theme.rosewater = value,
                    "flamingo" => theme.flamingo = value,
                    "pink" => theme.pink = value,
                    "mauve" => theme.mauve = value,
                    "red" => theme.red = value,
                    "maroon" => theme.maroon = value,
                    "peach" => theme.peach = value,
                    "yellow" => theme.yellow = value,
                    "green" => theme.green = value,
                    "teal" => theme.teal = value,
                    "sky" => theme.sky = value,
                    "sapphire" => theme.sapphire = value,
                    "blue" => theme.blue = value,
                    "lavender" => theme.lavender = value,
                    "text" => theme.text = value,
                    "subtext1" => theme.subtext1 = value,
                    "subtext0" => theme.subtext0 = value,
                    "overlay2" => theme.overlay2 = value,
                    "overlay1" => theme.overlay1 = value,
                    "overlay0" => theme.overlay0 = value,
                    "surface2" => theme.surface2 = value,
                    "surface1" => theme.surface1 = value,
                    "surface0" => theme.surface0 = value,
                    "base" => theme.base = value,
                    "mantle" => theme.mantle = value,
                    "crust" => theme.crust = value,
                    _ => {},
                }
            }
        }

        Ok(theme)
    }
}

pub fn get_config_dir() -> PathBuf {
    let home = std::env::var("HOME").unwrap_or_else(|_| ".".to_string());
    PathBuf::from(home).join(".config").join("pinel")
}

pub fn get_theme_path() -> PathBuf {
    get_config_dir().join("theme.lua")
}

pub fn load_theme() -> ThemeColors {
    let path = get_theme_path();
    if let Ok(content) = fs::read_to_string(&path) {
        ThemeColors::from_lua(&content).unwrap_or_default()
    } else {
        ThemeColors::default()
    }
}

#[allow(dead_code)]
pub fn save_theme(theme: &ThemeColors) -> Result<(), std::io::Error> {
    let path = get_theme_path();
    if let Some(parent) = path.parent() {
        fs::create_dir_all(parent)?;
    }
    let mut file = fs::File::create(path)?;
    file.write_all(theme.to_lua().as_bytes())?;
    Ok(())
}