manen

Fancy Lua REPL
Log | Files | Refs | README | LICENSE

config.rs (5603B)


      1 use directories::ProjectDirs;
      2 use mlua::prelude::*;
      3 use std::{fs, path::PathBuf, sync::Arc};
      4 
      5 use crate::{
      6     inspect::TableFormat,
      7     lua::{LuaExecutor, MluaExecutor, SystemLuaError, SystemLuaExecutor},
      8 };
      9 
     10 #[derive(Clone, Copy)]
     11 pub enum Executor {
     12     System,
     13     Embedded,
     14 }
     15 
     16 #[derive(Clone, FromLua)]
     17 pub struct Config {
     18     pub executor: Executor,
     19     pub system_lua: Option<PathBuf>,
     20     pub table_format: TableFormat,
     21     pub history_size: usize,
     22     pub color_output: bool,
     23 }
     24 
     25 impl Default for Config {
     26     fn default() -> Self {
     27         Self {
     28             executor: Executor::Embedded,
     29             system_lua: None,
     30             table_format: TableFormat::Inspect,
     31             history_size: 256,
     32             color_output: true,
     33         }
     34     }
     35 }
     36 
     37 impl Config {
     38     pub fn load() -> LuaResult<Self> {
     39         let config = Self::default();
     40 
     41         if let Some(proj_dirs) = ProjectDirs::from("net.sivory", "", "Manen") {
     42             let config_file = proj_dirs.config_dir().join("config.lua");
     43 
     44             if !config_file.exists() {
     45                 return Ok(config);
     46             }
     47 
     48             let lua = Lua::new();
     49 
     50             lua.globals().set("manen", config)?;
     51             lua.load(config_file).exec()?;
     52 
     53             return lua.globals().get("manen");
     54         }
     55 
     56         Ok(config)
     57     }
     58 
     59     pub fn get_executor(&self) -> Result<Arc<dyn LuaExecutor>, SystemLuaError> {
     60         let executor = match self.executor {
     61             Executor::Embedded => Arc::new(MluaExecutor::new()),
     62             Executor::System => {
     63                 if let Some(path) = &self.system_lua {
     64                     Arc::new(SystemLuaExecutor::new(&path.to_string_lossy())?)
     65                 } else {
     66                     Arc::new(MluaExecutor::new()) as Arc<dyn LuaExecutor>
     67                 }
     68             }
     69         };
     70 
     71         if let Some(proj_dirs) = ProjectDirs::from("net.sivory", "", "Manen") {
     72             let config_dir = proj_dirs.config_dir();
     73             let rc_file = config_dir.join("rc.lua");
     74 
     75             if rc_file.exists() {
     76                 let code = fs::read_to_string(rc_file)?;
     77 
     78                 executor.exec(&code)?;
     79 
     80                 let config = config_dir.to_string_lossy().to_string();
     81                 executor.exec(&format!(
     82                     "if package and package.path then
     83                         package.path = package.path .. ';{config}/?.lua;{config}/?/init.lua'
     84                     end"
     85                 ))?;
     86             }
     87         }
     88 
     89         Ok(executor)
     90     }
     91 }
     92 
     93 macro_rules! field {
     94     ($value:ident, $as_field:ident, $field:expr, $expected:expr) => {
     95         $value.$as_field().ok_or_else(|| {
     96             LuaError::RuntimeError(format!(
     97                 "invalid type '{}' for {}, expected {}",
     98                 $value.type_name(),
     99                 $field,
    100                 $expected,
    101             ))
    102         })?
    103     };
    104 }
    105 
    106 impl LuaUserData for Config {
    107     fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) {
    108         methods.add_meta_method_mut(
    109             LuaMetaMethod::NewIndex,
    110             |lua, this, (key, value): (String, LuaValue)| {
    111                 match key.as_str() {
    112                     "executor" => {
    113                         let executor = field!(value, as_string_lossy, "executor", "string");
    114 
    115                         match executor.as_str() {
    116                             "system" => this.executor = Executor::System,
    117                             "embedded" => this.executor = Executor::Embedded,
    118                             _ => {
    119                                 return Err(LuaError::RuntimeError(String::from(
    120                                     "expected valid executor format",
    121                                 )));
    122                             }
    123                         }
    124                     }
    125                     "system_lua" => {
    126                         if value.is_nil() {
    127                             this.system_lua = None;
    128                             return Ok(());
    129                         }
    130 
    131                         let path = PathBuf::from_lua(value, lua)?;
    132 
    133                         if !path.exists() {
    134                             return Err(LuaError::RuntimeError(format!(
    135                                 "path '{}' does not exist",
    136                                 path.to_string_lossy()
    137                             )));
    138                         }
    139 
    140                         this.system_lua = Some(path);
    141                     }
    142                     "table_format" => {
    143                         let format = field!(value, as_string_lossy, "table_format", "string");
    144 
    145                         match format.as_str() {
    146                             "address" => this.table_format = TableFormat::Address,
    147                             "inspect" => this.table_format = TableFormat::Inspect,
    148                             "comfytable" => this.table_format = TableFormat::ComfyTable,
    149                             _ => {
    150                                 return Err(LuaError::RuntimeError(String::from(
    151                                     "expected valid table format",
    152                                 )));
    153                             }
    154                         }
    155                     }
    156                     "history_size" => {
    157                         this.history_size = field!(value, as_usize, "history_size", "integer");
    158                     }
    159                     "color_output" => {
    160                         this.color_output = field!(value, as_boolean, "color_output", "bool");
    161                     }
    162                     key => return Err(LuaError::RuntimeError(format!("invalid key '{key}'"))),
    163                 }
    164                 Ok(())
    165             },
    166         );
    167     }
    168 }