formatting and more vscode settings
This commit is contained in:
parent
268b1ecc65
commit
587abe6f9a
4 changed files with 99 additions and 13 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -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.*
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
40
src/main.rs
40
src/main.rs
|
@ -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
29
src/tests.rs
Normal 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));
|
||||||
|
});
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue