aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/rc.pdfbin0 -> 79087 bytes
-rw-r--r--src/commandline.rs (renamed from src/parser.rs)31
-rw-r--r--src/commandline/builtins.rs45
-rw-r--r--src/commandline/command.rs (renamed from src/parser/command.rs)81
-rw-r--r--src/main.rs23
5 files changed, 91 insertions, 89 deletions
diff --git a/doc/rc.pdf b/doc/rc.pdf
new file mode 100644
index 0000000..6feab51
--- /dev/null
+++ b/doc/rc.pdf
Binary files differ
diff --git a/src/parser.rs b/src/commandline.rs
index 0c771f9..489eaa8 100644
--- a/src/parser.rs
+++ b/src/commandline.rs
@@ -7,20 +7,17 @@ use std::process::ExitStatus;
// || on prev cmd fail
mod command;
-use command::{CommandInfo, RunOn, RunResult};
+use command::{Command, RunIf, RunResult};
+mod builtins;
-pub struct CommandLine(Vec<CommandInfo>);
+pub struct CommandLine(Vec<Command>);
impl CommandLine {
pub fn new(line: &str) -> Self {
CommandLine(split(line))
}
- pub fn run(
- &self,
- home: &PathBuf,
- mut status: Option<ExitStatus>,
- ) -> Result<Option<ExitStatus>, Error> {
+ pub fn run(&self,home: &PathBuf, mut status: Option<ExitStatus>) -> Result<Option<ExitStatus>, Error> {
for cmd in &self.0 {
if cmd.when.can_run(&status) {
match cmd.run(&home, &status)? {
@@ -33,14 +30,14 @@ impl CommandLine {
}
}
-fn split(line: &str) -> Vec<CommandInfo> {
- let mut r: Vec<CommandInfo> = Vec::new();
+fn split(line: &str) -> Vec<Command> {
+ let mut r: Vec<Command> = Vec::new();
let mut next = line.chars().peekable();
let mut iter = line.chars().enumerate();
let mut start_idx = 0;
- let mut state = RunOn::Always;
+ let mut state = RunIf::Always;
while let Some((i, v)) = {
next.next();
@@ -49,23 +46,23 @@ fn split(line: &str) -> Vec<CommandInfo> {
let n = next.peek();
if v == ';' {
- r.push(CommandInfo::new(&line[start_idx..i], state));
- state = RunOn::Always;
+ r.push(Command::new(&line[start_idx..i], state));
+ state = RunIf::Always;
start_idx = i + 1;
} else if v == '|' && n == Some(&'|') {
- r.push(CommandInfo::new(&line[start_idx..i], state));
- state = RunOn::ExitFailure;
+ r.push(Command::new(&line[start_idx..i], state));
+ state = RunIf::ExitFailure;
start_idx = i + 2;
next.next();
iter.next();
} else if v == '&' && n == Some(&'&') {
- r.push(CommandInfo::new(&line[start_idx..i], state));
- state = RunOn::ExitSuccess;
+ r.push(Command::new(&line[start_idx..i], state));
+ state = RunIf::ExitSuccess;
start_idx = i + 2;
next.next();
iter.next();
} else if n == None {
- r.push(CommandInfo::new(&line[start_idx..], state));
+ r.push(Command::new(&line[start_idx..], state));
}
}
diff --git a/src/commandline/builtins.rs b/src/commandline/builtins.rs
new file mode 100644
index 0000000..c5999f2
--- /dev/null
+++ b/src/commandline/builtins.rs
@@ -0,0 +1,45 @@
+use std::io::{Error, ErrorKind::InvalidInput};
+use std::path::{Path, PathBuf};
+use super::command::RunResult;
+
+pub(in crate::commandline) fn cd(args: &[String], home: &PathBuf) -> Result<RunResult, Error> {
+ if args.len() > 1 {
+ return Err(Error::new(
+ InvalidInput,
+ "Too many arguments passed to cd",
+ ));
+ }
+
+ let root = if args.len() == 0 {
+ home.to_path_buf()
+ } else {
+ std::fs::canonicalize(Path::new(args[0].as_str()))?
+ };
+
+ match std::env::set_current_dir(&root) {
+ Ok(_) => Ok(RunResult::Builtin),
+ Err(e) => Err(e),
+ }
+}
+
+pub(in crate::commandline) fn set(args: &[String]) -> Result<RunResult, Error> {
+ if args.len() != 2 {
+ return Err(Error::new(
+ InvalidInput,
+ format!("set requires 2 arguments, got {}", args.len()),
+ ));
+ }
+ std::env::set_var(&args[0], &args[1]);
+ Ok(RunResult::Builtin)
+}
+
+pub(in crate::commandline) fn unset(args: &[String]) -> Result<RunResult, Error> {
+ if args.len() != 1 {
+ return Err(Error::new(
+ InvalidInput,
+ format!("unset requires 1 argument, got {}", args.len()),
+ ));
+ }
+ std::env::remove_var(&args[0]);
+ Ok(RunResult::Builtin)
+}
diff --git a/src/parser/command.rs b/src/commandline/command.rs
index 4dea8a6..d00f420 100644
--- a/src/parser/command.rs
+++ b/src/commandline/command.rs
@@ -1,6 +1,8 @@
-use std::io::{Error, ErrorKind};
-use std::path::{Path, PathBuf};
-use std::process::{Command, ExitStatus};
+use std::io::{Error};
+use std::path::{PathBuf};
+use std::process::ExitStatus;
+use std::process::Command as Process;
+use super::builtins::{cd, set, unset};
// > overwrite
// >> append
@@ -14,46 +16,42 @@ enum Redirect {
}
#[derive(Debug, PartialEq, Copy, Clone)]
-pub(in crate::parser) enum RunOn {
- Always,
- ExitSuccess,
- ExitFailure,
-}
+pub(in crate::commandline) enum RunIf { Always, ExitSuccess, ExitFailure }
-impl RunOn {
- pub(in crate::parser) fn can_run(&self, status: &Option<ExitStatus>) -> bool {
- if *self == RunOn::Always {
+impl RunIf {
+ pub(in crate::commandline) fn can_run(&self, status: &Option<ExitStatus>) -> bool {
+ if *self == RunIf::Always {
return true;
}
match status {
Some(s) => {
- (*self == RunOn::ExitSuccess && s.success())
- || (*self == RunOn::ExitFailure && !s.success())
+ (*self == RunIf::ExitSuccess && s.success())
+ || (*self == RunIf::ExitFailure && !s.success())
}
None => true,
}
}
}
-pub(in crate::parser) enum RunResult {
+pub(in crate::commandline) enum RunResult {
Command(ExitStatus),
Builtin,
}
#[derive(Debug)]
-pub struct CommandInfo {
+pub struct Command {
args: Vec<String>,
stdout: Redirect,
- pub(in crate::parser) when: RunOn,
+ pub(in crate::commandline) when: RunIf,
}
-impl CommandInfo {
- pub(in crate::parser) fn new(line: &str, when: RunOn) -> CommandInfo {
+impl Command {
+ pub(in crate::commandline) fn new(line: &str, when: RunIf) -> Command {
let (args, stdout) = tokenize(line);
- CommandInfo { args, stdout, when }
+ Command { args, stdout, when }
}
- pub(in crate::parser) fn run(
+ pub(in crate::commandline) fn run(
&self,
home: &PathBuf,
status: &Option<ExitStatus>,
@@ -70,7 +68,7 @@ impl CommandInfo {
"set" => set(&self.args[1..]),
"unset" => unset(&self.args[1..]),
_ => {
- let mut child = Command::new(&self.args[0]).args(&self.args[1..]).spawn()?;
+ let mut child = Process::new(&self.args[0]).args(&self.args[1..]).spawn()?;
Ok(RunResult::Command(child.wait().unwrap()))
}
}
@@ -161,44 +159,3 @@ fn test_tokenizer() {
println!("{:?}", tokenize("ls -l something >>'junction jan''s'"));
}
*/
-fn cd(args: &[String], home: &PathBuf) -> Result<RunResult, Error> {
- if args.len() > 1 {
- return Err(Error::new(
- ErrorKind::InvalidInput,
- "Too many arguments passed to cd",
- ));
- }
-
- let root = if args.len() == 0 {
- home.to_path_buf()
- } else {
- std::fs::canonicalize(Path::new(args[0].as_str()))?
- };
-
- match std::env::set_current_dir(&root) {
- Ok(_) => Ok(RunResult::Builtin),
- Err(e) => Err(e),
- }
-}
-
-fn set(args: &[String]) -> Result<RunResult, Error> {
- if args.len() != 2 {
- return Err(Error::new(
- ErrorKind::InvalidInput,
- format!("set requires 2 arguments, got {}", args.len()),
- ));
- }
- std::env::set_var(&args[0], &args[1]);
- Ok(RunResult::Builtin)
-}
-
-fn unset(args: &[String]) -> Result<RunResult, Error> {
- if args.len() != 1 {
- return Err(Error::new(
- ErrorKind::InvalidInput,
- format!("unset requires 1 argument, got {}", args.len()),
- ));
- }
- std::env::remove_var(&args[0]);
- Ok(RunResult::Builtin)
-}
diff --git a/src/main.rs b/src/main.rs
index 95c3c46..ca5dc00 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,20 +1,21 @@
use rustyline::error::ReadlineError;
use rustyline::Editor;
-mod parser;
+mod commandline;
+use commandline::CommandLine;
mod prompt;
-fn main() {
- match std::fs::read_to_string("/etc/motd") {
- Ok(motd) => print!("{}", motd),
- Err(_) => {}
+fn main() -> Result<(), std::io::Error>{
+ if let Ok(motd) = std::fs::read_to_string("/etc/motd") {
+ print!("{}", motd)
}
- let prompt = prompt::Prompt::new().unwrap();
- let mut status = None;
-
- // `()` can be used when no completer is required
+ // TODO: [completer] `()` can be used when no completer is required
let mut rl = Editor::<()>::new();
+ let prompt = prompt::Prompt::new()?;
+
+ let mut status = None; // exit status of last command
+ // map of variables
/*if rl.load_history("history.txt").is_err() {
println!("No previous history.");
@@ -25,7 +26,7 @@ fn main() {
Ok(line) => {
rl.add_history_entry(line.as_str());
- let cmd = parser::CommandLine::new(&line);
+ let cmd = CommandLine::new(&line);
match cmd.run(&prompt.home, status) {
Ok(s) => status = s,
Err(e) => eprintln!("{}", e),
@@ -47,4 +48,6 @@ fn main() {
}
//rl.save_history("history.txt").unwrap();
+
+ Ok(())
}