Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add shell aliases #357

Merged
merged 13 commits into from
Jun 26, 2022
Prev Previous commit
Next Next commit
Simplify arguments parsing
  • Loading branch information
vinc committed Jun 20, 2022
commit 0c9e10dc281694a03f863e119389f888c95c2b6a
23 changes: 17 additions & 6 deletions doc/shell.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
# MOROS Shell

## Config

The shell will read `/ini/shell.sh` during initialization to setup its
configuration.

## Commands

The main commands have a long name, a one-letter alias, and may have
additional common aliases.

<!--
**Alias** command:

> alias d delete

<!--
**Append** to file:

> a a.txt
@@ -130,20 +135,26 @@ Which is more efficient than doing:

Setting a variable in the shell environment is done with the following command:

> foo = "world"
> set foo 42

And accessing that variable is done with the `$` operator:
> set bar "Alice and Bob"

And accessing a variable is done with the `$` operator:

> print $foo
world
42

> print "hello $foo"
hello world
> print "Hello $bar"
Hello Alice and Bob

The process environment is copied to the shell environment when a session is
started. By convention a process env var should be in uppercase and a shell
env var should be lowercase.

Unsetting a variable is done like this:

> unset foo

## Globbing

MOROS Shell support filename expansion or globbing for `*` and `?` wildcard
52 changes: 28 additions & 24 deletions dsk/ini/shell.sh
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
alias p=print
alias c=copy
alias d=delete
alias del=delete
alias e=edit
alias f=find
alias g=goto
alias go=goto
alias h=help
alias l=list
alias m=move
alias q=quit
alias exit=quit
alias r=read
alias w=write
alias sh=shell
alias dsk=disk
alias mem=memory
alias kbd=keyboard
# alias cd=goto
# alias rm=delete
# alias ls=list
# alias cp=copy
# alias mv=move
# Command shortcuts
alias p print
alias c copy
alias d delete
alias del delete
alias e edit
alias f find
alias g goto
alias go goto
alias h help
alias l list
alias m move
alias q quit
alias exit quit
alias r read
alias w write
alias sh shell
alias dsk disk
alias mem memory
alias kbd keyboard

# Unix compatibility
# alias cd goto
# alias cp copy
# alias echo print
# alias ls list
# alias mv move
# alias rm delete
34 changes: 21 additions & 13 deletions src/usr/env.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
use crate::{sys, usr};

