Browse Source

feat: use shlex to parse line

main
fdai7451 2 years ago
parent
commit
66edb724bd
  1. 7
      Cargo.lock
  2. 1
      Cargo.toml
  3. 4
      src/builtins/cd.rs
  4. 2
      src/builtins/exit.rs
  5. 2
      src/builtins/mod.rs
  6. 1
      src/error.rs
  7. 4
      src/execute.rs
  8. 3
      src/main.rs
  9. 40
      src/parse.rs

7
Cargo.lock

@ -174,6 +174,7 @@ name = "pmuw-project"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"rustyline", "rustyline",
"shlex",
] ]
[[package]] [[package]]
@ -267,6 +268,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "shlex"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
[[package]] [[package]]
name = "smallvec" name = "smallvec"
version = "1.10.0" version = "1.10.0"

1
Cargo.toml

@ -5,3 +5,4 @@ edition = "2021"
[dependencies] [dependencies]
rustyline = "10.1.0" rustyline = "10.1.0"
shlex = "1.1"

4
src/builtins/cd.rs

@ -2,7 +2,7 @@ use std::env::set_current_dir;
use crate::error::ShellError; use crate::error::ShellError;
pub fn run(args: &[&str]) -> Result<(), ShellError> {
set_current_dir(args[0]);
pub fn run(args: Vec<String>) -> Result<(), ShellError> {
set_current_dir(args.get(0).unwrap());
Ok(()) Ok(())
} }

2
src/builtins/exit.rs

@ -2,4 +2,4 @@ use crate::error::ShellError;
pub fn run() -> Result<(), ShellError> { pub fn run() -> Result<(), ShellError> {
Err(ShellError::Exit) Err(ShellError::Exit)
}
}

2
src/builtins/mod.rs

@ -8,7 +8,7 @@ pub fn is_builtin(keyword: &str) -> bool {
BUILTINS.contains(&keyword) BUILTINS.contains(&keyword)
} }
pub fn execute_builtin(keyword: &str, args: &[&str]) -> Result<(), ShellError> {
pub fn execute_builtin(keyword: &str, args: Vec<String>) -> Result<(), ShellError> {
match keyword { match keyword {
"exit" => exit::run()?, "exit" => exit::run()?,
"cd" => cd::run(args)?, "cd" => cd::run(args)?,

1
src/error.rs

@ -5,4 +5,5 @@ pub enum ShellError {
Exit, Exit,
NotFound(Command), NotFound(Command),
ExecuteFailure(String), ExecuteFailure(String),
MalformedArgs(String),
} }

4
src/execute.rs

@ -9,10 +9,10 @@ pub fn interpret(line: &str) -> Result<(), ShellError> {
if line.is_empty() { if line.is_empty() {
return Err(ShellError::EmptyLine); return Err(ShellError::EmptyLine);
} }
let (keyword, args) = parse_line(line);
let (keyword, args) = parse_line(line)?;
if is_builtin(keyword) { if is_builtin(keyword) {
execute_builtin(keyword, &args)?;
execute_builtin(keyword, args)?;
} else { } else {
let mut command = Command::new(keyword); let mut command = Command::new(keyword);
command.args(args); command.args(args);

3
src/main.rs

@ -34,6 +34,9 @@ fn main() -> Result<()> {
Err(ShellError::ExecuteFailure(msg)) => { Err(ShellError::ExecuteFailure(msg)) => {
eprintln!("{}", msg) eprintln!("{}", msg)
} }
Err(ShellError::MalformedArgs(args)) => {
eprintln!("Malformed arguments: {}", args)
}
}, },
Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => { Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => {
break; break;

40
src/parse.rs

@ -1,37 +1,11 @@
pub fn parse_line(line: &str) -> (&str, Vec<&str>) {
let tokens = tokenize(line);
use crate::error::ShellError;
let keyword = tokens[0];
let mut args: Vec<&str> = Vec::new();
pub fn parse_line(line: &str) -> Result<(&str, Vec<String>), ShellError> {
let (keyword, unparsed_args) = line.split_once(' ').unwrap_or((line, ""));
if tokens.len() > 1 {
args = tokens[1..].to_vec();
}
(keyword, args)
}
fn tokenize(line: &str) -> Vec<&str> {
line.trim().split(' ').collect::<Vec<&str>>()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tokenize() {
assert_eq!(
tokenize("keyword arg1 arg2 arg3"),
vec!["keyword", "arg1", "arg2", "arg3"]
);
}
#[test]
fn test_parse_line() {
assert_eq!(
parse_line("keyword arg1 arg2 arg3"),
("keyword", vec!["arg1", "arg2", "arg3"])
);
if let Some(args) = shlex::split(unparsed_args) {
Ok((keyword, args))
} else {
Err(ShellError::MalformedArgs(unparsed_args.to_string()))
} }
} }
Loading…
Cancel
Save