From 375cc7a88f006631bed35eedadabe6362d711aa1 Mon Sep 17 00:00:00 2001
From: rhpidfyre <brandon@rhpidfyre.io>
Date: Sun, 19 Jan 2025 02:54:00 -0500
Subject: [PATCH] termianl rendering text, backspace needs fix

---
 Cargo.lock         |  65 ++++++++++++------------
 Cargo.toml         |   2 +-
 src/commands.rs    |  21 ++++----
 src/lib.rs         |   1 +
 src/ps.rs          |  36 ++++++-------
 src/rc.rs          |   2 +-
 src/session.rs     |  65 ++++++++----------------
 src/terminal.rs    | 122 +++++++++++++++++++++++++++++++++++++++++++++
 src/vm/mod.rs      |  26 +++++-----
 src/vm/shell.rs    |  12 ++---
 src/vm/terminal.rs |   4 +-
 11 files changed, 227 insertions(+), 129 deletions(-)
 create mode 100644 src/terminal.rs

diff --git a/Cargo.lock b/Cargo.lock
index b30e689..f364832 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -10,9 +10,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
 
 [[package]]
 name = "bitflags"
-version = "2.7.0"
+version = "2.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be"
+checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
 
 [[package]]
 name = "bstr"
@@ -32,9 +32,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
 
 [[package]]
 name = "cc"
-version = "1.2.8"
+version = "1.2.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad0cf6e91fde44c773c6ee7ec6bba798504641a8bc2eb7e37a04ffbf4dfaa55a"
+checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229"
 dependencies = [
  "shlex",
 ]
