left and right arrow keys work
This commit is contained in:
parent
ee0ed28f85
commit
c91b486214
24
Cargo.lock
generated
24
Cargo.lock
generated
@ -26,9 +26,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.16.0"
|
version = "3.17.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
@ -241,9 +241,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "luau0-src"
|
name = "luau0-src"
|
||||||
version = "0.11.2+luau653"
|
version = "0.12.0+luau657"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "02313a53daf1fae25e82f7e7ca56180b72d1f08c514426672877cd957298201c"
|
checksum = "3a4b4c16b82ddf60e0fa93ca5a6afc504a6db22310cc82ecec629cd2e405b2ca"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
@ -274,9 +274,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mlua"
|
name = "mlua"
|
||||||
version = "0.10.2"
|
version = "0.10.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9ea43c3ffac2d0798bd7128815212dd78c98316b299b7a902dabef13dc7b6b8d"
|
checksum = "d3f763c1041eff92ffb5d7169968a327e1ed2ebfe425dac0ee5a35f29082534b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bstr",
|
"bstr",
|
||||||
"either",
|
"either",
|
||||||
@ -289,9 +289,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mlua-sys"
|
name = "mlua-sys"
|
||||||
version = "0.6.6"
|
version = "0.6.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "63a11d485edf0f3f04a508615d36c7d50d299cf61a7ee6d3e2530651e0a31771"
|
checksum = "1901c1a635a22fe9250ffcc4fcc937c16b47c2e9e71adba8784af8bca1f69594"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
@ -390,9 +390,9 @@ checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.43"
|
version = "0.38.44"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6"
|
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"errno",
|
"errno",
|
||||||
@ -502,9 +502,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.14"
|
version = "1.0.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::{process, str::SplitWhitespace, path::{Path, PathBuf}};
|
use std::{env, path::{Path, PathBuf}, process, str::SplitWhitespace};
|
||||||
use uzers::User;
|
use uzers::User;
|
||||||
|
|
||||||
use crate::{session::{MapDisplay, Pse}, valid_pbuf::IsValid};
|
use crate::{session::{MapDisplay, Pse}, valid_pbuf::IsValid};
|
||||||
@ -12,18 +12,25 @@ impl PathBufIsValid for PathBuf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ChangeDirectory;
|
struct ChangeDirectory(Option<PathBuf>);
|
||||||
impl ChangeDirectory {
|
impl ChangeDirectory {
|
||||||
fn set_current_dir(&self, new_path: &Path) -> Option<PathBuf> {
|
fn set_dir(&mut self, new_path: &Path) -> Option<PathBuf> {
|
||||||
std::env::set_current_dir(new_path).map_or_display_none(|()| Some(new_path.to_path_buf()))
|
let past_dir = env::current_dir().ok();
|
||||||
|
env::set_current_dir(new_path).map_or_display_none(|()| {
|
||||||
|
self.0 = past_dir;
|
||||||
|
Some(new_path.to_path_buf())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn home_dir(&self) -> Option<PathBuf> {
|
fn home_dir(&mut self) -> Option<PathBuf> {
|
||||||
home::home_dir().map_or(self.set_current_dir(Path::new("/")), |home_pathbuf| self.set_current_dir(&home_pathbuf))
|
home::home_dir().map_or(self.set_dir(Path::new("/")), |home_pathbuf| self.set_dir(&home_pathbuf))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn previous_dir(&self) -> Option<PathBuf> {
|
fn previous_dir(&mut self) -> Option<PathBuf> {
|
||||||
unimplemented!()
|
match self.0.as_ref() {
|
||||||
|
Some(p_buf) => self.set_dir(&p_buf.to_path_buf()),
|
||||||
|
None => None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn specific_user_dir(&self, requested_user: String) -> Option<PathBuf> {
|
fn specific_user_dir(&self, requested_user: String) -> Option<PathBuf> {
|
||||||
@ -43,11 +50,11 @@ impl ChangeDirectory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cd_args(&self, vec_args: Vec<String>) -> Option<PathBuf> {
|
fn cd_args(&mut self, vec_args: Vec<String>) -> Option<PathBuf> {
|
||||||
let string_path = vec_args.concat();
|
let string_path = vec_args.concat();
|
||||||
let new_path = Path::new(string_path.as_str());
|
let new_path = Path::new(string_path.as_str());
|
||||||
match new_path.is_dir() {
|
match new_path.is_dir() {
|
||||||
true => self.set_current_dir(new_path),
|
true => self.set_dir(new_path),
|
||||||
false => {
|
false => {
|
||||||
match new_path.file_name() {
|
match new_path.file_name() {
|
||||||
Some(file_name) => println!("cd: {:?} is not a directory.", file_name),
|
Some(file_name) => println!("cd: {:?} is not a directory.", file_name),
|
||||||
@ -58,12 +65,12 @@ impl ChangeDirectory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_directory(&self, args: SplitWhitespace) -> Option<PathBuf> {
|
fn change_directory(&mut self, args: SplitWhitespace) -> Option<PathBuf> {
|
||||||
let vec_args: Vec<String> = args.map(|arg| arg.to_owned()).collect();
|
let vec_args: Vec<String> = args.map(|arg| arg.to_owned()).collect();
|
||||||
match vec_args.first() {
|
match vec_args.first() {
|
||||||
None => self.home_dir(),
|
None => self.home_dir(),
|
||||||
Some(arg) => match arg.as_str() {
|
Some(arg) => match arg.as_str() {
|
||||||
"/" => self.set_current_dir(Path::new("/")),
|
"/" => self.set_dir(Path::new("/")),
|
||||||
"-" => self.previous_dir(),
|
"-" => self.previous_dir(),
|
||||||
arg_str => {
|
arg_str => {
|
||||||
let mut arg_chars = arg_str.chars();
|
let mut arg_chars = arg_str.chars();
|
||||||
@ -85,15 +92,17 @@ pub trait Command {
|
|||||||
}
|
}
|
||||||
impl Command for Pse {
|
impl Command for Pse {
|
||||||
fn spawn_sys_cmd(&mut self) {
|
fn spawn_sys_cmd(&mut self) {
|
||||||
let mut args = self.rt.input.split_whitespace();
|
let mut args = self.rt.input.literal.split_whitespace();
|
||||||
if let Some(command) = args.next() {
|
if let Some(command) = args.next() {
|
||||||
match command {
|
match command {
|
||||||
"cd" => if ChangeDirectory.change_directory(args).is_some() { self.history.add(self.rt.input.as_str()) },
|
"cd" => if ChangeDirectory(None).change_directory(args).is_some() {
|
||||||
|
self.history.add(self.rt.input.literal.as_str())
|
||||||
|
},
|
||||||
command => if let Ok(mut child) = process::Command::new(command).args(args).spawn() {
|
command => if let Ok(mut child) = process::Command::new(command).args(args).spawn() {
|
||||||
self.history.add(self.rt.input.as_str());
|
self.history.add(self.rt.input.literal.as_str());
|
||||||
child.wait().ok();
|
child.wait().ok();
|
||||||
} else {
|
} else {
|
||||||
println!("\npse: Unknown command: {}", self.rt.input)
|
println!("pse: Unknown command: {}", self.rt.input.literal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use mlua::Lua as Luau;
|
use mlua::Lua as Luau;
|
||||||
use std::{cell::RefCell, fs, rc::Rc};
|
use std::{cell::RefCell, fs, rc::Rc, usize};
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -41,9 +41,14 @@ pub struct Config {
|
|||||||
pub norc: bool,
|
pub norc: bool,
|
||||||
pub vm: VmConfig,
|
pub vm: VmConfig,
|
||||||
}
|
}
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Input {
|
||||||
|
pub literal: String,
|
||||||
|
pub cursor: usize,
|
||||||
|
}
|
||||||
pub struct Rt {
|
pub struct Rt {
|
||||||
|
pub input: Input,
|
||||||
pub ps: Rc<RefCell<String>>,
|
pub ps: Rc<RefCell<String>>,
|
||||||
pub input: String,
|
|
||||||
pub vm: Luau,
|
pub vm: Luau,
|
||||||
}
|
}
|
||||||
pub struct Pse {
|
pub struct Pse {
|
||||||
@ -55,15 +60,16 @@ impl Pse {
|
|||||||
const DEFAULT_PS: &str = concat!("pse-", env!("CARGO_PKG_VERSION"), "$ ");
|
const DEFAULT_PS: &str = concat!("pse-", env!("CARGO_PKG_VERSION"), "$ ");
|
||||||
|
|
||||||
pub fn create(config: Config) -> Self {
|
pub fn create(config: Config) -> Self {
|
||||||
Self {
|
let rt = Rt {
|
||||||
rt: Rt {
|
ps: Rc::new(RefCell::new(Self::DEFAULT_PS.to_owned())),
|
||||||
ps: Rc::new(RefCell::new(Self::DEFAULT_PS.to_owned())),
|
vm: Luau::new(),
|
||||||
input: String::new(),
|
input: Input {
|
||||||
vm: Luau::new(),
|
literal: String::new(),
|
||||||
|
cursor: usize::MIN,
|
||||||
},
|
},
|
||||||
history: History::init(),
|
};
|
||||||
config,
|
|
||||||
}
|
Self { rt, config, history: History::init() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(&mut self) {
|
pub fn start(&mut self) {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crossterm::{cursor, event::{self, Event, KeyCode, KeyEvent, KeyModifiers}, execute, terminal};
|
use crossterm::{cursor, event::{self, Event, KeyCode, KeyEvent, KeyModifiers}, execute, terminal};
|
||||||
|
use core::fmt;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
@ -23,6 +24,13 @@ pub enum InputHandleError {
|
|||||||
}
|
}
|
||||||
type InputResult<T> = Result<T, InputHandleError>;
|
type InputResult<T> = Result<T, InputHandleError>;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn debug<S: fmt::Display>(s: S) {
|
||||||
|
terminal::disable_raw_mode().unwrap();
|
||||||
|
println!("{s}");
|
||||||
|
terminal::enable_raw_mode().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
trait SpecificKeybinds {
|
trait SpecificKeybinds {
|
||||||
const EXIT_1: &str;
|
const EXIT_1: &str;
|
||||||
const KEY_SPACE: char;
|
const KEY_SPACE: char;
|
||||||
@ -55,33 +63,72 @@ impl SpecificKeybinds for Pse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn key_enter(&mut self) -> InputResult<()> {
|
fn key_enter(&mut self) -> InputResult<()> {
|
||||||
if self.rt.input == Self::EXIT_1 { return Err(InputHandleError::UserExit) };
|
if self.rt.input.literal == Self::EXIT_1 { return Err(InputHandleError::UserExit) };
|
||||||
|
|
||||||
terminal::disable_raw_mode().map_err(InputHandleError::DisableRaw)?;
|
terminal::disable_raw_mode().map_err(InputHandleError::DisableRaw)?;
|
||||||
|
println!();
|
||||||
self.spawn_sys_cmd();
|
self.spawn_sys_cmd();
|
||||||
self.rt.input.clear();
|
self.rt.input.literal.clear();
|
||||||
|
self.rt.input.cursor = usize::MIN;
|
||||||
self.term_render_ps()
|
self.term_render_ps()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn key_backspace(&mut self) -> InputResult<()> {
|
fn key_backspace(&mut self) -> InputResult<()> {
|
||||||
if self.rt.input.pop().is_some() {
|
if self.rt.input.literal.pop().is_some() {
|
||||||
execute!(
|
execute!(
|
||||||
io::stdout(),
|
io::stdout(),
|
||||||
cursor::MoveLeft(1),
|
cursor::MoveLeft(1),
|
||||||
terminal::Clear(terminal::ClearType::UntilNewLine)
|
terminal::Clear(terminal::ClearType::UntilNewLine)
|
||||||
).map_err(InputHandleError::Flush)
|
).map_err(InputHandleError::Flush)?;
|
||||||
|
self.rt.input.cursor-=1;
|
||||||
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
//the string is empty, do terminal beep
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn key_arrow_right(&mut self) -> InputResult<()> {
|
fn key_arrow_right(&mut self) -> InputResult<()> {
|
||||||
execute!(io::stdout(), cursor::MoveRight(1)).map_err(InputHandleError::Flush)
|
match self.term_input_cursor_move_right() {
|
||||||
|
Some(()) => execute!(io::stdout(), cursor::MoveRight(1)).map_err(InputHandleError::Flush),
|
||||||
|
None => Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn key_arrow_left(&mut self) -> InputResult<()> {
|
fn key_arrow_left(&mut self) -> InputResult<()> {
|
||||||
execute!(io::stdout(), cursor::MoveLeft(1)).map_err(InputHandleError::Flush)
|
match self.term_input_cursor_move_left() {
|
||||||
|
Some(()) => execute!(io::stdout(), cursor::MoveLeft(1)).map_err(InputHandleError::Flush),
|
||||||
|
None => Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait TermInputCursor {
|
||||||
|
fn term_input_cursor_move_left(&mut self) -> Option<()>;
|
||||||
|
fn term_input_cursor_move_right(&mut self) -> Option<()>;
|
||||||
|
}
|
||||||
|
impl TermInputCursor for Pse {
|
||||||
|
fn term_input_cursor_move_left(&mut self) -> Option<()> {
|
||||||
|
if self.rt.input.cursor == usize::MIN { None } else {
|
||||||
|
match self.rt.input.cursor>usize::MIN {
|
||||||
|
true => {
|
||||||
|
self.rt.input.cursor-=1;
|
||||||
|
Some(())
|
||||||
|
},
|
||||||
|
false => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn term_input_cursor_move_right(&mut self) -> Option<()> {
|
||||||
|
if self.rt.input.cursor == usize::MAX { None } else {
|
||||||
|
match self.rt.input.cursor<self.rt.input.literal.chars().count() {
|
||||||
|
true => {
|
||||||
|
self.rt.input.cursor+=1;
|
||||||
|
Some(())
|
||||||
|
},
|
||||||
|
false => None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,8 +141,13 @@ pub trait TermProcessor {
|
|||||||
}
|
}
|
||||||
impl TermProcessor for Pse {
|
impl TermProcessor for Pse {
|
||||||
fn term_render(&mut self, def_string: String) -> InputResult<()> {
|
fn term_render(&mut self, def_string: String) -> InputResult<()> {
|
||||||
self.rt.input.push_str(&def_string);
|
self.rt.input.literal.insert_str(self.rt.input.cursor, &def_string);
|
||||||
write!(io::stdout(), "{def_string}").map_err(InputHandleError::Write)?;
|
self.rt.input.cursor+=1;
|
||||||
|
if self.rt.input.cursor != self.rt.input.literal.chars().count() {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
write!(io::stdout(), "{}", def_string).map_err(InputHandleError::Write)?;
|
||||||
|
}
|
||||||
io::stdout().flush().map_err(InputHandleError::Flush)
|
io::stdout().flush().map_err(InputHandleError::Flush)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,8 +29,13 @@ impl UserData for Shell {
|
|||||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||||
methods.add_meta_method_mut(MetaMethod::NewIndex, |_, this, (t_index, t_value): (String, String)| -> lResult<()> {
|
methods.add_meta_method_mut(MetaMethod::NewIndex, |_, this, (t_index, t_value): (String, String)| -> lResult<()> {
|
||||||
if t_index == "PROMPT" {
|
if t_index == "PROMPT" {
|
||||||
let mut prompt = this.0.borrow_mut();
|
match t_value.len() as u16 >= u16::MAX {
|
||||||
*prompt = t_value;
|
true => { mlua::Error::runtime(format!("SHELL.PROMPT's length exceeded or equals the max size. ({})", u16::MAX)); },
|
||||||
|
false => {
|
||||||
|
let mut prompt = this.0.borrow_mut();
|
||||||
|
*prompt = t_value;
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user