Compare commits
2 commits
b7c8dc3fba
...
fdfddec576
Author | SHA1 | Date | |
---|---|---|---|
fdfddec576 | |||
2bb2c69269 |
3 changed files with 73 additions and 22 deletions
32
build.rs
32
build.rs
|
@ -1,4 +1,6 @@
|
||||||
|
#![allow(unused_imports)]
|
||||||
use roff::{Roff, bold, italic, roman};
|
use roff::{Roff, bold, italic, roman};
|
||||||
|
use std::{env, path::PathBuf};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let page = Roff::new()
|
let page = Roff::new()
|
||||||
|
@ -6,27 +8,23 @@ fn main() {
|
||||||
.control("SH", ["NAME"])
|
.control("SH", ["NAME"])
|
||||||
.text([roman("sesh - Semantic Shell")])
|
.text([roman("sesh - Semantic Shell")])
|
||||||
.control("SH", ["SYNOPSIS"])
|
.control("SH", ["SYNOPSIS"])
|
||||||
.text([
|
.text([bold("sesh"), roman(" [options]")])
|
||||||
bold("sesh"),
|
|
||||||
roman(" [options]"),
|
|
||||||
])
|
|
||||||
.control("SH", ["DESCRIPTION"])
|
.control("SH", ["DESCRIPTION"])
|
||||||
.text([
|
.text([
|
||||||
bold("sesh"),
|
bold("sesh"),
|
||||||
roman("is a shell designed to be as semantic to use as possible"),
|
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();
|
.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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,10 @@
|
||||||
#![allow(clippy::type_complexity)]
|
#![allow(clippy::type_complexity)]
|
||||||
|
|
||||||
/// List of builtins
|
/// 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
|
/// Change the directory
|
||||||
pub fn cd(args: Vec<String>, _: String, state: &mut super::State) -> i32 {
|
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
|
/// Echo a string
|
||||||
pub fn echo(args: Vec<String>, mut unsplit_args: String, _: &mut super::State) -> i32 {
|
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" {
|
if args.len() != 1 && args[1] == "-e" {
|
||||||
unsplit_args = unsplit_args[3..].to_string();
|
unsplit_args = unsplit_args[3..].to_string();
|
||||||
let escaped = crate::escapes::interpret_escaped_string(&unsplit_args);
|
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);
|
println!("{}", unsplit_args);
|
||||||
0
|
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
|
||||||
|
}
|
||||||
|
|
30
src/main.rs
30
src/main.rs
|
@ -48,6 +48,14 @@ enum Variable {
|
||||||
Nonlocal(OsString),
|
Nonlocal(OsString),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A single alias
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
struct Alias {
|
||||||
|
/// alias from
|
||||||
|
name: String,
|
||||||
|
/// to
|
||||||
|
to: String
|
||||||
|
}
|
||||||
/// The state of the shell
|
/// The state of the shell
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
struct State {
|
struct State {
|
||||||
|
@ -61,6 +69,8 @@ struct State {
|
||||||
history: Vec<State>,
|
history: Vec<State>,
|
||||||
/// Current working directory.
|
/// Current working directory.
|
||||||
working_dir: PathBuf,
|
working_dir: PathBuf,
|
||||||
|
/// A list of aliases from name to actual
|
||||||
|
aliases: Vec<Alias>
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Sync for State {}
|
unsafe impl Sync for State {}
|
||||||
|
@ -160,13 +170,26 @@ fn eval(statement: &str, state: &mut State) {
|
||||||
let statements = split_statements(&statement);
|
let statements = split_statements(&statement);
|
||||||
|
|
||||||
for statement in statements {
|
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() {
|
if statement.is_empty() || statement_split[0].is_empty() {
|
||||||
continue;
|
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
|
if let Some(builtin) = builtins::BUILTINS
|
||||||
.iter()
|
.iter()
|
||||||
.find(|v| v.0 == statement_split[0])
|
.find(|v| v.0 == program_name)
|
||||||
{
|
{
|
||||||
let status = builtin.1(statement_split, statement.to_string(), state);
|
let status = builtin.1(statement_split, statement.to_string(), state);
|
||||||
for (i, var) in state.shell_env.clone().into_iter().enumerate() {
|
for (i, var) in state.shell_env.clone().into_iter().enumerate() {
|
||||||
|
@ -181,7 +204,7 @@ fn eval(statement: &str, state: &mut State) {
|
||||||
});
|
});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
match std::process::Command::new(statement_split[0].clone())
|
match std::process::Command::new(program_name.clone())
|
||||||
.args(&statement_split[1..])
|
.args(&statement_split[1..])
|
||||||
.current_dir(state.working_dir.clone())
|
.current_dir(state.working_dir.clone())
|
||||||
.spawn()
|
.spawn()
|
||||||
|
@ -258,6 +281,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
history: Vec::new(),
|
history: Vec::new(),
|
||||||
working_dir: std::env::current_dir()
|
working_dir: std::env::current_dir()
|
||||||
.unwrap_or(std::env::home_dir().unwrap_or(PathBuf::from("/"))),
|
.unwrap_or(std::env::home_dir().unwrap_or(PathBuf::from("/"))),
|
||||||
|
aliases: Vec::new(),
|
||||||
};
|
};
|
||||||
state.shell_env.push(ShellVar {
|
state.shell_env.push(ShellVar {
|
||||||
name: "PROMPT1".to_string(),
|
name: "PROMPT1".to_string(),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue