diff options
| author | Fuwn <[email protected]> | 2021-05-20 17:05:59 -0700 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2021-05-20 17:05:59 -0700 |
| commit | 9e2121baf98b6fdc15cde6c387a7845a0b3f95d6 (patch) | |
| tree | 15460f59799a9f655ac5b213e4b8a8903d1e57e4 /crates/whirl_prompt/src | |
| parent | feat(readme): add sqlfluff as a dev dep (diff) | |
| download | whirl-9e2121baf98b6fdc15cde6c387a7845a0b3f95d6.tar.xz whirl-9e2121baf98b6fdc15cde6c387a7845a0b3f95d6.zip | |
refactor(global): move crates around, stricter module isolation
Diffstat (limited to 'crates/whirl_prompt/src')
| -rw-r--r-- | crates/whirl_prompt/src/builtins/mod.rs | 108 | ||||
| -rw-r--r-- | crates/whirl_prompt/src/builtins/structures.rs | 34 | ||||
| -rw-r--r-- | crates/whirl_prompt/src/constants.rs | 19 | ||||
| -rw-r--r-- | crates/whirl_prompt/src/lib.rs | 150 | ||||
| -rw-r--r-- | crates/whirl_prompt/src/structure.rs | 10 |
5 files changed, 321 insertions, 0 deletions
diff --git a/crates/whirl_prompt/src/builtins/mod.rs b/crates/whirl_prompt/src/builtins/mod.rs new file mode 100644 index 0000000..0359443 --- /dev/null +++ b/crates/whirl_prompt/src/builtins/mod.rs @@ -0,0 +1,108 @@ +// Copyleft (ɔ) 2021-2021 The Whirlsplash Collective +// SPDX-License-Identifier: GPL-3.0-only + +pub mod structures; + +use std::io::Write; + +use sysinfo::SystemExt; +use whirl_config::Config; + +use crate::constants::{FILES, HELPABLES_BUILTINS, HELPABLES_BUILTIN_CONFIG}; + +pub fn builtin_echo(args: &[String]) -> i32 { + println!("{}", args.join(" ")); + 0 +} + +pub fn builtin_history(history: &[String]) -> i32 { + for (index, cmd) in history.iter().enumerate() { + println!("{} {}", index, cmd.trim()); + } + 0 +} + +pub fn builtin_help() -> i32 { + for help in HELPABLES_BUILTINS.iter() { + println!("{}", help); + } + + 0 +} + +pub fn builtin_ls() -> i32 { + for file in &FILES { + print!("{} ", file); + } + println!(); + + 0 +} + +pub async fn builtin_cat(args: &[String]) -> i32 { + let file; + if let Some(file_name) = args.get(0) { + file = file_name.to_string(); + } else { + return 0; + }; + + match file.as_str() { + "README.rst" => { + let mut easy = curl::easy::Easy::new(); + + easy + .url("https://raw.githubusercontent.com/Whirlsplash/whirl/develop/README.rst") + .unwrap(); + + let mut transfer = easy.transfer(); + transfer + .write_function(|data| { + std::io::stdout().write_all(data).unwrap(); + Ok(data.len()) + }) + .unwrap(); + transfer.perform().unwrap(); + } + "Whirl.toml" => { + colour::red_ln!("NOTE: This is just a wrapper for `config show`."); + println!("{:#?}", Config::get()); + } + _ => println!("/cat: {}: no such file or directory", file), + } + + 0 +} + +pub fn builtin_config(args: &[String]) -> i32 { + match args.get(0) { + Some(sub) => + match sub.as_str() { + "show" => println!("{:#?}", Config::get()), + "help" | "--help" | "-h" => + for help in HELPABLES_BUILTIN_CONFIG.iter() { + println!("{}", help); + }, + "refresh" => Config::refresh(), + _ => println!("invalid arguments provided"), + }, + None => println!("invalid amount arguments provided"), + } + 0 +} + +pub fn builtin_fetch() -> i32 { + // rfetch: https://github.com/Mangeshrex/rfetch + + let mut sys = sysinfo::System::new(); + sys.refresh_processes(); + + println!(" "); + println!(" .-. os {}", env!("CARGO_PKG_NAME")); + println!(" oo| ker {}", env!("CARGO_PKG_VERSION")); + println!(" / '\\ sh /wsh"); + println!(" (\\_;/) up null"); + println!(" "); + + 0 +} diff --git a/crates/whirl_prompt/src/builtins/structures.rs b/crates/whirl_prompt/src/builtins/structures.rs new file mode 100644 index 0000000..4217a38 --- /dev/null +++ b/crates/whirl_prompt/src/builtins/structures.rs @@ -0,0 +1,34 @@ +// Copyleft (ɔ) 2021-2021 The Whirlsplash Collective +// SPDX-License-Identifier: GPL-3.0-only + +use std::str::FromStr; + +pub enum BuiltIn { + Echo, + History, + Exit, + Null, + Help, + Ls, + Cat, + Config, + Fetch, +} +impl FromStr for BuiltIn { + type Err = (); + + fn from_str(s: &str) -> Result<Self, Self::Err> { + match s { + "echo" => Ok(BuiltIn::Echo), + "history" => Ok(BuiltIn::History), + "exit" => Ok(BuiltIn::Exit), + "null" => Ok(BuiltIn::Null), + "help" => Ok(BuiltIn::Help), + "ls" => Ok(BuiltIn::Ls), + "cat" => Ok(BuiltIn::Cat), + "config" => Ok(BuiltIn::Config), + "fetch" => Ok(BuiltIn::Fetch), + _ => Err(()), + } + } +} diff --git a/crates/whirl_prompt/src/constants.rs b/crates/whirl_prompt/src/constants.rs new file mode 100644 index 0000000..c173a57 --- /dev/null +++ b/crates/whirl_prompt/src/constants.rs @@ -0,0 +1,19 @@ +// Copyleft (ɔ) 2021-2021 The Whirlsplash Collective +// SPDX-License-Identifier: GPL-3.0-only + +pub const FILES: [&str; 2] = ["README.rst", "Whirl.toml"]; +pub const HELPABLES_BUILTINS: [&str; 8] = [ + "cat - display the contents of a present file", + "config - manipulate the configuration", + "echo - display a line of predefined text", + "exit - end the process", + "fetch - a neofetch like utility loosely based on rfetch", + "help - you are here", + "history - display the command history", + "ls - display the present files", +]; +pub const HELPABLES_BUILTIN_CONFIG: [&str; 3] = [ + "help - you are here", + "refresh - reload the configuration file", + "show - display the current configuration", +]; diff --git a/crates/whirl_prompt/src/lib.rs b/crates/whirl_prompt/src/lib.rs new file mode 100644 index 0000000..32b247f --- /dev/null +++ b/crates/whirl_prompt/src/lib.rs @@ -0,0 +1,150 @@ +// Copyleft (ɔ) 2021-2021 The Whirlsplash Collective +// SPDX-License-Identifier: GPL-3.0-only + +#![feature( + type_ascription, + hash_set_entry, + type_name_of_val, + decl_macro, + proc_macro_hygiene +)] +#![warn(rust_2018_idioms)] +#![recursion_limit = "128"] + +mod builtins; +mod constants; +mod structure; + +use std::{io, io::Write, str::FromStr}; + +use whirl_config::Config; + +use crate::{ + builtins::{ + builtin_cat, + builtin_config, + builtin_echo, + builtin_fetch, + builtin_help, + builtin_history, + builtin_ls, + structures::BuiltIn, + }, + structure::Command, +}; + +pub struct Prompt { + history: Vec<String>, +} +impl Prompt { + pub async fn handle() -> ! { + let mut prompt = Prompt { + history: vec![] + }; + + loop { + Prompt::write_prompt(); + let command = prompt.read_command(); + prompt + .process_command(Prompt::tokenize_command(command)) + .await; + } + } + + fn write_prompt() { + print!("{} ", Config::get().whirlsplash.prompt.ps1); + io::stdout().flush().unwrap(); + } + + fn read_command(&mut self) -> String { + let mut input = String::new(); + io::stdin() + .read_line(&mut input) + .expect("failed to read command from stdin"); + + if input.len() <= 2 { + input = "null".to_string(); + } + + input + } + + fn tokenize_command(c: String) -> Command { + let mut command_split: Vec<String> = c.split_whitespace().map(|s| s.to_string()).collect(); + + Command { + keyword: command_split.remove(0), + args: command_split, + } + } + + // TODO: Find a way to make this access itself `history` doesn't have to be + // passed everytime. + async fn process_command(&mut self, c: Command) -> i32 { + let exit_code = match BuiltIn::from_str(&c.keyword) { + Ok(BuiltIn::Echo) => builtin_echo(&c.args), + Ok(BuiltIn::Exit) => std::process::exit(0), + Ok(BuiltIn::History) => builtin_history(&self.history), + Ok(BuiltIn::Null) => 0, + Ok(BuiltIn::Help) => builtin_help(), + Ok(BuiltIn::Ls) => builtin_ls(), + Ok(BuiltIn::Cat) => builtin_cat(&c.args).await, + Ok(BuiltIn::Config) => builtin_config(&c.args), + Ok(BuiltIn::Fetch) => builtin_fetch(), + _ => { + println!("wsh: command not found: {}", &c.keyword); + 1 + } + }; + + if c.keyword != "null" { + self.history.push(c.to_line()); + } + + exit_code + } +} + +#[cfg(test)] +mod tokenize_command { + use crate::Prompt; + + #[test] + #[ignore] + fn empty_command() { assert_eq!("", Prompt::tokenize_command("".to_string()).keyword) } + + #[test] + fn test_keyword() { assert_eq!("test", Prompt::tokenize_command("test".to_string()).keyword) } + + #[test] + fn no_arg() { assert_eq!(0, Prompt::tokenize_command("test".to_string()).args.len()) } + + #[test] + fn one_arg() { + assert_eq!( + 1, + Prompt::tokenize_command("test one".to_string()).args.len() + ) + } + + #[test] + fn multi_arg() { + assert_eq!( + 3, + Prompt::tokenize_command("test one two three".to_string()) + .args + .len() + ) + } + + #[test] + #[ignore] + fn quotes() { + assert_eq!( + 2, + Prompt::tokenize_command("test \"one two\" three".to_string()) + .args + .len() + ) + } +} diff --git a/crates/whirl_prompt/src/structure.rs b/crates/whirl_prompt/src/structure.rs new file mode 100644 index 0000000..4603d37 --- /dev/null +++ b/crates/whirl_prompt/src/structure.rs @@ -0,0 +1,10 @@ +// Copyleft (ɔ) 2021-2021 The Whirlsplash Collective +// SPDX-License-Identifier: GPL-3.0-only + +pub struct Command { + pub keyword: String, + pub args: Vec<String>, +} +impl Command { + pub fn to_line(&self) -> String { format!("{} {}", self.keyword, self.args.join(" ")) } +} |