pub fn main(args: &[&str]) -> usr::shell::ExitCode {
if args.len() == 1 {
for (key, val) in sys::process::envs() {
println!("{}={}", key, val);
match args.len() {
1 => {
for (key, val) in sys::process::envs() {
println!("{:10} \"{}\"", key, val);
}
usr::shell::ExitCode::CommandSuccessful
}
} else {
for arg in args[1..].iter() {
if let Some(i) = arg.find('=') {
let (key, mut val) = arg.split_at(i);
val = &val[1..];
sys::process::set_env(key, val);
println!("{}={}", key, val);
2 => {
let key = args[1];
if let Some(val) = sys::process::env(key) {
println!("{}", val);
usr::shell::ExitCode::CommandSuccessful
} else {
error!("Could not parse '{}'", arg);
return usr::shell::ExitCode::CommandError;
error!("Could not get '{}'", key);
usr::shell::ExitCode::CommandError
}
}
3 => {
sys::process::set_env(args[1], args[2]);
usr::shell::ExitCode::CommandSuccessful
}
_ => {
error!("Invalid number of arguments");
usr::shell::ExitCode::CommandError
}
}
usr::shell::ExitCode::CommandSuccessful
}
120 changes: 41 additions & 79 deletions src/usr/shell.rs
Original file line number Diff line number Diff line change
@@ -41,34 +41,6 @@ impl Config {
env.insert(key, val); // Copy the process environment to the shell environment
}
env.insert("DIR".to_string(), sys::process::dir());
/*
let mut aliases = BTreeMap::new();
aliases.insert("p".to_string(), "print".to_string());
aliases.insert("c".to_string(), "copy".to_string());
aliases.insert("d".to_string(), "delete".to_string());
aliases.insert("del".to_string(), "delete".to_string());
aliases.insert("e".to_string(), "edit".to_string());
aliases.insert("f".to_string(), "find".to_string());
aliases.insert("g".to_string(), "goto".to_string());
aliases.insert("go".to_string(), "goto".to_string());
aliases.insert("h".to_string(), "help".to_string());
aliases.insert("l".to_string(), "list".to_string());
aliases.insert("m".to_string(), "move".to_string());
aliases.insert("q".to_string(), "quit".to_string());
aliases.insert("exit".to_string(), "quit".to_string());
aliases.insert("r".to_string(), "read".to_string());
aliases.insert("w".to_string(), "write".to_string());
aliases.insert("sh".to_string(), "shell".to_string());
aliases.insert("dsk".to_string(), "disk".to_string());
aliases.insert("mem".to_string(), "memory".to_string());
aliases.insert("kbd".to_string(), "keyboard".to_string());
//aliases.insert("cd".to_string(), "goto".to_string());
//aliases.insert("rm".to_string(), "delete".to_string());
//aliases.insert("ls".to_string(), "list".to_string());
//aliases.insert("cp".to_string(), "copy".to_string());
//aliases.insert("mv".to_string(), "move".to_string());
*/

Config { env, aliases }
}
}
@@ -281,64 +253,61 @@ fn cmd_change_dir(args: &[&str], config: &mut Config) -> ExitCode {
}

fn cmd_alias(args: &[&str], config: &mut Config) -> ExitCode {
let csi_option = Style::color("LightCyan");
let csi_title = Style::color("Yellow");
let csi_reset = Style::reset();
if args.len() == 1 {
println!("{}Usage:{} alias {}<key>=<val>{1}", csi_title, csi_reset, csi_option);
if args.len() != 3 {
let csi_option = Style::color("LightCyan");
let csi_title = Style::color("Yellow");
let csi_reset = Style::reset();
println!("{}Usage:{} alias {}<key> <val>{1}", csi_title, csi_reset, csi_option);
return usr::shell::ExitCode::CommandError;
}
config.aliases.insert(args[1].to_string(), args[2].to_string());
ExitCode::CommandSuccessful
}

fn cmd_unalias(args: &[&str], config: &mut Config) -> ExitCode {
if args.len() != 2 {
let csi_option = Style::color("LightCyan");
let csi_title = Style::color("Yellow");
let csi_reset = Style::reset();
println!("{}Usage:{} unalias {}<key>{1}", csi_title, csi_reset, csi_option);
return usr::shell::ExitCode::CommandError;
}

if config.aliases.remove(&args[1].to_string()).is_none() {
error!("Error: could not unalias '{}'", args[1]);
return usr::shell::ExitCode::CommandError;
} else {
for arg in args[1..].iter() {
if let Some(i) = arg.find('=') {
let (key, mut val) = arg.split_at(i);
val = &val[1..];
config.aliases.insert(key.to_string(), val.to_string());
} else {
error!("Error: could not parse '{}'", arg);
return usr::shell::ExitCode::CommandError;
}
}
}

ExitCode::CommandSuccessful
}

fn cmd_set(args: &[&str], config: &mut Config) -> ExitCode {
let csi_option = Style::color("LightCyan");
let csi_title = Style::color("Yellow");
let csi_reset = Style::reset();
if args.len() == 1 {
println!("{}Usage:{} set {}<key>=<val>{1}", csi_title, csi_reset, csi_option);
if args.len() != 3 {
let csi_option = Style::color("LightCyan");
let csi_title = Style::color("Yellow");
let csi_reset = Style::reset();
println!("{}Usage:{} set {}<key> <val>{1}", csi_title, csi_reset, csi_option);
return usr::shell::ExitCode::CommandError;
} else {
for arg in args[1..].iter() {
if let Some(i) = arg.find('=') {
let (key, mut val) = arg.split_at(i);
val = &val[1..];
config.env.insert(key.to_string(), val.to_string());
} else {
error!("Error: could not parse '{}'", arg);
return usr::shell::ExitCode::CommandError;
}
}
}

config.env.insert(args[1].to_string(), args[2].to_string());
ExitCode::CommandSuccessful
}

fn cmd_unset(args: &[&str], config: &mut Config) -> ExitCode {
let csi_option = Style::color("LightCyan");
let csi_title = Style::color("Yellow");
let csi_reset = Style::reset();
if args.len() == 1 {
if args.len() != 2 {
let csi_option = Style::color("LightCyan");
let csi_title = Style::color("Yellow");
let csi_reset = Style::reset();
println!("{}Usage:{} unset {}<key>{1}", csi_title, csi_reset, csi_option);
return usr::shell::ExitCode::CommandError;
} else {
for arg in args[1..].iter() {
if config.env.remove(&arg.to_string()).is_none() {
error!("Error: could not unset '{}'", arg);
return usr::shell::ExitCode::CommandError;
}
}
}

if config.env.remove(&args[1].to_string()).is_none() {
error!("Error: could not unset '{}'", args[1]);
return usr::shell::ExitCode::CommandError;
}

ExitCode::CommandSuccessful
}

@@ -353,14 +322,6 @@ fn exec_with_config(cmd: &str, config: &mut Config) -> ExitCode {
cmd = cmd.replace(&format!("${}", key), &val);
}

// Set env var like `foo=42` or `bar = "Hello, World!"
if Regex::new("^\\w+ *= *\\S").is_match(&cmd) {
let i = cmd.find('=').unwrap();
let (key, mut val) = cmd.split_at(i);
val = &val[1..];
cmd = format!("set \"{}={}\"", key.trim(), val.trim().trim_matches('"'));
}

let mut args = split_args(&cmd);

// Replace command alias
@@ -468,6 +429,7 @@ fn exec_with_config(cmd: &str, config: &mut Config) -> ExitCode {
"socket" => usr::socket::main(&args),
"tcp" => usr::tcp::main(&args),
"time" => usr::time::main(&args),
"unalias" => cmd_unalias(&args, config),
"unset" => cmd_unset(&args, config),
"user" => usr::user::main(&args),
"vga" => usr::vga::main(&args),