Compare commits

...

2 Commits

3 changed files with 76 additions and 33 deletions

View File

@ -6,27 +6,16 @@ use std::{
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
use crate::MapDisplay; use crate::{rc::History, MapDisplay};
enum ValidStatus { enum ValidStatus {
NoRootFolder, NoRootFolder,
TryExists(io::Error) TryExists(io::Error)
} }
trait PathBufIsValid { trait PathBufIsValid {
fn is_valid(&self) -> Result<PathBuf, ValidStatus>; fn is_valid(&self) -> Result<PathBuf, ValidStatus>;
fn is_valid_or_home(&self) -> Option<PathBuf>; fn is_valid_or_home(&self) -> Option<PathBuf>;
} }
trait ChangeDirectory {
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>;
fn cd_args(&self, vec_args: Vec<String>) -> Option<PathBuf>;
fn previous_dir(&self) -> Option<PathBuf>;
fn home_dir(&self) -> Option<PathBuf>;
}
impl PathBufIsValid for PathBuf { impl PathBufIsValid for PathBuf {
fn is_valid(&self) -> Result<PathBuf, ValidStatus> { fn is_valid(&self) -> Result<PathBuf, ValidStatus> {
match self.try_exists() { match self.try_exists() {
@ -50,6 +39,14 @@ impl PathBufIsValid for PathBuf {
} }
} }
trait ChangeDirectory {
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>;
fn cd_args(&self, vec_args: Vec<String>) -> Option<PathBuf>;
fn previous_dir(&self) -> Option<PathBuf>;
fn home_dir(&self) -> Option<PathBuf>;
}
impl ChangeDirectory for Command { impl ChangeDirectory for Command {
fn set_current_dir(&self, new_path: &Path) -> Option<PathBuf> { 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())) std::env::set_current_dir(new_path).map_or_display_none(|()| Some(new_path.to_path_buf()))
@ -117,26 +114,35 @@ impl ChangeDirectory for Command {
} }
} }
pub struct Command(String); pub struct Command {
input: String,
history: Option<History>
}
impl Command { impl Command {
pub fn new(input: String) -> Self { pub fn new(input: String) -> Self {
Self(input) Self {
history: History::init(),
input
}
} }
pub fn spawn(&self, command_process: io::Result<process::Child>) { pub fn spawn_handle(&mut self, command_process: io::Result<process::Child>) {
command_process.map_or_display_none(|mut child| Some(child.wait())); if let Ok(mut child) = command_process {
if let Some(history_file) = self.history.as_mut() {
history_file.write(&self.input);
};
child.wait().ok();
} else {
println!("Unknown command: {}", self.input)
}
} }
pub fn exec(&self) { pub fn exec(&mut self) {
let mut args = self.0.split_whitespace(); let mut args = self.input.split_whitespace();
if let Some(command) = args.next() { if let Some(command) = args.next() {
match command { match command {
"cd" => { "cd" => { self.change_directory(args); },
self.change_directory(args); command => { self.spawn_handle(process::Command::new(command).args(args).spawn()); }
},
command => {
self.spawn(process::Command::new(command).args(args).spawn());
}
} }
} }
} }

View File

@ -1,7 +1,7 @@
use std::{path::PathBuf, fs::{self, File}, io::{self, Write}}; use std::{fs::{self, File, OpenOptions}, io::{self, BufRead, BufReader, Write}, path::PathBuf};
use thiserror::Error; use thiserror::Error;
use crate::MapDisplay; use crate::{shell_error, MapDisplay};
pub const DEFAULT_CONFIG_CONTENT: &str = r#"--!strict pub const DEFAULT_CONFIG_CONTENT: &str = r#"--!strict
@ -95,9 +95,47 @@ pub fn config_file() -> Option<PathBuf> {
config_file.is_valid_file_or_create(DEFAULT_CONFIG_CONTENT.as_bytes()) config_file.is_valid_file_or_create(DEFAULT_CONFIG_CONTENT.as_bytes())
} }
// TODO: history.rs pub struct History {
pub fn history_file() -> Option<PathBuf> { history_file: PathBuf,
let mut config_file = config_dir()?; checked_empty: bool
config_file.push(".history"); }
config_file.is_valid_file_or_create(b"") impl History {
pub fn init() -> Option<Self> {
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<S: AsRef<str>>(&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<Vec<String>> {
File::open(&self.history_file).map_or_display_none(|file| {
Some(BufReader::new(file).lines().map_while(Result::ok).collect::<Vec<String>>())
})
}
} }

View File

@ -2,7 +2,7 @@ use std::{cell::RefCell, fs, io::{self}, rc::Rc};
use core::fmt; use core::fmt;
use crate::{ use crate::{
commands, ps::{self, Ps}, rc, shell_error, vm::{self, LuauVm}, MapDisplay commands, ps::{self, Ps}, rc::{self}, shell_error, vm::{self, LuauVm}, MapDisplay
}; };
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -48,7 +48,6 @@ impl LambdaShell {
fs::read_to_string(conf_file).map_or_display(|luau_conf| self.vm_exec(luau_conf)); fs::read_to_string(conf_file).map_or_display(|luau_conf| self.vm_exec(luau_conf));
} }
} }
self.ps.borrow().display(); self.ps.borrow().display();
loop { loop {
if self.terminate { break } else { if self.terminate { break } else {