@@ -139,9 +139,9 @@ dependencies = [
 
 [[package]]
 name = "js-sys"
-version = "0.3.76"
+version = "0.3.77"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7"
+checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
 dependencies = [
  "once_cell",
  "wasm-bindgen",
@@ -169,7 +169,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
 
 [[package]]
-name = "liblambdashell"
+name = "libloading"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
+dependencies = [
+ "cfg-if",
+ "windows-targets",
+]
+
+[[package]]
+name = "libpse"
 version = "0.1.0"
 dependencies = [
  "color-print",
@@ -182,16 +192,6 @@ dependencies = [
  "whoami",
 ]
 
-[[package]]
-name = "libloading"
-version = "0.8.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
-dependencies = [
- "cfg-if",
- "windows-targets",
-]
-
 [[package]]
 name = "linux-raw-sys"
 version = "0.4.15"
@@ -210,9 +210,9 @@ dependencies = [
 
 [[package]]
 name = "log"
-version = "0.4.22"
+version = "0.4.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
 
 [[package]]
 name = "lua-src"
@@ -530,9 +530,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.99"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396"
+checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
 dependencies = [
  "cfg-if",
  "once_cell",
@@ -541,9 +541,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.99"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79"
+checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
 dependencies = [
  "bumpalo",
  "log",
@@ -555,9 +555,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.99"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe"
+checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -565,9 +565,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.99"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2"
+checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -578,15 +578,18 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.99"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6"
+checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
+dependencies = [
+ "unicode-ident",
+]
 
 [[package]]
 name = "web-sys"
-version = "0.3.76"
+version = "0.3.77"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc"
+checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
 dependencies = [
  "js-sys",
  "wasm-bindgen",
diff --git a/Cargo.toml b/Cargo.toml
index b7ad3d7..e64ae29 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,5 +1,5 @@
 [package]
-name = "liblambdashell"
+name = "libpse"
 version = "0.1.0"
 edition = "2021"
 
diff --git a/src/commands.rs b/src/commands.rs
index 67cb193..05910cd 100644
--- a/src/commands.rs
+++ b/src/commands.rs
@@ -12,7 +12,7 @@ impl PathBufIsValid for PathBuf {
 	}
 }
 
-trait ChangeDirectory {
+trait ChangeDirectory<'a> {
 	fn change_directory(&self, args: SplitWhitespace) -> Option<PathBuf>;
 	fn set_current_dir(&self, new_path: &Path) -> Option<PathBuf>;
 	fn specific_user_dir(&self, user: String) -> Option<PathBuf>;
@@ -20,7 +20,7 @@ trait ChangeDirectory {
 	fn previous_dir(&self) -> Option<PathBuf>;
 	fn home_dir(&self) -> Option<PathBuf>;
 }
-impl ChangeDirectory for Command {
+impl<'a> ChangeDirectory<'a> for Command<'a> {
 	fn set_current_dir(&self, new_path: &Path) -> Option<PathBuf> {
 		std::env::set_current_dir(new_path).map_or_display_none(|()| Some(new_path.to_path_buf()))
 	}
@@ -87,18 +87,19 @@ impl ChangeDirectory for Command {
 	}
 }
 
-pub struct Command(String);
-impl Command {
-	pub const fn new(input: String) -> Self {
+pub struct Command<'a>(&'a String);
+impl<'a> Command<'a> {
+	pub const fn new(input: &'a String) -> Self {
 		Self(input)
 	}
 
 	pub fn spawn_sys_cmd(&mut self, history: &mut History, command_process: io::Result<process::Child>) {
-		if let Ok(mut child) = command_process {
-			history.add(self.0.as_str());
-			child.wait().ok();
-		} else {
-			println!("lambdashell: Unknown command: {}", self.0)
+		match command_process {
+		    Ok(mut child) => {
+				history.add(self.0.as_str());
+				child.wait().ok();
+			},
+		    Err(_) => println!("pse: Unknown command: {}", self.0),
 		}
 	}
 
diff --git a/src/lib.rs b/src/lib.rs
index 7a059ed..e7b6da0 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -3,6 +3,7 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION");
 pub mod session;
 pub mod commands;
 pub mod history;
+pub mod terminal;
 pub mod ps;
 pub mod rc;
 pub mod vm;
diff --git a/src/ps.rs b/src/ps.rs
index 5e0f352..ed7753a 100644
--- a/src/ps.rs
+++ b/src/ps.rs
@@ -1,4 +1,19 @@
-pub const DEFAULT_PS: &str = concat!("lambdashell-", env!("CARGO_PKG_VERSION"), " ");
+pub const DEFAULT_PS: &str = concat!("pse-", env!("CARGO_PKG_VERSION"), " ");
+
+pub trait PsMut {
+	fn get(&self) -> &str;
+	fn modify(&mut self, prompt: String);
+}
+impl PsMut for Ps {
+	#[inline]
+	fn get(&self) -> &str {
+		self.0.as_str()
+	}
+	#[inline]
+	fn modify(&mut self, prompt: String) {
+		self.0 = prompt
+	}
+}
 
 #[derive(Debug)]
 pub struct Ps(String);
@@ -6,23 +21,4 @@ impl Ps {
 	pub const fn set(prompt: String) -> Self {
 		Self(prompt)
 	}
-	//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| {
-			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/rc.rs b/src/rc.rs
index 120d686..10e21b6 100644
--- a/src/rc.rs
+++ b/src/rc.rs
@@ -18,7 +18,7 @@ pub fn config_dir() -> Option<PathBuf> {
 	let mut config = home::home_dir()?;
 	config.push(".config");
 	config.is_valid_dir_or_create()?;
-	config.push("lambdashell");
+	config.push("pse");
 	config.is_valid_dir_or_create()
 }
 
diff --git a/src/session.rs b/src/session.rs
index 706922e..faf79b9 100644
--- a/src/session.rs
+++ b/src/session.rs
@@ -1,16 +1,11 @@
-use std::{cell::RefCell, fs, io::{self}, rc::Rc};
+use std::{cell::RefCell, fs, rc::Rc};
 use core::fmt;
 use color_print::ceprintln;
 
 use crate::{
-	commands, history::History, ps::{self, Ps}, rc::{self}, vm::{self, LuauVm}
+	history::History, ps::{self, Ps}, rc::{self}, terminal, vm::LuauVm
 };
 
-#[inline]
-pub fn shell_error<E: fmt::Display>(err: E) {
-	ceprintln!("<bold,r>[!]:</> {err}")
-}
-
 pub trait MapDisplay<T, E: fmt::Display> {
 	fn map_or_display<F: FnOnce(T)>(self, f: F);
 	fn map_or_display_none<R, F: FnOnce(T) -> Option<R>>(self, f: F) -> Option<R>;
@@ -28,67 +23,47 @@ impl<T, E: fmt::Display> MapDisplay<T, E> for Result<T, E> {
 	}
 }
 
+pub fn shell_error<E: fmt::Display>(err: E) {
+	ceprintln!("<bold,r>[!]:</> {err}")
+}
+pub fn shell_error_none<T, E: fmt::Display>(err: E) -> Option<T> {
+	shell_error(err);
+	None
+}
+
 #[derive(Debug, Clone)]
 pub struct Config {
-	pub norc: bool
+	pub norc: bool,
+	pub nojit: bool,
+	pub nosandbox: bool
 }
 pub struct LambdaShell {
-	terminate: bool,
 	history: History,
 	config: Config,
-	vm: LuauVm,
-	ps: Rc<RefCell<Ps>>,
+	ps: Ps,
 }
 impl LambdaShell {
 	pub fn create(config: Config) -> Self {
-		let ps = Rc::new(RefCell::new(Ps::set(ps::DEFAULT_PS.to_owned())));
 		Self {
-			ps: Rc::clone(&ps),
-			vm: vm::LuauVm::new(ps),
+			ps: Ps::set(ps::DEFAULT_PS.to_owned()),
 			history: History::init(),
-			terminate: false,
 			config,
 		}
 	}
 
-	pub fn wait(&mut self) -> Result<(), io::Error> {
-		io::Write::flush(&mut io::stdout()).map(|()| {
-			let mut input = String::new();
-			io::stdin().read_line(&mut input).map_or_display(|_size| match input.trim() {
-				"exit" => {
-					self.terminate = true;
-					self.history.add("exit");
-				},
-				trim => commands::Command::new(trim.to_owned()).exec(&mut self.history)
-			})
-		})
-	}
-
-	pub fn error<E: fmt::Display>(&mut self, err: E) {
-		shell_error(err);
-		self.terminate = true;
-	}
-
 	pub fn start(&mut self) {
 		if !self.config.norc {
 			if let Some(conf_file) = rc::config_file() {
 				fs::read_to_string(conf_file).map_or_display(|luau_conf| self.vm_exec(luau_conf));
 			}
 		}
-		self.ps.borrow().display();
-
-		loop {
-			if self.terminate { break } else {
-				match self.wait() {
-			        Ok(()) => self.ps.borrow().display(),
-			        Err(flush_err) => self.error(flush_err),
-			    }
-			}
-		}
-		self.history.write_to_file_fallible();
+		terminal::Processor::init()
+			.input_processor(&mut self.history)
+			.map_or_display(|()| self.history.write_to_file_fallible());
 	}
 
 	pub fn vm_exec(&self, source: String) {
-		self.vm.exec(source);
+		let p = Rc::new(RefCell::new(&self.ps));
+		LuauVm::new(Rc::clone(p)).exec(source);
 	}
 }
diff --git a/src/terminal.rs b/src/terminal.rs
new file mode 100644
index 0000000..e8820a5
--- /dev/null
+++ b/src/terminal.rs
@@ -0,0 +1,122 @@
+use crossterm::{event::{self, Event, KeyCode, KeyEvent, KeyModifiers}, terminal};
+use std::io::{self, Write};
+use thiserror::Error;
+
+use crate::{commands::Command, history::History, session};
+
+#[derive(Debug, Error)]
+pub enum InputHandleError {
+	#[error("UserExit")]
+	UserExit,
+	#[error("Sigterm")]
+	Sigterm,
+	#[error("Render failure: {0}")]
+	Write(io::Error),
+	#[error("Flush failure: {0}")]
+	Flush(io::Error),
+	#[error("Disabling the terminal's raw mode failed: {0}")]
+	EnableRaw(io::Error),
+	#[error("Enabling the terminal's raw mode failed: {0}")]
+	DisableRaw(io::Error),
+	#[error("key input failure: {0}")]
+	Key(KeyCode),
+}
+type InputResult<T> = Result<T, InputHandleError>;
+
+trait SpecificKeybinds {
+	const TERM_ID_1: &str;
+	fn key_ctrl(&mut self, input_key: KeyEvent, keycode: KeyCode) -> InputResult<()>;
+	fn key_enter(&mut self, history: &mut History) -> InputResult<()>;
+	fn key_backspace(&mut self) -> InputResult<()>;
+}
+impl SpecificKeybinds for Processor {
+	const TERM_ID_1: &str = "exit";
+
+	fn key_ctrl(&mut self, input_key: KeyEvent, keycode: KeyCode) -> InputResult<()> {
+		if input_key.modifiers.contains(KeyModifiers::CONTROL) {
+			match keycode {
+				KeyCode::Char('c') => Err(InputHandleError::Sigterm),
+				_ => Ok(())
+			}
+		} else {
+			self.render(Some(keycode.to_string()))
+		}
+	}
+
+	fn key_enter(&mut self, history: &mut History) -> InputResult<()> {
+		if self.0 == Self::TERM_ID_1 { return Err(InputHandleError::UserExit) };
+
+		terminal::disable_raw_mode().map_err(InputHandleError::DisableRaw)?;
+		Command::new(&self.0).exec(history);
+		self.0.clear();
+		Ok(())
+	}
+
+	fn key_backspace(&mut self) -> InputResult<()> {
+		match self.0.pop() {
+		    Some(_) => self.render(None),
+		    None => {
+				//the string is empty, do terminal beep
+				Ok(())
+			},
+		}
+	}
+}
+
+pub struct Processor(String);
+impl Processor {
+	pub const fn init() -> Self {
+		Self(String::new())
+	}
+
+	pub fn render(&mut self, def: Option<String>) -> InputResult<()> {
+		match def {
+		    Some(def_string) => {
+				self.0.push_str(&def_string);
+				write!(io::stdout(), "{def_string}").map_err(InputHandleError::Write)?;
+			},
+		    None => {
+				write!(io::stdout(), "{}", self.0).map_err(InputHandleError::Write)?
+			}
+		};
+		io::stdout().flush().map_err(InputHandleError::Flush)
+	}
+
+	pub fn input_handler(&mut self, input_key: KeyEvent, history: &mut History) -> Option<()> {
+		let input_handle = match input_key.code {
+			KeyCode::Enter     => self.key_enter(history),
+			KeyCode::Backspace => self.key_backspace(),
+			KeyCode::Tab       => todo!(),
+			KeyCode::Right     => todo!(),
+			KeyCode::Left      => todo!(),
+			KeyCode::Up        => todo!(),
+			KeyCode::Down      => todo!(),
+			keycode            => self.key_ctrl(input_key, keycode)
+		};
+		input_handle.map_or_else(|inp_err| match inp_err {
+			InputHandleError::UserExit      => None,
+		    InputHandleError::Sigterm       => self.render(Some("^C".to_owned())).ok(),
+		    InputHandleError::Write(e)      => session::shell_error_none(e),
+		    InputHandleError::Flush(e)      => session::shell_error_none(e),
+		    InputHandleError::Key(e)        => session::shell_error_none(e),
+			InputHandleError::DisableRaw(e) => session::shell_error_none(e),
+			InputHandleError::EnableRaw(e)  => session::shell_error_none(e)
+		}, Some)
+	}
+
+	fn input_mainthread(&mut self, history: &mut History) -> io::Result<()> {
+		crossterm::execute!(io::stdout(), event::EnableBracketedPaste)?;
+		loop {
+			terminal::enable_raw_mode()?;
+		    if let Event::Key(event) = event::read()? {
+				if self.input_handler(event, history).is_none() { break Ok(()) }
+			}
+		}
+	}
+
+	pub fn input_processor(&mut self, history: &mut History) -> io::Result<()> {
+		self.input_mainthread(history)?;
+	    terminal::disable_raw_mode()?;
+	    crossterm::execute!(io::stdout(), event::DisableBracketedPaste)
+	}
+}
\ No newline at end of file
diff --git a/src/vm/mod.rs b/src/vm/mod.rs
index e3119b6..667b97d 100644
--- a/src/vm/mod.rs
+++ b/src/vm/mod.rs
@@ -1,8 +1,8 @@
 use mlua::{Function, Lua as Luau, MultiValue, Result as lResult, Table, Value};
 use color_print::{cformat, ceprintln};
 use terminal::TerminalGlobal;
-use std::{cell::RefCell, rc::Rc};
 use core::fmt;
+use std::{cell::RefCell, rc::Rc};
 use shell::ShellGlobal;
 
 use crate::{ps::Ps, session::MapDisplay};
@@ -27,14 +27,16 @@ impl<T, E: fmt::Display> LuauRuntimeErr<T> for Result<T, E> {
 trait Globals {
 	const LIB_VERSION: &str;
 	const CONV_ERROR: &str;
-	fn global_warn(&self, luau_globals: &Table) -> lResult<()>;
-	fn global_version(&self, luau_globals: &Table) -> lResult<()>;
+	const LIB_NAME: &str;
+	fn glob_warn(&self, luau_globals: &Table) -> lResult<()>;
+	fn glob_version(&self, luau_globals: &Table) -> lResult<()>;
 }
 impl Globals for LuauVm {
 	const LIB_VERSION: &str = env!("CARGO_PKG_VERSION");
+	const LIB_NAME: &str = env!("CARGO_PKG_NAME");
 	const CONV_ERROR: &str = "<SHELL CONVERSION ERROR>";
 
-	fn global_warn(&self, luau_globals: &Table) -> lResult<()> {
+	fn glob_warn(&self, luau_globals: &Table) -> lResult<()> {
 		let luau_print = luau_globals.get::<Function>("print")?;
 		luau_globals.raw_set("warn", self.vm.create_function(move |this, args: MultiValue| -> lResult<()> {
 			let luau_multi_values = args.into_iter()
@@ -46,9 +48,9 @@ impl Globals for LuauVm {
 		})?)
 	}
 
-	fn global_version(&self, luau_globals: &Table) -> lResult<()> {
+	fn glob_version(&self, luau_globals: &Table) -> lResult<()> {
 		let luau_info = luau_globals.get::<String>("_VERSION")?;
-		luau_globals.raw_set("_VERSION", format!("{luau_info}, liblambdashell {}", Self::LIB_VERSION))
+		luau_globals.raw_set("_VERSION", format!("{luau_info}, {} {}", Self::LIB_NAME, Self::LIB_VERSION))
 	}
 }
 
@@ -61,12 +63,12 @@ impl LuauVm {
 		Self { vm: Luau::new(), ps }
 	}
 
-	fn set_shell_globals(&self) -> lResult<()> {
+	fn setglobs(&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.glob_shell(&luau_globals)?;
+		self.glob_terminal(&luau_globals)?;
+		self.glob_warn(&luau_globals)?;
+		self.glob_version(&luau_globals)?;
 		luau_globals.raw_set("getfenv", mlua::Nil)?;
 		luau_globals.raw_set("setfenv", mlua::Nil)?;
 		self.vm.sandbox(true)?;
@@ -74,6 +76,6 @@ impl LuauVm {
 	}
 
 	pub fn exec(&self, source: String) {
-		self.set_shell_globals().map_or_display_none(|()| self.vm.load(source).exec().map_or_luau_rt_err(Some));
+		self.setglobs().map_or_display_none(|()| self.vm.load(source).exec().map_or_luau_rt_err(Some));
 	}
 }
\ No newline at end of file
diff --git a/src/vm/shell.rs b/src/vm/shell.rs
index c532d17..4accc36 100644
--- a/src/vm/shell.rs
+++ b/src/vm/shell.rs
@@ -2,7 +2,7 @@ use mlua::{Lua as Luau, MetaMethod, Result as lResult, Table, UserData, UserData
 use std::{cell::RefCell, rc::Rc};
 use whoami::fallible;
 
-use crate::{ps::Ps, vm::LuauVm};
+use crate::{ps::{Ps, PsMut}, vm::LuauVm};
 
 const DEFAULT_HOSTNAME: &str = "hostname";
 
@@ -27,20 +27,18 @@ impl UserData for Shell {
 	}
 
 	fn add_methods<M: UserDataMethods<Self>>(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);
-			}
+		methods.add_meta_method_mut(MetaMethod::NewIndex, |_, this, (t_index, t_value): (String, String)| -> lResult<()> {
+			if t_index == "PROMPT" { this.0.borrow_mut().modify(t_value); }
 			Ok(())
 		});
 	}
 }
 
 pub trait ShellGlobal {
-	fn global_shell(&self, luau_globals: &Table) -> lResult<()>;
+	fn glob_shell(&self, luau_globals: &Table) -> lResult<()>;
 }
 impl ShellGlobal for LuauVm {
-	fn global_shell(&self, luau_globals: &Table) -> lResult<()> {
+	fn glob_shell(&self, luau_globals: &Table) -> lResult<()> {
 		luau_globals.raw_set("SHELL", Shell(Rc::clone(&self.ps)))?;
 		Ok(())
 	}
diff --git a/src/vm/terminal.rs b/src/vm/terminal.rs
index 7ad38a4..bbd8251 100644
--- a/src/vm/terminal.rs
+++ b/src/vm/terminal.rs
@@ -84,10 +84,10 @@ impl UserData for Terminal {
 }
 
 pub trait TerminalGlobal {
-	fn global_terminal(&self, luau_globals: &Table) -> lResult<()>;
+	fn glob_terminal(&self, luau_globals: &Table) -> lResult<()>;
 }
 impl TerminalGlobal for LuauVm {
-	fn global_terminal(&self, luau_globals: &Table) -> lResult<()> {
+	fn glob_terminal(&self, luau_globals: &Table) -> lResult<()> {
 		luau_globals.raw_set("TERMINAL", Terminal)
 	}
 }
\ No newline at end of file