diff --git a/src/commands.rs b/src/commands.rs index 6335269..d452e64 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -6,7 +6,7 @@ use std::{ path::{Path, PathBuf}, }; -use crate::{rc::History, MapDisplay}; +use crate::{history::History, MapDisplay}; enum ValidStatus { NoRootFolder, @@ -126,11 +126,15 @@ impl Command { } } + 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) { if let Ok(mut child) = command_process { - if let Some(history_file) = self.history.as_mut() { - history_file.write(&self.input); - }; + self.write_history(); child.wait().ok(); } else { println!("Unknown command: {}", self.input) diff --git a/src/history.rs b/src/history.rs new file mode 100644 index 0000000..ec3d0d6 --- /dev/null +++ b/src/history.rs @@ -0,0 +1,48 @@ +use std::{fs::{File, OpenOptions}, io::{BufRead, BufReader, Write}, path::PathBuf}; + +use crate::{rc::{self}, shell_error, valid_pbuf::IsValid, MapDisplay}; + +pub struct History { + history_file: PathBuf, + checked_empty: bool +} +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 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 read(&self) -> Option> { + File::open(&self.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 c92cdf2..d5a360f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,10 +2,13 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION"); pub mod session; pub mod commands; +pub mod history; pub mod ps; pub mod rc; pub mod vm; +mod valid_pbuf; + #[inline] pub fn shell_error(err: E) { color_print::ceprintln!("[!]: {err}") diff --git a/src/rc.rs b/src/rc.rs index 9cd084a..120d686 100644 --- a/src/rc.rs +++ b/src/rc.rs @@ -1,7 +1,6 @@ -use std::{fs::{self, File, OpenOptions}, io::{self, BufRead, BufReader, Write}, path::PathBuf}; -use thiserror::Error; +use std::path::PathBuf; -use crate::{shell_error, MapDisplay}; +use crate::valid_pbuf::IsValid; pub const DEFAULT_CONFIG_CONTENT: &str = r#"--!strict @@ -15,72 +14,6 @@ username = if username == "root" then red(username) else cyan(username) SHELL.PROMPT = `{username}@{hostname} λ `"#; -#[derive(Debug, Error)] -#[allow(dead_code)] -enum IsValidDirErr { - #[error("Failed to see if a file exists: {0}")] - TryExists(#[from] io::Error), - #[error("Not a valid entry")] - NotAnEntry, - #[error("Directory missing")] - Missing -} - -#[allow(dead_code)] -enum CreateErr { - TryExists(io::Error), - Passable -} - -#[allow(dead_code)] -trait IsValid { - fn is_valid(&self, is_dir_or_file: bool) -> Result; - fn is_valid_option(&self, is_dir_or_file: bool) -> Option; - fn is_valid_file_or_create(&self, default_file_bytes: &[u8]) -> Option; - fn is_valid_dir_or_create(&self) -> Option; - fn is_valid_or(&self, is_content: bool, f: F) -> Option - where - F: FnOnce() -> Option; -} -impl IsValid for PathBuf { - fn is_valid(&self, is_content: bool) -> Result { - match self.try_exists() { - Ok(true) => if is_content { Ok(self.to_path_buf()) } else { Err(IsValidDirErr::NotAnEntry) }, - Ok(false) => Err(IsValidDirErr::Missing), - Err(try_e) => Err(IsValidDirErr::TryExists(try_e)) - } - } - - fn is_valid_or(&self, is_content: bool, f: F) -> Option - where - F: FnOnce() -> Option - { - self.is_valid(is_content).map_err(|e| match e { - IsValidDirErr::TryExists(try_e) => CreateErr::TryExists(try_e), - IsValidDirErr::NotAnEntry | IsValidDirErr::Missing => CreateErr::Passable - }).map_or_else(|e| match e { - CreateErr::TryExists(_) => None, - CreateErr::Passable => f() - }, Some) - } - - fn is_valid_dir_or_create(&self) -> Option { - self.is_valid_or(self.is_dir(), || fs::create_dir(self).map_or_display_none(|()| Some(self.to_path_buf()))) - } - - fn is_valid_file_or_create(&self, default_file_bytes: &[u8]) -> Option { - self.is_valid_or(self.is_file(), || { - File::create(self).map_or_display_none(|mut file| { - file.write_all(default_file_bytes).map_or_display_none(|()| Some(self.to_path_buf())) - }) - }) - } - - fn is_valid_option(&self, is_dir_or_file: bool) -> Option { - self.is_valid(is_dir_or_file).ok() - } -} - pub fn config_dir() -> Option { let mut config = home::home_dir()?; config.push(".config"); @@ -93,49 +26,4 @@ pub fn config_file() -> Option { let mut config_file = config_dir()?; config_file.push("init.luau"); config_file.is_valid_file_or_create(DEFAULT_CONFIG_CONTENT.as_bytes()) -} - -pub struct History { - history_file: PathBuf, - checked_empty: bool -} -impl History { - pub fn init() -> Option { - 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 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 read(&self) -> Option> { - File::open(&self.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/valid_pbuf.rs b/src/valid_pbuf.rs new file mode 100644 index 0000000..92a8984 --- /dev/null +++ b/src/valid_pbuf.rs @@ -0,0 +1,75 @@ +use std::{fs::{self, File}, io::{self, Write}, path::PathBuf}; +use thiserror::Error; + +use crate::MapDisplay; + +#[derive(Debug, Error)] +#[allow(dead_code)] +pub enum IsValidDirErr { + #[error("Failed to see if a file exists: {0}")] + TryExists(#[from] io::Error), + #[error("Not a valid entry")] + NotAnEntry, + #[error("Directory missing")] + Missing +} + +#[allow(dead_code)] +enum CreateErr { + TryExists(io::Error), + Passable +} + +#[allow(dead_code)] +pub trait IsValid { + fn is_valid(&self, is_dir_or_file: bool) -> Result; + fn is_valid_option(&self, is_dir_or_file: bool) -> Option; + fn is_valid_file_or_create(&self, default_file_bytes: &[u8]) -> Option; + fn is_valid_dir_or_create(&self) -> Option; + fn is_valid_or(&self, is_content: bool, f: F) -> Option + where + F: FnOnce() -> Option; +} +impl IsValid for PathBuf { + #[inline] + fn is_valid(&self, is_content: bool) -> Result { + match self.try_exists() { + Ok(true) => if is_content { Ok(self.to_path_buf()) } else { Err(IsValidDirErr::NotAnEntry) }, + Ok(false) => Err(IsValidDirErr::Missing), + Err(try_e) => Err(IsValidDirErr::TryExists(try_e)) + } + } + + #[inline] + fn is_valid_or(&self, is_content: bool, f: F) -> Option + where + F: FnOnce() -> Option + { + self.is_valid(is_content).map_err(|e| match e { + IsValidDirErr::TryExists(try_e) => CreateErr::TryExists(try_e), + IsValidDirErr::NotAnEntry | IsValidDirErr::Missing => CreateErr::Passable + }).map_or_else(|e| match e { + CreateErr::TryExists(_) => None, + CreateErr::Passable => f() + }, Some) + } + + #[inline] + fn is_valid_dir_or_create(&self) -> Option { + self.is_valid_or(self.is_dir(), || fs::create_dir(self).map_or_display_none(|()| Some(self.to_path_buf()))) + } + + #[inline] + fn is_valid_file_or_create(&self, default_file_bytes: &[u8]) -> Option { + self.is_valid_or(self.is_file(), || { + File::create(self).map_or_display_none(|mut file| { + file.write_all(default_file_bytes).map_or_display_none(|()| Some(self.to_path_buf())) + }) + }) + } + + #[inline] + fn is_valid_option(&self, is_dir_or_file: bool) -> Option { + self.is_valid(is_dir_or_file).ok() + } +}