diff --git a/Cargo.toml b/Cargo.toml index 5ca7c19..b7ad3d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,10 +11,4 @@ home = "0.5.9" mlua = { version = "0.10.0", features = ["luau-jit", "vendored"] } thiserror = "2.0.9" uzers = "0.12.1" -whoami = "1.5.2" - -[profile.release] -strip = true -opt-level = "z" -lto = true -codegen-units = 1 +whoami = "1.5.2" \ No newline at end of file diff --git a/src/ps.rs b/src/ps.rs index 49a13bb..5e0f352 100644 --- a/src/ps.rs +++ b/src/ps.rs @@ -1,27 +1,28 @@ pub const DEFAULT_PS: &str = concat!("lambdashell-", env!("CARGO_PKG_VERSION"), " "); -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct Ps(String); impl Ps { - pub fn set(prompt: String) -> Self { + pub const fn set(prompt: String) -> Self { Self(prompt) } - pub fn get(self) -> String { - self.0 + //rustc: `std::string::String::as_str` is not yet stable as a const fn + pub fn get(&self) -> &str { + self.0.as_str() + } + pub fn modify(&mut self, prompt: String) { + self.0 = prompt } pub fn display(&self) { print!("{}", self.0); } pub fn working_dir_name(&self) -> String { - std::env::current_dir().map_or("?".to_owned(), |path| { - path.file_name().map_or("?".to_owned(), |name| { - let name_os_string = name.to_os_string(); - match name_os_string == whoami::username_os() && name_os_string != "root" { - true => "~".to_owned(), - false => name.to_string_lossy().to_string(), - } - }) - }) + std::env::current_dir().map_or("?".to_owned(), |path| path.file_name().map_or("?".to_owned(), |name| { + match name.to_os_string() == whoami::username_os() { + true => "~".to_owned(), + false => name.to_string_lossy().to_string(), + } + })) } } \ No newline at end of file diff --git a/src/session.rs b/src/session.rs index 98ab344..ba87eda 100644 --- a/src/session.rs +++ b/src/session.rs @@ -1,4 +1,4 @@ -use std::{fs, io::{self}}; +use std::{cell::RefCell, fs, io::{self}, rc::Rc}; use core::fmt; use crate::{ @@ -14,16 +14,16 @@ pub struct LambdaShell { terminate: bool, config: Config, vm: LuauVm, - ps: Ps, + ps: Rc>, } impl LambdaShell { pub fn create(config: Config) -> Self { - let ps = Ps::set(ps::DEFAULT_PS.to_owned()); + let ps = Rc::new(RefCell::new(Ps::set(ps::DEFAULT_PS.to_owned()))); Self { - vm: vm::LuauVm::new(ps.to_owned()), + ps: Rc::clone(&ps), + vm: vm::LuauVm::new(ps), terminate: false, config, - ps } } @@ -48,12 +48,12 @@ impl LambdaShell { fs::read_to_string(conf_file).map_or_display(|luau_conf| self.vm_exec(luau_conf)); } } - self.ps.display(); + self.ps.borrow().display(); loop { if self.terminate { break } else { match self.wait() { - Ok(()) => self.ps.display(), + Ok(()) => self.ps.borrow().display(), Err(flush_err) => self.error(flush_err), } } diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 770eba1..5e4e8cb 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -1,5 +1,6 @@ use mlua::{Function, Lua as Luau, MultiValue, Result as lResult, Table, Value}; use color_print::{cformat, ceprintln}; +use std::{cell::RefCell, rc::Rc}; use core::fmt; use shell::Shell; @@ -34,7 +35,7 @@ impl Globals for LuauVm { fn global_warn(&self, luau_globals: &Table) -> lResult<()> { let luau_print = luau_globals.get::("print")?; - luau_globals.set("warn", self.vm.create_function(move |this, args: MultiValue| -> lResult<()> { + luau_globals.raw_set("warn", self.vm.create_function(move |this, args: MultiValue| -> lResult<()> { let luau_multi_values = args.into_iter() .map(|value| cformat!("{}", value.to_string().unwrap_or(Self::CONV_ERROR.to_owned()))) .map(|arg_v| Value::String(this.create_string(arg_v).unwrap())) @@ -46,27 +47,30 @@ impl Globals for LuauVm { fn global_version(&self, luau_globals: &Table) -> lResult<()> { let luau_info = luau_globals.get::("_VERSION")?; - luau_globals.set("_VERSION", format!("{luau_info}, liblambdashell {}", Self::LIB_VERSION)) + luau_globals.raw_set("_VERSION", format!("{luau_info}, liblambdashell {}", Self::LIB_VERSION)) } } pub struct LuauVm { vm: Luau, - ps: Ps, + ps: Rc> } impl LuauVm { - pub(crate) fn new(ps: Ps) -> Self { - Self { vm: Luau::new(), ps } + pub(crate) fn new(ps: Rc>) -> Self { + Self { + vm: Luau::new(), + ps + } } fn set_shell_globals(&self) -> lResult<()> { let luau_globals = self.vm.globals(); + self.global_shell(&luau_globals)?; + self.global_terminal(&luau_globals)?; self.global_warn(&luau_globals)?; self.global_version(&luau_globals)?; - self.global_terminal(&luau_globals)?; - self.global_shell(&luau_globals)?; - luau_globals.set("getfenv", mlua::Nil)?; - luau_globals.set("setfenv", mlua::Nil)?; + luau_globals.raw_set("getfenv", mlua::Nil)?; + luau_globals.raw_set("setfenv", mlua::Nil)?; self.vm.sandbox(true)?; Ok(()) } diff --git a/src/vm/shell.rs b/src/vm/shell.rs index eec923f..3335d30 100644 --- a/src/vm/shell.rs +++ b/src/vm/shell.rs @@ -1,28 +1,8 @@ -use mlua::{Result as lResult, Table}; +use mlua::{MetaMethod, Result as lResult, Table, UserData, UserDataFields, UserDataMethods}; +use std::{cell::RefCell, rc::Rc}; use whoami::fallible; -use crate::vm::LuauVm; - -trait PsPrompt { - fn ps_prompt(&self) -> lResult; -} -impl PsPrompt for LuauVm { - fn ps_prompt(&self) -> lResult
{ - let prompt_table = self.vm.create_table()?; - let prompt_metatable = self.vm.create_table()?; - let ps_owned = self.ps.to_owned(); - prompt_metatable.set("__index", self.vm.create_function(move |_, (s, s1): (Table, String)| -> lResult { - Ok(ps_owned.clone().get()) - })?)?; - prompt_metatable.set("__newindex", self.vm.create_function(|_, _: String| -> lResult { - Ok("placeholder".to_owned()) - })?)?; - // prompt_table.set("__metatable", mlua::Nil)?; - prompt_table.set_metatable(Some(prompt_metatable)); - prompt_table.set_readonly(false); - Ok(prompt_table) - } -} +use crate::{ps::Ps, vm::LuauVm}; trait System { const DEFAULT_HOSTNAME: &str; @@ -33,26 +13,42 @@ impl System for LuauVm { fn sys_details(&self) -> lResult
{ let system = self.vm.create_table()?; - system.set("DESKTOP_ENV", whoami::desktop_env().to_string())?; - system.set("DEVICENAME", whoami::devicename().to_string())?; - system.set("USERNAME", whoami::username().to_string())?; - system.set("REALNAME", whoami::realname().to_string())?; - system.set("PLATFORM", whoami::platform().to_string())?; - system.set("DISTRO", whoami::distro().to_string())?; - system.set("HOSTNAME", fallible::hostname().unwrap_or(Self::DEFAULT_HOSTNAME.to_owned()))?; + system.raw_set("DESKTOP_ENV", whoami::desktop_env().to_string())?; + system.raw_set("DEVICENAME", whoami::devicename().to_string())?; + system.raw_set("USERNAME", whoami::username().to_string())?; + system.raw_set("REALNAME", whoami::realname().to_string())?; + system.raw_set("PLATFORM", whoami::platform().to_string())?; + system.raw_set("DISTRO", whoami::distro().to_string())?; + system.raw_set("ARCH", whoami::arch().to_string())?; + system.raw_set("HOSTNAME", fallible::hostname().unwrap_or(Self::DEFAULT_HOSTNAME.to_owned()))?; Ok(system) } } +struct ShellUserdata(Rc>); +impl UserData for ShellUserdata { + fn add_fields>(fields: &mut F) { + fields.add_field_method_get("PROMPT", |_, this| Ok(this.0.borrow().get().to_owned())); + } + fn add_methods>(methods: &mut M) { + methods.add_meta_method_mut(MetaMethod::NewIndex, |_, this, (tindex, tvalue): (String, String)| -> lResult<()> { + if tindex == "PROMPT" { + this.0.borrow_mut().modify(tvalue); + } + Ok(()) + }); + } +} + pub trait Shell { fn global_shell(&self, luau_globals: &Table) -> lResult<()>; } impl Shell for LuauVm { fn global_shell(&self, luau_globals: &Table) -> lResult<()> { - let shell = self.vm.create_table()?; - shell.set("SYSTEM", self.sys_details()?)?; - shell.set("PROMPT", self.ps_prompt()?)?; - luau_globals.set("SHELL", shell)?; + // let shell = self.vm.create_table()?; + // shell.set("SYSTEM", self.sys_details()?)?; + // shell.set("PROMPT", self.ps_prompt()?)?; + luau_globals.set("SHELL", ShellUserdata(Rc::clone(&self.ps)))?; Ok(()) } } \ No newline at end of file