Compare commits

..

2 commits

Author SHA1 Message Date
fdfddec576
Add aliases 2025-05-02 17:30:25 -05:00
2bb2c69269
Implement man page generation 2025-05-02 17:30:14 -05:00
3 changed files with 73 additions and 22 deletions

View file

@ -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();
}

View file

@ -2,7 +2,10 @@
#![allow(clippy::type_complexity)]
/// List of builtins
pub const BUILTINS: [(&str, fn (args: Vec<String>, unsplit_args: String, state: &mut super::State) -> i32); 3] = [("cd", cd), ("exit", exit), ("echo", echo)];
pub const BUILTINS: [(
&str,
fn(args: Vec<String>, 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>, _: String, state: &mut super::State) -> i32 {
@ -25,7 +28,7 @@ pub fn exit(_: Vec<String>, _: String, _: &mut super::State) -> i32 {
/// Echo a string
pub fn echo(args: Vec<String>, 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<String>, mut unsplit_args: String, _: &mut super::State) -
println!("{}", unsplit_args);
0
}
/// Add an alias
pub fn alias(args: Vec<String>, _: 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
}

View file

@ -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<State>,
/// Current working directory.
working_dir: PathBuf,
/// A list of aliases from name to actual
aliases: Vec<Alias>
}
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<dyn std::error::Error>> {
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(),