aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAqua-sama <aqua@iserlohn-fortress.net>2020-10-13 22:59:23 +0300
committerAqua-sama <aqua@iserlohn-fortress.net>2020-10-13 22:59:23 +0300
commit55f75215607962def4cf83d2c27b2899dce24881 (patch)
treefb02591c5a6708b9dd8f2bbf871176995fae33b3
parentAdd dummy SIGINT handler (diff)
downloadrshell-55f75215607962def4cf83d2c27b2899dce24881.tar.xz
Use crates.io/rustyline as readline
-rw-r--r--.gitignore1
-rw-r--r--Cargo.lock14
-rw-r--r--Cargo.toml1
-rw-r--r--src/builtins.rs52
-rw-r--r--src/main.rs111
-rw-r--r--src/parser.rs21
-rw-r--r--src/prompt.rs21
-rw-r--r--src/prompt/user.rs (renamed from src/user.rs)0
8 files changed, 109 insertions, 112 deletions
diff --git a/.gitignore b/.gitignore
index ea8c4bf..06aba01 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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",
-]
diff --git a/Cargo.toml b/Cargo.toml
index 9859720..e455a3c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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