Add setf and getf and garbage_collect_vars

This commit is contained in:
Arthur Beck 2025-05-05 07:27:53 -05:00
parent 09c5dfbc5e
commit 04671f7b6a
2 changed files with 63 additions and 2 deletions

View file

@ -8,7 +8,7 @@ pub const BUILTINS: [(
&str,
fn(args: Vec<String>, unsplit_args: String, state: &mut super::State) -> i32,
&str,
); 13] = [
); 15] = [
("cd", cd, "[dir]"),
("exit", exit, ""),
("echo", echo, "[-e] [text ...]"),
@ -21,7 +21,9 @@ pub const BUILTINS: [(
("dumpvars", dumpvars, ""),
("unset", unset, "var [var ...]"),
("copyf", copyf, ""),
("pastef", pastef, "")
("pastef", pastef, ""),
("setf", setf, "var [var ...]"),
("getf", getf, "var"),
];
/// Change the directory
@ -282,3 +284,40 @@ pub fn pastef(args: Vec<String>, _: String, state: &mut super::State) -> i32 {
unsafe { unreachable_unchecked(); }
}
}
/// Set a variable to the contents of the focus.
pub fn setf(args: Vec<String>, _: String, state: &mut super::State) -> i32 {
if args.len() < 2 {
println!("sesh: {}: at least one variable required", args[0]);
println!("sesh: {0}: usage: {0} var [var ...]", args[0]);
return 1;
}
for var in &args[1..] {
state.shell_env.push(super::ShellVar {
name: var.to_string(),
value: match &state.focus {
super::Focus::Str(s) => s.clone(),
super::Focus::Vec(_) => format!("{}", state.focus)
},
});
}
0
}
/// Set the focus to the contents of a variable
pub fn getf(args: Vec<String>, _: String, state: &mut super::State) -> i32 {
if args.len() != 2 {
println!("sesh: {}: exactly one variable required", args[0]);
println!("sesh: {0}: usage: {0} var", args[0]);
return 1;
}
let mut val = String::new();
for var in &state.shell_env {
if var.name == args[1].clone() {
val = var.value.clone();
break;
}
}
state.focus = super::Focus::Str(val);
0
}

View file

@ -207,6 +207,27 @@ fn substitute_vars(statement: &str, state: State) -> String {
out
}
/// remove duplicates, keeping later ones
fn garbage_collect_vars(state: &mut State) {
state.shell_env.reverse();
let mut seen = vec![];
let mut remove_indexes = vec![];
let mut i = 0usize;
for var in &mut state.shell_env {
if seen.contains(&var.name) {
remove_indexes.push(i);
i += 1;
continue;
}
seen.push(var.name.clone());
i += 1;
}
for i in remove_indexes {
state.shell_env.remove(i);
}
state.shell_env.sort_by(|v1, v2| v1.name.cmp(&v2.name));
}
#[allow(clippy::arc_with_non_send_sync)]
/// Evaluate a statement. May include multiple.
fn eval(statement: &str, state: &mut State) {
@ -237,6 +258,7 @@ fn eval(statement: &str, state: &mut State) {
let _ = writer.suspend_raw_mode();
}
let status = builtin.1(statement_split, statement.to_string(), state);
garbage_collect_vars(state);
if let Some(raw_term) = state.raw_term.clone() {
let writer = raw_term.write().unwrap();
let _ = writer.activate_raw_mode();