Browse Source

Merge remote-tracking branch 'origin/main'

# Conflicts:
#	src/builtins/mod.rs
main
fdai7374 2 years ago
parent
commit
d6c8f5de43
  1. 4
      src/builtins/fetch.rs
  2. 31
      src/builtins/help.rs
  3. 41
      src/builtins/ls.rs
  4. 32
      src/builtins/mod.rs
  5. 36
      src/builtins/time.rs
  6. 10
      src/error.rs
  7. 6
      src/execute.rs

4
src/builtins/fetch.rs

@ -20,7 +20,7 @@ impl Builtin for Fetch {
"@".bold(), "@".bold(),
hostname().bright_green().bold() hostname().bright_green().bold()
); );
println!("{}", line);
println!("{line}");
println!( println!(
"{} {} {}", "{} {} {}",
"OS".bright_blue().bold(), "OS".bright_blue().bold(),
@ -50,7 +50,7 @@ fn format_uptime(uptime: u64) -> String {
let m = (uptime - h * 3600) / 60; let m = (uptime - h * 3600) / 60;
let s = uptime - (h * 3600 + m * 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 { fn bytes_to_mebi_bytes(bytes: u64) -> u64 {

31
src/builtins/help.rs

@ -1,6 +1,6 @@
use colored::Colorize;
use crate::builtins::{Builtin, BuiltinConfig}; use crate::builtins::{Builtin, BuiltinConfig};
use crate::error::ShellError; use crate::error::ShellError;
use colored::Colorize;
pub struct Help; pub struct Help;
@ -21,18 +21,22 @@ impl Builtin for Help {
"; ";
for line in commands.lines() { 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(()) Ok(())
} }
} }
fn split_command(commands: &str) -> Vec<&str> { 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 splitted_command;
} }
return vec!["", ""];
vec!["", ""]
} }
#[cfg(test)] #[cfg(test)]
@ -42,13 +46,22 @@ mod tests {
#[test] #[test]
fn test_split_command_split() { fn test_split_command_split() {
let test_string1 = "Hallo, Marcel Davis 1&1."; 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."; 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!"; 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] #[test]
@ -60,4 +73,4 @@ mod tests {
fn test_split_command_only_space() { fn test_split_command_only_space() {
assert_eq!(split_command(" "), vec!["", ""]); assert_eq!(split_command(" "), vec!["", ""]);
} }
}
}

41
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}; use chrono::{DateTime, Datelike, Local};
@ -19,7 +23,7 @@ impl Builtin for Ls {
//for entry in entries.by_ref().into_iter() {} //for entry in entries.by_ref().into_iter() {}
println!( println!(
"{} | dir | size | modified |",
"{} | dir | size | modified | accessed | created | readonly |",
right_padding(" filename", 20) right_padding(" filename", 20)
); );
@ -42,6 +46,18 @@ impl Builtin for Ls {
Err(_) => Local::now(), Err(_) => Local::now(),
}; };
let accessed: DateTime<Local> = match metadata.accessed() {
Ok(t) => DateTime::from(t),
Err(_) => Local::now(),
};
let created: DateTime<Local> = match metadata.created() {
Ok(t) => DateTime::from(t),
Err(_) => Local::now(),
};
let permissions = metadata.permissions();
let mut file_type = "unknown"; let mut file_type = "unknown";
if metadata.file_type().is_dir() { if metadata.file_type().is_dir() {
file_type = "dir" file_type = "dir"
@ -52,7 +68,16 @@ impl Builtin for Ls {
} }
println!( println!(
"{}", "{}",
format_line(20, &file_name, file_type, metadata.len(), modified)
format_line(
20,
&file_name,
file_type,
metadata.len(),
modified,
accessed,
created,
permissions
)
); );
} }
Ok(()) Ok(())
@ -86,13 +111,19 @@ fn format_line(
file_type: &str, file_type: &str,
file_size: u64, file_size: u64,
modified: DateTime<Local>, modified: DateTime<Local>,
accessed: DateTime<Local>,
created: DateTime<Local>,
permissions: Permissions,
) -> String { ) -> String {
format!( format!(
"{} | {:4} | {:6} | {} |",
"{} | {:4} | {:6} | {:<10} | {:<10} | {:<10} | {:<5} |",
right_padding(file_name, max_name_len), right_padding(file_name, max_name_len),
file_type, file_type,
format_filesize(file_size), format_filesize(file_size),
right_padding(&format_date(modified), 10)
format_date(modified),
format_date(accessed),
format_date(created),
permissions.readonly().to_string(),
) )
} }

32
src/builtins/mod.rs

