From f8d97ded00e1a655ecf84dc860fa1f4e19862013 Mon Sep 17 00:00:00 2001 From: rhpidfyre Date: Sun, 12 Jan 2025 02:00:56 -0500 Subject: [PATCH] history now logs "cd" and "exit", history bug when starting a new session and inputting a new command then leaving will concat onto the old history's same line --- Cargo.lock | 24 ++++++++-------- src/commands.rs | 65 +++++++++--------------------------------- src/history.rs | 72 +++++++++++++++++++++++++---------------------- src/lib.rs | 24 +--------------- src/session.rs | 37 +++++++++++++++++++++--- src/valid_pbuf.rs | 2 +- src/vm/mod.rs | 2 +- 7 files changed, 99 insertions(+), 127 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6665d6e..b30e689 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,9 +10,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be" [[package]] name = "bstr" @@ -32,9 +32,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "cc" -version = "1.2.7" +version = "1.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a012a0df96dd6d06ba9a1b29d6402d1a5d77c6befd2566afdc26e10603dc93d7" +checksum = "ad0cf6e91fde44c773c6ee7ec6bba798504641a8bc2eb7e37a04ffbf4dfaa55a" dependencies = [ "shlex", ] @@ -351,9 +351,9 @@ checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "proc-macro2" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] @@ -465,9 +465,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "syn" -version = "2.0.95" +version = "2.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f71c0377baf4ef1cc3e3402ded576dccc315800fbc62dfc7fe04b009773b4a" +checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" dependencies = [ "proc-macro2", "quote", @@ -476,18 +476,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.10" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3ac7f54ca534db81081ef1c1e7f6ea8a3ef428d2fc069097c079443d24124d3" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.10" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e9465d30713b56a37ede7185763c3492a91be2f5fa68d958c44e41ab9248beb" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" dependencies = [ "proc-macro2", "quote", diff --git a/src/commands.rs b/src/commands.rs index d452e64..e766125 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -1,41 +1,14 @@ +use std::{io, process, str::SplitWhitespace, path::{Path, PathBuf}}; use uzers::User; -use std::{ - io, - process, - str::SplitWhitespace, - path::{Path, PathBuf}, -}; -use crate::{history::History, MapDisplay}; +use crate::{history::History, session::MapDisplay, valid_pbuf::IsValid}; -enum ValidStatus { - NoRootFolder, - TryExists(io::Error) -} trait PathBufIsValid { - fn is_valid(&self) -> Result; fn is_valid_or_home(&self) -> Option; } impl PathBufIsValid for PathBuf { - fn is_valid(&self) -> Result { - match self.try_exists() { - Ok(true) => Ok(self.to_path_buf()), - Ok(false) => Err(ValidStatus::NoRootFolder), - Err(trye_error) => Err(ValidStatus::TryExists(trye_error)) - } - } - fn is_valid_or_home(&self) -> Option { - match self.is_valid() { - Ok(valid) => Some(valid), - Err(valid_status) => { - match valid_status { - ValidStatus::NoRootFolder => println!("cd: /root: No such file or directory"), - ValidStatus::TryExists(error) => println!("cd: {error}"), - }; - None - }, - } + self.is_valid_or(self.is_dir(), home::home_dir) } } @@ -114,39 +87,27 @@ impl ChangeDirectory for Command { } } -pub struct Command { - input: String, - history: Option -} +pub struct Command(String); impl Command { - pub fn new(input: String) -> Self { - Self { - history: History::init(), - input - } + pub const fn new(input: String) -> Self { + Self(input) } - pub fn write_history(&mut self) { - if let Some(history_file) = self.history.as_mut() { - history_file.write(&self.input); - }; - } - - pub fn spawn_handle(&mut self, command_process: io::Result) { + pub fn spawn_sys_cmd(&mut self, history: &mut History, command_process: io::Result) { if let Ok(mut child) = command_process { - self.write_history(); + history.add(self.0.as_str()); child.wait().ok(); } else { - println!("Unknown command: {}", self.input) + println!("Unknown command: {}", self.0) } } - pub fn exec(&mut self) { - let mut args = self.input.split_whitespace(); + pub fn exec(&mut self, history: &mut History) { + let mut args = self.0.split_whitespace(); if let Some(command) = args.next() { match command { - "cd" => { self.change_directory(args); }, - command => { self.spawn_handle(process::Command::new(command).args(args).spawn()); } + "cd" => if self.change_directory(args).is_some() { history.add(self.0.as_str()) }, + command => { self.spawn_sys_cmd(history, process::Command::new(command).args(args).spawn()); } } } } diff --git a/src/history.rs b/src/history.rs index ec3d0d6..7580263 100644 --- a/src/history.rs +++ b/src/history.rs @@ -1,48 +1,52 @@ use std::{fs::{File, OpenOptions}, io::{BufRead, BufReader, Write}, path::PathBuf}; -use crate::{rc::{self}, shell_error, valid_pbuf::IsValid, MapDisplay}; +use crate::{rc::{self}, session::{self, MapDisplay}, valid_pbuf::IsValid}; +#[derive(Debug, Clone)] pub struct History { - history_file: PathBuf, - checked_empty: bool + file: Option, + history: Vec, } impl History { - pub fn init() -> Option { - rc::config_dir().map(|mut config| { - config.push(".history"); - config.is_valid_file_or_create(b""); - Self { - history_file: config, - checked_empty: false - } - }) - } - - pub fn is_empty(&mut self) -> bool { - match self.checked_empty { - true => true, - false => self.read().map_or(false, |history_l| { - self.checked_empty = true; - history_l.is_empty() - }) + pub fn init() -> Self { + Self { + history: Vec::new(), + file: rc::config_dir().map(|mut history_pbuf| { + history_pbuf.push(".history"); + history_pbuf.is_valid_file_or_create(b""); + history_pbuf + }), } } - pub fn write>(&mut self, content: S) { - OpenOptions::new().append(true).open(self.history_file.as_path()).map_or_display(|mut file| { - let write_data = match self.is_empty() { - true => content.as_ref().to_owned(), - false => format!("\n{}", content.as_ref()), - }; - if let Err(write_err) = file.write_all(write_data.as_bytes()) { - shell_error(write_err); - }; - }); + pub fn add(&mut self, command: &str) { + match self.history.last() { + Some(last_cmd) => if last_cmd != command { self.history.push(command.to_owned()); }, + None => self.history.push(command.to_owned()), + }; } - pub fn read(&self) -> Option> { - File::open(&self.history_file).map_or_display_none(|file| { - Some(BufReader::new(file).lines().map_while(Result::ok).collect::>()) + pub fn write_to_file_fallible(&mut self) { + if !self.history.is_empty() { + if let Some(history_file) = &self.file { + OpenOptions::new().append(true).open(history_file.as_path()).map_or_display(|mut file| { + let history_content = match self.history.len()==1 { + true => format!("\n{}", self.history[0]), + false => self.history.join("\n") + }; + if let Err(write_err) = file.write_all(history_content.as_bytes()) { + session::shell_error(write_err); + }; + }); + } + } + } + + pub fn read_file_fallible(&self) -> Option> { + self.file.as_ref().and_then(|history_file| { + File::open(history_file).map_or_display_none(|file| { + Some(BufReader::new(file).lines().map_while(Result::ok).collect::>()) + }) }) } } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index d5a360f..7a059ed 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,26 +7,4 @@ pub mod ps; pub mod rc; pub mod vm; -mod valid_pbuf; - -#[inline] -pub fn shell_error(err: E) { - color_print::ceprintln!("[!]: {err}") -} - -pub trait MapDisplay { - fn map_or_display(self, f: F); - fn map_or_display_none Option>(self, f: F) -> Option; -} -impl MapDisplay for Result { - ///Map but display the error to stdout - #[inline] - fn map_or_display(self, f: F) { - self.map_or_else(|e| shell_error(e), f) - } - ///Map but display the error to stdout and return `None` - #[inline] - fn map_or_display_none Option>(self, f: F) -> Option { - self.map_or_else(|e| { shell_error(e); None }, f) - } -} \ No newline at end of file +mod valid_pbuf; \ No newline at end of file diff --git a/src/session.rs b/src/session.rs index 28f7a1d..706922e 100644 --- a/src/session.rs +++ b/src/session.rs @@ -1,17 +1,40 @@ use std::{cell::RefCell, fs, io::{self}, rc::Rc}; use core::fmt; +use color_print::ceprintln; use crate::{ - commands, ps::{self, Ps}, rc::{self}, shell_error, vm::{self, LuauVm}, MapDisplay + commands, history::History, ps::{self, Ps}, rc::{self}, vm::{self, LuauVm} }; +#[inline] +pub fn shell_error(err: E) { + ceprintln!("[!]: {err}") +} + +pub trait MapDisplay { + fn map_or_display(self, f: F); + fn map_or_display_none Option>(self, f: F) -> Option; +} +impl MapDisplay for Result { + ///Map but display the error to stdout + #[inline] + fn map_or_display(self, f: F) { + self.map_or_else(|e| shell_error(e), f) + } + ///Map but display the error to stdout and return `None` + #[inline] + fn map_or_display_none Option>(self, f: F) -> Option { + self.map_or_else(|e| { shell_error(e); None }, f) + } +} + #[derive(Debug, Clone)] pub struct Config { pub norc: bool } - pub struct LambdaShell { terminate: bool, + history: History, config: Config, vm: LuauVm, ps: Rc>, @@ -22,6 +45,7 @@ impl LambdaShell { Self { ps: Rc::clone(&ps), vm: vm::LuauVm::new(ps), + history: History::init(), terminate: false, config, } @@ -31,8 +55,11 @@ impl LambdaShell { 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, - trim => commands::Command::new(trim.to_owned()).exec() + "exit" => { + self.terminate = true; + self.history.add("exit"); + }, + trim => commands::Command::new(trim.to_owned()).exec(&mut self.history) }) }) } @@ -49,6 +76,7 @@ impl LambdaShell { } } self.ps.borrow().display(); + loop { if self.terminate { break } else { match self.wait() { @@ -57,6 +85,7 @@ impl LambdaShell { } } } + self.history.write_to_file_fallible(); } pub fn vm_exec(&self, source: String) { diff --git a/src/valid_pbuf.rs b/src/valid_pbuf.rs index 92a8984..611ddd3 100644 --- a/src/valid_pbuf.rs +++ b/src/valid_pbuf.rs @@ -1,7 +1,7 @@ use std::{fs::{self, File}, io::{self, Write}, path::PathBuf}; use thiserror::Error; -use crate::MapDisplay; +use crate::session::MapDisplay; #[derive(Debug, Error)] #[allow(dead_code)] diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 0583821..e3119b6 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -5,7 +5,7 @@ use std::{cell::RefCell, rc::Rc}; use core::fmt; use shell::ShellGlobal; -use crate::{ps::Ps, MapDisplay}; +use crate::{ps::Ps, session::MapDisplay}; mod shell; mod terminal;