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 }