diff options
author | Aqua-sama <aqua@iserlohn-fortress.net> | 2020-10-13 22:59:23 +0300 |
---|---|---|
committer | Aqua-sama <aqua@iserlohn-fortress.net> | 2020-10-13 22:59:23 +0300 |
commit | 55f75215607962def4cf83d2c27b2899dce24881 (patch) | |
tree | fb02591c5a6708b9dd8f2bbf871176995fae33b3 | |
parent | Add dummy SIGINT handler (diff) | |
download | rshell-55f75215607962def4cf83d2c27b2899dce24881.tar.xz |
Use crates.io/rustyline as readline
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Cargo.lock | 14 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/builtins.rs | 52 | ||||
-rw-r--r-- | src/main.rs | 111 | ||||
-rw-r--r-- | src/parser.rs | 21 | ||||
-rw-r--r-- | src/prompt.rs | 21 | ||||
-rw-r--r-- | src/prompt/user.rs (renamed from src/user.rs) | 0 |
8 files changed, 109 insertions, 112 deletions
@@ -1 +1,2 @@ +Cargo.lock /target diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index da0c46e..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,14 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "libc" -version = "0.2.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743" - -[[package]] -name = "rs" -version = "0.1.0" -dependencies = [ - "libc", -] @@ -10,4 +10,5 @@ edition = "2018" [dependencies] libc = "0.2" +rustyline = "6.3.0" diff --git a/src/builtins.rs b/src/builtins.rs index b81c4ba..ad41e59 100644 --- a/src/builtins.rs +++ b/src/builtins.rs @@ -1,8 +1,7 @@ use std::path::Path; +use std::process::Command; -pub fn cd(args: std::str::SplitWhitespace) -> std::path::PathBuf { - let new_dir = args.peekable().peek().map_or("/", |x| *x); - +pub fn cd(new_dir: &str) -> std::path::PathBuf { let root = match std::fs::canonicalize(Path::new(new_dir)) { Ok(p) => p, Err(_) => Path::new("/").to_path_buf(), @@ -14,3 +13,50 @@ pub fn cd(args: std::str::SplitWhitespace) -> std::path::PathBuf { root.to_path_buf() } + +pub fn run(command: &str, args: &[&str]) { + let mut child = Command::new(command).args(args).spawn().unwrap(); + child.wait().unwrap(); +} +/* + match command { + + command => { + let stdin = match previous_command { + None => Stdio::inherit(), + Some(cmd) => Stdio::from(cmd.stdout.unwrap()), + }; + let stdout = match commands.peek().is_some() { + true => Stdio::piped(), + false => Stdio::inherit(), + }; + + let child = Command::new(command) + .args(args) + .stdin(stdin) + .stdout(stdout) + .spawn(); + match child { + Ok(c) => previous_command = Some(c), + Err(e) => { + previous_command = None; + eprintln!("{}", e); + } + } + } + } +} + +if let Some(mut final_command) = previous_command { + match final_command.wait() { + Ok(ret) => match ret.code() { + Some(code) => { + if cfg!(debug_assertions) { + println!("exit code [{}]", code); + } + } + None => println!("Process termed by signal"), + }, + Err(e) => eprintln!("error waiting on final command: {}", e), + } +}*/ diff --git a/src/main.rs b/src/main.rs index 01e5fbd..e5e7a53 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,19 +1,11 @@ -use std::process::{Command, Stdio}; +use rustyline::error::ReadlineError; +use rustyline::Editor; mod builtins; +mod parser; mod prompt; -fn sigint_handler(dummy: i32) { - println!("sigint_handler: {}", dummy); -} - fn main() { - - unsafe { - // capture Ctrl+C (SIGINT) - libc::signal(libc::SIGINT, sigint_handler as libc::sighandler_t); - } - match std::fs::read_to_string("/etc/motd") { Ok(motd) => print!("{}", motd), Err(_) => {} @@ -22,77 +14,40 @@ fn main() { let prompt = prompt::Prompt::new().unwrap(); let mut cwd = std::env::current_dir().unwrap(); + // `()` can be used when no completer is required + let mut rl = Editor::<()>::new(); + /*if rl.load_history("history.txt").is_err() { + println!("No previous history."); + }*/ loop { - prompt.print(&cwd); - - let mut input = String::new(); - match std::io::stdin().read_line(&mut input) { - Ok(0) => return, // EOF - Ok(_) => {} // okay - Err(e) => { - eprintln!("error reading line: {}", e); - return; - } - }; - - let mut commands = input.trim().split(" | ").peekable(); - let mut previous_command: std::option::Option<std::process::Child> = None; - - while let Some(command) = commands.next() { - let mut parts = command.trim().split_whitespace(); - let command = match parts.next() { - Some(cmd) => cmd, - None => break, - }; - - let args = parts; - - match command { - "cd" => { - cwd = builtins::cd(args); - previous_command = None; - } - "exit" => return, - - command => { - let stdin = match previous_command { - None => Stdio::inherit(), - Some(cmd) => Stdio::from(cmd.stdout.unwrap()), - }; - let stdout = match commands.peek().is_some() { - true => Stdio::piped(), - false => Stdio::inherit(), - }; - - let child = Command::new(command) - .args(args) - .stdin(stdin) - .stdout(stdout) - .spawn(); - match child { - Ok(c) => previous_command = Some(c), - Err(e) => { - previous_command = None; - eprintln!("{}", e); - } + let readline = rl.readline(&prompt.print(&cwd)); + match readline { + Ok(line) => { + rl.add_history_entry(line.as_str()); + let commands = parser::parse(&line); + match commands[0] { + "cd" => { + cwd = builtins::cd(commands[1]); + } + _ => { + builtins::run(commands[0], &commands[1..]); } } + //println!("Line: {}", line); } - } - - if let Some(mut final_command) = previous_command { - match final_command.wait() { - Ok(ret) => match ret.code() { - Some(code) => { - if cfg!(debug_assertions) { - println!("exit code [{}]", code); - } - } - None => println!("Process termed by signal"), - }, - Err(e) => eprintln!("error waiting on final command: {}", e), + Err(ReadlineError::Interrupted) => { + println!("CTRL-C"); + continue; + } + Err(ReadlineError::Eof) => { + println!("CTRL-D"); + break; + } + Err(err) => { + println!("Error: {:?}", err); + break; } } - } // loop - + } + //rl.save_history("history.txt").unwrap(); } diff --git a/src/parser.rs b/src/parser.rs new file mode 100644 index 0000000..4b37074 --- /dev/null +++ b/src/parser.rs @@ -0,0 +1,21 @@ +//use std::process::{Command, Stdio}; + +// > overwrite +// >> append +// | pipe + +// && on prev cmd okay +// || on prev cmd fail + +pub fn parse(line: &std::string::String) -> Vec<&str> { + line.split(' ').collect() + /* let mut pipe_append = line.split(">>").peekable(); + if let Some(f) = pipe_append.next() { + println!("append to: {:?}", pipe_append.peek()); + + let mut commands = f.trim().split(" | ").peekable(); + while let Some(command) = commands.next() { + println!("run {}", command); + } + }*/ +} diff --git a/src/prompt.rs b/src/prompt.rs index acb11e4..e70c958 100644 --- a/src/prompt.rs +++ b/src/prompt.rs @@ -1,10 +1,7 @@ -use std::io::Write; - -#[path = "user.rs"] mod user; pub struct Prompt { - ps1: std::string::String, + pub ps1: std::string::String, pub home: std::path::PathBuf, } @@ -14,7 +11,7 @@ impl Prompt { let hostname = user::hostname()?; let ready = if username == "root" { "#" } else { "$" }.to_owned(); - let ps1 = match std::env::var("PRMOPT") { + let ps1 = match std::env::var("PROMPT") { Ok(val) => val, Err(_) => String::from(" {USER}@{HOST} [{PWD}]\n{$} "), } @@ -30,23 +27,13 @@ impl Prompt { Ok(Prompt { ps1, home }) } - pub fn print(&self, pwd: &std::path::PathBuf) { - if cfg!(debug_assertions) { - println!("pwd={}", pwd.display()); - } - + pub fn print(&self, pwd: &std::path::PathBuf) -> std::string::String { let path = if pwd.starts_with(&self.home) { "~".to_owned() + &pwd.strip_prefix(&self.home).unwrap().display().to_string() } else { pwd.display().to_string() }; - let ps1 = self.ps1.replace("{PWD}", &path); - - print!("{}", ps1); - match std::io::stdout().flush() { - Ok(_) => {} - Err(_) => println!(""), - }; + self.ps1.replace("{PWD}", &path) } } diff --git a/src/user.rs b/src/prompt/user.rs index 9744928..9744928 100644 --- a/src/user.rs +++ b/src/prompt/user.rs |