From 2bb2c69269a494f38d1a206f6748fdf6cc8cc152 Mon Sep 17 00:00:00 2001 From: Arthur Beck Date: Fri, 2 May 2025 17:30:14 -0500 Subject: [PATCH 1/2] Implement man page generation --- build.rs | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/build.rs b/build.rs index 0e00e07..4b9ff10 100644 --- a/build.rs +++ b/build.rs @@ -1,4 +1,6 @@ +#![allow(unused_imports)] use roff::{Roff, bold, italic, roman}; +use std::{env, path::PathBuf}; fn main() { let page = Roff::new() @@ -6,27 +8,23 @@ fn main() { .control("SH", ["NAME"]) .text([roman("sesh - Semantic Shell")]) .control("SH", ["SYNOPSIS"]) - .text([ - bold("sesh"), - roman(" [options]"), - ]) + .text([bold("sesh"), roman(" [options]")]) .control("SH", ["DESCRIPTION"]) .text([ bold("sesh"), roman("is a shell designed to be as semantic to use as possible"), ]) - .control("SH", ["OPTIONS"]) - .control("TP", []) - .text([ - bold("-n"), - roman(", "), - bold("--bits"), - roman("="), - italic("BITS"), - ]) - .text([roman( - "Set the number of bits to modify. Default is one bit.", - )]) .render(); - print!("{}", page); + std::fs::write( + PathBuf::from(env::var_os("OUT_DIR").unwrap()) + .parent() + .unwrap() + .parent() + .unwrap() + .parent() + .unwrap() + .join("sesh.1"), + page, + ) + .unwrap(); } From fdfddec5765a83e3b3008d27dcb0879efd0cebd8 Mon Sep 17 00:00:00 2001 From: Arthur Beck Date: Fri, 2 May 2025 17:30:25 -0500 Subject: [PATCH 2/2] Add aliases --- src/builtins.rs | 33 +++++++++++++++++++++++++++++++-- src/main.rs | 30 +++++++++++++++++++++++++++--- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/src/builtins.rs b/src/builtins.rs index b1a5de2..3174d3c 100644 --- a/src/builtins.rs +++ b/src/builtins.rs @@ -2,7 +2,10 @@ #![allow(clippy::type_complexity)] /// List of builtins -pub const BUILTINS: [(&str, fn (args: Vec, unsplit_args: String, state: &mut super::State) -> i32); 3] = [("cd", cd), ("exit", exit), ("echo", echo)]; +pub const BUILTINS: [( + &str, + fn(args: Vec, unsplit_args: String, state: &mut super::State) -> i32, +); 4] = [("cd", cd), ("exit", exit), ("echo", echo), ("alias", alias)]; /// Change the directory pub fn cd(args: Vec, _: String, state: &mut super::State) -> i32 { @@ -25,7 +28,7 @@ pub fn exit(_: Vec, _: String, _: &mut super::State) -> i32 { /// Echo a string pub fn echo(args: Vec, mut unsplit_args: String, _: &mut super::State) -> i32 { - unsplit_args = unsplit_args[5..].to_string(); + unsplit_args = unsplit_args[(args[0].len() + 1)..].to_string(); if args.len() != 1 && args[1] == "-e" { unsplit_args = unsplit_args[3..].to_string(); let escaped = crate::escapes::interpret_escaped_string(&unsplit_args); @@ -38,3 +41,29 @@ pub fn echo(args: Vec, mut unsplit_args: String, _: &mut super::State) - println!("{}", unsplit_args); 0 } + +/// Add an alias +pub fn alias(args: Vec, _: String, state: &mut super::State) -> i32 { + if args.len() == 1 { + for alias in &state.aliases { + println!("`{}`: `{}`", alias.name, alias.to); + } + return 0; + } + if args.len() == 2 { + for alias in &state.aliases { + if alias.name != args[1] { + continue; + } + println!("`{}`: `{}`", alias.name, alias.to); + } + return 0; + } + + state.aliases.push(super::Alias { + name: args[1].clone(), + to: args[2].clone(), + }); + + 0 +} diff --git a/src/main.rs b/src/main.rs index 3174965..584e1e7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -48,6 +48,14 @@ enum Variable { Nonlocal(OsString), } +/// A single alias +#[derive(Clone, Debug, PartialEq, Eq)] +struct Alias { + /// alias from + name: String, + /// to + to: String +} /// The state of the shell #[derive(Clone, Debug)] struct State { @@ -61,6 +69,8 @@ struct State { history: Vec, /// Current working directory. working_dir: PathBuf, + /// A list of aliases from name to actual + aliases: Vec } unsafe impl Sync for State {} @@ -160,13 +170,26 @@ fn eval(statement: &str, state: &mut State) { let statements = split_statements(&statement); for statement in statements { - let statement_split = split_statement(&statement); + let mut statement_split = split_statement(&statement); if statement.is_empty() || statement_split[0].is_empty() { continue; } + let mut program_name = statement_split[0].clone(); + + for alias in &state.aliases { + if program_name == alias.name { + let to_split = split_statement(&alias.to); + for (i, item) in to_split[1..].iter().enumerate() { + statement_split.insert(i+1, (*item).clone()); + } + program_name = to_split[0].clone(); + continue; + } + } + if let Some(builtin) = builtins::BUILTINS .iter() - .find(|v| v.0 == statement_split[0]) + .find(|v| v.0 == program_name) { let status = builtin.1(statement_split, statement.to_string(), state); for (i, var) in state.shell_env.clone().into_iter().enumerate() { @@ -181,7 +204,7 @@ fn eval(statement: &str, state: &mut State) { }); continue; } - match std::process::Command::new(statement_split[0].clone()) + match std::process::Command::new(program_name.clone()) .args(&statement_split[1..]) .current_dir(state.working_dir.clone()) .spawn() @@ -258,6 +281,7 @@ fn main() -> Result<(), Box> { history: Vec::new(), working_dir: std::env::current_dir() .unwrap_or(std::env::home_dir().unwrap_or(PathBuf::from("/"))), + aliases: Vec::new(), }; state.shell_env.push(ShellVar { name: "PROMPT1".to_string(),