formatting and more vscode settings

This commit is contained in:
Arthur Beck 2025-05-05 14:34:44 -05:00
parent 268b1ecc65
commit 587abe6f9a
4 changed files with 99 additions and 13 deletions

3
.gitignore vendored
View file

@ -23,3 +23,6 @@ Cargo.lock
# ignore files used for testing stuff like loadf # ignore files used for testing stuff like loadf
/test* /test*
# benchmark files
dhat.out.*

View file

@ -8,7 +8,7 @@ pub const BUILTINS: [(
&str, &str,
fn(args: Vec<String>, unsplit_args: String, state: &mut super::State) -> i32, fn(args: Vec<String>, unsplit_args: String, state: &mut super::State) -> i32,
&str, &str,
); 15] = [ ); 17] = [
("cd", cd, "[dir]"), ("cd", cd, "[dir]"),
("exit", exit, ""), ("exit", exit, ""),
("echo", echo, "[-e] [text ...]"), ("echo", echo, "[-e] [text ...]"),
@ -24,6 +24,8 @@ pub const BUILTINS: [(
("pastef", pastef, ""), ("pastef", pastef, ""),
("setf", setf, "var [var ...]"), ("setf", setf, "var [var ...]"),
("getf", getf, "var"), ("getf", getf, "var"),
("()", nop, ""),
("if", _if, "condition ( statement ) [ ( else_statement )"),
]; ];
/// Change the directory /// Change the directory
@ -52,6 +54,10 @@ pub fn exit(_: Vec<String>, _: String, state: &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 {
if args.len() == 1 {
println!();
return 0;
}
unsplit_args = unsplit_args[(args[0].len() + 1)..].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();
@ -325,3 +331,35 @@ pub fn getf(args: Vec<String>, _: String, state: &mut super::State) -> i32 {
state.focus = super::Focus::Str(val); state.focus = super::Focus::Str(val);
0 0
} }
/// Empty function that does nothing. Mainly used for benchmarking evaluating.
pub fn nop(_: Vec<String>, _: String, _: &mut super::State) -> i32 {
0
}
/// if statement
pub fn _if(args: Vec<String>, _: String, state: &mut super::State) -> i32 {
if args.len() < 3 {
println!(
"sesh: {0}: usage: {0} condition (statement) [ (else_statement) ]",
args[0]
);
return 1;
}
super::eval(&args[1].clone(), state);
state.shell_env.reverse();
let mut status = 0i32;
for var in &state.shell_env {
if var.name == "STATUS" {
status = var.value.parse().unwrap();
}
}
state.shell_env.sort_by(|v1, v2| v1.name.cmp(&v2.name));
if status == 0 {
super::eval(&args[2].clone(), state);
} else if args.len() == 8 {
super::eval(&args[3].clone(), state);
}
0
}

View file

@ -3,6 +3,7 @@
#![warn(missing_docs, clippy::missing_docs_in_private_items)] #![warn(missing_docs, clippy::missing_docs_in_private_items)]
#![feature(cfg_match)] #![feature(cfg_match)]
#![feature(slice_concat_trait)] #![feature(slice_concat_trait)]
#![feature(test)]
use std::{ use std::{
ffi::OsStr, ffi::OsStr,
@ -17,6 +18,8 @@ use termion::raw::IntoRawMode;
mod builtins; mod builtins;
mod escapes; mod escapes;
#[cfg(test)]
mod tests;
/// sesh is a shell designed to be as semantic to use as possible /// sesh is a shell designed to be as semantic to use as possible
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
@ -85,8 +88,6 @@ impl Display for Focus {
struct State { struct State {
/// Shell-local variables only accessible via builtins. /// Shell-local variables only accessible via builtins.
shell_env: ShellVars, shell_env: ShellVars,
/// The previous history of the states.
history: Vec<State>,
/// Current working directory. /// Current working directory.
working_dir: PathBuf, working_dir: PathBuf,
/// A list of aliases from name to actual. /// A list of aliases from name to actual.
@ -103,20 +104,37 @@ unsafe impl Send for State {}
/// Split a statement. /// Split a statement.
fn split_statement(statement: &str) -> Vec<String> { fn split_statement(statement: &str) -> Vec<String> {
let mut out = vec![String::new()]; let mut out = vec![String::new()];
let mut i: usize = 0; let mut i = 0usize;
let mut in_str = (false, ' '); let mut in_str = (false, ' ');
let mut escape = false; let mut escape = false;
let mut f = 0usize;
for ch in statement.chars() { for ch in statement.chars() {
if ch == '\\' && !in_str.0 { if ch == '\\' && !in_str.0 {
escape = true; escape = true;
} }
if ['"', '\'', '`'].contains(&ch) && !escape { if in_str.0 && in_str.1 == ch {
if in_str.0 && in_str.1 == ch { in_str.0 = false;
in_str.0 = false if ch == ']' {
} else { out[i].push(ch);
in_str = (true, ch);
} }
escape = false; escape = false;
f += 1;
continue;
}
if !(!['"', '\'', '`', '(', '['].contains(&ch) || escape || in_str.0 || ch == '[' && f <= 1)
{
in_str = (true, ch);
if ch == '(' {
in_str.1 = ')';
}
if ch == '[' {
in_str.1 = ']';
}
if ch == '[' {
out[i].push(ch);
}
escape = false;
f += 1;
continue; continue;
} }
if !in_str.0 && ch == ' ' { if !in_str.0 && ch == ' ' {
@ -125,10 +143,12 @@ fn split_statement(statement: &str) -> Vec<String> {
out.push(String::new()); out.push(String::new());
} }
escape = false; escape = false;
f += 1;
continue; continue;
} }
out[i].push(ch); out[i].push(ch);
escape = false; escape = false;
f += 1;
} }
out.iter() out.iter()
.map(|v| v.trim().to_string()) .map(|v| v.trim().to_string())
@ -326,9 +346,6 @@ fn eval(statement: &str, state: &mut State) {
} }
} }
} }
let s = state.clone();
state.history.push(s);
} }
/// Write the prompt to the screen. /// Write the prompt to the screen.
@ -388,7 +405,6 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut state = State { let mut state = State {
shell_env: Vec::new(), shell_env: Vec::new(),
history: Vec::new(),
focus: Focus::Str(String::new()), focus: Focus::Str(String::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("/"))),

29
src/tests.rs Normal file
View file

@ -0,0 +1,29 @@
#![allow(clippy::unit_arg)]
extern crate test; // needed
use super::*;
#[bench]
pub fn bench_eval(bencher: &mut test::Bencher) {
bencher.iter(|| {
let mut state = State {
shell_env: Vec::new(),
focus: Focus::Str(String::new()),
working_dir: std::env::current_dir()
.unwrap_or(std::env::home_dir().unwrap_or(PathBuf::from("/"))),
aliases: Vec::new(),
raw_term: None,
};
state.shell_env.push(ShellVar {
name: "PROMPT1".to_string(),
value: "\x1b[32m$u@$h\x1b[39m \x1b[34m$P\x1b[39m> ".to_string(),
});
state.shell_env.push(ShellVar {
name: "PROMPT2".to_string(),
value: "> ".to_string(),
});
core::hint::black_box(eval("", &mut state));
core::hint::black_box(eval("()", &mut state));
core::hint::black_box(eval("echo", &mut state));
});
}