@ -14,6 +14,7 @@ mod pwd;
mod quote; mod quote;
mod segfault; mod segfault;
mod sus; mod sus;
mod time;
pub struct BuiltinConfig { pub struct BuiltinConfig {
pub prompt_style: PromptStyle, pub prompt_style: PromptStyle,
@ -45,6 +46,8 @@ const BUILTINS: Lazy<Vec<(&str, Box<dyn Builtin>)>> = Lazy::new(|| {
("quote", Box::new(quote::Quote)), ("quote", Box::new(quote::Quote)),
("segfault", Box::new(segfault::Segfault)), ("segfault", Box::new(segfault::Segfault)),
("sus", Box::new(sus::Sus)), ("sus", Box::new(sus::Sus)),
("quote", Box::new(quote::Quote)),
("time", Box::new(time::Time)),
] ]
}); });
@ -73,27 +76,27 @@ mod tests {
#[test] #[test]
fn test_is_builtin_cd() { fn test_is_builtin_cd() {
assert_eq!(is_builtin("cd"), true);
assert!(is_builtin("cd"));
} }
#[test] #[test]
fn test_is_builtin_change_prompt() { fn test_is_builtin_change_prompt() {
assert_eq!(is_builtin("change-prompt"), true);
assert!(is_builtin("change-prompt"));
} }
#[test] #[test]
fn test_is_builtin_exit() { fn test_is_builtin_exit() {
assert_eq!(is_builtin("exit"), true);
assert!(is_builtin("exit"));
} }
#[test] #[test]
fn test_is_builtin_fetch() { fn test_is_builtin_fetch() {
assert_eq!(is_builtin("fetch"), true);
assert!(is_builtin("fetch"));
} }
#[test] #[test]
fn test_is_builtin_help() { fn test_is_builtin_help() {
assert_eq!(is_builtin("help"), true);
assert!(is_builtin("help"));
} }
#[test] #[test]
@ -103,36 +106,41 @@ mod tests {
#[test] #[test]
fn test_is_builtin_ls() { fn test_is_builtin_ls() {
assert_eq!(is_builtin("ls"), true);
assert!(is_builtin("ls"));
} }
#[test] #[test]
fn test_is_builtin_open() { fn test_is_builtin_open() {
assert_eq!(is_builtin("open"), true);
assert!(is_builtin("open"));
} }
#[test] #[test]
fn test_is_builtin_pwd() { fn test_is_builtin_pwd() {
assert_eq!(is_builtin("pwd"), true);
assert!(is_builtin("pwd"));
} }
#[test] #[test]
fn test_is_builtin_segfault() { fn test_is_builtin_segfault() {
assert_eq!(is_builtin("segfault"), true);
assert!(is_builtin("segfault"));
} }
#[test] #[test]
fn test_is_builtin_sus() { fn test_is_builtin_sus() {
assert_eq!(is_builtin("sus"), true);
assert!(is_builtin("sus"));
} }
#[test] #[test]
fn test_is_builtin_quote() { fn test_is_builtin_quote() {
assert_eq!(is_builtin("quote"), true);
assert!(is_builtin("quote"));
}
#[test]
fn test_is_builtin_time() {
assert!(is_builtin("time"));
} }
#[test] #[test]
fn test_is_builtin_notabuiltin() { fn test_is_builtin_notabuiltin() {
assert_eq!(is_builtin("notabuiltin"), false)
assert!(!is_builtin("notabuiltin"))
} }
} }

36
src/builtins/time.rs

@ -0,0 +1,36 @@
use chrono::{DateTime, Local};
use crate::error::ShellError;
use super::{Builtin, BuiltinConfig};
pub struct Time;
impl Builtin for Time {
fn execute(&mut self, _: &mut BuiltinConfig, args: Vec<String>) -> Result<(), ShellError> {
let time = Local::now();
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<Local>, formatting: &str) -> String {
match formatting {
"RFC2822" => time.to_rfc2822(),
"RFC3339" => time.to_rfc3339(),
_ => time.format("%T").to_string(),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_time() {
assert_eq!(Time.execute(&mut BuiltinConfig::new(), vec![]), Ok(()))
}
}

10
src/error.rs

@ -12,11 +12,11 @@ pub enum ShellError {
impl PartialEq<Self> for ShellError { impl PartialEq<Self> for ShellError {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
match self { 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),
} }
} }
} }

6
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. /// This function is not directly in main.rs because it might be called by other function too (eg.
/// when piping commands). /// when piping commands).
pub fn interpret(line: String, config: &mut BuiltinConfig, ctrlc_recv: Receiver<()>) { 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) => (), Ok(_) | Err(ShellError::Interrupt) | Err(ShellError::EmptyLine) => (),
Err(ShellError::NotFound(cmd)) => { Err(ShellError::NotFound(cmd)) => {
eprintln!("{}: command not found", cmd.get_program().to_string_lossy()) eprintln!("{}: command not found", cmd.get_program().to_string_lossy())
} }
Err(ShellError::ExecuteFailure(msg)) => { Err(ShellError::ExecuteFailure(msg)) => {
eprintln!("{}", msg)
eprintln!("{msg}")
} }
Err(ShellError::MalformedArgs(args)) => { Err(ShellError::MalformedArgs(args)) => {
eprintln!("Malformed arguments: {}", args)
eprintln!("Malformed arguments: {args}")
} }
} }
} }

Loading…
Cancel
Save