From c83dbe08baf9e9854e46695a6c99599e0a0608d9 Mon Sep 17 00:00:00 2001 From: fdai7375 Date: Thu, 2 Feb 2023 18:30:56 +0100 Subject: [PATCH 01/14] feat: add ls command accessed timestamp --- src/builtins/ls.rs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/builtins/ls.rs b/src/builtins/ls.rs index d621b81..1b6a891 100644 --- a/src/builtins/ls.rs +++ b/src/builtins/ls.rs @@ -19,7 +19,7 @@ impl Builtin for Ls { //for entry in entries.by_ref().into_iter() {} println!( - "{} | dir | size | modified |", + "{} | dir | size | modified | accessed |", right_padding(" filename", 20) ); @@ -42,6 +42,11 @@ impl Builtin for Ls { Err(_) => Local::now(), }; + let accessed: DateTime = match metadata.accessed() { + Ok(t) => DateTime::from(t), + Err(_) => Local::now(), + }; + let mut file_type = "unknown"; if metadata.file_type().is_dir() { file_type = "dir" @@ -52,7 +57,14 @@ impl Builtin for Ls { } println!( "{}", - format_line(20, &file_name, file_type, metadata.len(), modified) + format_line( + 20, + &file_name, + file_type, + metadata.len(), + modified, + accessed + ) ); } Ok(()) @@ -86,13 +98,15 @@ fn format_line( file_type: &str, file_size: u64, modified: DateTime, + accessed: DateTime, ) -> String { format!( - "{} | {:4} | {:6} | {} |", + "{} | {:4} | {:6} | {} | {} |", right_padding(file_name, max_name_len), file_type, format_filesize(file_size), - right_padding(&format_date(modified), 10) + right_padding(&format_date(modified), 10), + right_padding(&format_date(accessed), 10) ) } From 419c8b00b8e2dace94ac4c0a4d2a5953a510369f Mon Sep 17 00:00:00 2001 From: fdai7375 Date: Thu, 2 Feb 2023 18:38:04 +0100 Subject: [PATCH 02/14] feat: add ls command created timestamp --- src/builtins/ls.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/builtins/ls.rs b/src/builtins/ls.rs index 1b6a891..3b921ae 100644 --- a/src/builtins/ls.rs +++ b/src/builtins/ls.rs @@ -19,7 +19,7 @@ impl Builtin for Ls { //for entry in entries.by_ref().into_iter() {} println!( - "{} | dir | size | modified | accessed |", + "{} | dir | size | modified | accessed | created |", right_padding(" filename", 20) ); @@ -47,6 +47,11 @@ impl Builtin for Ls { Err(_) => Local::now(), }; + let created: DateTime = match metadata.created() { + Ok(t) => DateTime::from(t), + Err(_) => Local::now(), + }; + let mut file_type = "unknown"; if metadata.file_type().is_dir() { file_type = "dir" @@ -63,7 +68,8 @@ impl Builtin for Ls { file_type, metadata.len(), modified, - accessed + accessed, + created ) ); } @@ -99,14 +105,16 @@ fn format_line( file_size: u64, modified: DateTime, accessed: DateTime, + created: DateTime, ) -> String { format!( - "{} | {:4} | {:6} | {} | {} |", + "{} | {:4} | {:6} | {} | {} | {} |", right_padding(file_name, max_name_len), file_type, format_filesize(file_size), right_padding(&format_date(modified), 10), - right_padding(&format_date(accessed), 10) + right_padding(&format_date(accessed), 10), + right_padding(&format_date(created), 10), ) } From ea97546a43cf9e314b26945d81062bdfd1a78e01 Mon Sep 17 00:00:00 2001 From: fdai7375 Date: Thu, 2 Feb 2023 18:43:24 +0100 Subject: [PATCH 03/14] feat: add ls command readonly info --- src/builtins/ls.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/builtins/ls.rs b/src/builtins/ls.rs index 3b921ae..5779b72 100644 --- a/src/builtins/ls.rs +++ b/src/builtins/ls.rs @@ -1,4 +1,8 @@ -use std::{fs::metadata, path::PathBuf, str::FromStr}; +use std::{ + fs::{metadata, Permissions}, + path::PathBuf, + str::FromStr, +}; use chrono::{DateTime, Datelike, Local}; @@ -19,7 +23,7 @@ impl Builtin for Ls { //for entry in entries.by_ref().into_iter() {} println!( - "{} | dir | size | modified | accessed | created |", + "{} | dir | size | modified | accessed | created | readonly |", right_padding(" filename", 20) ); @@ -52,6 +56,8 @@ impl Builtin for Ls { Err(_) => Local::now(), }; + let permissions = metadata.permissions(); + let mut file_type = "unknown"; if metadata.file_type().is_dir() { file_type = "dir" @@ -69,7 +75,8 @@ impl Builtin for Ls { metadata.len(), modified, accessed, - created + created, + permissions ) ); } @@ -106,15 +113,17 @@ fn format_line( modified: DateTime, accessed: DateTime, created: DateTime, + permissions: Permissions, ) -> String { format!( - "{} | {:4} | {:6} | {} | {} | {} |", + "{} | {:4} | {:6} | {} | {} | {} | {} |", right_padding(file_name, max_name_len), file_type, format_filesize(file_size), right_padding(&format_date(modified), 10), right_padding(&format_date(accessed), 10), right_padding(&format_date(created), 10), + right_padding(&permissions.readonly().to_string(), 5), ) } From 51e855505f9006e9a9b80ddffdb875b0c24167d8 Mon Sep 17 00:00:00 2001 From: fdai7375 Date: Thu, 2 Feb 2023 18:50:14 +0100 Subject: [PATCH 04/14] refactoring: remove unnecessary padding function --- src/builtins/ls.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/builtins/ls.rs b/src/builtins/ls.rs index 5779b72..f2a2a28 100644 --- a/src/builtins/ls.rs +++ b/src/builtins/ls.rs @@ -116,14 +116,14 @@ fn format_line( permissions: Permissions, ) -> String { format!( - "{} | {:4} | {:6} | {} | {} | {} | {} |", + "{} | {:4} | {:6} | {:<10} | {:<10} | {:<10} | {:<5} |", right_padding(file_name, max_name_len), file_type, format_filesize(file_size), - right_padding(&format_date(modified), 10), - right_padding(&format_date(accessed), 10), - right_padding(&format_date(created), 10), - right_padding(&permissions.readonly().to_string(), 5), + format_date(modified), + format_date(accessed), + format_date(created), + permissions.readonly().to_string(), ) } From b2e0005092f066b7df4daa981c81d1a884f2f414 Mon Sep 17 00:00:00 2001 From: fdai7375 Date: Thu, 2 Feb 2023 18:55:59 +0100 Subject: [PATCH 05/14] refactoring: use assert instead of assert_eq --- src/builtins/mod.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/builtins/mod.rs b/src/builtins/mod.rs index 23a8a8b..f063ceb 100644 --- a/src/builtins/mod.rs +++ b/src/builtins/mod.rs @@ -71,61 +71,61 @@ mod tests { #[test] fn test_is_builtin_cd() { - assert_eq!(is_builtin("cd"), true); + assert!(is_builtin("cd")); } #[test] fn test_is_builtin_change_prompt() { - assert_eq!(is_builtin("change-prompt"), true); + assert!(is_builtin("change-prompt")); } #[test] fn test_is_builtin_exit() { - assert_eq!(is_builtin("exit"), true); + assert!(is_builtin("exit")); } #[test] fn test_is_builtin_fetch() { - assert_eq!(is_builtin("fetch"), true); + assert!(is_builtin("fetch")); } #[test] fn test_is_builtin_help() { - assert_eq!(is_builtin("help"), true); + assert!(is_builtin("help")); } #[test] fn test_is_builtin_ls() { - assert_eq!(is_builtin("ls"), true); + assert!(is_builtin("ls")); } #[test] fn test_is_builtin_open() { - assert_eq!(is_builtin("open"), true); + assert!(is_builtin("open")); } #[test] fn test_is_builtin_pwd() { - assert_eq!(is_builtin("pwd"), true); + assert!(is_builtin("pwd")); } #[test] fn test_is_builtin_segfault() { - assert_eq!(is_builtin("segfault"), true); + assert!(is_builtin("segfault")); } #[test] fn test_is_builtin_sus() { - assert_eq!(is_builtin("sus"), true); + assert!(is_builtin("sus")); } #[test] fn test_is_builtin_quote() { - assert_eq!(is_builtin("quote"), true); + assert!(is_builtin("quote")); } #[test] fn test_is_builtin_notabuiltin() { - assert_eq!(is_builtin("notabuiltin"), false) + assert!(!is_builtin("notabuiltin")) } } From 5dd33b2b068d339c85d60b1f3c26aeb8ba2e5be4 Mon Sep 17 00:00:00 2001 From: fdai7375 Date: Thu, 2 Feb 2023 19:00:00 +0100 Subject: [PATCH 06/14] refactoring: move variables into the format string --- src/builtins/fetch.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/builtins/fetch.rs b/src/builtins/fetch.rs index f07ea29..c334980 100644 --- a/src/builtins/fetch.rs +++ b/src/builtins/fetch.rs @@ -20,7 +20,7 @@ impl Builtin for Fetch { "@".bold(), hostname().bright_green().bold() ); - println!("{}", line); + println!("{line}"); println!( "{} {} {}", "OS".bright_blue().bold(), @@ -50,7 +50,7 @@ fn format_uptime(uptime: u64) -> String { let m = (uptime - h * 3600) / 60; let s = uptime - (h * 3600 + m * 60); - format!("{:.0}h {:.0}m {:.0}s", h, m, s) + format!("{h:.0}h {m:.0}m {s:.0}s") } fn bytes_to_mebi_bytes(bytes: u64) -> u64 { From 1d25d19cb4a018e40e6ec4580f53b10c5cf3c652 Mon Sep 17 00:00:00 2001 From: fdai7375 Date: Thu, 2 Feb 2023 19:03:10 +0100 Subject: [PATCH 07/14] refactoring: fix clippy warnings inside the split_command function --- src/builtins/help.rs | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/builtins/help.rs b/src/builtins/help.rs index 86e3fdd..0f12db1 100644 --- a/src/builtins/help.rs +++ b/src/builtins/help.rs @@ -1,6 +1,6 @@ -use colored::Colorize; use crate::builtins::{Builtin, BuiltinConfig}; use crate::error::ShellError; +use colored::Colorize; pub struct Help; @@ -20,18 +20,22 @@ impl Builtin for Help { "; for line in commands.lines() { - println!("{}{}", split_command(line)[0].bold(), split_command(line)[1]); + println!( + "{}{}", + split_command(line)[0].bold(), + split_command(line)[1] + ); } Ok(()) } } fn split_command(commands: &str) -> Vec<&str> { - if commands.trim_start().len() >= 1 { - let splitted_command = commands.trim_start().splitn(2, " ").collect(); + if !commands.trim_start().is_empty() { + let splitted_command = commands.trim_start().splitn(2, ' ').collect(); return splitted_command; } - return vec!["", ""]; + vec!["", ""] } #[cfg(test)] @@ -41,13 +45,22 @@ mod tests { #[test] fn test_split_command_split() { let test_string1 = "Hallo, Marcel Davis 1&1."; - assert_eq!(split_command(test_string1), vec!["Hallo,", "Marcel Davis 1&1."]); + assert_eq!( + split_command(test_string1), + vec!["Hallo,", "Marcel Davis 1&1."] + ); let test_string2 = "Leiter1 23für Kundenzufriedenheit."; - assert_eq!(split_command(test_string2), vec!["Leiter1", "23für Kundenzufriedenheit."]); + assert_eq!( + split_command(test_string2), + vec!["Leiter1", "23für Kundenzufriedenheit."] + ); let test_string3 = "Wir# $%gehen erst wieder, wenn ihre Leitung läuft!"; - assert_eq!(split_command(test_string3), vec!["Wir#", "$%gehen erst wieder, wenn ihre Leitung läuft!"]); + assert_eq!( + split_command(test_string3), + vec!["Wir#", "$%gehen erst wieder, wenn ihre Leitung läuft!"] + ); } #[test] @@ -59,4 +72,4 @@ mod tests { fn test_split_command_only_space() { assert_eq!(split_command(" "), vec!["", ""]); } -} \ No newline at end of file +} From 9550c54ba6bf7f5c36f7ba7a6407224adf61d64f Mon Sep 17 00:00:00 2001 From: fdai7375 Date: Thu, 2 Feb 2023 19:05:48 +0100 Subject: [PATCH 08/14] refactoring: remove unnecessary references --- src/error.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/error.rs b/src/error.rs index b73f6ed..ef27eff 100644 --- a/src/error.rs +++ b/src/error.rs @@ -12,11 +12,11 @@ pub enum ShellError { impl PartialEq for ShellError { fn eq(&self, other: &Self) -> bool { match self { - &ShellError::EmptyLine => matches!(other, ShellError::EmptyLine), - &ShellError::NotFound(_) => matches!(other, ShellError::NotFound(_)), - &ShellError::ExecuteFailure(_) => matches!(other, ShellError::ExecuteFailure(_)), - &ShellError::MalformedArgs(_) => matches!(other, ShellError::MalformedArgs(_)), - &ShellError::Interrupt => matches!(other, ShellError::Interrupt), + ShellError::EmptyLine => matches!(other, ShellError::EmptyLine), + ShellError::NotFound(_) => matches!(other, ShellError::NotFound(_)), + ShellError::ExecuteFailure(_) => matches!(other, ShellError::ExecuteFailure(_)), + ShellError::MalformedArgs(_) => matches!(other, ShellError::MalformedArgs(_)), + ShellError::Interrupt => matches!(other, ShellError::Interrupt), } } } From 2822f976c7c27a4c0a98c3e5f423cc641420d980 Mon Sep 17 00:00:00 2001 From: fdai7375 Date: Thu, 2 Feb 2023 19:13:50 +0100 Subject: [PATCH 09/14] refactoring: fix clippy warnings in interpret function --- src/execute.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/execute.rs b/src/execute.rs index 566e055..191b510 100644 --- a/src/execute.rs +++ b/src/execute.rs @@ -10,16 +10,16 @@ use std::{io, thread}; /// This function is not directly in main.rs because it might be called by other function too (eg. /// when piping commands). pub fn interpret(line: String, config: &mut BuiltinConfig, ctrlc_recv: Receiver<()>) { - match try_interpret(line, config, ctrlc_recv.clone()) { + match try_interpret(line, config, ctrlc_recv) { Ok(_) | Err(ShellError::Interrupt) | Err(ShellError::EmptyLine) => (), Err(ShellError::NotFound(cmd)) => { eprintln!("{}: command not found", cmd.get_program().to_string_lossy()) } Err(ShellError::ExecuteFailure(msg)) => { - eprintln!("{}", msg) + eprintln!("{msg}") } Err(ShellError::MalformedArgs(args)) => { - eprintln!("Malformed arguments: {}", args) + eprintln!("Malformed arguments: {args}") } } } From ecf1dd01c97c1902b507f563ec4222b99cb3599e Mon Sep 17 00:00:00 2001 From: fdai7375 Date: Thu, 2 Feb 2023 19:33:37 +0100 Subject: [PATCH 10/14] feat: add time command --- src/builtins/mod.rs | 2 ++ src/builtins/time.rs | 15 +++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 src/builtins/time.rs diff --git a/src/builtins/mod.rs b/src/builtins/mod.rs index f063ceb..b48b346 100644 --- a/src/builtins/mod.rs +++ b/src/builtins/mod.rs @@ -13,6 +13,7 @@ mod pwd; mod quote; mod segfault; mod sus; +mod time; pub struct BuiltinConfig { pub prompt_style: PromptStyle, @@ -43,6 +44,7 @@ const BUILTINS: Lazy)>> = Lazy::new(|| { ("segfault", Box::new(segfault::Segfault)), ("sus", Box::new(sus::Sus)), ("quote", Box::new(quote::Quote)), + ("time", Box::new(time::Time)), ] }); diff --git a/src/builtins/time.rs b/src/builtins/time.rs new file mode 100644 index 0000000..e1623cb --- /dev/null +++ b/src/builtins/time.rs @@ -0,0 +1,15 @@ +use chrono::{DateTime, Local, TimeZone}; + +use crate::error::ShellError; + +use super::{Builtin, BuiltinConfig}; + +pub struct Time; + +impl Builtin for Time { + fn execute(&mut self, _: &mut BuiltinConfig, _: Vec) -> Result<(), ShellError> { + let time = Local::now(); + println!("{time}"); + Ok(()) + } +} From e95e7733253422c4219b546add5e57a94ec7c931 Mon Sep 17 00:00:00 2001 From: fdai7375 Date: Thu, 2 Feb 2023 19:42:20 +0100 Subject: [PATCH 11/14] feat: add more formatting options to time command --- src/builtins/time.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/builtins/time.rs b/src/builtins/time.rs index e1623cb..58cc866 100644 --- a/src/builtins/time.rs +++ b/src/builtins/time.rs @@ -1,4 +1,4 @@ -use chrono::{DateTime, Local, TimeZone}; +use chrono::Local; use crate::error::ShellError; @@ -7,9 +7,20 @@ use super::{Builtin, BuiltinConfig}; pub struct Time; impl Builtin for Time { - fn execute(&mut self, _: &mut BuiltinConfig, _: Vec) -> Result<(), ShellError> { + fn execute(&mut self, _: &mut BuiltinConfig, args: Vec) -> Result<(), ShellError> { let time = Local::now(); - println!("{time}"); + + if args.is_empty() { + println!("{}", time.format("%T")); + return Ok(()); + } + + let time_string = match args[0].as_str() { + "RFC2822" => time.to_rfc2822(), + "RFC3339" => time.to_rfc3339(), + _ => time.format("%T").to_string(), + }; + println!("{time_string}"); Ok(()) } } From 9e928b70156e0e789bb61ede81aa901f32abd201 Mon Sep 17 00:00:00 2001 From: fdai7375 Date: Thu, 2 Feb 2023 19:51:09 +0100 Subject: [PATCH 12/14] feat: move time formatting in seperate function --- src/builtins/time.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/builtins/time.rs b/src/builtins/time.rs index 58cc866..0e79262 100644 --- a/src/builtins/time.rs +++ b/src/builtins/time.rs @@ -1,4 +1,4 @@ -use chrono::Local; +use chrono::{DateTime, Local}; use crate::error::ShellError; @@ -10,17 +10,17 @@ impl Builtin for Time { fn execute(&mut self, _: &mut BuiltinConfig, args: Vec) -> Result<(), ShellError> { let time = Local::now(); - if args.is_empty() { - println!("{}", time.format("%T")); - return Ok(()); - } - - let time_string = match args[0].as_str() { - "RFC2822" => time.to_rfc2822(), - "RFC3339" => time.to_rfc3339(), - _ => time.format("%T").to_string(), - }; + let formatting = args.get(0).cloned().unwrap_or_default(); + let time_string = format_time(time, &formatting); println!("{time_string}"); Ok(()) } } + +fn format_time(time: DateTime, formatting: &str) -> String { + match formatting { + "RFC2822" => time.to_rfc2822(), + "RFC3339" => time.to_rfc3339(), + _ => time.format("%T").to_string(), + } +} From b825d79b5eaa08cd061b6c732c13a332dddc6075 Mon Sep 17 00:00:00 2001 From: fdai7375 Date: Thu, 2 Feb 2023 19:53:09 +0100 Subject: [PATCH 13/14] test: add time is builtin test --- src/builtins/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/builtins/mod.rs b/src/builtins/mod.rs index b48b346..5977459 100644 --- a/src/builtins/mod.rs +++ b/src/builtins/mod.rs @@ -126,6 +126,11 @@ mod tests { assert!(is_builtin("quote")); } + #[test] + fn test_is_builtin_time() { + assert!(is_builtin("time")); + } + #[test] fn test_is_builtin_notabuiltin() { assert!(!is_builtin("notabuiltin")) From 7fe5de5614bd64de7a5068e03a8453298398475c Mon Sep 17 00:00:00 2001 From: fdai7375 Date: Thu, 2 Feb 2023 19:55:54 +0100 Subject: [PATCH 14/14] test: add time test --- src/builtins/time.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/builtins/time.rs b/src/builtins/time.rs index 0e79262..a831e99 100644 --- a/src/builtins/time.rs +++ b/src/builtins/time.rs @@ -24,3 +24,13 @@ fn format_time(time: DateTime, formatting: &str) -> String { _ => time.format("%T").to_string(), } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_time() { + assert_eq!(Time.execute(&mut BuiltinConfig::new(), vec![]), Ok(())) + } +}