From d195ccafbdb162f52f2dec987da21fb8bfd5bc6d Mon Sep 17 00:00:00 2001 From: Sag0Sag0 <laurencebelastevens@gmail.com> Date: Wed, 6 Dec 2017 19:48:56 +1100 Subject: [PATCH] Add tests for builtin is --- src/ascii_helpers.rs | 5 +- src/builtins/exists.rs | 143 +++++++++---- src/builtins/is.rs | 49 ++++- src/builtins/job_control.rs | 22 +- src/builtins/man_pages.rs | 61 +++--- src/builtins/mod.rs | 100 +++++---- src/builtins/random.rs | 5 +- src/builtins/set.rs | 5 +- src/builtins/test.rs | 78 ++++--- src/builtins/variables.rs | 50 +++-- src/lib.rs | 2 +- src/parser/arguments.rs | 22 +- src/parser/assignments/actions.rs | 59 ++++-- src/parser/assignments/checker.rs | 10 +- src/parser/assignments/keys.rs | 77 +++++-- src/parser/assignments/splitter.rs | 22 +- src/parser/loops/for_grammar.rs | 13 +- src/parser/pipelines/collector.rs | 120 +++++------ src/parser/pipelines/mod.rs | 21 +- src/parser/quotes.rs | 52 +++-- src/parser/shell_expand/braces.rs | 10 +- src/parser/shell_expand/mod.rs | 119 ++++++++--- src/parser/shell_expand/ranges.rs | 29 ++- .../shell_expand/words/methods/arrays.rs | 156 ++++++++------ src/parser/shell_expand/words/methods/mod.rs | 10 +- .../shell_expand/words/methods/strings.rs | 190 +++++++++--------- src/parser/shell_expand/words/mod.rs | 56 ++++-- src/parser/shell_expand/words/range.rs | 26 ++- src/parser/shell_expand/words/select.rs | 16 +- src/parser/shell_expand/words/tests.rs | 42 ++-- src/parser/statement/case.rs | 5 +- src/parser/statement/functions.rs | 20 +- src/parser/statement/mod.rs | 3 +- src/parser/statement/parse.rs | 92 ++++++--- src/parser/statement/splitter.rs | 57 ++++-- src/shell/assignments.rs | 76 +++++-- src/shell/binary/designators.rs | 19 +- src/shell/binary/mod.rs | 24 ++- src/shell/binary/readln.rs | 26 +-- src/shell/colors.rs | 40 +++- src/shell/completer.rs | 59 +++--- src/shell/directory_stack.rs | 93 ++++++--- src/shell/flow.rs | 175 +++++++++++----- src/shell/flow_control.rs | 62 +++--- src/shell/fork.rs | 8 +- src/shell/history.rs | 39 ++-- src/shell/job.rs | 55 +++-- src/shell/mod.rs | 113 ++++++----- src/shell/pipe_exec/command_not_found.rs | 2 +- src/shell/pipe_exec/foreground.rs | 20 +- src/shell/pipe_exec/fork.rs | 4 +- src/shell/pipe_exec/job_control.rs | 42 ++-- src/shell/pipe_exec/mod.rs | 106 +++++++--- src/shell/plugins/library_iter/redox.rs | 8 +- src/shell/plugins/library_iter/unix.rs | 10 +- src/shell/plugins/methods/redox.rs | 8 +- src/shell/plugins/methods/unix.rs | 44 ++-- src/shell/plugins/mod.rs | 14 +- src/shell/plugins/namespaces/redox.rs | 4 +- src/shell/plugins/namespaces/unix.rs | 18 +- src/shell/plugins/string.rs | 6 +- src/shell/signals.rs | 18 +- src/shell/status.rs | 4 +- src/shell/variables/mod.rs | 97 ++++++--- src/sys/redox.rs | 38 ++-- src/sys/unix/job_control.rs | 5 +- src/sys/unix/mod.rs | 24 ++- src/sys/unix/signals.rs | 12 +- 68 files changed, 2016 insertions(+), 1004 deletions(-) diff --git a/src/ascii_helpers.rs b/src/ascii_helpers.rs index 9cc2850e..8ca4fafc 100644 --- a/src/ascii_helpers.rs +++ b/src/ascii_helpers.rs @@ -23,7 +23,10 @@ impl AsciiReplaceInPlace for str { // I tried replacing these `assert!` calls with `debug_assert!` but it looks // like they get const-folded away anyway since it doesn't affect the speed fn ascii_replace_in_place(&mut self, needle: char, haystack: char) { - assert!(needle.is_ascii(), "AsciiReplace functions can only be used for ascii characters"); + assert!( + needle.is_ascii(), + "AsciiReplace functions can only be used for ascii characters" + ); assert!( haystack.is_ascii(), "AsciiReplace functions can only be used for ascii characters" diff --git a/src/builtins/exists.rs b/src/builtins/exists.rs index 2240f639..eab328d5 100644 --- a/src/builtins/exists.rs +++ b/src/builtins/exists.rs @@ -27,9 +27,9 @@ fn evaluate_arguments(arguments: &[&str], shell: &Shell) -> Result<bool, String> }) } Some(&s) if s.starts_with("-") => { - // Access the second character in the flag string: this will be type of the flag. - // If no flag was given, return `SUCCESS`, as this means a string with value "-" was - // checked. + // Access the second character in the flag string: this will be type of the + // flag. If no flag was given, return `SUCCESS`, as this means a + // string with value "-" was checked. s.chars().nth(1).map_or(Ok(true), |flag| { // If no argument was given, return `SUCCESS`, as this means a string starting // with a dash was given @@ -45,7 +45,8 @@ fn evaluate_arguments(arguments: &[&str], shell: &Shell) -> Result<bool, String> } } -/// Matches flag arguments to their respective functionaity when the `-` character is detected. +/// Matches flag arguments to their respective functionaity when the `-` +/// character is detected. fn match_flag_argument(flag: char, argument: &str, shell: &Shell) -> bool { match flag { 'a' => array_var_is_not_empty(argument, shell), @@ -67,20 +68,24 @@ fn match_option_argument(option: &str, argument: &str, shell: &Shell) -> bool { /// Returns true if the file is a regular file fn path_is_file(filepath: &str) -> bool { - fs::metadata(filepath).ok().map_or(false, |metadata| metadata.file_type().is_file()) + fs::metadata(filepath) + .ok() + .map_or(false, |metadata| metadata.file_type().is_file()) } /// Returns true if the file is a directory fn path_is_directory(filepath: &str) -> bool { - fs::metadata(filepath).ok().map_or(false, |metadata| metadata.file_type().is_dir()) + fs::metadata(filepath) + .ok() + .map_or(false, |metadata| metadata.file_type().is_dir()) } /// Returns true if the binary is found in path (and is executable) fn binary_is_in_path(binaryname: &str, shell: &Shell) -> bool { // TODO: Maybe this function should reflect the logic for spawning new processes - // TODO: Right now they use an entirely different logic which means that it *might* be possible - // TODO: that `exists` reports a binary to be in the path, while the shell cannot find it or - // TODO: vice-versa + // TODO: Right now they use an entirely different logic which means that it + // *might* be possible TODO: that `exists` reports a binary to be in the + // path, while the shell cannot find it or TODO: vice-versa if let Some(path) = shell.get_var("PATH") { for dir in path.split(":") { let fname = format!("{}/{}", dir, binaryname); @@ -113,7 +118,9 @@ fn file_has_execute_permission(filepath: &str) -> bool { } /// Returns true if the string is not empty -fn string_is_nonzero(string: &str) -> bool { !string.is_empty() } +fn string_is_nonzero(string: &str) -> bool { + !string.is_empty() +} /// Returns true if the variable is an array and the array is not empty fn array_var_is_not_empty(arrayvar: &str, shell: &Shell) -> bool { @@ -160,7 +167,9 @@ fn test_evaluate_arguments() { // check `exists -a` // no argument means we treat it as a string assert_eq!(evaluate_arguments(&["-a"], &shell), Ok(true)); - shell.variables.set_array("emptyarray", SmallVec::from_vec(Vec::new())); + shell + .variables + .set_array("emptyarray", SmallVec::from_vec(Vec::new())); assert_eq!(evaluate_arguments(&["-a", "emptyarray"], &shell), Ok(false)); let mut vec = Vec::new(); vec.push("element".to_owned()); @@ -176,27 +185,45 @@ fn test_evaluate_arguments() { let oldpath = shell.get_var("PATH").unwrap_or("/usr/bin".to_owned()); shell.set_var("PATH", "testing/"); - assert_eq!(evaluate_arguments(&["-b", "executable_file"], &shell), Ok(true)); + assert_eq!( + evaluate_arguments(&["-b", "executable_file"], &shell), + Ok(true) + ); assert_eq!(evaluate_arguments(&["-b", "empty_file"], &shell), Ok(false)); - assert_eq!(evaluate_arguments(&["-b", "file_does_not_exist"], &shell), Ok(false)); + assert_eq!( + evaluate_arguments(&["-b", "file_does_not_exist"], &shell), + Ok(false) + ); - // restore original PATH. Not necessary for the currently defined test cases but this might - // change in the future? Better safe than sorry! + // restore original PATH. Not necessary for the currently defined test cases + // but this might change in the future? Better safe than sorry! shell.set_var("PATH", &oldpath); // check `exists -d` // no argument means we treat it as a string assert_eq!(evaluate_arguments(&["-d"], &shell), Ok(true)); assert_eq!(evaluate_arguments(&["-d", "testing/"], &shell), Ok(true)); - assert_eq!(evaluate_arguments(&["-d", "testing/empty_file"], &shell), Ok(false)); - assert_eq!(evaluate_arguments(&["-d", "does/not/exist/"], &shell), Ok(false)); + assert_eq!( + evaluate_arguments(&["-d", "testing/empty_file"], &shell), + Ok(false) + ); + assert_eq!( + evaluate_arguments(&["-d", "does/not/exist/"], &shell), + Ok(false) + ); // check `exists -f` // no argument means we treat it as a string assert_eq!(evaluate_arguments(&["-f"], &shell), Ok(true)); assert_eq!(evaluate_arguments(&["-f", "testing/"], &shell), Ok(false)); - assert_eq!(evaluate_arguments(&["-f", "testing/empty_file"], &shell), Ok(true)); - assert_eq!(evaluate_arguments(&["-f", "does-not-exist"], &shell), Ok(false)); + assert_eq!( + evaluate_arguments(&["-f", "testing/empty_file"], &shell), + Ok(true) + ); + assert_eq!( + evaluate_arguments(&["-f", "does-not-exist"], &shell), + Ok(false) + ); // check `exists -s` // no argument means we treat it as a string @@ -218,18 +245,25 @@ fn test_evaluate_arguments() { let name_str = "test_function"; let name = SmallString::from_str(name_str); let mut args = Vec::new(); - args.push(KeyBuf { name: "testy".into(), kind: Primitive::Any }); + args.push(KeyBuf { + name: "testy".into(), + kind: Primitive::Any, + }); let mut statements = Vec::new(); statements.push(Statement::End); let description = "description".to_owned(); - shell.functions.insert(name.clone(), Function::new(Some(description), name, args, statements)); + shell.functions.insert( + name.clone(), + Function::new(Some(description), name, args, statements), + ); assert_eq!(evaluate_arguments(&["--fn", name_str], &shell), Ok(true)); shell.functions.remove(name_str); assert_eq!(evaluate_arguments(&["--fn", name_str], &shell), Ok(false)); - // check invalid flags / parameters (should all be treated as strings and therefore succeed) + // check invalid flags / parameters (should all be treated as strings and + // therefore succeed) assert_eq!(evaluate_arguments(&["--foo"], &shell), Ok(true)); assert_eq!(evaluate_arguments(&["-x"], &shell), Ok(true)); } @@ -238,12 +272,28 @@ fn test_evaluate_arguments() { fn test_match_flag_argument() { let shell = Shell::new(); - // we don't really care about the passed values, as long as both sited return the same value - assert_eq!(match_flag_argument('a', "ARRAY", &shell), array_var_is_not_empty("ARRAY", &shell)); - assert_eq!(match_flag_argument('b', "binary", &shell), binary_is_in_path("binary", &shell)); - assert_eq!(match_flag_argument('d', "path", &shell), path_is_directory("path")); - assert_eq!(match_flag_argument('f', "file", &shell), path_is_file("file")); - assert_eq!(match_flag_argument('s', "STR", &shell), string_var_is_not_empty("STR", &shell)); + // we don't really care about the passed values, as long as both sited return + // the same value + assert_eq!( + match_flag_argument('a', "ARRAY", &shell), + array_var_is_not_empty("ARRAY", &shell) + ); + assert_eq!( + match_flag_argument('b', "binary", &shell), + binary_is_in_path("binary", &shell) + ); + assert_eq!( + match_flag_argument('d', "path", &shell), + path_is_directory("path") + ); + assert_eq!( + match_flag_argument('f', "file", &shell), + path_is_file("file") + ); + assert_eq!( + match_flag_argument('s', "STR", &shell), + string_var_is_not_empty("STR", &shell) + ); // Any flag which is not implemented assert_eq!(match_flag_argument('x', "ARG", &shell), false); @@ -253,8 +303,12 @@ fn test_match_flag_argument() { fn test_match_option_argument() { let shell = Shell::new(); - // we don't really care about the passed values, as long as both sited return the same value - assert_eq!(match_option_argument("fn", "FUN", &shell), array_var_is_not_empty("FUN", &shell)); + // we don't really care about the passed values, as long as both sited return + // the same value + assert_eq!( + match_option_argument("fn", "FUN", &shell), + array_var_is_not_empty("FUN", &shell) + ); // Any option which is not implemented assert_eq!(match_option_argument("foo", "ARG", &shell), false); @@ -280,8 +334,8 @@ fn test_binary_is_in_path() { // TODO: multiple/:directories/ // TODO: PATH containing directories which do not exist // TODO: PATH containing directories without read permission (for user) - // TODO: PATH containing directories without execute ("enter") permission (for user) - // TODO: empty PATH? + // TODO: PATH containing directories without execute ("enter") permission (for + // user) TODO: empty PATH? shell.set_var("PATH", "testing/"); assert_eq!(binary_is_in_path("executable_file", &shell), true); @@ -307,19 +361,24 @@ fn test_string_is_nonzero() { fn test_array_var_is_not_empty() { let mut shell = Shell::new(); - shell.variables.set_array("EMPTY_ARRAY", SmallVec::from_vec(Vec::new())); + shell + .variables + .set_array("EMPTY_ARRAY", SmallVec::from_vec(Vec::new())); assert_eq!(array_var_is_not_empty("EMPTY_ARRAY", &shell), false); let mut not_empty_vec = Vec::new(); not_empty_vec.push("array not empty".to_owned()); - shell.variables.set_array("NOT_EMPTY_ARRAY", SmallVec::from_vec(not_empty_vec)); + shell + .variables + .set_array("NOT_EMPTY_ARRAY", SmallVec::from_vec(not_empty_vec)); assert_eq!(array_var_is_not_empty("NOT_EMPTY_ARRAY", &shell), true); // test for array which does not even exist shell.variables.unset_array("NOT_EMPTY_ARRAY"); assert_eq!(array_var_is_not_empty("NOT_EMPTY_ARRAY", &shell), false); - // array_var_is_not_empty should NOT match for non-array variables with the same name + // array_var_is_not_empty should NOT match for non-array variables with the + // same name shell.set_var("VARIABLE", "notempty-variable"); assert_eq!(array_var_is_not_empty("VARIABLE", &shell), false); } @@ -337,7 +396,9 @@ fn test_string_var_is_not_empty() { // string_var_is_not_empty should NOT match for arrays with the same name let mut vec = Vec::new(); vec.push("not-empty".to_owned()); - shell.variables.set_array("ARRAY_NOT_EMPTY", SmallVec::from_vec(vec)); + shell + .variables + .set_array("ARRAY_NOT_EMPTY", SmallVec::from_vec(vec)); assert_eq!(string_var_is_not_empty("ARRAY_NOT_EMPTY", &shell), false); // test for a variable which does not even exist @@ -354,12 +415,18 @@ fn test_function_is_defined() { let name_str = "test_function"; let name = SmallString::from_str(name_str); let mut args = Vec::new(); - args.push(KeyBuf { name: "testy".into(), kind: Primitive::Any }); + args.push(KeyBuf { + name: "testy".into(), + kind: Primitive::Any, + }); let mut statements = Vec::new(); statements.push(Statement::End); let description = "description".to_owned(); - shell.functions.insert(name.clone(), Function::new(Some(description), name, args, statements)); + shell.functions.insert( + name.clone(), + Function::new(Some(description), name, args, statements), + ); assert_eq!(function_is_defined(name_str, &shell), true); shell.functions.remove(name_str); diff --git a/src/builtins/is.rs b/src/builtins/is.rs index 79b80a4b..7f4b021d 100644 --- a/src/builtins/is.rs +++ b/src/builtins/is.rs @@ -21,10 +21,9 @@ pub(crate) fn is(args: &[&str], shell: &mut Shell) -> Result<(), String> { } fn eval_arg(arg: &str, shell: &mut Shell) -> String { - let var_value = get_var_string(arg, shell); - - if var_value != "" { - return var_value; + let value = get_var_string(arg, shell); + if value != "" { + return value; } arg.to_string() } @@ -43,3 +42,45 @@ fn get_var_string(name: &str, shell: &mut Shell) -> String { sh_var.to_string() } + +#[test] +fn test_is() { + let mut shell = Shell::new(); + shell.set_var("x", "value"); + shell.set_var("y", "0"); + + // Four arguments + assert_eq!( + is(&["is", " ", " ", " "], &mut shell), + Err("Expected 'not' instead found ' '\n".to_string()) + ); + assert_eq!( + is(&["is", "not", " ", " "], &mut shell), + Err("".to_string()) + ); + assert_eq!( + is(&["is", "not", "$x", "$x"], &mut shell), + Err("".to_string()) + ); + assert_eq!(is(&["is", "not", "2", "1"], &mut shell), Ok(())); + assert_eq!(is(&["is", "not", "$x", "$y"], &mut shell), Ok(())); + + // Three arguments + assert_eq!(is(&["is", "1", "2"], &mut shell), Err("".to_string())); + assert_eq!(is(&["is", "$x", "$y"], &mut shell), Err("".to_string())); + assert_eq!(is(&["is", " ", " "], &mut shell), Ok(())); + assert_eq!(is(&["is", "$x", "$x"], &mut shell), Ok(())); + + // Two arguments + assert_eq!( + is(&["is", " "], &mut shell), + Err("is needs 3 or 4 arguments\n".to_string()) + ); + assert_eq!(is(&["is", "-h"], &mut shell), Ok(())); + + // One argument + assert_eq!( + is(&["is"], &mut shell), + Err("is needs 3 or 4 arguments\n".to_string()) + ); +} diff --git a/src/builtins/job_control.rs b/src/builtins/job_control.rs index f50e1a00..2f3961fb 100644 --- a/src/builtins/job_control.rs +++ b/src/builtins/job_control.rs @@ -1,4 +1,5 @@ -//! Contains the `jobs`, `disown`, `bg`, and `fg` commands that manage job control in the shell. +//! Contains the `jobs`, `disown`, `bg`, and `fg` commands that manage job +//! control in the shell. use shell::Shell; use shell::job_control::{JobControl, ProcessState}; @@ -10,7 +11,6 @@ use std::io::{stderr, Write}; /// The `-a` flag selects all jobs, `-r` selects all running jobs, and `-h` specifies to mark /// SIGHUP ignoral. pub(crate) fn disown(shell: &mut Shell, args: &[&str]) -> Result<(), String> { - const NO_SIGHUP: u8 = 1; const ALL_JOBS: u8 = 2; const RUN_JOBS: u8 = 4; @@ -84,8 +84,14 @@ pub(crate) fn jobs(shell: &mut Shell) { let mut stderr = stderr.lock(); for (id, process) in shell.background.lock().unwrap().iter().enumerate() { if process.state != ProcessState::Empty { - let _ = - writeln!(stderr, "[{}] {} {}\t{}", id, process.pid, process.state, process.name); + let _ = writeln!( + stderr, + "[{}] {} {}\t{}", + id, + process.pid, + process.state, + process.name + ); } } } @@ -146,7 +152,13 @@ pub(crate) fn fg(shell: &mut Shell, args: &[&str]) -> i32 { /// Resumes a stopped background process, if it was stopped. pub(crate) fn bg(shell: &mut Shell, args: &[&str]) -> i32 { fn bg_job(shell: &mut Shell, njob: u32) -> bool { - if let Some(job) = shell.background.lock().unwrap().iter_mut().nth(njob as usize) { + if let Some(job) = shell + .background + .lock() + .unwrap() + .iter_mut() + .nth(njob as usize) + { match job.state { ProcessState::Running => { eprintln!("ion: bg: job {} is already running", njob); diff --git a/src/builtins/man_pages.rs b/src/builtins/man_pages.rs index d5b5355f..6d3ca583 100644 --- a/src/builtins/man_pages.rs +++ b/src/builtins/man_pages.rs @@ -4,7 +4,10 @@ use std::io::{stdout, Write}; pub(crate) fn print_man(man_page: &'static str) { let stdout = stdout(); let mut stdout = stdout.lock(); - match stdout.write_all(man_page.as_bytes()).and_then(|_| stdout.flush()) { + match stdout + .write_all(man_page.as_bytes()) + .and_then(|_| stdout.flush()) + { Ok(_) => (), Err(err) => panic!("{}", err.description().to_owned()), } @@ -14,7 +17,7 @@ pub(crate) fn check_help(args: &[&str], man_page: &'static str) -> bool { for arg in args { if *arg == "-h" || *arg == "--help" { print_man(man_page); - return true + return true; } } false @@ -106,31 +109,33 @@ DESCRIPTION pushd adds directories to the stack. "#; -/*pub(crate) const MAN_FN: &'static str = r#"NAME - fn - print a list of all functions or create a function - -SYNOPSIS - fn - - fn example arg:int - echo $arg - end - -DESCRIPTION - fn prints a list of all functions that exist in the shell or creates a function when combined - with the 'end' keyword. Functions can have type hints, to tell ion to check the type of a - functions arguments. An error will occur if an argument supplied to a function is of the wrong type. - The supported types in ion are, [], bool, bool[], float, float[], int, int[], str, str[]. - - Functions are called by typing the function name and then the function arguments, separated - by a space. - - fn example arg0:int arg1:int - echo $arg - end - - example 1 -"#;*/ +// pub(crate) const MAN_FN: &'static str = r#"NAME +// fn - print a list of all functions or create a function +// +// SYNOPSIS +// fn +// +// fn example arg:int +// echo $arg +// end +// +// DESCRIPTION +// fn prints a list of all functions that exist in the shell or creates a +// function when combined with the 'end' keyword. Functions can have type +// hints, to tell ion to check the type of a functions arguments. An error will +// occur if an argument supplied to a function is of the wrong type. +// The supported types in ion are, [], bool, bool[], float, float[], int, +// int[], str, str[]. +// +// Functions are called by typing the function name and then the function +// arguments, separated by a space. +// +// fn example arg0:int arg1:int +// echo $arg +// end +// +// example 1 +// "#; pub(crate) const MAN_READ: &'static str = r#"NAME read - read a line of input into some variables @@ -582,4 +587,4 @@ SYNOPSIS DESCRIPTION The which utility takes a list of command names and searches for the alias/builtin/function/executable that would be executed if you ran that command. -"#; \ No newline at end of file +"#; diff --git a/src/builtins/mod.rs b/src/builtins/mod.rs index cd6361a9..dafbbbc9 100644 --- a/src/builtins/mod.rs +++ b/src/builtins/mod.rs @@ -60,8 +60,8 @@ macro_rules! map { } }} -/// If you are implementing a builtin add it to the table below, create a well named manpage in man_pages -/// and check for help flags by adding to the start of your builtin the following +/// If you are implementing a builtin add it to the table below, create a well named manpage in +/// man_pages and check for help flags by adding to the start of your builtin the following /// if check_help(args, MAN_CD) { /// return SUCCESS /// } @@ -120,8 +120,8 @@ pub struct Builtin { } pub struct BuiltinMap { - pub(crate) name: &'static [&'static str], - pub(crate) help: &'static [&'static str], + pub(crate) name: &'static [&'static str], + pub(crate) help: &'static [&'static str], pub(crate) functions: &'static [BuiltinFunction], } @@ -136,9 +136,13 @@ impl BuiltinMap { }) } - pub fn keys(&self) -> &'static [&'static str] { self.name } + pub fn keys(&self) -> &'static [&'static str] { + self.name + } - pub fn contains_key(&self, func: &str) -> bool { self.name.iter().any(|&name| name == func) } + pub fn contains_key(&self, func: &str) -> bool { + self.name.iter().any(|&name| name == func) + } } // Definitions of simple builtins go here @@ -156,7 +160,7 @@ fn builtin_status(args: &[&str], shell: &mut Shell) -> i32 { pub fn builtin_cd(args: &[&str], shell: &mut Shell) -> i32 { if check_help(args, MAN_CD) { - return SUCCESS + return SUCCESS; } match shell.directory_stack.cd(args, &shell.variables) { @@ -212,15 +216,15 @@ fn builtin_is(args: &[&str], shell: &mut Shell) -> i32 { fn builtin_dirs(args: &[&str], shell: &mut Shell) -> i32 { if check_help(args, MAN_DIRS) { - return SUCCESS + return SUCCESS; } - shell.directory_stack.dirs(args) + shell.directory_stack.dirs(args) } fn builtin_pushd(args: &[&str], shell: &mut Shell) -> i32 { if check_help(args, MAN_PUSHD) { - return SUCCESS + return SUCCESS; } match shell.directory_stack.pushd(args, &shell.variables) { Ok(()) => SUCCESS, @@ -235,7 +239,7 @@ fn builtin_pushd(args: &[&str], shell: &mut Shell) -> i32 { fn builtin_popd(args: &[&str], shell: &mut Shell) -> i32 { if check_help(args, MAN_POPD) { - return SUCCESS + return SUCCESS; } match shell.directory_stack.popd(args) { @@ -258,21 +262,22 @@ fn builtin_unalias(args: &[&str], shell: &mut Shell) -> i32 { drop_alias(&mut shell.variables, args) } -// TODO There is a man page for fn however the -h and --help flags are not checked for. +// TODO There is a man page for fn however the -h and --help flags are not +// checked for. fn builtin_fn(_: &[&str], shell: &mut Shell) -> i32 { fn_(&mut shell.functions) } fn builtin_read(args: &[&str], shell: &mut Shell) -> i32 { if check_help(args, MAN_READ) { - return SUCCESS + return SUCCESS; } - shell.variables.read(args) + shell.variables.read(args) } fn builtin_drop(args: &[&str], shell: &mut Shell) -> i32 { if check_help(args, MAN_DROP) { - return SUCCESS + return SUCCESS; } if args.len() >= 2 && args[1] == "-a" { drop_array(&mut shell.variables, args) @@ -283,14 +288,14 @@ fn builtin_drop(args: &[&str], shell: &mut Shell) -> i32 { fn builtin_set(args: &[&str], shell: &mut Shell) -> i32 { if check_help(args, MAN_SET) { - return SUCCESS + return SUCCESS; } set::set(args, shell) } fn builtin_eval(args: &[&str], shell: &mut Shell) -> i32 { if check_help(args, MAN_EVAL) { - return SUCCESS + return SUCCESS; } let evaluated_command = args[1..].join(" "); let mut buffer = Terminator::new(evaluated_command); @@ -305,16 +310,16 @@ fn builtin_eval(args: &[&str], shell: &mut Shell) -> i32 { } } -fn builtin_history(args: &[&str], shell: &mut Shell) -> i32 { +fn builtin_history(args: &[&str], shell: &mut Shell) -> i32 { if check_help(args, MAN_HISTORY) { - return SUCCESS + return SUCCESS; } shell.print_history(args) } fn builtin_source(args: &[&str], shell: &mut Shell) -> i32 { if check_help(args, MAN_SOURCE) { - return SUCCESS + return SUCCESS; } match source(shell, args) { Ok(()) => SUCCESS, @@ -329,7 +334,7 @@ fn builtin_source(args: &[&str], shell: &mut Shell) -> i32 { fn builtin_echo(args: &[&str], _: &mut Shell) -> i32 { if check_help(args, MAN_ECHO) { - return SUCCESS + return SUCCESS; } match echo(args) { Ok(()) => SUCCESS, @@ -344,7 +349,7 @@ fn builtin_echo(args: &[&str], _: &mut Shell) -> i32 { fn builtin_test(args: &[&str], _: &mut Shell) -> i32 { if check_help(args, MAN_TEST) { - return SUCCESS + return SUCCESS; } match test(args) { Ok(true) => SUCCESS, @@ -373,7 +378,7 @@ fn builtin_calc(args: &[&str], _: &mut Shell) -> i32 { fn builtin_random(args: &[&str], _: &mut Shell) -> i32 { if check_help(args, MAN_RANDOM) { - return SUCCESS + return SUCCESS; } match random::random(&args[1..]) { Ok(()) => SUCCESS, @@ -386,16 +391,16 @@ fn builtin_random(args: &[&str], _: &mut Shell) -> i32 { } } -fn builtin_true(args: &[&str], _: &mut Shell) -> i32 { +fn builtin_true(args: &[&str], _: &mut Shell) -> i32 { check_help(args, MAN_TRUE); SUCCESS } fn builtin_false(args: &[&str], _: &mut Shell) -> i32 { if check_help(args, MAN_FALSE) { - return SUCCESS + return SUCCESS; } - FAILURE + FAILURE } // TODO create a manpage @@ -412,21 +417,21 @@ fn builtin_jobs(args: &[&str], shell: &mut Shell) -> i32 { fn builtin_bg(args: &[&str], shell: &mut Shell) -> i32 { if check_help(args, MAN_BG) { - return SUCCESS + return SUCCESS; } job_control::bg(shell, &args[1..]) } fn builtin_fg(args: &[&str], shell: &mut Shell) -> i32 { if check_help(args, MAN_FG) { - return SUCCESS + return SUCCESS; } - job_control::fg(shell, &args[1..]) + job_control::fg(shell, &args[1..]) } fn builtin_suspend(args: &[&str], _: &mut Shell) -> i32 { if check_help(args, MAN_SUSPEND) { - return SUCCESS + return SUCCESS; } shell::signals::suspend(0); SUCCESS @@ -436,7 +441,7 @@ fn builtin_disown(args: &[&str], shell: &mut Shell) -> i32 { for arg in args { if *arg == "--help" { print_man(MAN_DISOWN); - return SUCCESS + return SUCCESS; } } match job_control::disown(shell, &args[1..]) { @@ -478,7 +483,7 @@ fn builtin_help(args: &[&str], shell: &mut Shell) -> i32 { fn builtin_exit(args: &[&str], shell: &mut Shell) -> i32 { if check_help(args, MAN_EXIT) { - return SUCCESS + return SUCCESS; } // Kill all active background tasks before exiting the shell. for process in shell.background.lock().unwrap().iter() { @@ -487,13 +492,17 @@ fn builtin_exit(args: &[&str], shell: &mut Shell) -> i32 { } } let previous_status = shell.previous_status; - shell.exit(args.get(1).and_then(|status| status.parse::<i32>().ok()).unwrap_or(previous_status)) + shell.exit( + args.get(1) + .and_then(|status| status.parse::<i32>().ok()) + .unwrap_or(previous_status), + ) } use regex::Regex; fn builtin_matches(args: &[&str], _: &mut Shell) -> i32 { if check_help(args, MAN_MATCHES) { - return SUCCESS + return SUCCESS; } if args[1..].len() != 2 { let stderr = io::stderr(); @@ -521,14 +530,18 @@ fn builtin_matches(args: &[&str], _: &mut Shell) -> i32 { } fn args_to_pipeline(args: &[&str]) -> Pipeline { - let owned = args.into_iter().map(|&x| String::from(x)).collect::<Array>(); + let owned = args.into_iter() + .map(|&x| String::from(x)) + .collect::<Array>(); let pipe_item = PipeItem::new(Job::new(owned, JobKind::And), Vec::new(), Vec::new()); - Pipeline { items: vec![pipe_item] } + Pipeline { + items: vec![pipe_item], + } } fn builtin_not(args: &[&str], shell: &mut Shell) -> i32 { if check_help(args, MAN_NOT) { - return SUCCESS + return SUCCESS; } shell.run_pipeline(&mut args_to_pipeline(&args[1..])); match shell.previous_status { @@ -540,7 +553,7 @@ fn builtin_not(args: &[&str], shell: &mut Shell) -> i32 { fn builtin_and(args: &[&str], shell: &mut Shell) -> i32 { if check_help(args, MAN_AND) { - return SUCCESS + return SUCCESS; } match shell.previous_status { SUCCESS => { @@ -553,7 +566,7 @@ fn builtin_and(args: &[&str], shell: &mut Shell) -> i32 { fn builtin_or(args: &[&str], shell: &mut Shell) -> i32 { if check_help(args, MAN_OR) { - return SUCCESS + return SUCCESS; } match shell.previous_status { FAILURE => { @@ -566,7 +579,7 @@ fn builtin_or(args: &[&str], shell: &mut Shell) -> i32 { fn builtin_exists(args: &[&str], shell: &mut Shell) -> i32 { if check_help(args, MAN_EXISTS) { - return SUCCESS + return SUCCESS; } match exists(args, shell) { Ok(true) => SUCCESS, @@ -582,7 +595,7 @@ fn builtin_exists(args: &[&str], shell: &mut Shell) -> i32 { fn builtin_which(args: &[&str], shell: &mut Shell) -> i32 { if check_help(args, MAN_WHICH) { - return SUCCESS + return SUCCESS; } let mut result = SUCCESS; @@ -597,7 +610,10 @@ fn builtin_which(args: &[&str], shell: &mut Shell) -> i32 { println!("{}: built-in shell command", command); continue; } else { - for path in env::var("PATH").unwrap_or("/bin".to_string()).split(sys::PATH_SEPARATOR) { + for path in env::var("PATH") + .unwrap_or("/bin".to_string()) + .split(sys::PATH_SEPARATOR) + { let executable = Path::new(path).join(command); if executable.is_file() { println!("{}", executable.display()); diff --git a/src/builtins/random.rs b/src/builtins/random.rs index 45873b11..958b0d93 100644 --- a/src/builtins/random.rs +++ b/src/builtins/random.rs @@ -32,7 +32,10 @@ pub(crate) fn random(args: &[&str]) -> Result<(), String> { writeln!(stdout, "{}", rand_num); } 1 => { - writeln!(stdout, "Ion Shell does not currently support changing the seed"); + writeln!( + stdout, + "Ion Shell does not currently support changing the seed" + ); } 2 => { let arg1 = match args[0].parse::<u64>() { diff --git a/src/builtins/set.rs b/src/builtins/set.rs index 815ae5cb..c48049a6 100644 --- a/src/builtins/set.rs +++ b/src/builtins/set.rs @@ -23,7 +23,6 @@ pub(crate) fn set(args: &[&str], shell: &mut Shell) -> i32 { break; } return 0; - } else if arg.starts_with('-') { if arg.len() == 1 { positionals = Some(RetainIfNone); @@ -74,7 +73,9 @@ pub(crate) fn set(args: &[&str], shell: &mut Shell) -> i32 { // This used to take a `&[String]` but cloned them all, so although // this is non-ideal and could probably be better done with `Rc`, it // hasn't got any slower. - let arguments = iter::once(command).chain(args_iter.map(|i| i.to_string())).collect(); + let arguments = iter::once(command) + .chain(args_iter.map(|i| i.to_string())) + .collect(); match kind { UnsetIfNone => shell.variables.set_array("args", arguments), RetainIfNone => if arguments.len() != 1 { diff --git a/src/builtins/test.rs b/src/builtins/test.rs index 36ceff26..101a7980 100644 --- a/src/builtins/test.rs +++ b/src/builtins/test.rs @@ -12,8 +12,8 @@ pub(crate) fn test(args: &[&str]) -> Result<bool, String> { fn evaluate_arguments(arguments: &[&str]) -> Result<bool, String> { match arguments.first() { Some(&s) if s.starts_with("-") && s[1..].starts_with(char::is_alphabetic) => { - // Access the second character in the flag string: this will be type of the flag. - // If no flag was given, return `SUCCESS` + // Access the second character in the flag string: this will be type of the + // flag. If no flag was given, return `SUCCESS` s.chars().nth(1).map_or(Ok(true), |flag| { // If no argument was given, return `SUCCESS` arguments.get(1).map_or(Ok(true), { @@ -25,13 +25,15 @@ fn evaluate_arguments(arguments: &[&str]) -> Result<bool, String> { } Some(arg) => { // If there is no operator, check if the first argument is non-zero - arguments.get(1).map_or(Ok(string_is_nonzero(arg)), |operator| { - // If there is no right hand argument, a condition was expected - let right_arg = arguments - .get(2) - .ok_or_else(|| SmallString::from("parse error: condition expected"))?; - evaluate_expression(arg, operator, right_arg) - }) + arguments + .get(1) + .map_or(Ok(string_is_nonzero(arg)), |operator| { + // If there is no right hand argument, a condition was expected + let right_arg = arguments + .get(2) + .ok_or_else(|| SmallString::from("parse error: condition expected"))?; + evaluate_expression(arg, operator, right_arg) + }) } None => Ok(false), } @@ -73,7 +75,9 @@ fn files_have_same_device_and_inode_numbers(first: &str, second: &str) -> bool { /// Obtains the device and inode numbers of the file specified fn get_dev_and_inode(filename: &str) -> Option<(u64, u64)> { - fs::metadata(filename).map(|file| (file.dev(), file.ino())).ok() + fs::metadata(filename) + .map(|file| (file.dev(), file.ino())) + .ok() } /// Exits SUCCESS if the first file is newer than the second file. @@ -90,7 +94,9 @@ fn file_is_newer_than(first: &str, second: &str) -> bool { /// Obtain the time the file was last modified as a `SystemTime` type. fn get_modified_file_time(filename: &str) -> Option<SystemTime> { - fs::metadata(filename).ok().and_then(|file| file.modified().ok()) + fs::metadata(filename) + .ok() + .and_then(|file| file.modified().ok()) } /// Attempt to parse a &str as a usize. @@ -111,7 +117,8 @@ fn parse_integers(left: &str, right: &str) -> Result<(Option<isize>, Option<isiz }) } -/// Matches flag arguments to their respective functionaity when the `-` character is detected. +/// Matches flag arguments to their respective functionaity when the `-` +/// character is detected. fn match_flag_argument(flag: char, argument: &str) -> bool { // TODO: Implement missing flags match flag { @@ -140,7 +147,9 @@ fn match_flag_argument(flag: char, argument: &str) -> bool { /// Exits SUCCESS if the file size is greather than zero. fn file_size_is_greater_than_zero(filepath: &str) -> bool { - fs::metadata(filepath).ok().map_or(false, |metadata| metadata.len() > 0) + fs::metadata(filepath) + .ok() + .map_or(false, |metadata| metadata.len() > 0) } /// Exits SUCCESS if the file has read permissions. This function is rather low level because @@ -192,42 +201,60 @@ fn file_has_execute_permission(filepath: &str) -> bool { /// Exits SUCCESS if the file argument is a socket fn file_is_socket(filepath: &str) -> bool { - fs::metadata(filepath).ok().map_or(false, |metadata| metadata.file_type().is_socket()) + fs::metadata(filepath) + .ok() + .map_or(false, |metadata| metadata.file_type().is_socket()) } /// Exits SUCCESS if the file argument is a block device fn file_is_block_device(filepath: &str) -> bool { - fs::metadata(filepath).ok().map_or(false, |metadata| metadata.file_type().is_block_device()) + fs::metadata(filepath) + .ok() + .map_or(false, |metadata| metadata.file_type().is_block_device()) } /// Exits SUCCESS if the file argument is a character device fn file_is_character_device(filepath: &str) -> bool { - fs::metadata(filepath).ok().map_or(false, |metadata| metadata.file_type().is_char_device()) + fs::metadata(filepath) + .ok() + .map_or(false, |metadata| metadata.file_type().is_char_device()) } /// Exits SUCCESS if the file exists -fn file_exists(filepath: &str) -> bool { Path::new(filepath).exists() } +fn file_exists(filepath: &str) -> bool { + Path::new(filepath).exists() +} /// Exits SUCCESS if the file is a regular file fn file_is_regular(filepath: &str) -> bool { - fs::metadata(filepath).ok().map_or(false, |metadata| metadata.file_type().is_file()) + fs::metadata(filepath) + .ok() + .map_or(false, |metadata| metadata.file_type().is_file()) } /// Exits SUCCESS if the file is a directory fn file_is_directory(filepath: &str) -> bool { - fs::metadata(filepath).ok().map_or(false, |metadata| metadata.file_type().is_dir()) + fs::metadata(filepath) + .ok() + .map_or(false, |metadata| metadata.file_type().is_dir()) } /// Exits SUCCESS if the file is a symbolic link fn file_is_symlink(filepath: &str) -> bool { - fs::symlink_metadata(filepath).ok().map_or(false, |metadata| metadata.file_type().is_symlink()) + fs::symlink_metadata(filepath) + .ok() + .map_or(false, |metadata| metadata.file_type().is_symlink()) } /// Exits SUCCESS if the string is not empty -fn string_is_nonzero(string: &str) -> bool { !string.is_empty() } +fn string_is_nonzero(string: &str) -> bool { + !string.is_empty() +} /// Exits SUCCESS if the string is empty -fn string_is_zero(string: &str) -> bool { string.is_empty() } +fn string_is_zero(string: &str) -> bool { + string.is_empty() +} #[test] fn test_strings() { @@ -320,6 +347,9 @@ fn test_file_has_execute_permission() { #[test] fn test_file_size_is_greater_than_zero() { - assert_eq!(file_size_is_greater_than_zero("testing/file_with_text"), true); + assert_eq!( + file_size_is_greater_than_zero("testing/file_with_text"), + true + ); assert_eq!(file_size_is_greater_than_zero("testing/empty_file"), false); -} \ No newline at end of file +} diff --git a/src/builtins/variables.rs b/src/builtins/variables.rs index c18753fd..289c011f 100644 --- a/src/builtins/variables.rs +++ b/src/builtins/variables.rs @@ -125,7 +125,11 @@ pub(crate) fn alias(vars: &mut Variables, args: &str) -> i32 { Binding::ListEntries => print_list(&vars.aliases), Binding::KeyOnly(key) => { let stderr = io::stderr(); - let _ = writeln!(&mut stderr.lock(), "ion: please provide value for alias '{}'", key); + let _ = writeln!( + &mut stderr.lock(), + "ion: please provide value for alias '{}'", + key + ); return FAILURE; } _ => { @@ -140,7 +144,8 @@ pub(crate) fn alias(vars: &mut Variables, args: &str) -> i32 { /// Dropping an alias will erase it from the shell. pub(crate) fn drop_alias<I: IntoIterator>(vars: &mut Variables, args: I) -> i32 - where I::Item: AsRef<str> +where + I::Item: AsRef<str>, { let args = args.into_iter().collect::<Vec<I::Item>>(); if args.len() <= 1 { @@ -151,7 +156,11 @@ pub(crate) fn drop_alias<I: IntoIterator>(vars: &mut Variables, args: I) -> i32 for alias in args.iter().skip(1) { if vars.aliases.remove(alias.as_ref()).is_none() { let stderr = io::stderr(); - let _ = writeln!(&mut stderr.lock(), "ion: undefined alias: {}", alias.as_ref()); + let _ = writeln!( + &mut stderr.lock(), + "ion: undefined alias: {}", + alias.as_ref() + ); return FAILURE; } } @@ -160,7 +169,8 @@ pub(crate) fn drop_alias<I: IntoIterator>(vars: &mut Variables, args: I) -> i32 /// Dropping an array will erase it from the shell. pub(crate) fn drop_array<I: IntoIterator>(vars: &mut Variables, args: I) -> i32 - where I::Item: AsRef<str> +where + I::Item: AsRef<str>, { let args = args.into_iter().collect::<Vec<I::Item>>(); if args.len() <= 2 { @@ -171,14 +181,21 @@ pub(crate) fn drop_array<I: IntoIterator>(vars: &mut Variables, args: I) -> i32 if args[1].as_ref() != "-a" { let stderr = io::stderr(); - let _ = writeln!(&mut stderr.lock(), "ion: drop_array must be used with -a option"); + let _ = writeln!( + &mut stderr.lock(), + "ion: drop_array must be used with -a option" + ); return FAILURE; } for array in args.iter().skip(2) { if vars.unset_array(array.as_ref()).is_none() { let stderr = io::stderr(); - let _ = writeln!(&mut stderr.lock(), "ion: undefined array: {}", array.as_ref()); + let _ = writeln!( + &mut stderr.lock(), + "ion: undefined array: {}", + array.as_ref() + ); return FAILURE; } } @@ -187,7 +204,8 @@ pub(crate) fn drop_array<I: IntoIterator>(vars: &mut Variables, args: I) -> i32 /// Dropping a variable will erase it from the shell. pub(crate) fn drop_variable<I: IntoIterator>(vars: &mut Variables, args: I) -> i32 - where I::Item: AsRef<str> +where + I::Item: AsRef<str>, { let args = args.into_iter().collect::<Vec<I::Item>>(); if args.len() <= 1 { @@ -199,7 +217,11 @@ pub(crate) fn drop_variable<I: IntoIterator>(vars: &mut Variables, args: I) -> i for variable in args.iter().skip(1) { if vars.unset_var(variable.as_ref()).is_none() { let stderr = io::stderr(); - let _ = writeln!(&mut stderr.lock(), "ion: undefined variable: {}", variable.as_ref()); + let _ = writeln!( + &mut stderr.lock(), + "ion: undefined variable: {}", + variable.as_ref() + ); return FAILURE; } } @@ -217,7 +239,9 @@ mod test { struct VariableExpander(pub Variables); impl Expander for VariableExpander { - fn variable(&self, var: &str, _: bool) -> Option<Value> { self.0.get_var(var) } + fn variable(&self, var: &str, _: bool) -> Option<Value> { + self.0.get_var(var) + } } // TODO: Rewrite tests now that let is part of the grammar. @@ -226,8 +250,8 @@ mod test { // let mut variables = Variables::default(); // let dir_stack = new_dir_stack(); // let_(&mut variables, vec!["let", "FOO", "=", "BAR"]); - // let expanded = expand_string("$FOO", &variables, &dir_stack, false).join(""); - // assert_eq!("BAR", &expanded); + // let expanded = expand_string("$FOO", &variables, &dir_stack, + // false).join(""); assert_eq!("BAR", &expanded); // } // // #[test] @@ -240,8 +264,8 @@ mod test { // #[test] // fn let_checks_variable_name() { // let mut variables = Variables::default(); - // let return_status = let_(&mut variables, vec!["let", ",;!:", "=", "FOO"]); - // assert_eq!(FAILURE, return_status); + // let return_status = let_(&mut variables, vec!["let", ",;!:", "=", + // "FOO"]); assert_eq!(FAILURE, return_status); // } #[test] diff --git a/src/lib.rs b/src/lib.rs index 6dfe8eb4..00599028 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,6 @@ #![feature(pointer_methods)] #![feature(getpid)] -extern crate xdg; #[macro_use] extern crate bitflags; extern crate calc; @@ -32,6 +31,7 @@ extern crate syscall; extern crate unicode_segmentation; #[cfg(all(unix, not(target_os = "redox")))] extern crate users as users_unix; +extern crate xdg; #[cfg(target_os = "redox")] #[path = "sys/redox.rs"] diff --git a/src/parser/arguments.rs b/src/parser/arguments.rs index b52db35c..dedee06a 100644 --- a/src/parser/arguments.rs +++ b/src/parser/arguments.rs @@ -7,14 +7,18 @@ const METHOD: u8 = 32; /// An efficient `Iterator` structure for splitting arguments pub struct ArgumentSplitter<'a> { - data: &'a str, - read: usize, + data: &'a str, + read: usize, flags: u8, } impl<'a> ArgumentSplitter<'a> { pub fn new(data: &'a str) -> ArgumentSplitter<'a> { - ArgumentSplitter { data: data, read: 0, flags: 0 } + ArgumentSplitter { + data: data, + read: 0, + flags: 0, + } } } @@ -135,14 +139,22 @@ mod tests { #[test] fn arrays() { let input = "echo [ one two @[echo three four] five ] [ six seven ]"; - let expected = vec!["echo", "[ one two @[echo three four] five ]", "[ six seven ]"]; + let expected = vec![ + "echo", + "[ one two @[echo three four] five ]", + "[ six seven ]", + ]; compare(input, expected); } #[test] fn quotes() { let input = "echo 'one two \"three four\"' \"five six 'seven eight'\""; - let expected = vec!["echo", "'one two \"three four\"'", "\"five six 'seven eight'\""]; + let expected = vec![ + "echo", + "'one two \"three four\"'", + "\"five six 'seven eight'\"", + ]; compare(input, expected); } } diff --git a/src/parser/assignments/actions.rs b/src/parser/assignments/actions.rs index 9745ade0..c1bc9175 100644 --- a/src/parser/assignments/actions.rs +++ b/src/parser/assignments/actions.rs @@ -28,11 +28,11 @@ impl<'a> Display for AssignmentError<'a> { /// Each request will tell the shell whether the assignment is asking to update an array or a /// string, and will contain the key/value pair to assign. pub(crate) struct AssignmentActions<'a> { - keys: KeyIterator<'a>, + keys: KeyIterator<'a>, operator: Operator, - values: ArgumentSplitter<'a>, - prevkey: &'a str, - prevval: &'a str, + values: ArgumentSplitter<'a>, + prevkey: &'a str, + prevval: &'a str, } impl<'a> AssignmentActions<'a> { @@ -118,7 +118,11 @@ mod tests { fn split(input: &str) -> (String, Operator, String) { let (keys, op, vals) = split_assignment(input); - (keys.unwrap().into(), Operator::parse(op.unwrap()).unwrap(), vals.unwrap().into()) + ( + keys.unwrap().into(), + Operator::parse(op.unwrap()).unwrap(), + vals.unwrap().into(), + ) } #[test] @@ -129,7 +133,10 @@ mod tests { assert_eq!( actions[0], Ok(Action::UpdateString( - Key { name: "abc", kind: Primitive::Any }, + Key { + name: "abc", + kind: Primitive::Any, + }, Operator::Equal, "123", )) @@ -137,7 +144,10 @@ mod tests { assert_eq!( actions[1], Ok(Action::UpdateString( - Key { name: "def", kind: Primitive::Any }, + Key { + name: "def", + kind: Primitive::Any, + }, Operator::Equal, "456", )) @@ -149,7 +159,10 @@ mod tests { assert_eq!( actions[0], Ok(Action::UpdateString( - Key { name: "ab", kind: Primitive::Integer }, + Key { + name: "ab", + kind: Primitive::Integer, + }, Operator::Multiply, "3", )) @@ -161,7 +174,10 @@ mod tests { assert_eq!( actions[0], Ok(Action::UpdateString( - Key { name: "a", kind: Primitive::Any }, + Key { + name: "a", + kind: Primitive::Any, + }, Operator::Equal, "one", )) @@ -169,7 +185,10 @@ mod tests { assert_eq!( actions[1], Ok(Action::UpdateArray( - Key { name: "b", kind: Primitive::AnyArray }, + Key { + name: "b", + kind: Primitive::AnyArray, + }, Operator::Equal, "[two three]", )) @@ -177,7 +196,10 @@ mod tests { assert_eq!( actions[2], Ok(Action::UpdateArray( - Key { name: "c", kind: Primitive::IntegerArray }, + Key { + name: "c", + kind: Primitive::IntegerArray, + }, Operator::Equal, "[4 5 6]", )) @@ -189,7 +211,10 @@ mod tests { assert_eq!( actions[0], Ok(Action::UpdateArray( - Key { name: "a", kind: Primitive::AnyArray }, + Key { + name: "a", + kind: Primitive::AnyArray, + }, Operator::Equal, "[one two]", )) @@ -197,7 +222,10 @@ mod tests { assert_eq!( actions[1], Ok(Action::UpdateString( - Key { name: "b", kind: Primitive::Any }, + Key { + name: "b", + kind: Primitive::Any, + }, Operator::Equal, "three", )) @@ -205,7 +233,10 @@ mod tests { assert_eq!( actions[2], Ok(Action::UpdateArray( - Key { name: "c", kind: Primitive::AnyArray }, + Key { + name: "c", + kind: Primitive::AnyArray, + }, Operator::Equal, "[four five]", )) diff --git a/src/parser/assignments/checker.rs b/src/parser/assignments/checker.rs index 496bb069..fffacc42 100644 --- a/src/parser/assignments/checker.rs +++ b/src/parser/assignments/checker.rs @@ -220,7 +220,13 @@ mod test { #[test] fn is_integer_array_() { let expected = Ok(ReturnValue::Vector(array!["1", "2", "3"])); - assert_eq!(is_integer_array(ReturnValue::Vector(array!["1", "2", "3"])), expected); - assert_eq!(is_integer_array(ReturnValue::Vector(array!["1", "2", "three"])), Err(())); + assert_eq!( + is_integer_array(ReturnValue::Vector(array!["1", "2", "3"])), + expected + ); + assert_eq!( + is_integer_array(ReturnValue::Vector(array!["1", "2", "three"])), + Err(()) + ); } } diff --git a/src/parser/assignments/keys.rs b/src/parser/assignments/keys.rs index d0cd48d4..b12502d7 100644 --- a/src/parser/assignments/keys.rs +++ b/src/parser/assignments/keys.rs @@ -42,7 +42,12 @@ impl<'a> Key<'a> { } impl<'a> From<Key<'a>> for KeyBuf { - fn from(key: Key<'a>) -> KeyBuf { KeyBuf { kind: key.kind, name: key.name.to_owned() } } + fn from(key: Key<'a>) -> KeyBuf { + KeyBuf { + kind: key.kind, + name: key.name.to_owned(), + } + } } /// A primitive defines the type that a requested value should satisfy. @@ -102,7 +107,9 @@ pub(crate) struct KeyIterator<'a> { } impl<'a> KeyIterator<'a> { - pub(crate) fn new(data: &'a str) -> KeyIterator<'a> { KeyIterator { data, read: 0 } } + pub(crate) fn new(data: &'a str) -> KeyIterator<'a> { + KeyIterator { data, read: 0 } + } // Parameters are values that follow the semicolon (':'). fn parse_parameter(&mut self, name: &'a str) -> Result<Key<'a>, TypeError<'a>> { @@ -129,7 +136,12 @@ impl<'a> KeyIterator<'a> { for byte in self.data.bytes().skip(self.read) { if byte == b' ' { match &self.data[start..self.read] { - "]" => return Ok(Key { name, kind: Primitive::AnyArray }), + "]" => { + return Ok(Key { + name, + kind: Primitive::AnyArray, + }) + } data @ _ => return Err(TypeError::Invalid(data)), } } @@ -137,7 +149,12 @@ impl<'a> KeyIterator<'a> { } match &self.data[start..] { - "]" => return Ok(Key { name, kind: Primitive::AnyArray }), + "]" => { + return Ok(Key { + name, + kind: Primitive::AnyArray, + }) + } data @ _ => return Err(TypeError::Invalid(data)), } } @@ -152,9 +169,10 @@ impl<'a> Iterator for KeyIterator<'a> { match byte { b' ' if start + 1 == self.read => start += 1, b' ' => { - return Some( - Ok(Key { name: &self.data[start..self.read].trim(), kind: Primitive::Any }), - ) + return Some(Ok(Key { + name: &self.data[start..self.read].trim(), + kind: Primitive::Any, + })) } b':' => { // NOTE: Borrowck issue? @@ -172,7 +190,10 @@ impl<'a> Iterator for KeyIterator<'a> { if start == self.read { None } else { - Some(Ok(Key { name: &self.data[start..self.read].trim(), kind: Primitive::Any })) + Some(Ok(Key { + name: &self.data[start..self.read].trim(), + kind: Primitive::Any, + })) } } } @@ -184,11 +205,41 @@ mod tests { #[test] fn key_parsing() { let mut parser = KeyIterator::new("a:int b[] c:bool d e:int[] d:a"); - assert_eq!(parser.next().unwrap(), Ok(Key { name: "a", kind: Primitive::Integer })); - assert_eq!(parser.next().unwrap(), Ok(Key { name: "b", kind: Primitive::AnyArray })); - assert_eq!(parser.next().unwrap(), Ok(Key { name: "c", kind: Primitive::Boolean })); - assert_eq!(parser.next().unwrap(), Ok(Key { name: "d", kind: Primitive::Any })); - assert_eq!(parser.next().unwrap(), Ok(Key { name: "e", kind: Primitive::IntegerArray })); + assert_eq!( + parser.next().unwrap(), + Ok(Key { + name: "a", + kind: Primitive::Integer, + }) + ); + assert_eq!( + parser.next().unwrap(), + Ok(Key { + name: "b", + kind: Primitive::AnyArray, + }) + ); + assert_eq!( + parser.next().unwrap(), + Ok(Key { + name: "c", + kind: Primitive::Boolean, + }) + ); + assert_eq!( + parser.next().unwrap(), + Ok(Key { + name: "d", + kind: Primitive::Any, + }) + ); + assert_eq!( + parser.next().unwrap(), + Ok(Key { + name: "e", + kind: Primitive::IntegerArray, + }) + ); assert_eq!(parser.next().unwrap(), Err(TypeError::Invalid("a"))); } } diff --git a/src/parser/assignments/splitter.rs b/src/parser/assignments/splitter.rs index 9af552d7..5de8aadd 100644 --- a/src/parser/assignments/splitter.rs +++ b/src/parser/assignments/splitter.rs @@ -1,4 +1,5 @@ -/// Given an valid assignment expression, this will split it into `keys`, `operator`, `values`. +/// Given an valid assignment expression, this will split it into `keys`, +/// `operator`, `values`. pub(crate) fn split_assignment<'a>( statement: &'a str, ) -> (Option<&'a str>, Option<&'a str>, Option<&'a str>) { @@ -48,7 +49,9 @@ pub(crate) fn split_assignment<'a>( (Some(keys), Some(operator), Some(values.trim())) } -fn is_operator(byte: u8) -> bool { byte == b'+' || byte == b'-' || byte == b'*' || byte == b'/' } +fn is_operator(byte: u8) -> bool { + byte == b'+' || byte == b'-' || byte == b'*' || byte == b'/' +} #[cfg(test)] mod tests { @@ -58,11 +61,20 @@ mod tests { fn assignment_splitting() { assert_eq!(split_assignment(""), (None, None, None)); assert_eq!(split_assignment("abc"), (Some("abc"), None, None)); - assert_eq!(split_assignment("abc+=def"), (Some("abc"), Some("+="), Some("def"))); + assert_eq!( + split_assignment("abc+=def"), + (Some("abc"), Some("+="), Some("def")) + ); assert_eq!(split_assignment("abc ="), (Some("abc"), Some("="), None)); assert_eq!(split_assignment("abc = "), (Some("abc"), Some("="), None)); - assert_eq!(split_assignment("abc = def"), (Some("abc"), Some("="), Some("def"))); - assert_eq!(split_assignment("abc=def"), (Some("abc"), Some("="), Some("def"))); + assert_eq!( + split_assignment("abc = def"), + (Some("abc"), Some("="), Some("def")) + ); + assert_eq!( + split_assignment("abc=def"), + (Some("abc"), Some("="), Some("def")) + ); assert_eq!( split_assignment("def ghi += 124 523"), (Some("def ghi"), Some("+="), Some("124 523")) diff --git a/src/parser/loops/for_grammar.rs b/src/parser/loops/for_grammar.rs index 48eab333..e6b639b5 100644 --- a/src/parser/loops/for_grammar.rs +++ b/src/parser/loops/for_grammar.rs @@ -70,7 +70,9 @@ mod tests { struct VariableExpander(pub Variables); impl Expander for VariableExpander { - fn variable(&self, var: &str, _: bool) -> Option<Value> { self.0.get_var(var) } + fn variable(&self, var: &str, _: bool) -> Option<Value> { + self.0.get_var(var) + } } #[test] @@ -96,8 +98,13 @@ mod tests { #[test] fn for_normal() { let variables = Variables::default(); - let output = - vec!["1".to_owned(), "2".to_owned(), "3".to_owned(), "4".to_owned(), "5".to_owned()]; + let output = vec![ + "1".to_owned(), + "2".to_owned(), + "3".to_owned(), + "4".to_owned(), + "5".to_owned(), + ]; assert_eq!( ForExpression::new(&output.clone(), &VariableExpander(variables)), ForExpression::Multiple(output) diff --git a/src/parser/pipelines/collector.rs b/src/parser/pipelines/collector.rs index 3df924bd..5de5ae46 100644 --- a/src/parser/pipelines/collector.rs +++ b/src/parser/pipelines/collector.rs @@ -17,7 +17,9 @@ lazy_static! { } impl<'a> Collector<'a> { - pub(crate) fn new(data: &'a str) -> Self { Collector { data } } + pub(crate) fn new(data: &'a str) -> Self { + Collector { data } + } pub(crate) fn run(data: &'a str) -> Result<Pipeline, &'static str> { Collector::new(data).parse() @@ -36,7 +38,8 @@ impl<'a> Collector<'a> { bytes: &mut Peekable<I>, start: usize, ) -> Result<&'a str, &'static str> - where I: Iterator<Item = (usize, u8)> + where + I: Iterator<Item = (usize, u8)>, { while let Some(&(i, b)) = bytes.peek() { match b { @@ -57,7 +60,8 @@ impl<'a> Collector<'a> { bytes: &mut Peekable<I>, start: usize, ) -> Result<&'a str, &'static str> - where I: Iterator<Item = (usize, u8)> + where + I: Iterator<Item = (usize, u8)>, { while let Some(&(i, b)) = bytes.peek() { match b { @@ -77,10 +81,11 @@ impl<'a> Collector<'a> { } fn arg<I>(&self, bytes: &mut Peekable<I>) -> Result<Option<&'a str>, &'static str> - where I: Iterator<Item = (usize, u8)> + where + I: Iterator<Item = (usize, u8)>, { - // XXX: I don't think its the responsibility of the pipeline parser to do this but I'm - // not sure of a better solution + // XXX: I don't think its the responsibility of the pipeline parser to do this + // but I'm not sure of a better solution let mut array_level = 0; let mut proc_level = 0; let mut brace_level = 0; @@ -326,7 +331,9 @@ impl<'a> Collector<'a> { bytes.next(); bytes.next(); if let Some(cmd) = self.arg(&mut bytes)? { - inputs.as_mut().map(|x| x.push(Input::HereString(cmd.into()))); + inputs + .as_mut() + .map(|x| x.push(Input::HereString(cmd.into()))); } else { return Err("expected string argument after '<<<'"); } @@ -345,13 +352,9 @@ impl<'a> Collector<'a> { }; let heredoc = heredoc.lines().collect::<Vec<&str>>(); // Then collect the heredoc from standard input. - inputs.as_mut().map( - |x| { - x.push( - Input::HereString(heredoc[1..heredoc.len() - 1].join("\n")), - ) - }, - ); + inputs.as_mut().map(|x| { + x.push(Input::HereString(heredoc[1..heredoc.len() - 1].join("\n"))) + }); } } else if let Some(file) = self.arg(&mut bytes)? { // Otherwise interpret it as stdin redirection @@ -396,8 +399,8 @@ mod tests { let expected = vec![ Redirection { - from: RedirectFrom::Stderr, - file: "/dev/null".to_owned(), + from: RedirectFrom::Stderr, + file: "/dev/null".to_owned(), append: false, }, ]; @@ -761,30 +764,30 @@ mod tests { let expected = Pipeline { items: vec![ PipeItem { - job: Job::new(array!["cat"], JobKind::Pipe(RedirectFrom::Stdout)), - inputs: vec![ + job: Job::new(array!["cat"], JobKind::Pipe(RedirectFrom::Stdout)), + inputs: vec![ Input::File("file1".into()), Input::HereString("\"herestring\"".into()), ], outputs: Vec::new(), }, PipeItem { - job: Job::new(array!["tr", "'x'", "'y'"], JobKind::Last), - inputs: Vec::new(), + job: Job::new(array!["tr", "'x'", "'y'"], JobKind::Last), + inputs: Vec::new(), outputs: vec![ Redirection { - from: RedirectFrom::Stderr, - file: "err".into(), + from: RedirectFrom::Stderr, + file: "err".into(), append: true, }, Redirection { - from: RedirectFrom::Both, - file: "both".into(), + from: RedirectFrom::Both, + file: "both".into(), append: false, }, Redirection { - from: RedirectFrom::Stdout, - file: "out".into(), + from: RedirectFrom::Stdout, + file: "out".into(), append: false, }, ], @@ -802,22 +805,22 @@ mod tests { let expected = Pipeline { items: vec![ PipeItem { - job: Job::new(array!["cat"], JobKind::Pipe(RedirectFrom::Stdout)), - inputs: Vec::new(), + job: Job::new(array!["cat"], JobKind::Pipe(RedirectFrom::Stdout)), + inputs: Vec::new(), outputs: Vec::new(), }, PipeItem { - job: Job::new(array!["echo", "hello"], JobKind::Pipe(RedirectFrom::Stdout)), - inputs: Vec::new(), + job: Job::new(array!["echo", "hello"], JobKind::Pipe(RedirectFrom::Stdout)), + inputs: Vec::new(), outputs: Vec::new(), }, PipeItem { - job: Job::new(array!["cat"], JobKind::Last), - inputs: vec![Input::File("stuff".into())], + job: Job::new(array!["cat"], JobKind::Last), + inputs: vec![Input::File("stuff".into())], outputs: vec![ Redirection { - from: RedirectFrom::Stderr, - file: "other".into(), + from: RedirectFrom::Stderr, + file: "other".into(), append: true, }, ], @@ -835,22 +838,22 @@ mod tests { let expected = Pipeline { items: vec![ PipeItem { - job: Job::new(array!["cat"], JobKind::Pipe(RedirectFrom::Stdout)), - inputs: Vec::new(), + job: Job::new(array!["cat"], JobKind::Pipe(RedirectFrom::Stdout)), + inputs: Vec::new(), outputs: Vec::new(), }, PipeItem { - job: Job::new(array!["echo", "hello"], JobKind::Pipe(RedirectFrom::Stdout)), - inputs: Vec::new(), + job: Job::new(array!["echo", "hello"], JobKind::Pipe(RedirectFrom::Stdout)), + inputs: Vec::new(), outputs: Vec::new(), }, PipeItem { - job: Job::new(array!["cat"], JobKind::Last), - inputs: vec![Input::File("stuff".into())], + job: Job::new(array!["cat"], JobKind::Last), + inputs: vec![Input::File("stuff".into())], outputs: vec![ Redirection { - from: RedirectFrom::Both, - file: "other".into(), + from: RedirectFrom::Both, + file: "other".into(), append: true, }, ], @@ -901,8 +904,8 @@ mod tests { let expected = Pipeline { items: vec![ PipeItem { - job: Job::new(array!["calc"], JobKind::Last), - inputs: vec![Input::HereString("$(cat math.txt)".into())], + job: Job::new(array!["calc"], JobKind::Last), + inputs: vec![Input::HereString("$(cat math.txt)".into())], outputs: vec![], }, ], @@ -916,8 +919,8 @@ mod tests { let expected = Pipeline { items: vec![ PipeItem { - job: Job::new(array!["calc"], JobKind::Last), - inputs: vec![Input::HereString("1 + 2\n3 + 4".into())], + job: Job::new(array!["calc"], JobKind::Last), + inputs: vec![Input::HereString("1 + 2\n3 + 4".into())], outputs: vec![], }, ], @@ -933,17 +936,17 @@ mod tests { let expected = Pipeline { items: vec![ PipeItem { - job: Job::new(array!["cat"], JobKind::Pipe(RedirectFrom::Stdout)), - inputs: Vec::new(), + job: Job::new(array!["cat"], JobKind::Pipe(RedirectFrom::Stdout)), + inputs: Vec::new(), outputs: Vec::new(), }, PipeItem { - job: Job::new(array!["tr", "'o'", "'x'"], JobKind::Last), - inputs: vec![Input::HereString("$VAR".into())], + job: Job::new(array!["tr", "'o'", "'x'"], JobKind::Last), + inputs: vec![Input::HereString("$VAR".into())], outputs: vec![ Redirection { - from: RedirectFrom::Stdout, - file: "out.log".into(), + from: RedirectFrom::Stdout, + file: "out.log".into(), append: false, }, ], @@ -960,7 +963,10 @@ mod tests { assert_eq!("awk", &pipeline.clone().items[0].job.args[0]); assert_eq!("-v", &pipeline.clone().items[0].job.args[1]); assert_eq!("x=$x", &pipeline.clone().items[0].job.args[2]); - assert_eq!("'{ if (1) print $1 }'", &pipeline.clone().items[0].job.args[3]); + assert_eq!( + "'{ if (1) print $1 }'", + &pipeline.clone().items[0].job.args[3] + ); assert_eq!("myfile", &pipeline.clone().items[0].job.args[4]); } else { assert!(false); @@ -973,12 +979,12 @@ mod tests { let expected = Pipeline { items: vec![ PipeItem { - job: Job::new(array!["echo", "zardoz"], JobKind::Last), - inputs: Vec::new(), + job: Job::new(array!["echo", "zardoz"], JobKind::Last), + inputs: Vec::new(), outputs: vec![ Redirection { - from: RedirectFrom::Stdout, - file: "foo\\'bar".into(), + from: RedirectFrom::Stdout, + file: "foo\\'bar".into(), append: true, }, ], diff --git a/src/parser/pipelines/mod.rs b/src/parser/pipelines/mod.rs index 0dd91721..859516fb 100644 --- a/src/parser/pipelines/mod.rs +++ b/src/parser/pipelines/mod.rs @@ -15,8 +15,8 @@ pub(crate) enum RedirectFrom { #[derive(Debug, PartialEq, Clone)] pub(crate) struct Redirection { - pub from: RedirectFrom, - pub file: String, + pub from: RedirectFrom, + pub file: String, pub append: bool, } @@ -24,7 +24,8 @@ pub(crate) struct Redirection { /// Represents input that a process could initially receive from `stdin` #[derive(Debug, PartialEq, Clone)] pub(crate) enum Input { - /// A file; the contents of said file will be written to the `stdin` of a process + /// A file; the contents of said file will be written to the `stdin` of a + /// process File(String), /// A string literal that is written to the `stdin` of a process. /// If there is a second string, that second string is the EOF phrase for the heredoc. @@ -38,14 +39,18 @@ pub(crate) struct Pipeline { #[derive(Debug, PartialEq, Clone)] pub(crate) struct PipeItem { - pub job: Job, + pub job: Job, pub outputs: Vec<Redirection>, - pub inputs: Vec<Input>, + pub inputs: Vec<Input>, } impl PipeItem { pub(crate) fn new(job: Job, outputs: Vec<Redirection>, inputs: Vec<Input>) -> Self { - PipeItem { job, outputs, inputs } + PipeItem { + job, + outputs, + inputs, + } } pub(crate) fn expand(&mut self, shell: &Shell) { @@ -67,7 +72,9 @@ impl PipeItem { } impl Pipeline { - pub(crate) fn new() -> Self { Pipeline { items: Vec::new() } } + pub(crate) fn new() -> Self { + Pipeline { items: Vec::new() } + } pub(crate) fn expand(&mut self, shell: &Shell) { self.items.iter_mut().for_each(|i| i.expand(shell)); diff --git a/src/parser/quotes.rs b/src/parser/quotes.rs index 10efcefa..fcf604f8 100644 --- a/src/parser/quotes.rs +++ b/src/parser/quotes.rs @@ -18,39 +18,46 @@ bitflags! { /// This example comes from the shell's REPL, which ensures that the user's input /// will only be submitted for execution once a terminated command is supplied. pub struct Terminator { - buffer: String, - eof: Option<String>, + buffer: String, + eof: Option<String>, eof_buffer: String, - array: usize, - read: usize, - flags: Flags, + array: usize, + read: usize, + flags: Flags, } impl<'a> From<&'a str> for Terminator { - fn from(string: &'a str) -> Terminator { Terminator::new(string.to_owned()) } + fn from(string: &'a str) -> Terminator { + Terminator::new(string.to_owned()) + } } impl From<String> for Terminator { - fn from(string: String) -> Terminator { Terminator::new(string) } + fn from(string: String) -> Terminator { + Terminator::new(string) + } } impl Terminator { pub fn new(input: String) -> Terminator { Terminator { - buffer: input, - eof: None, + buffer: input, + eof: None, eof_buffer: String::new(), - array: 0, - read: 0, - flags: Flags::empty(), + array: 0, + read: 0, + flags: Flags::empty(), } } /// Appends a string to the internal buffer. pub fn append(&mut self, input: &str) { if self.eof.is_none() { - self.buffer - .push_str(if self.flags.contains(Flags::TRIM) { input.trim() } else { input }); + self.buffer.push_str(if self.flags.contains(Flags::TRIM) { + input.trim() + } else { + input + }); } else { self.eof_buffer.push_str(input); } @@ -127,18 +134,25 @@ impl Terminator { return false; } else if instance.contains(Flags::COMM) { self.buffer.truncate(self.read - 1); - return !self.flags.intersects(Flags::SQUOTE | Flags::DQUOTE | Flags::ARRAY); + return !self.flags + .intersects(Flags::SQUOTE | Flags::DQUOTE | Flags::ARRAY); } } - if self.flags.intersects(Flags::SQUOTE | Flags::DQUOTE | Flags::ARRAY) { + if self.flags + .intersects(Flags::SQUOTE | Flags::DQUOTE | Flags::ARRAY) + { if let Some(b'\\') = self.buffer.bytes().last() { let _ = self.buffer.pop(); self.read -= 1; self.flags |= Flags::TRIM; } else { self.read += 1; - self.buffer.push(if self.flags.contains(Flags::ARRAY) { ' ' } else { '\n' }); + self.buffer.push(if self.flags.contains(Flags::ARRAY) { + ' ' + } else { + '\n' + }); } false } else { @@ -173,5 +187,7 @@ impl Terminator { } /// Consumes the `Terminator`, and returns the underlying `String`. - pub fn consume(self) -> String { self.buffer } + pub fn consume(self) -> String { + self.buffer + } } diff --git a/src/parser/shell_expand/braces.rs b/src/parser/shell_expand/braces.rs index 35dd1d9d..9d37e266 100644 --- a/src/parser/shell_expand/braces.rs +++ b/src/parser/shell_expand/braces.rs @@ -16,7 +16,10 @@ pub(crate) fn expand_braces(tokens: &[BraceToken], mut expanders: Vec<Vec<String let vector_of_arrays: Vec<&[&str]> = tmp.iter().map(AsRef::as_ref).collect(); multiple_brace_expand(&vector_of_arrays[..], tokens) } else if expanders.len() == 1 { - let elements = expanders.drain(..).next().expect("there should be at least one value"); + let elements = expanders + .drain(..) + .next() + .expect("there should be at least one value"); let elements: Vec<&str> = elements.iter().map(AsRef::as_ref).collect(); single_brace_expand(&elements, tokens) } else { @@ -144,5 +147,8 @@ fn test_single_brace_expand() { let elements = &["one", "two", "three"]; let tokens: &[BraceToken] = &[BraceToken::Normal("A=".to_owned()), BraceToken::Expander]; let out = single_brace_expand(elements, &tokens); - assert_eq!(out, vec!["A=one".to_owned(), "A=two".to_owned(), "A=three".to_owned()]); + assert_eq!( + out, + vec!["A=one".to_owned(), "A=two".to_owned(), "A=three".to_owned()] + ); } diff --git a/src/parser/shell_expand/mod.rs b/src/parser/shell_expand/mod.rs index 673bac58..c97a1c14 100644 --- a/src/parser/shell_expand/mod.rs +++ b/src/parser/shell_expand/mod.rs @@ -26,13 +26,21 @@ pub(crate) fn is_expression(s: &str) -> bool { /// Trait representing different elements of string expansion pub(crate) trait Expander { /// Expand a tilde form to the correct directory - fn tilde(&self, &str) -> Option<String> { None } + fn tilde(&self, &str) -> Option<String> { + None + } /// Expand an array variable with some selection - fn array(&self, &str, Select) -> Option<Array> { None } + fn array(&self, &str, Select) -> Option<Array> { + None + } /// Expand a string variable given if its quoted / unquoted - fn variable(&self, &str, bool) -> Option<Value> { None } + fn variable(&self, &str, bool) -> Option<Value> { + None + } /// Expand a subshell expression - fn command(&self, &str) -> Option<Value> { None } + fn command(&self, &str) -> Option<Value> { + None + } } fn expand_process<E: Expander>( @@ -94,7 +102,9 @@ fn expand_brace<E: Expander>( reverse_quoting: bool, ) { let mut temp = Vec::new(); - for word in nodes.into_iter().flat_map(|node| expand_string(node, expand_func, reverse_quoting)) + for word in nodes + .into_iter() + .flat_map(|node| expand_string(node, expand_func, reverse_quoting)) { match parse_range(&word) { Some(elements) => for word in elements { @@ -119,15 +129,22 @@ fn expand_brace<E: Expander>( fn array_expand<E: Expander>(elements: &[&str], expand_func: &E, selection: Select) -> Array { match selection { Select::None => Array::new(), - Select::All => elements.iter().flat_map(|e| expand_string(e, expand_func, false)).collect(), - Select::Index(index) => array_nth(elements, expand_func, index).into_iter().collect(), + Select::All => elements + .iter() + .flat_map(|e| expand_string(e, expand_func, false)) + .collect(), + Select::Index(index) => array_nth(elements, expand_func, index) + .into_iter() + .collect(), Select::Range(range) => array_range(elements, expand_func, range), Select::Key(_) => Array::new(), } } fn array_nth<E: Expander>(elements: &[&str], expand_func: &E, index: Index) -> Option<Value> { - let mut expanded = elements.iter().flat_map(|e| expand_string(e, expand_func, false)); + let mut expanded = elements + .iter() + .flat_map(|e| expand_string(e, expand_func, false)); match index { Index::Forward(n) => expanded.nth(n), Index::Backward(n) => expanded.rev().nth(n), @@ -135,8 +152,10 @@ fn array_nth<E: Expander>(elements: &[&str], expand_func: &E, index: Index) -> O } fn array_range<E: Expander>(elements: &[&str], expand_func: &E, range: Range) -> Array { - let expanded = - elements.iter().flat_map(|e| expand_string(e, expand_func, false)).collect::<Array>(); + let expanded = elements + .iter() + .flat_map(|e| expand_string(e, expand_func, false)) + .collect::<Array>(); let len = expanded.len(); if let Some((start, length)) = range.bounds(len) { expanded.into_iter().skip(start).take(length).collect() @@ -155,14 +174,20 @@ fn slice<S: AsRef<str>>(output: &mut String, expanded: S, selection: Select) { output.push_str(character); }, Select::Index(Index::Backward(id)) => if let Some(character) = - UnicodeSegmentation::graphemes(expanded.as_ref(), true).rev().nth(id) + UnicodeSegmentation::graphemes(expanded.as_ref(), true) + .rev() + .nth(id) { output.push_str(character); }, Select::Range(range) => { let graphemes = UnicodeSegmentation::graphemes(expanded.as_ref(), true); if let Some((start, length)) = range.bounds(graphemes.clone().count()) { - let substring = graphemes.skip(start).take(length).collect::<Vec<&str>>().join(""); + let substring = graphemes + .skip(start) + .take(length) + .collect::<Vec<&str>>() + .join(""); output.push_str(&substring); } } @@ -234,8 +259,10 @@ fn expand_braces<E: Expander>( expand_process(&mut temp, command, Select::All, expand_func, false); let len = temp.split_whitespace().count(); if let Some((start, length)) = range.bounds(len) { - let res = - temp.split_whitespace().skip(start).take(length).collect::<Vec<&str>>(); + let res = temp.split_whitespace() + .skip(start) + .take(length) + .collect::<Vec<&str>>(); output.push_str(&res.join(" ")); } } @@ -270,7 +297,14 @@ fn expand_braces<E: Expander>( slice(&mut output, expanded, index.clone()); } WordToken::Normal(text, do_glob, tilde) => { - expand(&mut output, &mut expanded_words, expand_func, text, do_glob, tilde); + expand( + &mut output, + &mut expanded_words, + expand_func, + text, + do_glob, + tilde, + ); } WordToken::Arithmetic(s) => expand_arithmetic(&mut output, s, expand_func), } @@ -311,11 +345,26 @@ fn expand_single_array_token<E: Expander>(token: &WordToken, expand_func: &E) -> } Select::Index(Index::Forward(id)) => { expand_process(&mut output, command, Select::All, expand_func, false); - Some(output.split_whitespace().nth(id).map(Into::into).into_iter().collect()) + Some( + output + .split_whitespace() + .nth(id) + .map(Into::into) + .into_iter() + .collect(), + ) } Select::Index(Index::Backward(id)) => { expand_process(&mut output, command, Select::All, expand_func, false); - Some(output.split_whitespace().rev().nth(id).map(Into::into).into_iter().collect()) + Some( + output + .split_whitespace() + .rev() + .nth(id) + .map(Into::into) + .into_iter() + .collect(), + ) } Select::Range(range) => { expand_process(&mut output, command, Select::All, expand_func, false); @@ -350,7 +399,14 @@ fn expand_single_string_token<E: Expander>( match *token { WordToken::StringMethod(ref method) => method.handle(&mut output, expand_func), WordToken::Normal(text, do_glob, tilde) => { - expand(&mut output, &mut expanded_words, expand_func, text, do_glob, tilde); + expand( + &mut output, + &mut expanded_words, + expand_func, + text, + do_glob, + tilde, + ); } WordToken::Whitespace(text) => output.push_str(text), WordToken::Process(command, quoted, ref index) => { @@ -487,7 +543,14 @@ pub(crate) fn expand_tokens<E: Expander>( } WordToken::Brace(_) => unreachable!(), WordToken::Normal(text, do_glob, tilde) => { - expand(&mut output, &mut expanded_words, expand_func, text, do_glob, tilde); + expand( + &mut output, + &mut expanded_words, + expand_func, + text, + do_glob, + tilde, + ); } WordToken::Whitespace(text) => { output.push_str(text); @@ -584,7 +647,9 @@ mod test { struct CommandExpander; impl Expander for CommandExpander { - fn command(&self, cmd: &str) -> Option<Value> { Some(cmd.to_owned()) } + fn command(&self, cmd: &str) -> Option<Value> { + Some(cmd.to_owned()) + } } #[test] @@ -617,7 +682,13 @@ mod test { let expected = "prodigal programmer processed prototype procedures proficiently proving \ prospective projections"; let expanded = expand_string(line, &VariableExpander, false); - assert_eq!(expected.split_whitespace().map(|x| x.to_owned()).collect::<Array>(), expanded); + assert_eq!( + expected + .split_whitespace() + .map(|x| x.to_owned()) + .collect::<Array>(), + expanded + ); } #[test] @@ -702,8 +773,10 @@ mod test { #[test] fn inline_expression() { - let cases = - vec![(array!["5"], "$len([0 1 2 3 4])"), (array!["FxOxO"], "$join(@chars(FOO), 'x')")]; + let cases = vec![ + (array!["5"], "$len([0 1 2 3 4])"), + (array!["FxOxO"], "$join(@chars(FOO), 'x')"), + ]; for (expected, input) in cases { assert_eq!(expected, expand_string(input, &VariableExpander, false)); } diff --git a/src/parser/shell_expand/ranges.rs b/src/parser/shell_expand/ranges.rs index dd1aa903..5751d136 100644 --- a/src/parser/shell_expand/ranges.rs +++ b/src/parser/shell_expand/ranges.rs @@ -67,7 +67,9 @@ fn numeric_range( } #[inline] -fn byte_is_valid_range(b: u8) -> bool { (b >= b'a' && b <= b'z') || (b >= b'A' && b <= b'Z') } +fn byte_is_valid_range(b: u8) -> bool { + (b >= b'a' && b <= b'z') || (b >= b'A' && b <= b'Z') +} use std::u8; fn char_range(start: u8, mut end: u8, step: isize, inclusive: bool) -> Option<Vec<String>> { @@ -286,11 +288,26 @@ pub(crate) fn parse_index_range(input: &str) -> Option<Range> { #[test] fn index_ranges() { let valid_cases = vec![ - (Range::exclusive(Index::Forward(0), Index::Forward(3)), "0..3"), - (Range::inclusive(Index::Forward(0), Index::Forward(2)), "0...2"), - (Range::inclusive(Index::Forward(2), Index::Backward(1)), "2...-2"), - (Range::inclusive(Index::Forward(0), Index::Backward(0)), "0...-1"), - (Range::exclusive(Index::Backward(2), Index::Backward(0)), "-3..-1"), + ( + Range::exclusive(Index::Forward(0), Index::Forward(3)), + "0..3", + ), + ( + Range::inclusive(Index::Forward(0), Index::Forward(2)), + "0...2", + ), + ( + Range::inclusive(Index::Forward(2), Index::Backward(1)), + "2...-2", + ), + ( + Range::inclusive(Index::Forward(0), Index::Backward(0)), + "0...-1", + ), + ( + Range::exclusive(Index::Backward(2), Index::Backward(0)), + "-3..-1", + ), (Range::from(Index::Backward(2)), "-3.."), (Range::to(Index::Forward(5)), "..5"), ]; diff --git a/src/parser/shell_expand/words/methods/arrays.rs b/src/parser/shell_expand/words/methods/arrays.rs index dd7373e2..7df75fc8 100644 --- a/src/parser/shell_expand/words/methods/arrays.rs +++ b/src/parser/shell_expand/words/methods/arrays.rs @@ -9,9 +9,9 @@ use unicode_segmentation::UnicodeSegmentation; #[derive(Debug, PartialEq, Clone)] pub(crate) struct ArrayMethod<'a> { - pub(crate) method: &'a str, - pub(crate) variable: &'a str, - pub(crate) pattern: Pattern<'a>, + pub(crate) method: &'a str, + pub(crate) variable: &'a str, + pub(crate) pattern: Pattern<'a>, pub(crate) selection: Select, } @@ -59,7 +59,8 @@ impl<'a> ArrayMethod<'a> { let res = match (&self.pattern, self.selection.clone()) { (_, Select::None) => Some("".into()).into_iter().collect(), (&Pattern::StringPattern(pattern), Select::All) => variable - .split(&unescape(&expand_string(pattern, expand_func, false).join(" "))?) + .split(&unescape(&expand_string(pattern, expand_func, false) + .join(" "))?) .map(From::from) .collect(), (&Pattern::Whitespace, Select::All) => variable @@ -68,7 +69,8 @@ impl<'a> ArrayMethod<'a> { .map(From::from) .collect(), (&Pattern::StringPattern(pattern), Select::Index(Index::Forward(id))) => variable - .split(&unescape(&expand_string(pattern, expand_func, false).join(" "))?) + .split(&unescape(&expand_string(pattern, expand_func, false) + .join(" "))?) .nth(id) .map(From::from) .into_iter() @@ -81,7 +83,8 @@ impl<'a> ArrayMethod<'a> { .into_iter() .collect(), (&Pattern::StringPattern(pattern), Select::Index(Index::Backward(id))) => variable - .rsplit(&unescape(&expand_string(pattern, expand_func, false).join(" "))?) + .rsplit(&unescape(&expand_string(pattern, expand_func, false) + .join(" "))?) .nth(id) .map(From::from) .into_iter() @@ -103,7 +106,10 @@ impl<'a> ArrayMethod<'a> { } } (&Pattern::Whitespace, Select::Range(range)) => { - let len = variable.split(char::is_whitespace).filter(|x| !x.is_empty()).count(); + let len = variable + .split(char::is_whitespace) + .filter(|x| !x.is_empty()) + .count(); if let Some((start, length)) = range.bounds(len) { variable .split(char::is_whitespace) @@ -125,7 +131,9 @@ impl<'a> ArrayMethod<'a> { let variable = self.resolve_var(expand_func); match self.pattern { Pattern::StringPattern(string) => if let Ok(value) = - expand_string(string, expand_func, false).join(" ").parse::<usize>() + expand_string(string, expand_func, false) + .join(" ") + .parse::<usize>() { if value < variable.len() { let (l, r) = variable.split_at(value); @@ -142,8 +150,9 @@ impl<'a> ArrayMethod<'a> { fn graphemes<E: Expander>(&self, expand_func: &E) -> Result<Array, &'static str> { let variable = self.resolve_var(expand_func); - let graphemes: Vec<String> = - UnicodeSegmentation::graphemes(variable.as_str(), true).map(From::from).collect(); + let graphemes: Vec<String> = UnicodeSegmentation::graphemes(variable.as_str(), true) + .map(From::from) + .collect(); let len = graphemes.len(); Ok(graphemes.into_iter().select(self.selection.clone(), len)) } @@ -151,13 +160,19 @@ impl<'a> ArrayMethod<'a> { fn bytes<E: Expander>(&self, expand_func: &E) -> Result<Array, &'static str> { let variable = self.resolve_var(expand_func); let len = variable.as_bytes().len(); - Ok(variable.bytes().map(|b| b.to_string()).select(self.selection.clone(), len)) + Ok(variable + .bytes() + .map(|b| b.to_string()) + .select(self.selection.clone(), len)) } fn chars<E: Expander>(&self, expand_func: &E) -> Result<Array, &'static str> { let variable = self.resolve_var(expand_func); let len = variable.chars().count(); - Ok(variable.chars().map(|c| c.to_string()).select(self.selection.clone(), len)) + Ok(variable + .chars() + .map(|c| c.to_string()) + .select(self.selection.clone(), len)) } } @@ -184,9 +199,9 @@ mod test { fn test_split_string_all() { let mut output = String::new(); let method = ArrayMethod { - method: "split", - variable: "$FOO", - pattern: Pattern::StringPattern("OB"), + method: "split", + variable: "$FOO", + pattern: Pattern::StringPattern("OB"), selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -197,9 +212,9 @@ mod test { fn test_split_whitespace_all() { let mut output = String::new(); let method = ArrayMethod { - method: "split", - variable: "$SPACEDFOO", - pattern: Pattern::Whitespace, + method: "split", + variable: "$SPACEDFOO", + pattern: Pattern::Whitespace, selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -210,9 +225,9 @@ mod test { fn test_split_string_index_forward() { let mut output = String::new(); let method = ArrayMethod { - method: "split", - variable: "$FOO", - pattern: Pattern::StringPattern("OB"), + method: "split", + variable: "$FOO", + pattern: Pattern::StringPattern("OB"), selection: Select::Index(Index::Forward(1)), }; method.handle(&mut output, &VariableExpander); @@ -223,9 +238,9 @@ mod test { fn test_split_whitespace_index_forward() { let mut output = String::new(); let method = ArrayMethod { - method: "split", - variable: "$SPACEDFOO", - pattern: Pattern::Whitespace, + method: "split", + variable: "$SPACEDFOO", + pattern: Pattern::Whitespace, selection: Select::Index(Index::Forward(1)), }; method.handle(&mut output, &VariableExpander); @@ -236,9 +251,9 @@ mod test { fn test_split_string_index_backward() { let mut output = String::new(); let method = ArrayMethod { - method: "split", - variable: "$FOO", - pattern: Pattern::StringPattern("OB"), + method: "split", + variable: "$FOO", + pattern: Pattern::StringPattern("OB"), selection: Select::Index(Index::Backward(1)), }; method.handle(&mut output, &VariableExpander); @@ -249,9 +264,9 @@ mod test { fn test_split_whitespace_index_backward() { let mut output = String::new(); let method = ArrayMethod { - method: "split", - variable: "$SPACEDFOO", - pattern: Pattern::Whitespace, + method: "split", + variable: "$SPACEDFOO", + pattern: Pattern::Whitespace, selection: Select::Index(Index::Backward(1)), }; method.handle(&mut output, &VariableExpander); @@ -262,9 +277,9 @@ mod test { fn test_split_string_range() { let mut output = String::new(); let method = ArrayMethod { - method: "split", - variable: "$FOO", - pattern: Pattern::StringPattern("OB"), + method: "split", + variable: "$FOO", + pattern: Pattern::StringPattern("OB"), selection: Select::Range(Range::from(Index::Forward(0))), }; method.handle(&mut output, &VariableExpander); @@ -275,9 +290,9 @@ mod test { fn test_split_whitespace_range() { let mut output = String::new(); let method = ArrayMethod { - method: "split", - variable: "$SPACEDFOO", - pattern: Pattern::Whitespace, + method: "split", + variable: "$SPACEDFOO", + pattern: Pattern::Whitespace, selection: Select::Range(Range::from(Index::Forward(0))), }; method.handle(&mut output, &VariableExpander); @@ -288,9 +303,9 @@ mod test { fn test_split_none() { let mut output = String::new(); let method = ArrayMethod { - method: "split", - variable: "$SPACEDFOO", - pattern: Pattern::Whitespace, + method: "split", + variable: "$SPACEDFOO", + pattern: Pattern::Whitespace, selection: Select::None, }; method.handle(&mut output, &VariableExpander); @@ -301,9 +316,9 @@ mod test { fn test_split_key() { let mut output = String::new(); let method = ArrayMethod { - method: "split", - variable: "$SPACEDFOO", - pattern: Pattern::Whitespace, + method: "split", + variable: "$SPACEDFOO", + pattern: Pattern::Whitespace, selection: Select::Key(Key::new("1")), }; method.handle(&mut output, &VariableExpander); @@ -313,9 +328,9 @@ mod test { #[test] fn test_split_at_failing_whitespace() { let method = ArrayMethod { - method: "split_at", - variable: "$SPACEDFOO", - pattern: Pattern::Whitespace, + method: "split_at", + variable: "$SPACEDFOO", + pattern: Pattern::Whitespace, selection: Select::All, }; assert_eq!(method.handle_as_array(&VariableExpander), array![]); @@ -324,9 +339,9 @@ mod test { #[test] fn test_split_at_failing_no_number() { let method = ArrayMethod { - method: "split_at", - variable: "$SPACEDFOO", - pattern: Pattern::StringPattern("a"), + method: "split_at", + variable: "$SPACEDFOO", + pattern: Pattern::StringPattern("a"), selection: Select::All, }; assert_eq!(method.handle_as_array(&VariableExpander), array![]); @@ -335,9 +350,9 @@ mod test { #[test] fn test_split_at_failing_out_of_bound() { let method = ArrayMethod { - method: "split_at", - variable: "$SPACEDFOO", - pattern: Pattern::StringPattern("100"), + method: "split_at", + variable: "$SPACEDFOO", + pattern: Pattern::StringPattern("100"), selection: Select::All, }; assert_eq!(method.handle_as_array(&VariableExpander), array![]); @@ -346,31 +361,37 @@ mod test { #[test] fn test_split_at_succeeding() { let method = ArrayMethod { - method: "split_at", - variable: "$FOO", - pattern: Pattern::StringPattern("3"), + method: "split_at", + variable: "$FOO", + pattern: Pattern::StringPattern("3"), selection: Select::All, }; - assert_eq!(method.handle_as_array(&VariableExpander), array!["FOO", "BAR"]); + assert_eq!( + method.handle_as_array(&VariableExpander), + array!["FOO", "BAR"] + ); } #[test] fn test_graphemes() { let method = ArrayMethod { - method: "graphemes", - variable: "$FOO", - pattern: Pattern::StringPattern("3"), + method: "graphemes", + variable: "$FOO", + pattern: Pattern::StringPattern("3"), selection: Select::All, }; - assert_eq!(method.handle_as_array(&VariableExpander), array!["F", "O", "O", "B", "A", "R"]); + assert_eq!( + method.handle_as_array(&VariableExpander), + array!["F", "O", "O", "B", "A", "R"] + ); } #[test] fn test_bytes() { let method = ArrayMethod { - method: "bytes", - variable: "$FOO", - pattern: Pattern::StringPattern("3"), + method: "bytes", + variable: "$FOO", + pattern: Pattern::StringPattern("3"), selection: Select::All, }; assert_eq!( @@ -382,11 +403,14 @@ mod test { #[test] fn test_chars() { let method = ArrayMethod { - method: "chars", - variable: "$FOO", - pattern: Pattern::StringPattern("3"), + method: "chars", + variable: "$FOO", + pattern: Pattern::StringPattern("3"), selection: Select::All, }; - assert_eq!(method.handle_as_array(&VariableExpander), array!["F", "O", "O", "B", "A", "R"]); + assert_eq!( + method.handle_as_array(&VariableExpander), + array!["F", "O", "O", "B", "A", "R"] + ); } } diff --git a/src/parser/shell_expand/words/methods/mod.rs b/src/parser/shell_expand/words/methods/mod.rs index 34d85533..90ed166e 100644 --- a/src/parser/shell_expand/words/methods/mod.rs +++ b/src/parser/shell_expand/words/methods/mod.rs @@ -21,12 +21,16 @@ pub(crate) struct Key { impl Key { #[cfg(test)] - pub(crate) fn new<K: Into<::types::Key>>(key: K) -> Key { Key { key: key.into() } } - pub(crate) fn get(&self) -> &::types::Key { return &self.key; } + pub(crate) fn new<K: Into<::types::Key>>(key: K) -> Key { + Key { key: key.into() } + } + pub(crate) fn get(&self) -> &::types::Key { + return &self.key; + } } pub(crate) struct MethodArgs<'a, 'b, E: 'b + Expander> { - args: &'a str, + args: &'a str, expand: &'b E, } diff --git a/src/parser/shell_expand/words/methods/strings.rs b/src/parser/shell_expand/words/methods/strings.rs index 6b99fd6c..c20f0124 100644 --- a/src/parser/shell_expand/words/methods/strings.rs +++ b/src/parser/shell_expand/words/methods/strings.rs @@ -241,7 +241,9 @@ impl<'a> StringMethod<'a> { let out = if let Some(value) = expand.variable(variable, false) { value.find(&pattern.join(" ")) } else if is_expression(variable) { - expand_string(variable, expand, false).join(" ").find(&pattern.join(" ")) + expand_string(variable, expand, false) + .join(" ") + .find(&pattern.join(" ")) } else { None }; @@ -342,9 +344,9 @@ mod test { fn test_ends_with_succeeding() { let mut output = String::new(); let method = StringMethod { - method: "ends_with", - variable: "$FOO", - pattern: "\"BAR\"", + method: "ends_with", + variable: "$FOO", + pattern: "\"BAR\"", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -355,9 +357,9 @@ mod test { fn test_ends_with_failing() { let mut output = String::new(); let method = StringMethod { - method: "ends_with", - variable: "$FOO", - pattern: "\"BA\"", + method: "ends_with", + variable: "$FOO", + pattern: "\"BA\"", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -368,9 +370,9 @@ mod test { fn test_contains_succeeding() { let mut output = String::new(); let method = StringMethod { - method: "contains", - variable: "$FOO", - pattern: "\"OBA\"", + method: "contains", + variable: "$FOO", + pattern: "\"OBA\"", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -381,9 +383,9 @@ mod test { fn test_contains_failing() { let mut output = String::new(); let method = StringMethod { - method: "contains", - variable: "$FOO", - pattern: "\"OBI\"", + method: "contains", + variable: "$FOO", + pattern: "\"OBI\"", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -394,9 +396,9 @@ mod test { fn test_starts_with_succeeding() { let mut output = String::new(); let method = StringMethod { - method: "starts_with", - variable: "$FOO", - pattern: "\"FOO\"", + method: "starts_with", + variable: "$FOO", + pattern: "\"FOO\"", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -407,9 +409,9 @@ mod test { fn test_starts_with_failing() { let mut output = String::new(); let method = StringMethod { - method: "starts_with", - variable: "$FOO", - pattern: "\"OO\"", + method: "starts_with", + variable: "$FOO", + pattern: "\"OO\"", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -420,9 +422,9 @@ mod test { fn test_basename() { let mut output = String::new(); let method = StringMethod { - method: "basename", - variable: "\"/home/redox/file.txt\"", - pattern: "", + method: "basename", + variable: "\"/home/redox/file.txt\"", + pattern: "", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -433,9 +435,9 @@ mod test { fn test_extension() { let mut output = String::new(); let method = StringMethod { - method: "extension", - variable: "\"/home/redox/file.txt\"", - pattern: "", + method: "extension", + variable: "\"/home/redox/file.txt\"", + pattern: "", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -446,9 +448,9 @@ mod test { fn test_filename() { let mut output = String::new(); let method = StringMethod { - method: "filename", - variable: "\"/home/redox/file.txt\"", - pattern: "", + method: "filename", + variable: "\"/home/redox/file.txt\"", + pattern: "", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -459,9 +461,9 @@ mod test { fn test_parent() { let mut output = String::new(); let method = StringMethod { - method: "parent", - variable: "\"/home/redox/file.txt\"", - pattern: "", + method: "parent", + variable: "\"/home/redox/file.txt\"", + pattern: "", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -472,9 +474,9 @@ mod test { fn test_to_lowercase() { let mut output = String::new(); let method = StringMethod { - method: "to_lowercase", - variable: "\"Ford Prefect\"", - pattern: "", + method: "to_lowercase", + variable: "\"Ford Prefect\"", + pattern: "", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -485,9 +487,9 @@ mod test { fn test_to_uppercase() { let mut output = String::new(); let method = StringMethod { - method: "to_uppercase", - variable: "\"Ford Prefect\"", - pattern: "", + method: "to_uppercase", + variable: "\"Ford Prefect\"", + pattern: "", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -498,9 +500,9 @@ mod test { fn test_repeat_succeeding() { let mut output = String::new(); let method = StringMethod { - method: "repeat", - variable: "$FOO", - pattern: "2", + method: "repeat", + variable: "$FOO", + pattern: "2", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -511,9 +513,9 @@ mod test { fn test_repeat_failing() { let mut output = String::new(); let method = StringMethod { - method: "repeat", - variable: "$FOO", - pattern: "-2", + method: "repeat", + variable: "$FOO", + pattern: "-2", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -524,9 +526,9 @@ mod test { fn test_replace_succeeding() { let mut output = String::new(); let method = StringMethod { - method: "replace", - variable: "$FOO", - pattern: "[\"FOO\" \"BAR\"]", + method: "replace", + variable: "$FOO", + pattern: "[\"FOO\" \"BAR\"]", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -537,9 +539,9 @@ mod test { fn test_replace_failing() { let mut output = String::new(); let method = StringMethod { - method: "replace", - variable: "$FOO", - pattern: "[]", + method: "replace", + variable: "$FOO", + pattern: "[]", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -550,9 +552,9 @@ mod test { fn test_replacen_succeeding() { let mut output = String::new(); let method = StringMethod { - method: "replacen", - variable: "\"FOO$FOO\"", - pattern: "[\"FOO\" \"BAR\" 1]", + method: "replacen", + variable: "\"FOO$FOO\"", + pattern: "[\"FOO\" \"BAR\" 1]", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -563,9 +565,9 @@ mod test { fn test_replacen_failing() { let mut output = String::new(); let method = StringMethod { - method: "replacen", - variable: "$FOO", - pattern: "[]", + method: "replacen", + variable: "$FOO", + pattern: "[]", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -576,9 +578,9 @@ mod test { fn test_regex_replace_succeeding() { let mut output = String::new(); let method = StringMethod { - method: "regex_replace", - variable: "$FOO", - pattern: "[\"^F\" \"f\"]", + method: "regex_replace", + variable: "$FOO", + pattern: "[\"^F\" \"f\"]", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -589,9 +591,9 @@ mod test { fn test_regex_replace_failing() { let mut output = String::new(); let method = StringMethod { - method: "regex_replace", - variable: "$FOO", - pattern: "[\"^f\" \"F\"]", + method: "regex_replace", + variable: "$FOO", + pattern: "[\"^f\" \"F\"]", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -602,9 +604,9 @@ mod test { fn test_join_with_string() { let mut output = String::new(); let method = StringMethod { - method: "join", - variable: "[\"FOO\" \"BAR\"]", - pattern: "\" \"", + method: "join", + variable: "[\"FOO\" \"BAR\"]", + pattern: "\" \"", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -615,9 +617,9 @@ mod test { fn test_join_with_array() { let mut output = String::new(); let method = StringMethod { - method: "join", - variable: "[\"FOO\" \"BAR\"]", - pattern: "[\"-\" \"-\"]", + method: "join", + variable: "[\"FOO\" \"BAR\"]", + pattern: "[\"-\" \"-\"]", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -628,9 +630,9 @@ mod test { fn test_len_with_array() { let mut output = String::new(); let method = StringMethod { - method: "len", - variable: "[\"1\"]", - pattern: "", + method: "len", + variable: "[\"1\"]", + pattern: "", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -641,9 +643,9 @@ mod test { fn test_len_with_string() { let mut output = String::new(); let method = StringMethod { - method: "len", - variable: "\"FOO\"", - pattern: "", + method: "len", + variable: "\"FOO\"", + pattern: "", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -654,9 +656,9 @@ mod test { fn test_len_with_variable() { let mut output = String::new(); let method = StringMethod { - method: "len", - variable: "$FOO", - pattern: "", + method: "len", + variable: "$FOO", + pattern: "", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -667,9 +669,9 @@ mod test { fn test_len_bytes_with_variable() { let mut output = String::new(); let method = StringMethod { - method: "len_bytes", - variable: "$FOO", - pattern: "", + method: "len_bytes", + variable: "$FOO", + pattern: "", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -680,9 +682,9 @@ mod test { fn test_len_bytes_with_string() { let mut output = String::new(); let method = StringMethod { - method: "len_bytes", - variable: "\"oh là là \"", - pattern: "", + method: "len_bytes", + variable: "\"oh là là \"", + pattern: "", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -693,9 +695,9 @@ mod test { fn test_reverse_with_variable() { let mut output = String::new(); let method = StringMethod { - method: "reverse", - variable: "$FOO", - pattern: "", + method: "reverse", + variable: "$FOO", + pattern: "", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -706,9 +708,9 @@ mod test { fn test_reverse_with_string() { let mut output = String::new(); let method = StringMethod { - method: "reverse", - variable: "\"FOOBAR\"", - pattern: "", + method: "reverse", + variable: "\"FOOBAR\"", + pattern: "", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -719,9 +721,9 @@ mod test { fn test_find_succeeding() { let mut output = String::new(); let method = StringMethod { - method: "find", - variable: "$FOO", - pattern: "\"O\"", + method: "find", + variable: "$FOO", + pattern: "\"O\"", selection: Select::All, }; method.handle(&mut output, &VariableExpander); @@ -732,9 +734,9 @@ mod test { fn test_find_failing() { let mut output = String::new(); let method = StringMethod { - method: "find", - variable: "$FOO", - pattern: "\"L\"", + method: "find", + variable: "$FOO", + pattern: "\"L\"", selection: Select::All, }; method.handle(&mut output, &VariableExpander); diff --git a/src/parser/shell_expand/words/mod.rs b/src/parser/shell_expand/words/mod.rs index 38a09e7d..7cf7cec1 100644 --- a/src/parser/shell_expand/words/mod.rs +++ b/src/parser/shell_expand/words/mod.rs @@ -48,20 +48,26 @@ pub(crate) enum WordToken<'a> { } pub(crate) struct WordIterator<'a, E: Expander + 'a> { - data: &'a str, - read: usize, - flags: Flags, + data: &'a str, + read: usize, + flags: Flags, expanders: &'a E, } impl<'a, E: Expander + 'a> WordIterator<'a, E> { pub(crate) fn new(data: &'a str, expanders: &'a E) -> WordIterator<'a, E> { - WordIterator { data, read: 0, flags: Flags::empty(), expanders } + WordIterator { + data, + read: 0, + flags: Flags::empty(), + expanders, + } } // Contains the grammar for collecting whitespace characters fn whitespaces<I>(&mut self, iterator: &mut I) -> WordToken<'a> - where I: Iterator<Item = u8> + where + I: Iterator<Item = u8>, { let start = self.read; self.read += 1; @@ -78,7 +84,8 @@ impl<'a, E: Expander + 'a> WordIterator<'a, E> { // Contains the logic for parsing braced variables fn braced_variable<I>(&mut self, iterator: &mut I) -> WordToken<'a> - where I: Iterator<Item = u8> + where + I: Iterator<Item = u8>, { let start = self.read; while let Some(character) = iterator.next() { @@ -96,7 +103,8 @@ impl<'a, E: Expander + 'a> WordIterator<'a, E> { /// Contains the logic for parsing variable syntax fn variable<I>(&mut self, iterator: &mut I) -> WordToken<'a> - where I: Iterator<Item = u8> + where + I: Iterator<Item = u8>, { let mut start = self.read; self.read += 1; @@ -202,11 +210,16 @@ impl<'a, E: Expander + 'a> WordIterator<'a, E> { self.read += 1; } - WordToken::Variable(&self.data[start..], self.flags.contains(Flags::DQUOTE), Select::All) + WordToken::Variable( + &self.data[start..], + self.flags.contains(Flags::DQUOTE), + Select::All, + ) } fn read_selection<I>(&mut self, iterator: &mut I) -> Select - where I: Iterator<Item = u8> + where + I: Iterator<Item = u8>, { self.read += 1; let start = self.read; @@ -229,7 +242,8 @@ impl<'a, E: Expander + 'a> WordIterator<'a, E> { /// Contains the logic for parsing array variable syntax fn array_variable<I>(&mut self, iterator: &mut I) -> WordToken<'a> - where I: Iterator<Item = u8> + where + I: Iterator<Item = u8>, { let mut start = self.read; self.read += 1; @@ -331,7 +345,8 @@ impl<'a, E: Expander + 'a> WordIterator<'a, E> { } fn braced_array_variable<I>(&mut self, iterator: &mut I) -> WordToken<'a> - where I: Iterator<Item = u8> + where + I: Iterator<Item = u8>, { let start = self.read; // self.read += 1; @@ -382,7 +397,8 @@ impl<'a, E: Expander + 'a> WordIterator<'a, E> { /// Contains the logic for parsing subshell syntax. fn process<I>(&mut self, iterator: &mut I) -> WordToken<'a> - where I: Iterator<Item = u8> + where + I: Iterator<Item = u8>, { let start = self.read; let mut level = 0; @@ -424,7 +440,8 @@ impl<'a, E: Expander + 'a> WordIterator<'a, E> { /// Contains the logic for parsing array subshell syntax. fn array_process<I>(&mut self, iterator: &mut I) -> WordToken<'a> - where I: Iterator<Item = u8> + where + I: Iterator<Item = u8>, { let start = self.read; let mut level = 0; @@ -470,7 +487,8 @@ impl<'a, E: Expander + 'a> WordIterator<'a, E> { /// Contains the grammar for parsing brace expansion syntax fn braces<I>(&mut self, iterator: &mut I) -> WordToken<'a> - where I: Iterator<Item = u8> + where + I: Iterator<Item = u8>, { let mut start = self.read; let mut level = 0; @@ -503,7 +521,8 @@ impl<'a, E: Expander + 'a> WordIterator<'a, E> { /// Contains the grammar for parsing array expression syntax fn array<I>(&mut self, iterator: &mut I) -> WordToken<'a> - where I: Iterator<Item = u8> + where + I: Iterator<Item = u8>, { let start = self.read; let mut level = 0; @@ -537,10 +556,11 @@ impl<'a, E: Expander + 'a> WordIterator<'a, E> { } fn glob_check<I>(&mut self, iterator: &mut I) -> bool - where I: Iterator<Item = u8> + Clone + where + I: Iterator<Item = u8> + Clone, { - // Clone the iterator and scan for illegal characters until the corresponding ] is - // discovered. If none are found, then it's a valid glob signature. + // Clone the iterator and scan for illegal characters until the corresponding ] + // is discovered. If none are found, then it's a valid glob signature. let mut moves = 0; let mut glob = false; let mut square_bracket = 0; diff --git a/src/parser/shell_expand/words/range.rs b/src/parser/shell_expand/words/range.rs index 366cf1a8..846fb86a 100644 --- a/src/parser/shell_expand/words/range.rs +++ b/src/parser/shell_expand/words/range.rs @@ -13,18 +13,36 @@ pub(crate) struct Range { } impl Range { - pub(crate) fn to(end: Index) -> Range { Range { start: Index::new(0), end, inclusive: false } } + pub(crate) fn to(end: Index) -> Range { + Range { + start: Index::new(0), + end, + inclusive: false, + } + } pub(crate) fn from(start: Index) -> Range { - Range { start, end: Index::new(-1), inclusive: true } + Range { + start, + end: Index::new(-1), + inclusive: true, + } } pub(crate) fn inclusive(start: Index, end: Index) -> Range { - Range { start, end, inclusive: true } + Range { + start, + end, + inclusive: true, + } } pub(crate) fn exclusive(start: Index, end: Index) -> Range { - Range { start, end, inclusive: false } + Range { + start, + end, + inclusive: false, + } } /// Returns the bounds of this range as a tuple containing: diff --git a/src/parser/shell_expand/words/select.rs b/src/parser/shell_expand/words/select.rs index 84396091..7099df1f 100644 --- a/src/parser/shell_expand/words/select.rs +++ b/src/parser/shell_expand/words/select.rs @@ -23,22 +23,26 @@ pub(crate) enum Select { pub(crate) trait SelectWithSize { type Item; fn select<O>(&mut self, Select, usize) -> O - where O: FromIterator<Self::Item>; + where + O: FromIterator<Self::Item>; } impl<I, T> SelectWithSize for I - where I: Iterator<Item = T> +where + I: Iterator<Item = T>, { type Item = T; fn select<O>(&mut self, s: Select, size: usize) -> O - where O: FromIterator<Self::Item> + where + O: FromIterator<Self::Item>, { match s { Select::None => empty().collect(), Select::All => self.collect(), - Select::Index(idx) => { - idx.resolve(size).and_then(|idx| self.nth(idx)).into_iter().collect() - } + Select::Index(idx) => idx.resolve(size) + .and_then(|idx| self.nth(idx)) + .into_iter() + .collect(), Select::Range(range) => if let Some((start, length)) = range.bounds(size) { self.skip(start).take(length).collect() } else { diff --git a/src/parser/shell_expand/words/tests.rs b/src/parser/shell_expand/words/tests.rs index f3b1b809..839d2f5b 100644 --- a/src/parser/shell_expand/words/tests.rs +++ b/src/parser/shell_expand/words/tests.rs @@ -30,16 +30,16 @@ fn string_method() { let input = "$join(array, 'pattern') $join(array, 'pattern')"; let expected = vec![ WordToken::StringMethod(StringMethod { - method: "join", - variable: "array", - pattern: "'pattern'", + method: "join", + variable: "array", + pattern: "'pattern'", selection: Select::All, }), WordToken::Whitespace(" "), WordToken::StringMethod(StringMethod { - method: "join", - variable: "array", - pattern: "'pattern'", + method: "join", + variable: "array", + pattern: "'pattern'", selection: Select::All, }), ]; @@ -152,7 +152,11 @@ fn words_process_with_quotes() { let expected = vec![ WordToken::Normal("echo", false, false), WordToken::Whitespace(" "), - WordToken::Process("git branch | rg '[*]' | awk '{print $2}'", false, Select::All), + WordToken::Process( + "git branch | rg '[*]' | awk '{print $2}'", + false, + Select::All, + ), ]; compare(input, expected); @@ -160,7 +164,11 @@ fn words_process_with_quotes() { let expected = vec![ WordToken::Normal("echo", false, false), WordToken::Whitespace(" "), - WordToken::Process("git branch | rg \"[*]\" | awk '{print $2}'", false, Select::All), + WordToken::Process( + "git branch | rg \"[*]\" | awk '{print $2}'", + false, + Select::All, + ), ]; compare(input, expected); } @@ -257,25 +265,25 @@ impl Expander for WithVars { fn array_methods() { let expanders = WithVars; let method = ArrayMethod { - method: "graphemes", - variable: "pkmn1", - pattern: Pattern::Whitespace, + method: "graphemes", + variable: "pkmn1", + pattern: Pattern::Whitespace, selection: Select::Index(Index::Forward(3)), }; let expected = array!["é"]; assert_eq!(method.handle_as_array(&expanders), expected); let method = ArrayMethod { - method: "chars", - variable: "pkmn2", - pattern: Pattern::Whitespace, + method: "chars", + variable: "pkmn2", + pattern: Pattern::Whitespace, selection: Select::Index(Index::Forward(3)), }; let expected = array!["e"]; assert_eq!(method.handle_as_array(&expanders), expected); let method = ArrayMethod { - method: "bytes", - variable: "pkmn2", - pattern: Pattern::Whitespace, + method: "bytes", + variable: "pkmn2", + pattern: Pattern::Whitespace, selection: Select::Index(Index::Forward(1)), }; let expected = array!["111"]; diff --git a/src/parser/statement/case.rs b/src/parser/statement/case.rs index d5193636..75732370 100644 --- a/src/parser/statement/case.rs +++ b/src/parser/statement/case.rs @@ -76,7 +76,10 @@ mod tests { Ok((Some("test"), Some("test"), Some("exists".into()))), parse_case("test @ test if exists") ); - assert_eq!(Ok((Some("test"), Some("test"), None)), parse_case("test @ test")); + assert_eq!( + Ok((Some("test"), Some("test"), None)), + parse_case("test @ test") + ); assert_eq!(Ok((Some("test"), None, None)), parse_case("test")); } } diff --git a/src/parser/statement/functions.rs b/src/parser/statement/functions.rs index 00ad0dff..3bd6a01c 100644 --- a/src/parser/statement/functions.rs +++ b/src/parser/statement/functions.rs @@ -29,10 +29,22 @@ mod tests { assert_eq!( args, Ok(vec![ - KeyBuf { name: "a".into(), kind: Primitive::Integer }, - KeyBuf { name: "b".into(), kind: Primitive::Boolean }, - KeyBuf { name: "c".into(), kind: Primitive::AnyArray }, - KeyBuf { name: "d".into(), kind: Primitive::Any }, + KeyBuf { + name: "a".into(), + kind: Primitive::Integer, + }, + KeyBuf { + name: "b".into(), + kind: Primitive::Boolean, + }, + KeyBuf { + name: "c".into(), + kind: Primitive::AnyArray, + }, + KeyBuf { + name: "d".into(), + kind: Primitive::Any, + }, ]) ); assert_eq!(description, Some("description")) diff --git a/src/parser/statement/mod.rs b/src/parser/statement/mod.rs index 5a464e46..058101aa 100644 --- a/src/parser/statement/mod.rs +++ b/src/parser/statement/mod.rs @@ -7,7 +7,8 @@ pub(crate) use self::parse::parse; pub(crate) use self::splitter::{StatementError, StatementSplitter}; use shell::flow_control::Statement; -/// Parses a given statement string and return's the corresponding mapped `Statement` +/// Parses a given statement string and return's the corresponding mapped +/// `Statement` pub(crate) fn parse_and_validate<'a>(statement: Result<&str, StatementError<'a>>) -> Statement { match statement { Ok(statement) => parse(statement), diff --git a/src/parser/statement/parse.rs b/src/parser/statement/parse.rs index 0bde0c25..a6fbd930 100644 --- a/src/parser/statement/parse.rs +++ b/src/parser/statement/parse.rs @@ -7,7 +7,8 @@ use shell::flow_control::{Case, ElseIf, ExportAction, LocalAction, Statement}; use std::char; fn collect<F>(arguments: &str, statement: F) -> Statement - where F: Fn(Pipeline) -> Statement +where + F: Fn(Pipeline) -> Statement, { match pipelines::Collector::run(arguments) { Ok(pipeline) => statement(pipeline), @@ -18,7 +19,9 @@ fn collect<F>(arguments: &str, statement: F) -> Statement } } -fn is_valid_name(name: &str) -> bool { !name.chars().any(|c| !(c.is_alphanumeric() || c == '_')) } +fn is_valid_name(name: &str) -> bool { + !name.chars().any(|c| !(c.is_alphanumeric() || c == '_')) +} pub(crate) fn parse(code: &str) -> Statement { let cmd = code.trim(); @@ -51,7 +54,8 @@ pub(crate) fn parse(code: &str) -> Statement { } }; - // After also ensuring the the operator is a valid operator, create the let statement. + // After also ensuring the the operator is a valid operator, create the let + // statement. match Operator::parse(op) { Ok(operator) => { return Statement::Let(LocalAction::Assign(keys, operator, values)); @@ -85,7 +89,8 @@ pub(crate) fn parse(code: &str) -> Statement { } }; - // After also ensuring the the operator is a valid operator, create the let statement. + // After also ensuring the the operator is a valid operator, create the let + // statement. match Operator::parse(op) { Ok(operator) => { return Statement::Export(ExportAction::Assign(keys, operator, values)); @@ -100,9 +105,9 @@ pub(crate) fn parse(code: &str) -> Statement { return collect(cmd[3..].trim_left(), |pipeline| { Statement::If { expression: pipeline, - success: Vec::new(), - else_if: Vec::new(), - failure: Vec::new(), + success: Vec::new(), + else_if: Vec::new(), + failure: Vec::new(), } }) } @@ -113,13 +118,19 @@ pub(crate) fn parse(code: &str) -> Statement { return Statement::Else; } else if cmd.starts_with("if ") { return collect(cmd[3..].trim_left(), |pipeline| { - Statement::ElseIf(ElseIf { expression: pipeline, success: Vec::new() }) + Statement::ElseIf(ElseIf { + expression: pipeline, + success: Vec::new(), + }) }); } } _ if cmd.starts_with("while ") => { return collect(cmd[6..].trim_left(), |pipeline| { - Statement::While { expression: pipeline, statements: Vec::new() } + Statement::While { + expression: pipeline, + statements: Vec::new(), + } }) } _ if cmd.starts_with("for ") => { @@ -141,8 +152,10 @@ pub(crate) fn parse(code: &str) -> Statement { } return Statement::For { - variable: variable.into(), - values: ArgumentSplitter::new(cmd[3..].trim_left()).map(String::from).collect(), + variable: variable.into(), + values: ArgumentSplitter::new(cmd[3..].trim_left()) + .map(String::from) + .collect(), statements: Vec::new(), }; } @@ -166,12 +179,17 @@ pub(crate) fn parse(code: &str) -> Statement { } }; - return Statement::Case(Case { value, binding, conditional, statements: Vec::new() }); + return Statement::Case(Case { + value, + binding, + conditional, + statements: Vec::new(), + }); } _ if cmd.starts_with("match ") => { return Statement::Match { expression: cmd[6..].trim_left().into(), - cases: Vec::new(), + cases: Vec::new(), } } _ if cmd.starts_with("fn ") => { @@ -234,7 +252,7 @@ mod tests { expression: Pipeline { items: vec![ PipeItem { - job: Job::new( + job: Job::new( vec![ "test".to_owned(), "1".to_owned(), @@ -245,13 +263,13 @@ mod tests { JobKind::Last, ), outputs: Vec::new(), - inputs: Vec::new(), + inputs: Vec::new(), }, ], }, - success: vec![], - else_if: vec![], - failure: vec![], + success: vec![], + else_if: vec![], + failure: vec![], }; assert_eq!(correct_parse, parsed_if); @@ -300,9 +318,9 @@ mod tests { let parsed_if = parse("fn bob"); let correct_parse = Statement::Function { description: None, - name: "bob".into(), - args: Default::default(), - statements: Default::default(), + name: "bob".into(), + args: Default::default(), + statements: Default::default(), }; assert_eq!(correct_parse, parsed_if); @@ -318,12 +336,18 @@ mod tests { let parsed_if = parse("fn bob a b"); let correct_parse = Statement::Function { description: None, - name: "bob".into(), - args: vec![ - KeyBuf { name: "a".into(), kind: Primitive::Any }, - KeyBuf { name: "b".into(), kind: Primitive::Any }, + name: "bob".into(), + args: vec![ + KeyBuf { + name: "a".into(), + kind: Primitive::Any, + }, + KeyBuf { + name: "b".into(), + kind: Primitive::Any, + }, ], - statements: Default::default(), + statements: Default::default(), }; assert_eq!(correct_parse, parsed_if); @@ -334,12 +358,18 @@ mod tests { let parsed_if = parse("fn bob a b --bob is a nice function"); let correct_parse = Statement::Function { description: Some("bob is a nice function".to_string()), - name: "bob".into(), - args: vec![ - KeyBuf { name: "a".into(), kind: Primitive::Any }, - KeyBuf { name: "b".into(), kind: Primitive::Any }, + name: "bob".into(), + args: vec![ + KeyBuf { + name: "a".into(), + kind: Primitive::Any, + }, + KeyBuf { + name: "b".into(), + kind: Primitive::Any, + }, ], - statements: vec![], + statements: vec![], }; assert_eq!(correct_parse, parsed_if); let parsed_if = parse("fn bob a b -- bob is a nice function"); diff --git a/src/parser/statement/splitter.rs b/src/parser/statement/splitter.rs index df010dc3..61e229b8 100644 --- a/src/parser/statement/splitter.rs +++ b/src/parser/statement/splitter.rs @@ -70,26 +70,26 @@ fn is_invalid(byte: u8) -> bool { } pub(crate) struct StatementSplitter<'a> { - data: &'a str, - read: usize, - flags: Flags, - a_level: u8, - ap_level: u8, - p_level: u8, - brace_level: u8, + data: &'a str, + read: usize, + flags: Flags, + a_level: u8, + ap_level: u8, + p_level: u8, + brace_level: u8, math_paren_level: i8, } impl<'a> StatementSplitter<'a> { pub(crate) fn new(data: &'a str) -> StatementSplitter<'a> { StatementSplitter { - data: data, - read: 0, - flags: Flags::empty(), - a_level: 0, - ap_level: 0, - p_level: 0, - brace_level: 0, + data: data, + read: 0, + flags: Flags::empty(), + a_level: 0, + ap_level: 0, + p_level: 0, + brace_level: 0, math_paren_level: 0, } } @@ -134,7 +134,10 @@ impl<'a> Iterator for StatementSplitter<'a> { { // If we are just ending the braced section continue as normal if error.is_none() { - error = Some(StatementError::InvalidCharacter(character as char, self.read)) + error = Some(StatementError::InvalidCharacter( + character as char, + self.read, + )) } } b'\'' if !self.flags.contains(Flags::DQUOTE) => { @@ -159,7 +162,10 @@ impl<'a> Iterator for StatementSplitter<'a> { b'}' if self.flags.contains(Flags::VBRACE) => self.flags.toggle(Flags::VBRACE), b'}' if !self.flags.contains(Flags::DQUOTE) => if self.brace_level == 0 { if error.is_none() { - error = Some(StatementError::InvalidCharacter(character as char, self.read)) + error = Some(StatementError::InvalidCharacter( + character as char, + self.read, + )) } } else { self.brace_level -= 1; @@ -167,9 +173,14 @@ impl<'a> Iterator for StatementSplitter<'a> { b'(' if self.flags.contains(Flags::MATHEXPR) => { self.math_paren_level += 1; } - b'(' if !self.flags.intersects(Flags::COMM_1 | Flags::VARIAB | Flags::ARRAY) => { + b'(' if !self.flags + .intersects(Flags::COMM_1 | Flags::VARIAB | Flags::ARRAY) => + { if error.is_none() && !self.flags.contains(Flags::DQUOTE) { - error = Some(StatementError::InvalidCharacter(character as char, self.read)) + error = Some(StatementError::InvalidCharacter( + character as char, + self.read, + )) } } b'(' if self.flags.intersects(Flags::COMM_1 | Flags::METHOD) => { @@ -210,7 +221,10 @@ impl<'a> Iterator for StatementSplitter<'a> { } b')' if self.p_level + self.ap_level == 0 => { if error.is_none() && !self.flags.contains(Flags::DQUOTE) { - error = Some(StatementError::InvalidCharacter(character as char, self.read)) + error = Some(StatementError::InvalidCharacter( + character as char, + self.read, + )) } } b')' if self.p_level != 0 => self.p_level -= 1, @@ -324,7 +338,10 @@ fn syntax_errors() { let command = ">echo"; let results = StatementSplitter::new(command).collect::<Vec<Result<&str, StatementError>>>(); - assert_eq!(results[0], Err(StatementError::ExpectedCommandButFound("redirection"))); + assert_eq!( + results[0], + Err(StatementError::ExpectedCommandButFound("redirection")) + ); assert_eq!(results.len(), 1); let command = "echo $((foo bar baz)"; diff --git a/src/shell/assignments.rs b/src/shell/assignments.rs index 0fa9bc55..dfd51711 100644 --- a/src/shell/assignments.rs +++ b/src/shell/assignments.rs @@ -41,7 +41,11 @@ fn list_vars(shell: &Shell) { // Then immediately follow that with a list of array variables. let _ = buffer.write(b"\n# Array Variables\n"); - shell.variables.arrays.iter().for_each(|(key, val)| print_array(&mut buffer, &key, &val)); + shell + .variables + .arrays + .iter() + .for_each(|(key, val)| print_array(&mut buffer, &key, &val)); } /// Represents: A variable store capable of setting local variables or @@ -86,7 +90,7 @@ impl VariableStore for Shell { Ok(Action::UpdateArray(..)) => { eprintln!( "ion: arithmetic operators on array expressions aren't supported \ - yet." + yet." ); return FAILURE; } @@ -105,13 +109,12 @@ impl VariableStore for Shell { .map(|x| x.as_str()) .unwrap_or("0") as *const str; - let result = math( - unsafe { &*lhs }, - key.kind, - operator, - &value, - |value| self.set_var(key_name, unsafe { str::from_utf8_unchecked(value) }), - ); + let result = + math(unsafe { &*lhs }, key.kind, operator, &value, |value| { + self.set_var(key_name, unsafe { + str::from_utf8_unchecked(value) + }) + }); if let Err(why) = result { eprintln!("ion: assignment error: {}", why); @@ -230,15 +233,23 @@ impl Display for MathError { } fn parse_f64<F: Fn(f64, f64) -> f64>(lhs: &str, rhs: &str, operation: F) -> Result<f64, MathError> { - lhs.parse::<f64>().map_err(|_| MathError::LHS).and_then( - |lhs| rhs.parse::<f64>().map_err(|_| MathError::RHS).map(|rhs| operation(lhs, rhs)), - ) + lhs.parse::<f64>() + .map_err(|_| MathError::LHS) + .and_then(|lhs| { + rhs.parse::<f64>() + .map_err(|_| MathError::RHS) + .map(|rhs| operation(lhs, rhs)) + }) } fn parse_i64<F: Fn(i64, i64) -> i64>(lhs: &str, rhs: &str, operation: F) -> Result<i64, MathError> { - lhs.parse::<i64>().map_err(|_| MathError::LHS).and_then( - |lhs| rhs.parse::<i64>().map_err(|_| MathError::RHS).map(|rhs| operation(lhs, rhs)), - ) + lhs.parse::<i64>() + .map_err(|_| MathError::LHS) + .and_then(|lhs| { + rhs.parse::<i64>() + .map_err(|_| MathError::RHS) + .map(|rhs| operation(lhs, rhs)) + }) } fn write_integer<F: FnMut(&[u8])>(integer: i64, mut func: F) { @@ -256,7 +267,11 @@ fn math<'a, F: FnMut(&[u8])>( ) -> Result<(), MathError> { match operator { Operator::Add => if Primitive::Any == key || Primitive::Float == key { - writefn(parse_f64(lhs, value, |lhs, rhs| lhs + rhs)?.to_string().as_bytes()); + writefn( + parse_f64(lhs, value, |lhs, rhs| lhs + rhs)? + .to_string() + .as_bytes(), + ); } else if let Primitive::Integer = key { write_integer(parse_i64(lhs, value, |lhs, rhs| lhs + rhs)?, writefn); } else { @@ -264,7 +279,11 @@ fn math<'a, F: FnMut(&[u8])>( }, Operator::Divide => { if Primitive::Any == key || Primitive::Float == key || Primitive::Integer == key { - writefn(parse_f64(lhs, value, |lhs, rhs| lhs / rhs)?.to_string().as_bytes()); + writefn( + parse_f64(lhs, value, |lhs, rhs| lhs / rhs)? + .to_string() + .as_bytes(), + ); } else { return Err(MathError::Unsupported); } @@ -275,23 +294,38 @@ fn math<'a, F: FnMut(&[u8])>( return Err(MathError::Unsupported); }, Operator::Subtract => if Primitive::Any == key || Primitive::Float == key { - writefn(parse_f64(lhs, value, |lhs, rhs| lhs - rhs)?.to_string().as_bytes()); + writefn( + parse_f64(lhs, value, |lhs, rhs| lhs - rhs)? + .to_string() + .as_bytes(), + ); } else if let Primitive::Integer = key { write_integer(parse_i64(lhs, value, |lhs, rhs| lhs - rhs)?, writefn); } else { return Err(MathError::Unsupported); }, Operator::Multiply => if Primitive::Any == key || Primitive::Float == key { - writefn(parse_f64(lhs, value, |lhs, rhs| lhs * rhs)?.to_string().as_bytes()); + writefn( + parse_f64(lhs, value, |lhs, rhs| lhs * rhs)? + .to_string() + .as_bytes(), + ); } else if let Primitive::Integer = key { write_integer(parse_i64(lhs, value, |lhs, rhs| lhs * rhs)?, writefn); } else { return Err(MathError::Unsupported); }, Operator::Exponent => if Primitive::Any == key || Primitive::Float == key { - writefn(parse_f64(lhs, value, |lhs, rhs| lhs.powf(rhs))?.to_string().as_bytes()); + writefn( + parse_f64(lhs, value, |lhs, rhs| lhs.powf(rhs))? + .to_string() + .as_bytes(), + ); } else if let Primitive::Integer = key { - write_integer(parse_i64(lhs, value, |lhs, rhs| lhs.pow(rhs as u32))?, writefn); + write_integer( + parse_i64(lhs, value, |lhs, rhs| lhs.pow(rhs as u32))?, + writefn, + ); } else { return Err(MathError::Unsupported); }, diff --git a/src/shell/binary/designators.rs b/src/shell/binary/designators.rs index 20141ed4..6bfc468a 100644 --- a/src/shell/binary/designators.rs +++ b/src/shell/binary/designators.rs @@ -18,13 +18,16 @@ enum Token<'a> { } struct DesignatorSearcher<'a> { - data: &'a [u8], + data: &'a [u8], flags: Flags, } impl<'a> DesignatorSearcher<'a> { fn new(data: &'a [u8]) -> DesignatorSearcher { - DesignatorSearcher { data, flags: Flags::empty() } + DesignatorSearcher { + data, + flags: Flags::empty(), + } } fn grab_and_shorten(&mut self, id: usize) -> &'a str { @@ -101,7 +104,9 @@ pub(crate) fn expand_designators<'a>(shell: &Shell, cmd: &'a str) -> Cow<'a, str Cow::Borrowed(cmd) } -fn command<'a>(text: &'a str) -> &'a str { ArgumentSplitter::new(text).next().unwrap_or(text) } +fn command<'a>(text: &'a str) -> &'a str { + ArgumentSplitter::new(text).next().unwrap_or(text) +} fn args(text: &str) -> &str { let bytes = text.as_bytes(); @@ -118,6 +123,10 @@ fn args(text: &str) -> &str { .unwrap_or(text) } -fn first_arg<'a>(text: &'a str) -> &'a str { ArgumentSplitter::new(text).nth(1).unwrap_or(text) } +fn first_arg<'a>(text: &'a str) -> &'a str { + ArgumentSplitter::new(text).nth(1).unwrap_or(text) +} -fn last_arg<'a>(text: &'a str) -> &'a str { ArgumentSplitter::new(text).last().unwrap_or(text) } +fn last_arg<'a>(text: &'a str) -> &'a str { + ArgumentSplitter::new(text).last().unwrap_or(text) +} diff --git a/src/shell/binary/mod.rs b/src/shell/binary/mod.rs index 0978222e..d7c0a283 100644 --- a/src/shell/binary/mod.rs +++ b/src/shell/binary/mod.rs @@ -26,7 +26,8 @@ pub(crate) trait Binary { fn main(self); /// Parses and executes the arguments that were supplied to the shell. fn execute_arguments<A: Iterator<Item = String>>(&mut self, args: A); - /// Creates an interactive session that reads from a prompt provided by Liner. + /// Creates an interactive session that reads from a prompt provided by + /// Liner. fn execute_interactive(self); /// Ensures that read statements from a script are terminated. fn terminate_script_quotes<I: Iterator<Item = String>>(&mut self, lines: I) -> i32; @@ -48,11 +49,17 @@ pub(crate) trait Binary { } impl Binary for Shell { - fn prompt(&mut self) -> String { prompt(self) } + fn prompt(&mut self) -> String { + prompt(self) + } - fn prompt_fn(&mut self) -> Option<String> { prompt_fn(self) } + fn prompt_fn(&mut self) -> Option<String> { + prompt_fn(self) + } - fn readln(&mut self) -> Option<String> { readln(self) } + fn readln(&mut self) -> Option<String> { + readln(self) + } fn terminate_script_quotes<I: Iterator<Item = String>>(&mut self, lines: I) -> i32 { terminate_script_quotes(self, lines) @@ -106,7 +113,11 @@ impl Binary for Shell { } Err(ref err) if err.kind() == ErrorKind::NotFound => { let history_filename = self.get_var_or_empty("HISTFILE"); - eprintln!("ion: failed to find history file {}: {}", history_filename, err); + eprintln!( + "ion: failed to find history file {}: {}", + history_filename, + err + ); } Err(err) => { eprintln!("ion: failed to load history: {}", err); @@ -118,7 +129,8 @@ impl Binary for Shell { self.evaluate_init_file(); - self.variables.set_array("args", iter::once(env::args().next().unwrap()).collect()); + self.variables + .set_array("args", iter::once(env::args().next().unwrap()).collect()); loop { if let Some(command) = self.readln() { diff --git a/src/shell/binary/readln.rs b/src/shell/binary/readln.rs index ba45e8ed..dae0c5d8 100644 --- a/src/shell/binary/readln.rs +++ b/src/shell/binary/readln.rs @@ -97,8 +97,11 @@ pub(crate) fn readln(shell: &mut Shell) -> Option<String> { // completion list. if let Ok(current_dir) = env::current_dir() { if let Some(url) = current_dir.to_str() { - file_completers - .push(IonFileCompleter::new(Some(url), dirs_ptr, vars_ptr)); + file_completers.push(IonFileCompleter::new( + Some(url), + dirs_ptr, + vars_ptr, + )); } } @@ -141,7 +144,8 @@ fn complete_as_file(current_dir: PathBuf, filename: String, index: usize) -> boo let filename = filename.trim(); let mut file = current_dir.clone(); file.push(&filename); - // If the user explicitly requests a file through this syntax then complete as a file + // If the user explicitly requests a file through this syntax then complete as + // a file if filename.starts_with(".") { return true; } @@ -157,9 +161,9 @@ fn complete_as_file(current_dir: PathBuf, filename: String, index: usize) -> boo if file.exists() { return true; } - // If we have a partial file inside an existing directory, e.g. /foo/b when /foo/bar - // exists, then treat it as file as long as `foo` isn't the current directory, otherwise - // this would apply to any string `foo` + // If we have a partial file inside an existing directory, e.g. /foo/b when + // /foo/bar exists, then treat it as file as long as `foo` isn't the + // current directory, otherwise this would apply to any string `foo` if let Some(parent) = file.parent() { return parent.exists() && parent != current_dir; } @@ -170,19 +174,17 @@ fn complete_as_file(current_dir: PathBuf, filename: String, index: usize) -> boo /// prints prompt info lines and /// returns the last prompt line. fn handle_prompt(full_prompt: String) -> Result<String, String> { - if let Some(index) = full_prompt.rfind('\n') { - let (info, prompt) = full_prompt.split_at(index+1); + let (info, prompt) = full_prompt.split_at(index + 1); let stdout = io::stdout(); let mut handle = stdout.lock(); - if let Err(why) = - handle.write(info.as_bytes()) { + if let Err(why) = handle.write(info.as_bytes()) { return Err(format!("unable to print prompt info: {}", why)); } - return Ok(String::from(prompt)) + return Ok(String::from(prompt)); } else { - return Ok(full_prompt) + return Ok(full_prompt); } } diff --git a/src/shell/colors.rs b/src/shell/colors.rs index f15921cc..46ec0f09 100644 --- a/src/shell/colors.rs +++ b/src/shell/colors.rs @@ -69,7 +69,8 @@ enum Mode { } #[derive(Debug, PartialEq)] -/// Stores a reprensetation of text formatting data which can be used to get an ANSI color code. +/// Stores a reprensetation of text formatting data which can be used to get an +/// ANSI color code. pub(crate) struct Colors { foreground: Option<Mode>, background: Option<Mode>, @@ -81,10 +82,18 @@ impl Colors { /// transformation into ANSI code parameters, which may be obtained by calling the /// `into_string()` method on the newly-created `Colors` structure. pub(crate) fn collect(input: &str) -> Colors { - let mut colors = Colors { foreground: None, background: None, attributes: None }; + let mut colors = Colors { + foreground: None, + background: None, + attributes: None, + }; for variable in input.split(",") { if variable == "reset" { - return Colors { foreground: None, background: None, attributes: Some(vec!["0"]) }; + return Colors { + foreground: None, + background: None, + attributes: Some(vec!["0"]), + }; } else if let Some(attribute) = ATTRIBUTES.get(&variable) { colors.append_attribute(attribute); } else if let Some(color) = COLORS.get(&variable) { @@ -98,7 +107,8 @@ impl Colors { colors } - /// Attributes can be stacked, so this function serves to enable that stacking. + /// Attributes can be stacked, so this function serves to enable that + /// stacking. fn append_attribute(&mut self, attribute: &'static str) { let vec_exists = match self.attributes.as_mut() { Some(vec) => { @@ -238,8 +248,11 @@ mod test { #[test] fn set_multiple_color_attributes() { - let expected = - Colors { attributes: Some(vec!["1", "4", "5"]), background: None, foreground: None }; + let expected = Colors { + attributes: Some(vec!["1", "4", "5"]), + background: None, + foreground: None, + }; let actual = Colors::collect("bold,underlined,blink"); assert_eq!(actual, expected); assert_eq!(Some("\x1b[1;4;5m".to_owned()), actual.into_string()); @@ -266,7 +279,10 @@ mod test { }; let actual = Colors::collect("0x4b,0x4dbg"); assert_eq!(actual, expected); - assert_eq!(Some("\x1b[38;5;75;48;5;77m".to_owned()), actual.into_string()) + assert_eq!( + Some("\x1b[38;5;75;48;5;77m".to_owned()), + actual.into_string() + ) } #[test] @@ -278,7 +294,10 @@ mod test { }; let actual = Colors::collect("78bg,32"); assert_eq!(actual, expected); - assert_eq!(Some("\x1b[38;5;32;48;5;78m".to_owned()), actual.into_string()) + assert_eq!( + Some("\x1b[38;5;32;48;5;78m".to_owned()), + actual.into_string() + ) } #[test] @@ -290,7 +309,10 @@ mod test { }; let actual = Colors::collect("0x000,0xFFFbg"); assert_eq!(expected, actual); - assert_eq!(Some("\x1b[38;2;0;0;0;48;2;255;255;255m".to_owned()), actual.into_string()); + assert_eq!( + Some("\x1b[38;2;0;0;0;48;2;255;255;255m".to_owned()), + actual.into_string() + ); } #[test] diff --git a/src/shell/completer.rs b/src/shell/completer.rs index 92025968..8aa55d86 100644 --- a/src/shell/completer.rs +++ b/src/shell/completer.rs @@ -21,9 +21,9 @@ impl IonFileCompleter { vars: *const Variables, ) -> IonFileCompleter { IonFileCompleter { - inner: FilenameCompleter::new(path), + inner: FilenameCompleter::new(path), dir_stack: dir_stack, - vars: vars, + vars: vars, } } } @@ -43,8 +43,10 @@ impl Completer for IonFileCompleter { if start.starts_with('~') { // Dereferencing the raw pointers here should be entirely safe, theoretically, // because no changes will occur to either of the underlying references in the - // duration between creation of the completers and execution of their completions. - if let Some(expanded) = unsafe { (*self.vars).tilde_expansion(start, &*self.dir_stack) } + // duration between creation of the completers and execution of their + // completions. + if let Some(expanded) = + unsafe { (*self.vars).tilde_expansion(start, &*self.dir_stack) } { // Now we obtain completions for the `expanded` form of the `start` value. let completions = self.inner.completions(&expanded); @@ -54,8 +56,9 @@ impl Completer for IonFileCompleter { // of the tilde pattern and replace it with that pattern yet again. let mut completions = Vec::new(); - // We can do that by obtaining the index position where the tilde character ends. - // We don't search with `~` because we also want to handle other tilde variants. + // We can do that by obtaining the index position where the tilde character + // ends. We don't search with `~` because we also want to + // handle other tilde variants. let t_index = start.find('/').unwrap_or(1); // `tilde` is the tilde pattern, and `search` is the pattern that follows. let (tilde, search) = start.split_at(t_index as usize); @@ -90,7 +93,11 @@ impl Completer for IonFileCompleter { } } - self.inner.completions(&unescape(start)).iter().map(|x| escape(x.as_str())).collect() + self.inner + .completions(&unescape(start)) + .iter() + .map(|x| escape(x.as_str())) + .collect() } } @@ -102,23 +109,8 @@ fn escape(input: &str) -> String { let mut output = Vec::with_capacity(input.len()); for character in input.bytes() { match character { - b'(' - | b')' - | b'[' - | b']' - | b'&' - | b'$' - | b'@' - | b'{' - | b'}' - | b'<' - | b'>' - | b';' - | b'"' - | b'\'' - | b'#' - | b'^' - | b'*' => output.push(b'\\'), + b'(' | b')' | b'[' | b']' | b'&' | b'$' | b'@' | b'{' | b'}' | b'<' | b'>' | b';' + | b'"' | b'\'' | b'#' | b'^' | b'*' => output.push(b'\\'), _ => (), } output.push(character); @@ -146,23 +138,28 @@ fn unescape(input: &str) -> String { /// A completer that combines suggestions from multiple completers. #[derive(Clone, Eq, PartialEq)] pub(crate) struct MultiCompleter<A, B> - where A: Completer, - B: Completer +where + A: Completer, + B: Completer, { a: Vec<A>, b: B, } impl<A, B> MultiCompleter<A, B> - where A: Completer, - B: Completer +where + A: Completer, + B: Completer, { - pub(crate) fn new(a: Vec<A>, b: B) -> MultiCompleter<A, B> { MultiCompleter { a: a, b: b } } + pub(crate) fn new(a: Vec<A>, b: B) -> MultiCompleter<A, B> { + MultiCompleter { a: a, b: b } + } } impl<A, B> Completer for MultiCompleter<A, B> - where A: Completer, - B: Completer +where + A: Completer, + B: Completer, { fn completions(&self, start: &str) -> Vec<String> { let mut completions = self.b.completions(start); diff --git a/src/shell/directory_stack.rs b/src/shell/directory_stack.rs index 25684f2a..a20150a3 100644 --- a/src/shell/directory_stack.rs +++ b/src/shell/directory_stack.rs @@ -10,7 +10,8 @@ pub struct DirectoryStack { } impl DirectoryStack { - /// Create a new `DirectoryStack` containing the current working directory, if available. + /// Create a new `DirectoryStack` containing the current working directory, + /// if available. pub(crate) fn new() -> DirectoryStack { let mut dirs: VecDeque<PathBuf> = VecDeque::new(); match current_dir() { @@ -31,13 +32,17 @@ impl DirectoryStack { /// variable, /// else it will return a default value of 1000. fn get_size(variables: &Variables) -> usize { - variables.get_var_or_empty("DIRECTORY_STACK_SIZE").parse::<usize>().unwrap_or(1000) + variables + .get_var_or_empty("DIRECTORY_STACK_SIZE") + .parse::<usize>() + .unwrap_or(1000) } /// Attempts to set the current directory to the directory stack's previous directory, /// and then removes the front directory from the stack. pub(crate) fn popd<I: IntoIterator>(&mut self, args: I) -> Result<(), Cow<'static, str>> - where I::Item: AsRef<str> + where + I::Item: AsRef<str>, { let mut keep_front = false; // whether the -n option is present let mut count_from_front = true; // <=> input number is positive @@ -54,7 +59,10 @@ impl DirectoryStack { num = y; } None => { - return Err(Cow::Owned(format!("ion: popd: {}: invalid argument\n", arg))) + return Err(Cow::Owned(format!( + "ion: popd: {}: invalid argument\n", + arg + ))) } }; } @@ -68,9 +76,11 @@ impl DirectoryStack { let mut index: usize = if count_from_front { num } else { - (len - 1).checked_sub(num).ok_or_else( - || Cow::Owned(format!("ion: popd: negative directory stack index out of range\n")), - )? + (len - 1).checked_sub(num).ok_or_else(|| { + Cow::Owned(format!( + "ion: popd: negative directory stack index out of range\n" + )) + })? }; // apply -n @@ -85,9 +95,10 @@ impl DirectoryStack { // pop element if self.dirs.remove(index).is_none() { - return Err( - Cow::Owned(format!("ion: popd: {}: directory stack index out of range\n", index)), - ); + return Err(Cow::Owned(format!( + "ion: popd: {}: directory stack index out of range\n", + index + ))); } self.print_dirs(); @@ -99,7 +110,8 @@ impl DirectoryStack { args: I, variables: &Variables, ) -> Result<(), Cow<'static, str>> - where I::Item: AsRef<str> + where + I::Item: AsRef<str>, { enum Action { Switch, // <no arguments> @@ -162,7 +174,8 @@ impl DirectoryStack { args: I, variables: &Variables, ) -> Result<(), Cow<'static, str>> - where I::Item: AsRef<str> + where + I::Item: AsRef<str>, { match args.into_iter().nth(1) { Some(dir) => { @@ -178,12 +191,17 @@ impl DirectoryStack { } fn switch_to_home_directory(&mut self, variables: &Variables) -> Result<(), Cow<'static, str>> { - home_dir().map_or(Err(Cow::Borrowed("ion: failed to get home directory")), |home| { - home.to_str().map_or( - Err(Cow::Borrowed("ion: failed to convert home directory to str")), - |home| self.change_and_push_dir(home, variables), - ) - }) + home_dir().map_or( + Err(Cow::Borrowed("ion: failed to get home directory")), + |home| { + home.to_str().map_or( + Err(Cow::Borrowed( + "ion: failed to convert home directory to str", + )), + |home| self.change_and_push_dir(home, variables), + ) + }, + ) } fn switch_to_previous_directory( @@ -219,9 +237,11 @@ impl DirectoryStack { self.push_dir(cur_dir, variables); Ok(()) } - (Err(err), _) => { - Err(Cow::Owned(format!("ion: failed to set current dir to {}: {}\n", dir, err))) - } + (Err(err), _) => Err(Cow::Owned(format!( + "ion: failed to set current dir to {}: {}\n", + dir, + err + ))), (..) => Err(Cow::Borrowed( "ion: change_and_push_dir(): error occurred that should never happen\n", )), // This should not happen @@ -240,7 +260,8 @@ impl DirectoryStack { } pub(crate) fn dirs<I: IntoIterator>(&mut self, args: I) -> i32 - where I::Item: AsRef<str> + where + I::Item: AsRef<str>, { const CLEAR: u8 = 1; // -c const ABS_PATHNAMES: u8 = 2; // -l @@ -308,17 +329,18 @@ impl DirectoryStack { SUCCESS } - pub(crate) fn dir_from_top(&self, num: usize) -> Option<&PathBuf> { self.dirs.get(num) } + pub(crate) fn dir_from_top(&self, num: usize) -> Option<&PathBuf> { + self.dirs.get(num) + } pub(crate) fn dir_from_bottom(&self, num: usize) -> Option<&PathBuf> { self.dirs.iter().rev().nth(num) } fn print_dirs(&self) { - let dir = - self.dirs.iter().fold(String::new(), |acc, dir| { - acc + " " + dir.to_str().unwrap_or("ion: no directory found") - }); + let dir = self.dirs.iter().fold(String::new(), |acc, dir| { + acc + " " + dir.to_str().unwrap_or("ion: no directory found") + }); println!("{}", dir.trim_left()); } @@ -328,9 +350,13 @@ impl DirectoryStack { index: usize, caller: &str, ) -> Result<(), Cow<'static, str>> { - let dir = self.dirs.iter().nth(index).ok_or_else( - || Cow::Owned(format!("ion: {}: {}: directory stack out of range\n", caller, index)), - )?; + let dir = self.dirs.iter().nth(index).ok_or_else(|| { + Cow::Owned(format!( + "ion: {}: {}: directory stack out of range\n", + caller, + index + )) + })?; set_current_dir(dir) .map_err(|_| Cow::Owned(format!("ion: {}: Failed setting current dir\n", caller))) @@ -363,5 +389,10 @@ fn parse_numeric_arg(arg: &str) -> Option<(bool, usize)> { // converts pbuf to an absolute path if possible fn try_abs_path(pbuf: &PathBuf) -> Cow<str> { - Cow::Owned(pbuf.canonicalize().unwrap_or_else(|_| pbuf.clone()).to_string_lossy().to_string()) + Cow::Owned( + pbuf.canonicalize() + .unwrap_or_else(|_| pbuf.clone()) + .to_string_lossy() + .to_string(), + ) } diff --git a/src/shell/flow.rs b/src/shell/flow.rs index 611bd66f..301b458f 100644 --- a/src/shell/flow.rs +++ b/src/shell/flow.rs @@ -1,6 +1,7 @@ use super::Shell; use super::flags::*; -use super::flow_control::{collect_cases, collect_if, collect_loops, Case, ElseIf, Function, Statement}; +use super::flow_control::{collect_cases, collect_if, collect_loops, Case, ElseIf, Function, + Statement}; use super::job_control::JobControl; use super::status::*; use parser::{expand_string, parse_and_validate, ForExpression, StatementSplitter}; @@ -30,12 +31,15 @@ pub(crate) trait FlowLogic { iterator: &mut I, statement: Statement, ) -> Result<(), &'static str> - where I: Iterator<Item = Statement>; + where + I: Iterator<Item = Statement>; - /// Executes all of the statements within a while block until a certain condition is met. + /// Executes all of the statements within a while block until a certain + /// condition is met. fn execute_while(&mut self, expression: Pipeline, statements: Vec<Statement>) -> Condition; - /// Executes all of the statements within a for block for each value specified in the range. + /// Executes all of the statements within a for block for each value + /// specified in the range. fn execute_for( &mut self, variable: &str, @@ -43,7 +47,8 @@ pub(crate) trait FlowLogic { statements: Vec<Statement>, ) -> Condition; - /// Conditionally executes branches of statements according to evaluated expressions + /// Conditionally executes branches of statements according to evaluated + /// expressions fn execute_if( &mut self, expression: Pipeline, @@ -57,9 +62,11 @@ pub(crate) trait FlowLogic { /// Executes a single statement fn execute_statement<I>(&mut self, iterator: &mut I, statement: Statement) -> Condition - where I: Iterator<Item = Statement>; + where + I: Iterator<Item = Statement>; - /// Expand an expression and run a branch based on the value of the expanded expression + /// Expand an expression and run a branch based on the value of the + /// expanded expression fn execute_match(&mut self, expression: String, cases: Vec<Case>) -> Condition; } @@ -68,8 +75,9 @@ impl FlowLogic for Shell { self.break_flow = false; let mut iterator = StatementSplitter::new(command_string).map(parse_and_validate); - // If the value is set to `0`, this means that we don't need to append to an existing - // partial statement block in memory, but can read and execute new statements. + // If the value is set to `0`, this means that we don't need to append to an + // existing partial statement block in memory, but can read and execute + // new statements. if self.flow_control.level == 0 { while let Some(statement) = iterator.next() { // Executes all statements that it can, and stores the last remaining partial @@ -92,9 +100,15 @@ impl FlowLogic for Shell { current_if_mode: &mut u8, ) { match current_statement { - &mut Statement::While { ref mut statements, .. } - | &mut Statement::For { ref mut statements, .. } - | &mut Statement::Function { ref mut statements, .. } => { + &mut Statement::While { + ref mut statements, .. + } + | &mut Statement::For { + ref mut statements, .. + } + | &mut Statement::Function { + ref mut statements, .. + } => { collect_loops(&mut iterator, statements, level); } &mut Statement::If { @@ -166,25 +180,42 @@ impl FlowLogic for Shell { Statement::Export(action) => { shell.previous_status = shell.export(action); } - Statement::While { expression, statements } => { + Statement::While { + expression, + statements, + } => { if let Condition::SigInt = shell.execute_while(expression, statements) { return Condition::SigInt; } } - Statement::For { variable, values, statements } => { + Statement::For { + variable, + values, + statements, + } => { if let Condition::SigInt = shell.execute_for(&variable, &values, statements) { return Condition::SigInt; } } - Statement::Function { name, args, statements, description } => { + Statement::Function { + name, + args, + statements, + description, + } => { shell.functions.insert( name.clone(), Function::new(description, name, args, statements), ); } - Statement::If { expression, success, else_if, failure } => { + Statement::If { + expression, + success, + else_if, + failure, + } => { shell.execute_if(expression, success, else_if, failure); } Statement::Match { expression, cases } => { @@ -239,10 +270,10 @@ impl FlowLogic for Shell { } fn execute_match(&mut self, expression: String, cases: Vec<Case>) -> Condition { - // Logic for determining if the LHS of a match-case construct (the value we are matching - // against) matches the RHS of a match-case construct (a value in a case statement). For - // example, checking to see if the value "foo" matches the pattern "bar" would be invoked - // like so : + // Logic for determining if the LHS of a match-case construct (the value we are + // matching against) matches the RHS of a match-case construct (a value + // in a case statement). For example, checking to see if the value + // "foo" matches the pattern "bar" would be invoked like so : // ```ignore // matches("foo", "bar") // ``` @@ -352,7 +383,8 @@ impl FlowLogic for Shell { } fn execute_statement<I>(&mut self, mut iterator: &mut I, statement: Statement) -> Condition - where I: Iterator<Item = Statement> + where + I: Iterator<Item = Statement>, { match statement { Statement::Error(number) => self.previous_status = number, @@ -362,21 +394,33 @@ impl FlowLogic for Shell { Statement::Export(action) => { self.previous_status = self.export(action); } - Statement::While { expression, mut statements } => { + Statement::While { + expression, + mut statements, + } => { self.flow_control.level += 1; collect_loops(&mut iterator, &mut statements, &mut self.flow_control.level); if let Condition::SigInt = self.execute_while(expression, statements) { return Condition::SigInt; } } - Statement::For { variable, values, mut statements } => { + Statement::For { + variable, + values, + mut statements, + } => { self.flow_control.level += 1; collect_loops(&mut iterator, &mut statements, &mut self.flow_control.level); if let Condition::SigInt = self.execute_for(&variable, &values, statements) { return Condition::SigInt; } } - Statement::If { expression, mut success, mut else_if, mut failure } => { + Statement::If { + expression, + mut success, + mut else_if, + mut failure, + } => { self.flow_control.level += 1; if let Err(why) = collect_if( &mut iterator, @@ -401,11 +445,18 @@ impl FlowLogic for Shell { Condition::SigInt => return Condition::SigInt, } } - Statement::Function { name, args, mut statements, description } => { + Statement::Function { + name, + args, + mut statements, + description, + } => { self.flow_control.level += 1; collect_loops(&mut iterator, &mut statements, &mut self.flow_control.level); - self.functions - .insert(name.clone(), Function::new(description, name, args, statements)); + self.functions.insert( + name.clone(), + Function::new(description, name, args, statements), + ); } Statement::Pipeline(mut pipeline) => { self.run_pipeline(&mut pipeline); @@ -446,7 +497,10 @@ impl FlowLogic for Shell { } Statement::Break => return Condition::Break, Statement::Continue => return Condition::Continue, - Statement::Match { expression, mut cases } => { + Statement::Match { + expression, + mut cases, + } => { self.flow_control.level += 1; if let Err(why) = collect_cases(&mut iterator, &mut cases, &mut self.flow_control.level) @@ -557,7 +611,9 @@ impl FlowLogic for Shell { failure: Vec<Statement>, ) -> Condition { let first_condition = iter::once((expression, success)); - let else_conditions = else_if.into_iter().map(|cond| (cond.expression, cond.success)); + let else_conditions = else_if + .into_iter() + .map(|cond| (cond.expression, cond.success)); for (mut condition, mut statements) in first_condition.chain(else_conditions) { if self.run_pipeline(&mut condition) == Some(SUCCESS) { @@ -573,7 +629,8 @@ impl FlowLogic for Shell { iterator: &mut I, statement: Statement, ) -> Result<(), &'static str> - where I: Iterator<Item = Statement> + where + I: Iterator<Item = Statement>, { match statement { Statement::Error(number) => self.previous_status = number, @@ -586,7 +643,10 @@ impl FlowLogic for Shell { } // Collect the statements for the while loop, and if the loop is complete, // execute the while loop with the provided expression. - Statement::While { expression, mut statements } => { + Statement::While { + expression, + mut statements, + } => { self.flow_control.level += 1; // Collect all of the statements contained within the while block. @@ -597,13 +657,19 @@ impl FlowLogic for Shell { self.execute_while(expression, statements); } else { // Store the partial `Statement::While` to memory - self.flow_control.current_statement = - Statement::While { expression: expression, statements: statements } + self.flow_control.current_statement = Statement::While { + expression: expression, + statements: statements, + } } } // Collect the statements for the for loop, and if the loop is complete, // execute the for loop with the provided expression. - Statement::For { variable, values, mut statements } => { + Statement::For { + variable, + values, + mut statements, + } => { self.flow_control.level += 1; // Collect all of the statements contained within the for block. @@ -615,15 +681,20 @@ impl FlowLogic for Shell { } else { // Store the partial `Statement::For` to memory self.flow_control.current_statement = Statement::For { - variable: variable, - values: values, + variable: variable, + values: values, statements: statements, } } } // Collect the statements needed for the `success`, `else_if`, and `failure` // conditions; then execute the if statement if it is complete. - Statement::If { expression, mut success, mut else_if, mut failure } => { + Statement::If { + expression, + mut success, + mut else_if, + mut failure, + } => { self.flow_control.level += 1; // Collect all of the success and failure statements within the if condition. @@ -646,15 +717,20 @@ impl FlowLogic for Shell { self.flow_control.current_if_mode = mode; self.flow_control.current_statement = Statement::If { expression: expression, - success: success, - else_if: else_if, - failure: failure, + success: success, + else_if: else_if, + failure: failure, }; } } // Collect the statements needed by the function and add the function to the // list of functions if it is complete. - Statement::Function { name, args, mut statements, description } => { + Statement::Function { + name, + args, + mut statements, + description, + } => { self.flow_control.level += 1; // The same logic that applies to loops, also applies here. @@ -662,15 +738,17 @@ impl FlowLogic for Shell { if self.flow_control.level == 0 { // All blocks were read, thus we can add it to the list - self.functions - .insert(name.clone(), Function::new(description, name, args, statements)); + self.functions.insert( + name.clone(), + Function::new(description, name, args, statements), + ); } else { // Store the partial function declaration in memory. self.flow_control.current_statement = Statement::Function { description: description, - name: name, - args: args, - statements: statements, + name: name, + args: args, + statements: statements, } } } @@ -732,7 +810,10 @@ impl FlowLogic for Shell { let _ = writeln!(stderr, "ion: syntax error: no block to end"); } // Collect all cases that are being used by a match construct - Statement::Match { expression, mut cases } => { + Statement::Match { + expression, + mut cases, + } => { self.flow_control.level += 1; if let Err(why) = collect_cases(iterator, &mut cases, &mut self.flow_control.level) { diff --git a/src/shell/flow_control.rs b/src/shell/flow_control.rs index e5eeadab..663774d1 100644 --- a/src/shell/flow_control.rs +++ b/src/shell/flow_control.rs @@ -10,7 +10,7 @@ use types::Identifier; #[derive(Debug, PartialEq, Clone)] pub(crate) struct ElseIf { pub expression: Pipeline, - pub success: Vec<Statement>, + pub success: Vec<Statement>, } /// Represents a single branch in a match statement. For example, in the expression @@ -35,10 +35,10 @@ pub(crate) struct ElseIf { /// ``` #[derive(Debug, PartialEq, Clone)] pub(crate) struct Case { - pub value: Option<String>, - pub binding: Option<String>, + pub value: Option<String>, + pub binding: Option<String>, pub conditional: Option<String>, - pub statements: Vec<Statement>, + pub statements: Vec<Statement>, } #[derive(Debug, PartialEq, Clone)] @@ -62,20 +62,20 @@ pub(crate) enum Statement { Export(ExportAction), If { expression: Pipeline, - success: Vec<Statement>, - else_if: Vec<ElseIf>, - failure: Vec<Statement>, + success: Vec<Statement>, + else_if: Vec<ElseIf>, + failure: Vec<Statement>, }, ElseIf(ElseIf), Function { - name: Identifier, + name: Identifier, description: Option<String>, - args: Vec<KeyBuf>, - statements: Vec<Statement>, + args: Vec<KeyBuf>, + statements: Vec<Statement>, }, For { - variable: Identifier, - values: Vec<String>, + variable: Identifier, + values: Vec<String>, statements: Vec<Statement>, }, While { @@ -84,7 +84,7 @@ pub(crate) enum Statement { }, Match { expression: String, - cases: Vec<Case>, + cases: Vec<Case>, }, Else, End, @@ -121,17 +121,17 @@ impl Statement { } pub(crate) struct FlowControl { - pub level: usize, + pub level: usize, pub current_statement: Statement, - pub current_if_mode: u8, // { 0 = SUCCESS; 1 = FAILURE } + pub current_if_mode: u8, // { 0 = SUCCESS; 1 = FAILURE } } impl Default for FlowControl { fn default() -> FlowControl { FlowControl { - level: 0, + level: 0, current_statement: Statement::Default, - current_if_mode: 0, + current_if_mode: 0, } } } @@ -139,9 +139,9 @@ impl Default for FlowControl { #[derive(Clone)] pub struct Function { description: Option<String>, - name: Identifier, - args: Vec<KeyBuf>, - statements: Vec<Statement>, + name: Identifier, + args: Vec<KeyBuf>, + statements: Vec<Statement>, } #[derive(Debug, PartialEq, Clone)] @@ -167,10 +167,17 @@ impl Function { args: Vec<KeyBuf>, statements: Vec<Statement>, ) -> Function { - Function { description, name, args, statements } + Function { + description, + name, + args, + statements, + } } - pub(crate) fn get_description<'a>(&'a self) -> Option<&'a String> { self.description.as_ref() } + pub(crate) fn get_description<'a>(&'a self) -> Option<&'a String> { + self.description.as_ref() + } pub(crate) fn execute(self, shell: &mut Shell, args: &[&str]) -> Result<(), FunctionError> { if args.len() - 1 != self.args.len() { @@ -187,7 +194,10 @@ impl Function { let value = match value_check(shell, value, type_.kind) { Ok(value) => value, Err(_) => { - return Err(FunctionError::InvalidArgumentType(type_.kind, (*value).into())) + return Err(FunctionError::InvalidArgumentType( + type_.kind, + (*value).into(), + )) } }; @@ -233,7 +243,8 @@ pub(crate) fn collect_cases<I>( cases: &mut Vec<Case>, level: &mut usize, ) -> Result<(), String> - where I: Iterator<Item = Statement> +where + I: Iterator<Item = Statement>, { macro_rules! add_to_case { ($statement:expr) => { @@ -336,7 +347,8 @@ pub(crate) fn collect_if<I>( level: &mut usize, mut current_block: u8, ) -> Result<u8, &'static str> - where I: Iterator<Item = Statement> +where + I: Iterator<Item = Statement>, { #[allow(while_let_on_iterator)] while let Some(statement) = iterator.next() { diff --git a/src/shell/fork.rs b/src/shell/fork.rs index 761eb8ed..86cac8a3 100644 --- a/src/shell/fork.rs +++ b/src/shell/fork.rs @@ -24,7 +24,7 @@ pub enum Capture { /// /// Using this structure directly is equivalent to using `Shell`'s fork method. pub struct Fork<'a> { - shell: &'a Shell, + shell: &'a Shell, capture: Capture, } @@ -34,14 +34,16 @@ pub struct Fork<'a> { /// in the future, once there's a better means of obtaining the exit status without having to /// wait on the PID. pub struct IonResult { - pub pid: u32, + pub pid: u32, pub stdout: Option<File>, pub stderr: Option<File>, } impl<'a> Fork<'a> { /// Creates a new `Fork` state from an existing shell. - pub fn new(shell: &'a Shell, capture: Capture) -> Fork<'a> { Fork { shell, capture } } + pub fn new(shell: &'a Shell, capture: Capture) -> Fork<'a> { + Fork { shell, capture } + } /// Executes a closure within the child of the fork, and returning an `IonResult` in a /// non-blocking fashion. diff --git a/src/shell/history.rs b/src/shell/history.rs index 265ce0e5..bbdb0a10 100644 --- a/src/shell/history.rs +++ b/src/shell/history.rs @@ -27,13 +27,17 @@ pub(crate) struct IgnoreSetting { impl IgnoreSetting { pub(crate) fn default() -> IgnoreSetting { - IgnoreSetting { flags: IgnoreFlags::empty(), regexes: None } + IgnoreSetting { + flags: IgnoreFlags::empty(), + regexes: None, + } } } /// Contains all history-related functionality for the `Shell`. pub(crate) trait ShellHistory { - /// Prints the commands contained within the history buffers to standard output. + /// Prints the commands contained within the history buffers to standard + /// output. fn print_history(&self, _arguments: &[&str]) -> i32; /// Sets the history size for the shell context equal to the HISTORY_SIZE shell variable if @@ -54,7 +58,8 @@ pub(crate) trait ShellHistory { /// immediately after `on_command()` fn save_command_in_history(&mut self, command: &str); - /// Updates the history ignore patterns. Call this whenever HISTORY_IGNORE is changed. + /// Updates the history ignore patterns. Call this whenever HISTORY_IGNORE + /// is changed. fn update_ignore_patterns(&mut self, patterns: &Array); } @@ -83,7 +88,10 @@ impl ShellHistory for Shell { fn set_context_history_from_vars(&mut self) { let context = self.context.as_mut().unwrap(); let variables = &self.variables; - let max_history_size = variables.get_var_or_empty("HISTORY_SIZE").parse().unwrap_or(1000); + let max_history_size = variables + .get_var_or_empty("HISTORY_SIZE") + .parse() + .unwrap_or(1000); context.history.set_max_size(max_history_size); @@ -91,8 +99,10 @@ impl ShellHistory for Shell { let file_name = variables.get_var("HISTFILE"); context.history.set_file_name(file_name.map(|f| f.into())); - let max_histfile_size = - variables.get_var_or_empty("HISTFILE_SIZE").parse().unwrap_or(1000); + let max_histfile_size = variables + .get_var_or_empty("HISTFILE_SIZE") + .parse() + .unwrap_or(1000); context.history.set_max_file_size(max_histfile_size); } else { context.history.set_file_name(None); @@ -133,7 +143,11 @@ impl ShellHistory for Shell { } self.ignore_setting.flags = flags; - self.ignore_setting.regexes = if regexes.len() > 0 { Some(regexes) } else { None } + self.ignore_setting.regexes = if regexes.len() > 0 { + Some(regexes) + } else { + None + } } } @@ -143,14 +157,14 @@ impl ShellHistoryPrivate for Shell { let ignore = &self.ignore_setting.flags; let regexes = &self.ignore_setting.regexes; - // without the second check the command which sets the local variable would also be - // ignored. However, this behavior might not be wanted. + // without the second check the command which sets the local variable would + // also be ignored. However, this behavior might not be wanted. if ignore.contains(IgnoreFlags::ALL) && !command.contains("HISTORY_IGNORE") { return false; } - // Here we allow to also ignore the setting of the local variable because we assume - // the user entered the leading whitespace on purpose. + // Here we allow to also ignore the setting of the local variable because we + // assume the user entered the leading whitespace on purpose. if ignore.contains(IgnoreFlags::WHITESPACE) { if command.chars().next().map_or(false, |b| b.is_whitespace()) { return false; @@ -173,7 +187,8 @@ impl ShellHistoryPrivate for Shell { } } - // default to true, as it's more likely that we want to save a command in history + // default to true, as it's more likely that we want to save a command in + // history true } } diff --git a/src/shell/job.rs b/src/shell/job.rs index 6a9e0d52..6b998418 100644 --- a/src/shell/job.rs +++ b/src/shell/job.rs @@ -21,8 +21,8 @@ pub(crate) enum JobKind { #[derive(Clone)] pub(crate) struct Job { pub command: Identifier, - pub args: Array, - pub kind: JobKind, + pub args: Array, + pub kind: JobKind, pub builtin: Option<BuiltinFunction>, } @@ -30,7 +30,12 @@ impl Job { pub(crate) fn new(args: Array, kind: JobKind) -> Self { let command = SmallString::from_str(&args[0]); let builtin = BUILTINS.get(command.as_ref()).map(|b| b.main); - Job { command, args, kind, builtin } + Job { + command, + args, + kind, + builtin, + } } /// Takes the current job's arguments and expands them, one argument at a @@ -105,8 +110,8 @@ pub(crate) enum RefinedJob { /// Represents redirection into stdin from more than one source Cat { sources: Vec<File>, - stdin: Option<File>, - stdout: Option<File>, + stdin: Option<File>, + stdout: Option<File>, }, Tee { /// 0 for stdout, 1 for stderr @@ -134,7 +139,8 @@ impl TeeItem { use std::io::{self, Read, Write}; use std::os::unix::io::*; fn write_out<R>(source: &mut R, sinks: &mut [File]) -> io::Result<()> - where R: Read + where + R: Read, { let mut buf = [0; 4096]; loop { @@ -198,19 +204,40 @@ macro_rules! set_field { impl RefinedJob { pub(crate) fn builtin(main: BuiltinFunction, args: Array) -> Self { - RefinedJob::Builtin { main, args, stdin: None, stdout: None, stderr: None } + RefinedJob::Builtin { + main, + args, + stdin: None, + stdout: None, + stderr: None, + } } pub(crate) fn function(name: Identifier, args: Array) -> Self { - RefinedJob::Function { name, args, stdin: None, stdout: None, stderr: None } + RefinedJob::Function { + name, + args, + stdin: None, + stdout: None, + stderr: None, + } } pub(crate) fn cat(sources: Vec<File>) -> Self { - RefinedJob::Cat { sources, stdin: None, stdout: None } + RefinedJob::Cat { + sources, + stdin: None, + stdout: None, + } } pub(crate) fn tee(tee_out: Option<TeeItem>, tee_err: Option<TeeItem>) -> Self { - RefinedJob::Tee { items: (tee_out, tee_err), stdin: None, stdout: None, stderr: None } + RefinedJob::Tee { + items: (tee_out, tee_err), + stdin: None, + stdout: None, + stderr: None, + } } pub(crate) fn stdin(&mut self, file: File) { @@ -237,9 +264,11 @@ impl RefinedJob { /// or builtin name pub(crate) fn short(&self) -> String { match *self { - RefinedJob::External(ref cmd) => { - format!("{:?}", cmd).split('"').nth(1).unwrap_or("").to_string() - } + RefinedJob::External(ref cmd) => format!("{:?}", cmd) + .split('"') + .nth(1) + .unwrap_or("") + .to_string(), RefinedJob::Builtin { .. } => String::from("Shell Builtin"), RefinedJob::Function { ref name, .. } => name.to_string(), // TODO: Print for real diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 05fea73e..88e36656 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -54,14 +54,10 @@ use xdg::BaseDirectories; #[allow(dead_code)] #[derive(Debug, Fail)] pub enum IonError { - #[fail(display = "failed to fork: {}", why)] - Fork { why: io::Error }, - #[fail(display = "element does not exist")] - DoesNotExist, - #[fail(display = "input was not terminated")] - Unterminated, - #[fail(display = "function error: {}", why)] - Function { why: FunctionError }, + #[fail(display = "failed to fork: {}", why)] Fork { why: io::Error }, + #[fail(display = "element does not exist")] DoesNotExist, + #[fail(display = "input was not terminated")] Unterminated, + #[fail(display = "function error: {}", why)] Function { why: FunctionError }, } /// The shell structure is a megastructure that manages all of the state of the shell throughout @@ -69,7 +65,8 @@ pub enum IonError { /// program. It is initialized at the beginning of the program, and lives until the end of the /// program. pub struct Shell { - /// Contains a list of built-in commands that were created when the program started. + /// Contains a list of built-in commands that were created when the program + /// started. pub(crate) builtins: &'static BuiltinMap, /// Contains the history, completions, and manages writes to the history file. /// Note that the context is only available in an interactive session. @@ -82,20 +79,23 @@ pub struct Shell { pub(crate) directory_stack: DirectoryStack, /// Contains all of the user-defined functions that have been created. pub(crate) functions: FnvHashMap<Identifier, Function>, - /// When a command is executed, the final result of that command is stored here. + /// When a command is executed, the final result of that command is stored + /// here. pub previous_status: i32, /// The job ID of the previous command sent to the background. pub(crate) previous_job: u32, /// Contains all the boolean flags that control shell behavior. pub flags: u8, - /// A temporary field for storing foreground PIDs used by the pipeline execution. + /// A temporary field for storing foreground PIDs used by the pipeline + /// execution. foreground: Vec<u32>, /// Contains information on all of the active background processes that are being managed /// by the shell. pub(crate) background: Arc<Mutex<Vec<BackgroundProcess>>>, /// If set, denotes that this shell is running as a background job. pub(crate) is_background_shell: bool, - /// Set when a signal is received, this will tell the flow control logic to abort. + /// Set when a signal is received, this will tell the flow control logic to + /// abort. pub(crate) break_flow: bool, // Useful for disabling the execution of the `tcsetpgrp` call. pub(crate) is_library: bool, @@ -112,22 +112,22 @@ impl<'a> Shell { /// Panics if DirectoryStack construction fails pub(crate) fn new_bin() -> Shell { Shell { - builtins: BUILTINS, - context: None, - variables: Variables::default(), - flow_control: FlowControl::default(), - directory_stack: DirectoryStack::new(), - functions: FnvHashMap::default(), - previous_job: !0, - previous_status: 0, - flags: 0, - foreground: Vec::new(), - background: Arc::new(Mutex::new(Vec::new())), + builtins: BUILTINS, + context: None, + variables: Variables::default(), + flow_control: FlowControl::default(), + directory_stack: DirectoryStack::new(), + functions: FnvHashMap::default(), + previous_job: !0, + previous_status: 0, + flags: 0, + foreground: Vec::new(), + background: Arc::new(Mutex::new(Vec::new())), is_background_shell: false, - is_library: false, - break_flow: false, - foreground_signals: Arc::new(ForegroundSignals::new()), - ignore_setting: IgnoreSetting::default(), + is_library: false, + break_flow: false, + foreground_signals: Arc::new(ForegroundSignals::new()), + ignore_setting: IgnoreSetting::default(), } } @@ -135,22 +135,22 @@ impl<'a> Shell { /// Creates a new shell within memory. pub fn new() -> Shell { Shell { - builtins: BUILTINS, - context: None, - variables: Variables::default(), - flow_control: FlowControl::default(), - directory_stack: DirectoryStack::new(), - functions: FnvHashMap::default(), - previous_job: !0, - previous_status: 0, - flags: 0, - foreground: Vec::new(), - background: Arc::new(Mutex::new(Vec::new())), + builtins: BUILTINS, + context: None, + variables: Variables::default(), + flow_control: FlowControl::default(), + directory_stack: DirectoryStack::new(), + functions: FnvHashMap::default(), + previous_job: !0, + previous_status: 0, + flags: 0, + foreground: Vec::new(), + background: Arc::new(Mutex::new(Vec::new())), is_background_shell: false, - is_library: true, - break_flow: false, - foreground_signals: Arc::new(ForegroundSignals::new()), - ignore_setting: IgnoreSetting::default(), + is_library: true, + break_flow: false, + foreground_signals: Arc::new(ForegroundSignals::new()), + ignore_setting: IgnoreSetting::default(), } } @@ -176,8 +176,8 @@ impl<'a> Shell { /// the /// the current working directory. fn update_variables(&mut self) { - // Update the PWD (Present Working Directory) variable if the current working directory has - // been updated. + // Update the PWD (Present Working Directory) variable if the current working + // directory has been updated. env::current_dir().ok().map_or_else( || env::set_var("PWD", "?"), |path| { @@ -206,7 +206,7 @@ impl<'a> Shell { if let Err(err) = self.execute_script(&initrc) { eprintln!("ion: {}", err); } - }, + } None => { if let Err(err) = base_dirs.place_config_file("initrc") { eprintln!("ion: could not create initrc file: {}", err); @@ -295,9 +295,9 @@ impl<'a> Shell { Some(self.execute_pipeline(pipeline)) }; - // If `RECORD_SUMMARY` is set to "1" (True, Yes), then write a summary of the pipline - // just executed to the the file and context histories. At the moment, this means - // record how long it took. + // If `RECORD_SUMMARY` is set to "1" (True, Yes), then write a summary of the + // pipline just executed to the the file and context histories. At the + // moment, this means record how long it took. if let Some(context) = self.context.as_mut() { if "1" == self.variables.get_var_or_empty("RECORD_SUMMARY") { if let Ok(elapsed_time) = command_start_time.elapsed() { @@ -323,11 +323,16 @@ impl<'a> Shell { exit_status } - /// Sets a variable of `name` with the given `value` in the shell's variable map. - pub fn set_var(&mut self, name: &str, value: &str) { self.variables.set_var(name, value); } + /// Sets a variable of `name` with the given `value` in the shell's + /// variable map. + pub fn set_var(&mut self, name: &str, value: &str) { + self.variables.set_var(name, value); + } /// Gets a string variable, if it exists within the shell's variable map. - pub fn get_var(&self, name: &str) -> Option<String> { self.variables.get_var(name) } + pub fn get_var(&self, name: &str) -> Option<String> { + self.variables.get_var(name) + } /// Obtains a variable, returning an empty string if it does not exist. pub(crate) fn get_var_or_empty(&self, name: &str) -> String { @@ -348,7 +353,8 @@ impl<'a> Shell { /// not /// terminated, then an error will be returned. pub fn execute_command<CMD>(&mut self, command: CMD) -> Result<i32, IonError> - where CMD: Into<Terminator> + where + CMD: Into<Terminator>, { let mut terminator = command.into(); if terminator.is_terminated() { @@ -466,7 +472,8 @@ impl<'a> Expander for Shell { if quoted { self.get_var(variable) } else { - self.get_var(variable).map(|x| x.ascii_replace('\n', ' ').into()) + self.get_var(variable) + .map(|x| x.ascii_replace('\n', ' ').into()) } } diff --git a/src/shell/pipe_exec/command_not_found.rs b/src/shell/pipe_exec/command_not_found.rs index 55954949..888a39b9 100644 --- a/src/shell/pipe_exec/command_not_found.rs +++ b/src/shell/pipe_exec/command_not_found.rs @@ -5,7 +5,7 @@ use sys; pub(crate) fn command_not_found(shell: &mut Shell, command: &str) -> bool { let function = match shell.functions.get("COMMAND_NOT_FOUND") { Some(func) => func as *const Function, - None => return false + None => return false, }; if let Err(err) = shell.fork(Capture::None, |child| { diff --git a/src/shell/pipe_exec/foreground.rs b/src/shell/pipe_exec/foreground.rs index 222a1f03..d69bcd46 100644 --- a/src/shell/pipe_exec/foreground.rs +++ b/src/shell/pipe_exec/foreground.rs @@ -15,21 +15,23 @@ const ERRORED: u8 = 2; /// structure to notify a background thread that it needs to wait for and return /// the exit status back to the `fg` function. pub(crate) struct ForegroundSignals { - grab: AtomicU32, + grab: AtomicU32, status: AtomicU8, - reply: AtomicU8, + reply: AtomicU8, } impl ForegroundSignals { pub(crate) fn new() -> ForegroundSignals { ForegroundSignals { - grab: AtomicU32::new(0), + grab: AtomicU32::new(0), status: AtomicU8::new(0), - reply: AtomicU8::new(0), + reply: AtomicU8::new(0), } } - pub(crate) fn signal_to_grab(&self, pid: u32) { self.grab.store(pid, Ordering::Relaxed); } + pub(crate) fn signal_to_grab(&self, pid: u32) { + self.grab.store(pid, Ordering::Relaxed); + } pub(crate) fn reply_with(&self, status: i8) { self.grab.store(0, Ordering::Relaxed); @@ -48,11 +50,15 @@ impl ForegroundSignals { if reply & ERRORED != 0 { Some(BackgroundResult::Errored) } else if reply & REPLIED != 0 { - Some(BackgroundResult::Status(self.status.load(Ordering::Relaxed) as u8)) + Some(BackgroundResult::Status( + self.status.load(Ordering::Relaxed) as u8, + )) } else { None } } - pub(crate) fn was_grabbed(&self, pid: u32) -> bool { self.grab.load(Ordering::Relaxed) == pid } + pub(crate) fn was_grabbed(&self, pid: u32) -> bool { + self.grab.load(Ordering::Relaxed) == pid + } } diff --git a/src/shell/pipe_exec/fork.rs b/src/shell/pipe_exec/fork.rs index 47db5635..4ab8611c 100644 --- a/src/shell/pipe_exec/fork.rs +++ b/src/shell/pipe_exec/fork.rs @@ -1,7 +1,9 @@ use sys; /// Ensures that the forked child is given a unique process ID. -pub(crate) fn create_process_group(pgid: u32) { let _ = sys::setpgid(0, pgid); } +pub(crate) fn create_process_group(pgid: u32) { + let _ = sys::setpgid(0, pgid); +} use super::job_control::{JobControl, ProcessState}; use super::pipe; diff --git a/src/shell/pipe_exec/job_control.rs b/src/shell/pipe_exec/job_control.rs index b391a8ac..ebc03148 100644 --- a/src/shell/pipe_exec/job_control.rs +++ b/src/shell/pipe_exec/job_control.rs @@ -12,7 +12,8 @@ use sys; use sys::job_control as self_sys; pub(crate) use sys::job_control::watch_background; -/// When given a process ID, that process's group will be assigned as the foreground process group. +/// When given a process ID, that process's group will be assigned as the +/// foreground process group. pub(crate) fn set_foreground_as(pid: u32) { signals::block(); let _ = sys::tcsetpgrp(0, pid); @@ -38,8 +39,9 @@ pub(crate) trait JobControl { get_command: F, drop_command: D, ) -> i32 - where F: FnOnce() -> String, - D: FnMut(i32); + where + F: FnOnce() -> String, + D: FnMut(i32); fn send_to_background(&mut self, child: u32, state: ProcessState, command: String); } @@ -68,23 +70,26 @@ pub(crate) fn add_to_background( command: String, ) -> u32 { let mut processes = processes.lock().unwrap(); - match (*processes).iter().position(|x| x.state == ProcessState::Empty) { + match (*processes) + .iter() + .position(|x| x.state == ProcessState::Empty) + { Some(id) => { (*processes)[id] = BackgroundProcess { - pid: pid, + pid: pid, ignore_sighup: false, - state: state, - name: command, + state: state, + name: command, }; id as u32 } None => { let njobs = (*processes).len(); (*processes).push(BackgroundProcess { - pid: pid, + pid: pid, ignore_sighup: false, - state: state, - name: command, + state: state, + name: command, }); njobs as u32 } @@ -97,10 +102,10 @@ pub(crate) fn add_to_background( /// as the process ID, state that the process is in, and the command that the /// process is executing. pub struct BackgroundProcess { - pub pid: u32, + pub pid: u32, pub ignore_sighup: bool, - pub state: ProcessState, - pub name: String, + pub state: ProcessState, + pub name: String, } impl JobControl for Shell { @@ -114,9 +119,9 @@ impl JobControl for Shell { // Signal the background thread that is waiting on this process to stop waiting. self.foreground_signals.signal_to_grab(pid); let status = loop { - // When the background thread that is monitoring the task receives an exit/stop signal, - // the status of that process will be communicated back. To avoid consuming CPU cycles, - // we wait 25 ms between polls. + // When the background thread that is monitoring the task receives an exit/stop + // signal, the status of that process will be communicated back. To + // avoid consuming CPU cycles, we wait 25 ms between polls. match self.foreground_signals.was_processed() { Some(BackgroundResult::Status(stat)) => break stat as i32, Some(BackgroundResult::Errored) => break TERMINATED, @@ -158,8 +163,9 @@ impl JobControl for Shell { get_command: F, drop_command: D, ) -> i32 - where F: FnOnce() -> String, - D: FnMut(i32) + where + F: FnOnce() -> String, + D: FnMut(i32), { self_sys::watch_foreground(self, pid, last_pid, get_command, drop_command) } diff --git a/src/shell/pipe_exec/mod.rs b/src/shell/pipe_exec/mod.rs index 84d1c10c..27333e74 100644 --- a/src/shell/pipe_exec/mod.rs +++ b/src/shell/pipe_exec/mod.rs @@ -1,8 +1,9 @@ -//! The purpose of the pipeline execution module is to create commands from supplied pieplines, and -//! manage their execution thereof. That includes forking, executing commands, managing process -//! group -//! IDs, watching foreground and background tasks, sending foreground tasks to the background, -//! handling pipeline and conditional operators, and std{in,out,err} redirections. +//! The purpose of the pipeline execution module is to create commands from +//! supplied pieplines, and manage their execution thereof. That includes +//! forking, executing commands, managing process group +//! IDs, watching foreground and background tasks, sending foreground tasks to +//! the background, handling pipeline and conditional operators, and +//! std{in,out,err} redirections. mod command_not_found; pub mod foreground; @@ -43,8 +44,9 @@ pub unsafe fn stdin_of<T: AsRef<[u8]>>(input: T) -> Result<RawFd, Error> { // the entire string is written infile.write_all(input.as_ref())?; infile.flush()?; - // `infile` currently owns the writer end RawFd. If we just return the reader end - // and let `infile` go out of scope, it will be closed, sending EOF to the reader! + // `infile` currently owns the writer end RawFd. If we just return the reader + // end and let `infile` go out of scope, it will be closed, sending EOF to + // the reader! Ok(reader) } @@ -231,7 +233,10 @@ fn do_redirection(piped_commands: Vec<RefinedItem>) -> Option<Vec<(RefinedJob, J (0, _) => {} (1, JobKind::Pipe(_)) => { let sources = vec![get_infile!(inputs[0])?]; - new_commands.push((RefinedJob::cat(sources), JobKind::Pipe(RedirectFrom::Stdout))); + new_commands.push(( + RefinedJob::cat(sources), + JobKind::Pipe(RedirectFrom::Stdout), + )); } (1, _) => job.stdin(get_infile!(inputs[0])?), _ => { @@ -243,7 +248,10 @@ fn do_redirection(piped_commands: Vec<RefinedItem>) -> Option<Vec<(RefinedJob, J return None; }); } - new_commands.push((RefinedJob::cat(sources), JobKind::Pipe(RedirectFrom::Stdout))); + new_commands.push(( + RefinedJob::cat(sources), + JobKind::Pipe(RedirectFrom::Stdout), + )); } } prev_kind = kind; @@ -263,11 +271,21 @@ fn do_redirection(piped_commands: Vec<RefinedItem>) -> Option<Vec<(RefinedJob, J (true, false) => set_one_tee!(new_commands, outputs, job, kind, Stdout, Stderr), // tee both (true, true) => { - let mut tee_out = TeeItem { sinks: Vec::new(), source: None }; - let mut tee_err = TeeItem { sinks: Vec::new(), source: None }; + let mut tee_out = TeeItem { + sinks: Vec::new(), + source: None, + }; + let mut tee_err = TeeItem { + sinks: Vec::new(), + source: None, + }; for output in outputs { match if output.append { - OpenOptions::new().create(true).write(true).append(true).open(&output.file) + OpenOptions::new() + .create(true) + .write(true) + .append(true) + .open(&output.file) } else { File::create(&output.file) } { @@ -390,11 +408,12 @@ impl PipelineExecution for Shell { fn execute_pipeline(&mut self, pipeline: &mut Pipeline) -> i32 { // Remove any leftover foreground tasks from the last execution. self.foreground.clear(); - // If the supplied pipeline is a background, a string representing the command will be - // stored here. + // If the supplied pipeline is a background, a string representing the command + // will be stored here. let possible_background_name = gen_background_string(&pipeline, self.flags & PRINT_COMMS != 0); - // Generates commands for execution, differentiating between external and builtin commands. + // Generates commands for execution, differentiating between external and + // builtin commands. let piped_commands = match self.generate_commands(pipeline) { Ok(commands) => commands, Err(error) => return error, @@ -431,7 +450,11 @@ impl PipelineExecution for Shell { fn generate_commands(&self, pipeline: &mut Pipeline) -> Result<Vec<RefinedItem>, i32> { let mut results = Vec::new(); for item in pipeline.items.drain(..) { - let PipeItem { mut job, outputs, inputs } = item; + let PipeItem { + mut job, + outputs, + inputs, + } = item; let refined = { if is_implicit_cd(&job.args[0]) { RefinedJob::builtin( @@ -457,7 +480,11 @@ impl PipelineExecution for Shell { fn wait(&mut self, mut children: Vec<u32>, mut commands: Vec<RefinedJob>) -> i32 { // TODO: Find a way to only do this when absolutely necessary. - let as_string = commands.iter().map(RefinedJob::long).collect::<Vec<String>>().join(" | "); + let as_string = commands + .iter() + .map(RefinedJob::long) + .collect::<Vec<String>>() + .join(" | "); // Each process in the pipe has the same PGID, which is the first process's PID. let pgid = children[0]; @@ -506,24 +533,42 @@ impl PipelineExecution for Shell { COULD_NOT_EXEC }, }, - RefinedJob::Builtin { main, ref args, ref stdin, ref stdout, ref stderr } => { + RefinedJob::Builtin { + main, + ref args, + ref stdin, + ref stdout, + ref stderr, + } => { if let Ok((stdin_bk, stdout_bk, stderr_bk)) = duplicate_streams() { let args: Vec<&str> = args.iter().map(|x| x as &str).collect(); let code = self.exec_builtin(main, &args, stdout, stderr, stdin); redirect_streams(stdin_bk, stdout_bk, stderr_bk); return code; } - eprintln!("ion: failed to `dup` STDOUT, STDIN, or STDERR: not running '{}'", long); + eprintln!( + "ion: failed to `dup` STDOUT, STDIN, or STDERR: not running '{}'", + long + ); COULD_NOT_EXEC } - RefinedJob::Function { ref name, ref args, ref stdin, ref stdout, ref stderr } => { + RefinedJob::Function { + ref name, + ref args, + ref stdin, + ref stdout, + ref stderr, + } => { if let Ok((stdin_bk, stdout_bk, stderr_bk)) = duplicate_streams() { let args: Vec<&str> = args.iter().map(|x| x as &str).collect(); let code = self.exec_function(name, &args, stdout, stderr, stdin); redirect_streams(stdin_bk, stdout_bk, stderr_bk); return code; } - eprintln!("ion: failed to `dup` STDOUT, STDIN, or STDERR: not running '{}'", long); + eprintln!( + "ion: failed to `dup` STDOUT, STDIN, or STDERR: not running '{}'", + long + ); COULD_NOT_EXEC } _ => panic!("exec job should not be able to be called on Cat or Tee jobs"), @@ -698,8 +743,8 @@ pub(crate) fn pipe( let mut ext_stdio: Option<Vec<RawFd>> = None; loop { if let Some((mut parent, mut kind)) = commands.next() { - // When an `&&` or `||` operator is utilized, execute commands based on the previous - // status. + // When an `&&` or `||` operator is utilized, execute commands based on the + // previous status. match previous_kind { JobKind::And => if previous_status != SUCCESS { if let JobKind::Or = kind { @@ -932,8 +977,11 @@ pub(crate) fn pipe( // If parent is a RefindJob::External, then we need to keep track of the // output pipes, so we can properly close them after the job has been // spawned. - let is_external = - if let RefinedJob::External(..) = parent { true } else { false }; + let is_external = if let RefinedJob::External(..) = parent { + true + } else { + false + }; // If we need to tee both stdout and stderr, we directly connect pipes to // the relevant sources in both of them. @@ -976,10 +1024,14 @@ pub(crate) fn pipe( child.stdin(unsafe { File::from_raw_fd(reader) }); match mode { RedirectFrom::Stderr => { - parent.stderr(unsafe { File::from_raw_fd(writer) }); + parent.stderr(unsafe { + File::from_raw_fd(writer) + }); } RedirectFrom::Stdout => { - parent.stdout(unsafe { File::from_raw_fd(writer) }); + parent.stdout(unsafe { + File::from_raw_fd(writer) + }); } RedirectFrom::Both => { let temp = unsafe { File::from_raw_fd(writer) }; diff --git a/src/shell/plugins/library_iter/redox.rs b/src/shell/plugins/library_iter/redox.rs index 61fed872..402b237b 100644 --- a/src/shell/plugins/library_iter/redox.rs +++ b/src/shell/plugins/library_iter/redox.rs @@ -9,7 +9,9 @@ pub(crate) struct LibraryIterator { } impl LibraryIterator { - pub(crate) fn new(directory: ReadDir) -> LibraryIterator { LibraryIterator { directory } } + pub(crate) fn new(directory: ReadDir) -> LibraryIterator { + LibraryIterator { directory } + } } impl Iterator for LibraryIterator { @@ -17,5 +19,7 @@ impl Iterator for LibraryIterator { // The `Library` is a handle to dynamic library loaded into memory. type Item = (Identifier, Library); - fn next(&mut self) -> Option<(Identifier, Library)> { None } + fn next(&mut self) -> Option<(Identifier, Library)> { + None + } } diff --git a/src/shell/plugins/library_iter/unix.rs b/src/shell/plugins/library_iter/unix.rs index 4b1ba399..17a313f8 100644 --- a/src/shell/plugins/library_iter/unix.rs +++ b/src/shell/plugins/library_iter/unix.rs @@ -8,7 +8,9 @@ pub(crate) struct LibraryIterator { } impl LibraryIterator { - pub(crate) fn new(directory: ReadDir) -> LibraryIterator { LibraryIterator { directory } } + pub(crate) fn new(directory: ReadDir) -> LibraryIterator { + LibraryIterator { directory } + } } impl Iterator for LibraryIterator { @@ -18,7 +20,11 @@ impl Iterator for LibraryIterator { fn next(&mut self) -> Option<(Identifier, Library)> { while let Some(entry) = self.directory.next() { - let entry = if let Ok(entry) = entry { entry } else { continue }; + let entry = if let Ok(entry) = entry { + entry + } else { + continue; + }; let path = entry.path(); // An entry is a library if it is a file with a 'so' extension. if path.is_file() && path.extension().map_or(false, |ext| ext == "so") { diff --git a/src/shell/plugins/methods/redox.rs b/src/shell/plugins/methods/redox.rs index 0f77cb0e..c082e7db 100644 --- a/src/shell/plugins/methods/redox.rs +++ b/src/shell/plugins/methods/redox.rs @@ -9,7 +9,9 @@ pub(crate) enum MethodArguments { pub(crate) struct StringMethodPlugins; impl StringMethodPlugins { - pub(crate) fn new() -> StringMethodPlugins { StringMethodPlugins } + pub(crate) fn new() -> StringMethodPlugins { + StringMethodPlugins + } pub(crate) fn execute( &self, @@ -24,4 +26,6 @@ impl StringMethodPlugins { /// /// This function is meant to be called with `lazy_static` to ensure that there isn't a /// cost to collecting all this information when the shell never uses it in the first place! -pub(crate) fn collect() -> StringMethodPlugins { StringMethodPlugins::new() } +pub(crate) fn collect() -> StringMethodPlugins { + StringMethodPlugins::new() +} diff --git a/src/shell/plugins/methods/unix.rs b/src/shell/plugins/methods/unix.rs index 8e9dc536..3e7d5564 100644 --- a/src/shell/plugins/methods/unix.rs +++ b/src/shell/plugins/methods/unix.rs @@ -15,11 +15,11 @@ use types::Identifier; /// corresponding field to `NULL`. Libraries importing this structure should check for nullness. #[repr(C)] pub(crate) struct RawMethodArguments { - key_ptr: *mut c_char, + key_ptr: *mut c_char, key_array_ptr: *mut *mut c_char, - args_ptr: *mut *mut c_char, - key_len: usize, - args_len: usize, + args_ptr: *mut *mut c_char, + key_len: usize, + args_len: usize, } pub(crate) enum MethodArguments { @@ -82,11 +82,11 @@ impl From<MethodArguments> for RawMethodArguments { } } MethodArguments::NoArgs => RawMethodArguments { - key_ptr: ptr::null_mut(), + key_ptr: ptr::null_mut(), key_array_ptr: ptr::null_mut(), - args_ptr: ptr::null_mut(), - key_len: 0, - args_len: 0, + args_ptr: ptr::null_mut(), + key_len: 0, + args_len: 0, }, } } @@ -100,7 +100,8 @@ impl From<MethodArguments> for RawMethodArguments { /// the namespace. pub(crate) struct StringMethodPlugins { #[allow(dead_code)] - /// Contains all of the loaded libraries from whence the symbols were obtained. + /// Contains all of the loaded libraries from whence the symbols were + /// obtained. libraries: Vec<Library>, /// A map of all the symbols that were collected from the above libraries. pub symbols: @@ -109,7 +110,10 @@ pub(crate) struct StringMethodPlugins { impl StringMethodPlugins { pub(crate) fn new() -> StringMethodPlugins { - StringMethodPlugins { libraries: Vec::new(), symbols: FnvHashMap::default() } + StringMethodPlugins { + libraries: Vec::new(), + symbols: FnvHashMap::default(), + } } pub(crate) fn load(&mut self, library: Library) -> Result<(), StringError> { @@ -156,9 +160,10 @@ impl StringMethodPlugins { // Then attempt to load that symbol from the dynamic library. let symbol: Symbol< - unsafe extern "C" fn(RawMethodArguments) - -> *mut c_char, - > = library.get(symbol.as_slice()).map_err(StringError::SymbolErr)?; + unsafe extern "C" fn(RawMethodArguments) -> *mut c_char, + > = library + .get(symbol.as_slice()) + .map_err(StringError::SymbolErr)?; // And finally add the name of the function and it's function into the // map. @@ -169,8 +174,8 @@ impl StringMethodPlugins { counter += 1; } - // Identical to the logic in the loop above. Handles any unparsed stragglers that - // have been left over. + // Identical to the logic in the loop above. Handles any unparsed stragglers + // that have been left over. if counter != start { let slice = &symbol_list[start..]; let identifier = str::from_utf8(slice) @@ -182,7 +187,9 @@ impl StringMethodPlugins { symbol.push(b'\0'); let symbol: Symbol< unsafe extern "C" fn(RawMethodArguments) -> *mut c_char, - > = library.get(symbol.as_slice()).map_err(StringError::SymbolErr)?; + > = library + .get(symbol.as_slice()) + .map_err(StringError::SymbolErr)?; self.symbols.insert(identifier, symbol.into_raw()); } } @@ -201,8 +208,9 @@ impl StringMethodPlugins { function: &str, arguments: MethodArguments, ) -> Result<Option<String>, StringError> { - let func = - self.symbols.get(function.into()).ok_or(StringError::FunctionMissing(function.into()))?; + let func = self.symbols + .get(function.into()) + .ok_or(StringError::FunctionMissing(function.into()))?; unsafe { let data = (*func)(RawMethodArguments::from(arguments)); if data.is_null() { diff --git a/src/shell/plugins/mod.rs b/src/shell/plugins/mod.rs index de55cb49..527d0f44 100644 --- a/src/shell/plugins/mod.rs +++ b/src/shell/plugins/mod.rs @@ -11,15 +11,11 @@ use xdg::BaseDirectories; pub(crate) fn config_dir() -> Option<PathBuf> { match BaseDirectories::with_prefix("ion") { - Ok(base_dirs) => { - match base_dirs.create_config_directory("plugins") { - Ok(mut path) => { - Some(path) - }, - Err(err) => { - eprintln!("ion: unable to create config directory: {:?}", err); - None - } + Ok(base_dirs) => match base_dirs.create_config_directory("plugins") { + Ok(mut path) => Some(path), + Err(err) => { + eprintln!("ion: unable to create config directory: {:?}", err); + None } }, Err(err) => { diff --git a/src/shell/plugins/namespaces/redox.rs b/src/shell/plugins/namespaces/redox.rs index 480b69ce..3f9fc050 100644 --- a/src/shell/plugins/namespaces/redox.rs +++ b/src/shell/plugins/namespaces/redox.rs @@ -6,7 +6,9 @@ use types::Identifier; pub(crate) struct StringNamespace; impl StringNamespace { - pub(crate) fn new() -> Result<StringNamespace, StringError> { Ok(StringNamespace) } + pub(crate) fn new() -> Result<StringNamespace, StringError> { + Ok(StringNamespace) + } pub(crate) fn execute(&self, _function: Identifier) -> Result<Option<String>, StringError> { Ok(None) diff --git a/src/shell/plugins/namespaces/unix.rs b/src/shell/plugins/namespaces/unix.rs index cd56c95e..a57c158d 100644 --- a/src/shell/plugins/namespaces/unix.rs +++ b/src/shell/plugins/namespaces/unix.rs @@ -73,7 +73,9 @@ impl StringNamespace { // Then attempt to load that symbol from the dynamic library. let symbol: Symbol< unsafe extern "C" fn() -> *mut c_char, - > = library.get(symbol.as_slice()).map_err(StringError::SymbolErr)?; + > = library + .get(symbol.as_slice()) + .map_err(StringError::SymbolErr)?; // And finally add the name of the function and it's function into the // map. @@ -84,8 +86,8 @@ impl StringNamespace { counter += 1; } - // Identical to the logic in the loop above. Handles any unparsed stragglers that - // have been left over. + // Identical to the logic in the loop above. Handles any unparsed stragglers + // that have been left over. if counter != start { let slice = &symbol_list[start..]; let identifier = str::from_utf8(slice) @@ -95,8 +97,9 @@ impl StringNamespace { symbol.reserve_exact(slice.len() + 1); symbol.extend_from_slice(slice); symbol.push(b'\0'); - let symbol: Symbol<unsafe extern "C" fn() -> *mut c_char> = - library.get(symbol.as_slice()).map_err(StringError::SymbolErr)?; + let symbol: Symbol<unsafe extern "C" fn() -> *mut c_char> = library + .get(symbol.as_slice()) + .map_err(StringError::SymbolErr)?; symbols.insert(identifier, symbol.into_raw()); } } @@ -110,8 +113,9 @@ impl StringNamespace { /// If the function exists, it is executed, and it's return value is then converted into a /// proper Rusty type. pub(crate) fn execute(&self, function: Identifier) -> Result<Option<String>, StringError> { - let func = - self.symbols.get(&function).ok_or(StringError::FunctionMissing(function.clone()))?; + let func = self.symbols + .get(&function) + .ok_or(StringError::FunctionMissing(function.clone()))?; unsafe { let data = (*func)(); if data.is_null() { diff --git a/src/shell/plugins/string.rs b/src/shell/plugins/string.rs index fef188f0..09e6f79a 100644 --- a/src/shell/plugins/string.rs +++ b/src/shell/plugins/string.rs @@ -9,9 +9,11 @@ pub(crate) enum StringError { /// This occurs when a symbol could not be loaded from the library in question. It is an /// error that infers that the problem is with the plugin, not Ion itself. SymbolErr(io::Error), - /// Function names must be valid UTF-8. If they aren't something's wrong with the plugin. + /// Function names must be valid UTF-8. If they aren't something's wrong + /// with the plugin. UTF8Function, - /// The result from a plugin must be valid UTF-8. If it isn't, the plugin's bad. + /// The result from a plugin must be valid UTF-8. If it isn't, the plugin's + /// bad. UTF8Result, /// This infers that the user called a function that doesn't exist in the library. Bad /// user, bad. diff --git a/src/shell/signals.rs b/src/shell/signals.rs index 7fa8a6b4..bbf8fde0 100644 --- a/src/shell/signals.rs +++ b/src/shell/signals.rs @@ -1,6 +1,6 @@ -//! This module contains all of the code that manages signal handling in the shell. Primarily, this -//! will be used to block signals in the shell at startup, and unblock signals for each of the -//! forked +//! This module contains all of the code that manages signal handling in the +//! shell. Primarily, this will be used to block signals in the shell at +//! startup, and unblock signals for each of the forked //! children of the shell. use std::sync::atomic::{ATOMIC_U8_INIT, AtomicU8}; @@ -15,10 +15,14 @@ pub const SIGHUP: u8 = 2; pub const SIGTERM: u8 = 4; /// Suspends a given process by it's process ID. -pub(crate) fn suspend(pid: u32) { let _ = sys::killpg(pid, sys::SIGSTOP); } +pub(crate) fn suspend(pid: u32) { + let _ = sys::killpg(pid, sys::SIGSTOP); +} /// Resumes a given process by it's process ID. -pub(crate) fn resume(pid: u32) { let _ = sys::killpg(pid, sys::SIGCONT); } +pub(crate) fn resume(pid: u32) { + let _ = sys::killpg(pid, sys::SIGCONT); +} /// The purpose of the signal handler is to ignore signals when it is active, and then continue /// listening to signals once the handler is dropped. @@ -32,5 +36,7 @@ impl SignalHandler { } impl Drop for SignalHandler { - fn drop(&mut self) { unblock(); } + fn drop(&mut self) { + unblock(); + } } diff --git a/src/shell/status.rs b/src/shell/status.rs index 65d0b1ef..6f99c27d 100644 --- a/src/shell/status.rs +++ b/src/shell/status.rs @@ -5,4 +5,6 @@ pub const COULD_NOT_EXEC: i32 = 126; pub const NO_SUCH_COMMAND: i32 = 127; pub const TERMINATED: i32 = 143; -pub fn get_signal_code(signal: i32) -> i32 { 128 + signal } +pub fn get_signal_code(signal: i32) -> i32 { + 128 + signal +} diff --git a/src/shell/variables/mod.rs b/src/shell/variables/mod.rs index cf08c856..93881487 100644 --- a/src/shell/variables/mod.rs +++ b/src/shell/variables/mod.rs @@ -8,10 +8,8 @@ use std::env; use std::io::{self, BufRead}; use sys::variables as self_sys; use sys::{self, getpid, is_root}; -use types::{ - Array, ArrayVariableContext, HashMap, HashMapVariableContext, Identifier, Key, Value, - VariableContext, -}; +use types::{Array, ArrayVariableContext, HashMap, HashMapVariableContext, Identifier, Key, Value, + VariableContext}; use unicode_segmentation::UnicodeSegmentation; use xdg::BaseDirectories; @@ -21,11 +19,11 @@ lazy_static! { #[derive(Clone, Debug)] pub struct Variables { - pub hashmaps: HashMapVariableContext, - pub arrays: ArrayVariableContext, + pub hashmaps: HashMapVariableContext, + pub arrays: ArrayVariableContext, pub variables: VariableContext, - pub aliases: VariableContext, - flags: u8, + pub aliases: VariableContext, + flags: u8, } impl Default for Variables { @@ -39,7 +37,9 @@ impl Default for Variables { "${c::0x55,bold}${USER}${c::default}:${c::0x4B}${SWD}${c::default}# ${c::reset}".into(), ); // Set the PID variable to the PID of the shell - let pid = getpid().map(|p| p.to_string()).unwrap_or_else(|e| e.to_string()); + let pid = getpid() + .map(|p| p.to_string()) + .unwrap_or_else(|e| e.to_string()); map.insert("PID".into(), pid.into()); // Initialize the HISTFILE variable @@ -62,11 +62,11 @@ impl Default for Variables { |path| env::set_var("HOME", path.to_str().unwrap_or("?")), ); Variables { - hashmaps: FnvHashMap::with_capacity_and_hasher(64, Default::default()), - arrays: FnvHashMap::with_capacity_and_hasher(64, Default::default()), + hashmaps: FnvHashMap::with_capacity_and_hasher(64, Default::default()), + arrays: FnvHashMap::with_capacity_and_hasher(64, Default::default()), variables: map, - aliases: FnvHashMap::with_capacity_and_hasher(64, Default::default()), - flags: 0, + aliases: FnvHashMap::with_capacity_and_hasher(64, Default::default()), + flags: 0, } } } @@ -74,14 +74,21 @@ impl Default for Variables { const PLUGIN: u8 = 1; impl Variables { - pub(crate) fn has_plugin_support(&self) -> bool { self.flags & PLUGIN != 0 } + pub(crate) fn has_plugin_support(&self) -> bool { + self.flags & PLUGIN != 0 + } - pub(crate) fn enable_plugins(&mut self) { self.flags |= PLUGIN; } + pub(crate) fn enable_plugins(&mut self) { + self.flags |= PLUGIN; + } - pub(crate) fn disable_plugins(&mut self) { self.flags &= 255 ^ PLUGIN; } + pub(crate) fn disable_plugins(&mut self) { + self.flags &= 255 ^ PLUGIN; + } pub(crate) fn read<I: IntoIterator>(&mut self, args: I) -> i32 - where I::Item: AsRef<str> + where + I::Item: AsRef<str>, { if sys::isatty(sys::STDIN_FILENO) { let mut con = Context::new(); @@ -148,18 +155,26 @@ impl Variables { } } - pub fn get_map(&self, name: &str) -> Option<&HashMap> { self.hashmaps.get(name) } + pub fn get_map(&self, name: &str) -> Option<&HashMap> { + self.hashmaps.get(name) + } - pub fn get_array(&self, name: &str) -> Option<&Array> { self.arrays.get(name) } + pub fn get_array(&self, name: &str) -> Option<&Array> { + self.arrays.get(name) + } - pub fn unset_array(&mut self, name: &str) -> Option<Array> { self.arrays.remove(name) } + pub fn unset_array(&mut self, name: &str) -> Option<Array> { + self.arrays.remove(name) + } /// Obtains the value for the **SWD** variable. /// /// Useful for getting smaller prompts, this will produce a simplified variant of the /// working directory which the leading `HOME` prefix replaced with a tilde character. fn get_simplified_directory(&self) -> Value { - self.get_var("PWD").unwrap().replace(&self.get_var("HOME").unwrap(), "~") + self.get_var("PWD") + .unwrap() + .replace(&self.get_var("HOME").unwrap(), "~") } /// Obtains the value for the **MWD** variable. @@ -174,7 +189,9 @@ impl Variables { // Temporarily borrow the `swd` variable while we attempt to assemble a minimal // variant of the directory path. If that is not possible, we will cancel the // borrow and return `swd` itself as the minified path. - let elements = swd.split("/").filter(|s| !s.is_empty()).collect::<Vec<&str>>(); + let elements = swd.split("/") + .filter(|s| !s.is_empty()) + .collect::<Vec<&str>>(); if elements.len() > 2 { let mut output = String::new(); for element in &elements[0..elements.len() - 1] { @@ -202,8 +219,8 @@ impl Variables { } if let Some((name, variable)) = name.find("::").map(|pos| (&name[..pos], &name[pos + 2..])) { - // If the parsed name contains the '::' pattern, then a namespace was designated. Find - // it. + // If the parsed name contains the '::' pattern, then a namespace was + // designated. Find it. match name { "c" | "color" => Colors::collect(variable).into_string(), "env" => env::var(variable).map(Into::into).ok(), @@ -241,16 +258,26 @@ impl Variables { } } else { // Otherwise, it's just a simple variable name. - self.variables.get(name).cloned().or_else(|| env::var(name).map(Into::into).ok()) + self.variables + .get(name) + .cloned() + .or_else(|| env::var(name).map(Into::into).ok()) } } - pub fn get_var_or_empty(&self, name: &str) -> Value { self.get_var(name).unwrap_or_default() } + pub fn get_var_or_empty(&self, name: &str) -> Value { + self.get_var(name).unwrap_or_default() + } - pub fn unset_var(&mut self, name: &str) -> Option<Value> { self.variables.remove(name) } + pub fn unset_var(&mut self, name: &str) -> Option<Value> { + self.variables.remove(name) + } pub fn get_vars<'a>(&'a self) -> impl Iterator<Item = Identifier> + 'a { - self.variables.keys().cloned().chain(env::vars().map(|(k, _)| k.into())) + self.variables + .keys() + .cloned() + .chain(env::vars().map(|(k, _)| k.into())) } pub(crate) fn is_valid_variable_character(c: char) -> bool { @@ -356,7 +383,9 @@ mod tests { struct VariableExpander(pub Variables); impl Expander for VariableExpander { - fn variable(&self, var: &str, _: bool) -> Option<Value> { self.0.get_var(var) } + fn variable(&self, var: &str, _: bool) -> Option<Value> { + self.0.get_var(var) + } } #[test] @@ -388,13 +417,19 @@ mod tests { fn minimal_directory_var_should_compact_path() { let mut variables = Variables::default(); variables.set_var("PWD", "/var/log/nix"); - assert_eq!("v/l/nix", variables.get_var("MWD").expect("no value returned")); + assert_eq!( + "v/l/nix", + variables.get_var("MWD").expect("no value returned") + ); } #[test] fn minimal_directory_var_shouldnt_compact_path() { let mut variables = Variables::default(); variables.set_var("PWD", "/var/log"); - assert_eq!("/var/log", variables.get_var("MWD").expect("no value returned")); + assert_eq!( + "/var/log", + variables.get_var("MWD").expect("no value returned") + ); } } diff --git a/src/sys/redox.rs b/src/sys/redox.rs index 64782ec7..919f51cd 100644 --- a/src/sys/redox.rs +++ b/src/sys/redox.rs @@ -19,11 +19,17 @@ pub(crate) const STDIN_FILENO: RawFd = 0; pub(crate) const STDOUT_FILENO: RawFd = 1; pub(crate) const STDERR_FILENO: RawFd = 2; -pub(crate) fn is_root() -> bool { syscall::geteuid().map(|id| id == 0).unwrap_or(false) } +pub(crate) fn is_root() -> bool { + syscall::geteuid().map(|id| id == 0).unwrap_or(false) +} -pub unsafe fn fork() -> io::Result<u32> { cvt(syscall::clone(0)).map(|pid| pid as u32) } +pub unsafe fn fork() -> io::Result<u32> { + cvt(syscall::clone(0)).map(|pid| pid as u32) +} -pub(crate) fn getpid() -> io::Result<u32> { cvt(syscall::getpid()).map(|pid| pid as u32) } +pub(crate) fn getpid() -> io::Result<u32> { + cvt(syscall::getpid()).map(|pid| pid as u32) +} pub(crate) fn kill(pid: u32, signal: i32) -> io::Result<()> { cvt(syscall::kill(pid as usize, signal as usize)).and(Ok(())) @@ -47,8 +53,8 @@ pub(crate) fn setpgid(pid: u32, pgid: u32) -> io::Result<()> { pub(crate) fn signal(signal: i32, handler: extern "C" fn(i32)) -> io::Result<()> { let new = SigAction { sa_handler: unsafe { mem::transmute(handler) }, - sa_mask: [0; 2], - sa_flags: 0, + sa_mask: [0; 2], + sa_flags: 0, }; cvt(syscall::sigaction(signal as usize, Some(&new), None)).and(Ok(())) } @@ -56,8 +62,8 @@ pub(crate) fn signal(signal: i32, handler: extern "C" fn(i32)) -> io::Result<()> pub(crate) fn reset_signal(signal: i32) -> io::Result<()> { let new = SigAction { sa_handler: unsafe { mem::transmute(syscall::flag::SIG_DFL) }, - sa_mask: [0; 2], - sa_flags: 0, + sa_mask: [0; 2], + sa_flags: 0, }; cvt(syscall::sigaction(signal as usize, Some(&new), None)).and(Ok(())) } @@ -67,7 +73,10 @@ pub(crate) fn tcsetpgrp(tty_fd: RawFd, pgid: u32) -> io::Result<()> { let pgid_usize = pgid as usize; let res = syscall::write(fd, unsafe { - slice::from_raw_parts(&pgid_usize as *const usize as *const u8, mem::size_of::<usize>()) + slice::from_raw_parts( + &pgid_usize as *const usize as *const u8, + mem::size_of::<usize>(), + ) }); let _ = syscall::close(fd); @@ -75,13 +84,17 @@ pub(crate) fn tcsetpgrp(tty_fd: RawFd, pgid: u32) -> io::Result<()> { cvt(res).and(Ok(())) } -pub(crate) fn dup(fd: RawFd) -> io::Result<RawFd> { cvt(syscall::dup(fd, &[])) } +pub(crate) fn dup(fd: RawFd) -> io::Result<RawFd> { + cvt(syscall::dup(fd, &[])) +} pub(crate) fn dup2(old: RawFd, new: RawFd) -> io::Result<RawFd> { cvt(syscall::dup2(old, new, &[])) } -pub(crate) fn close(fd: RawFd) -> io::Result<()> { cvt(syscall::close(fd)).and(Ok(())) } +pub(crate) fn close(fd: RawFd) -> io::Result<()> { + cvt(syscall::close(fd)).and(Ok(())) +} pub(crate) fn isatty(fd: RawFd) -> bool { if let Ok(tfd) = syscall::dup(fd, b"termios") { @@ -135,8 +148,9 @@ pub mod job_control { _get_command: F, mut drop_command: D, ) -> i32 - where F: FnOnce() -> String, - D: FnMut(i32) + where + F: FnOnce() -> String, + D: FnMut(i32), { let mut exit_status = 0; loop { diff --git a/src/sys/unix/job_control.rs b/src/sys/unix/job_control.rs index 3881f2f4..4e1c5995 100644 --- a/src/sys/unix/job_control.rs +++ b/src/sys/unix/job_control.rs @@ -88,8 +88,9 @@ pub(crate) fn watch_foreground<F, D>( get_command: F, mut drop_command: D, ) -> i32 - where F: FnOnce() -> String, - D: FnMut(i32) +where + F: FnOnce() -> String, + D: FnMut(i32), { let mut exit_status = 0; let mut found = 0; diff --git a/src/sys/unix/mod.rs b/src/sys/unix/mod.rs index 40e7dabb..83abc799 100644 --- a/src/sys/unix/mod.rs +++ b/src/sys/unix/mod.rs @@ -21,11 +21,17 @@ pub(crate) const STDOUT_FILENO: i32 = libc::STDOUT_FILENO; pub(crate) const STDERR_FILENO: i32 = libc::STDERR_FILENO; pub(crate) const STDIN_FILENO: i32 = libc::STDIN_FILENO; -pub(crate) fn is_root() -> bool { unsafe { libc::geteuid() == 0 } } +pub(crate) fn is_root() -> bool { + unsafe { libc::geteuid() == 0 } +} -pub unsafe fn fork() -> io::Result<u32> { cvt(libc::fork()).map(|pid| pid as u32) } +pub unsafe fn fork() -> io::Result<u32> { + cvt(libc::fork()).map(|pid| pid as u32) +} -pub(crate) fn getpid() -> io::Result<u32> { cvt(unsafe { libc::getpid() }).map(|pid| pid as u32) } +pub(crate) fn getpid() -> io::Result<u32> { + cvt(unsafe { libc::getpid() }).map(|pid| pid as u32) +} pub(crate) fn kill(pid: u32, signal: i32) -> io::Result<()> { cvt(unsafe { libc::kill(pid as pid_t, signal as c_int) }).and(Ok(())) @@ -72,15 +78,21 @@ pub(crate) fn tcsetpgrp(fd: RawFd, pgrp: u32) -> io::Result<()> { cvt(unsafe { libc::tcsetpgrp(fd as c_int, pgrp as pid_t) }).and(Ok(())) } -pub(crate) fn dup(fd: RawFd) -> io::Result<RawFd> { cvt(unsafe { libc::dup(fd) }) } +pub(crate) fn dup(fd: RawFd) -> io::Result<RawFd> { + cvt(unsafe { libc::dup(fd) }) +} pub(crate) fn dup2(old: RawFd, new: RawFd) -> io::Result<RawFd> { cvt(unsafe { libc::dup2(old, new) }) } -pub(crate) fn close(fd: RawFd) -> io::Result<()> { cvt(unsafe { libc::close(fd) }).and(Ok(())) } +pub(crate) fn close(fd: RawFd) -> io::Result<()> { + cvt(unsafe { libc::close(fd) }).and(Ok(())) +} -pub(crate) fn isatty(fd: RawFd) -> bool { unsafe { libc::isatty(fd) == 1 } } +pub(crate) fn isatty(fd: RawFd) -> bool { + unsafe { libc::isatty(fd) == 1 } +} trait IsMinusOne { fn is_minus_one(&self) -> bool; diff --git a/src/sys/unix/signals.rs b/src/sys/unix/signals.rs index e4203c03..97fa4d51 100644 --- a/src/sys/unix/signals.rs +++ b/src/sys/unix/signals.rs @@ -12,7 +12,11 @@ pub(crate) fn block() { sigaddset(&mut sigset as *mut sigset_t, SIGTTOU); sigaddset(&mut sigset as *mut sigset_t, SIGTTIN); sigaddset(&mut sigset as *mut sigset_t, SIGCHLD); - sigprocmask(SIG_BLOCK, &sigset as *const sigset_t, ptr::null_mut() as *mut sigset_t); + sigprocmask( + SIG_BLOCK, + &sigset as *const sigset_t, + ptr::null_mut() as *mut sigset_t, + ); } } @@ -27,6 +31,10 @@ pub(crate) fn unblock() { sigaddset(&mut sigset as *mut sigset_t, SIGTTOU); sigaddset(&mut sigset as *mut sigset_t, SIGTTIN); sigaddset(&mut sigset as *mut sigset_t, SIGCHLD); - sigprocmask(SIG_UNBLOCK, &sigset as *const sigset_t, ptr::null_mut() as *mut sigset_t); + sigprocmask( + SIG_UNBLOCK, + &sigset as *const sigset_t, + ptr::null_mut() as *mut sigset_t, + ); } } -- GitLab