Merge branch 'better-env-print' into 'main'
usability improvements to env and def See merge request whom/relish!2
This commit is contained in:
commit
91ad4eed12
7 changed files with 309 additions and 131 deletions
|
|
@ -16,3 +16,5 @@ nix = "0.26.2"
|
||||||
# string escaping in the lexer
|
# string escaping in the lexer
|
||||||
phf = { version = "0.11", default-features = false, features = ["macros"] }
|
phf = { version = "0.11", default-features = false, features = ["macros"] }
|
||||||
libc = "0.2.144"
|
libc = "0.2.144"
|
||||||
|
# used by main shell to update consol dimensions
|
||||||
|
termion = "2.0.1"
|
||||||
|
|
|
||||||
10
Readme.org
10
Readme.org
|
|
@ -488,12 +488,18 @@ Note: this section will not show the status of each item unless you are viewing
|
||||||
Note: this section only tracks the state of incomplete TODO items. Having everything on here would be cluttered.
|
Note: this section only tracks the state of incomplete TODO items. Having everything on here would be cluttered.
|
||||||
|
|
||||||
** TODO alpha tasks
|
** TODO alpha tasks
|
||||||
- env prints without using columns
|
|
||||||
- lambdas shouldn't hit the env
|
|
||||||
- circuit should actually be ~(reduce (lambda (form state) (and state (bool form))) my-args)~
|
- circuit should actually be ~(reduce (lambda (form state) (and state (bool form))) my-args)~
|
||||||
- error display must improve at all costs
|
- error display must improve at all costs
|
||||||
|
- exit function (causes program to shut down and return code)
|
||||||
|
- probably push the symtable inserts into functions in individual stl modules (like posix.rs does)
|
||||||
|
- fix the links in the readme like the ones in shell.org
|
||||||
|
|
||||||
** TODO v1.0 tasks
|
** TODO v1.0 tasks
|
||||||
|
- Be able to use features to compile without env or posix stuff
|
||||||
|
- add a new binary target that is a simple posix repl demo
|
||||||
|
- I think you'll need to refactor userlib to hide set behind a conditional
|
||||||
|
based on whether CFG_RELISH_POSIX is set or not
|
||||||
|
- add a compilation task to CI
|
||||||
- finish basic goals in file:snippets/interactive-devel.rls
|
- finish basic goals in file:snippets/interactive-devel.rls
|
||||||
- Investigate has_next member function for &Seg and maybe simplify stdlib and probably also eval/sym
|
- Investigate has_next member function for &Seg and maybe simplify stdlib and probably also eval/sym
|
||||||
- Rename to Flesh
|
- Rename to Flesh
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,13 @@ use {
|
||||||
relish::{
|
relish::{
|
||||||
ast::{
|
ast::{
|
||||||
eval, lex, run,
|
eval, lex, run,
|
||||||
Ctr, Seg, SymTable,
|
Ctr, Seg, SymTable, Symbol,
|
||||||
load_defaults, load_environment
|
|
||||||
},
|
},
|
||||||
stdlib::{
|
stdlib::{
|
||||||
static_stdlib, dynamic_stdlib
|
static_stdlib, dynamic_stdlib, load_defaults,
|
||||||
|
load_environment,
|
||||||
|
CONSOLE_XDIM_VNAME, CONSOLE_YDIM_VNAME, CFG_FILE_VNAME,
|
||||||
|
L_PROMPT_VNAME, R_PROMPT_VNAME, PROMPT_DELIM_VNAME,
|
||||||
},
|
},
|
||||||
aux::{ShellState, check_jobs},
|
aux::{ShellState, check_jobs},
|
||||||
},
|
},
|
||||||
|
|
@ -46,6 +48,7 @@ use {
|
||||||
nix::unistd,
|
nix::unistd,
|
||||||
nu_ansi_term::{Color, Style},
|
nu_ansi_term::{Color, Style},
|
||||||
dirs::home_dir,
|
dirs::home_dir,
|
||||||
|
termion::terminal_size,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
@ -252,7 +255,7 @@ fn main() {
|
||||||
// this is a user shell. attempt to load configuration
|
// this is a user shell. attempt to load configuration
|
||||||
{
|
{
|
||||||
// scope the below borrow of syms
|
// scope the below borrow of syms
|
||||||
let cfg_file = env::var("RELISH_CFG_FILE").unwrap_or(cfg_file_name);
|
let cfg_file = env::var(CFG_FILE_VNAME).unwrap_or(cfg_file_name);
|
||||||
run(cfg_file.clone(), &mut syms)
|
run(cfg_file.clone(), &mut syms)
|
||||||
.unwrap_or_else(|err: String| eprintln!("failed to load script {}\n{}", cfg_file, err));
|
.unwrap_or_else(|err: String| eprintln!("failed to load script {}\n{}", cfg_file, err));
|
||||||
}
|
}
|
||||||
|
|
@ -284,8 +287,11 @@ fn main() {
|
||||||
.with_style(Style::new().italic().fg(Color::LightGray)),
|
.with_style(Style::new().italic().fg(Color::LightGray)),
|
||||||
)).with_validator(Box::new(DefaultValidator));
|
)).with_validator(Box::new(DefaultValidator));
|
||||||
|
|
||||||
|
let mut xdimension: u16 = 0;
|
||||||
|
let mut ydimension: u16 = 0;
|
||||||
loop {
|
loop {
|
||||||
{
|
{
|
||||||
|
// update state
|
||||||
check_jobs(&mut prompt_ss.borrow_mut());
|
check_jobs(&mut prompt_ss.borrow_mut());
|
||||||
}
|
}
|
||||||
let readline_prompt = make_prompt(&mut syms);
|
let readline_prompt = make_prompt(&mut syms);
|
||||||
|
|
@ -293,6 +299,11 @@ fn main() {
|
||||||
// realloc with each loop because syms can change
|
// realloc with each loop because syms can change
|
||||||
rl = rl.with_completer(Box::new(completer));
|
rl = rl.with_completer(Box::new(completer));
|
||||||
let user_doc = rl.read_line(&readline_prompt).unwrap();
|
let user_doc = rl.read_line(&readline_prompt).unwrap();
|
||||||
|
|
||||||
|
// doing this update here prevents needing to update twice before dimensions take effect
|
||||||
|
(xdimension, ydimension) =
|
||||||
|
check_and_update_console_dimensions(&mut syms, xdimension, ydimension);
|
||||||
|
|
||||||
match user_doc {
|
match user_doc {
|
||||||
Signal::Success(line) => {
|
Signal::Success(line) => {
|
||||||
println!(""); // add a new line before output gets printed
|
println!(""); // add a new line before output gets printed
|
||||||
|
|
@ -320,19 +331,19 @@ fn main() {
|
||||||
|
|
||||||
fn make_prompt(syms: &mut SymTable) -> CustomPrompt {
|
fn make_prompt(syms: &mut SymTable) -> CustomPrompt {
|
||||||
let l_ctr = *syms
|
let l_ctr = *syms
|
||||||
.call_symbol(&"CFG_RELISH_L_PROMPT".to_string(), &Seg::new(), true)
|
.call_symbol(&L_PROMPT_VNAME.to_string(), &Seg::new(), true)
|
||||||
.unwrap_or_else(|err: String| {
|
.unwrap_or_else(|err: String| {
|
||||||
eprintln!("{}", err);
|
eprintln!("{}", err);
|
||||||
Box::new(Ctr::String("<prompt broken!>".to_string()))
|
Box::new(Ctr::String("<prompt broken!>".to_string()))
|
||||||
});
|
});
|
||||||
let r_ctr = *syms
|
let r_ctr = *syms
|
||||||
.call_symbol(&"CFG_RELISH_R_PROMPT".to_string(), &Seg::new(), true)
|
.call_symbol(&R_PROMPT_VNAME.to_string(), &Seg::new(), true)
|
||||||
.unwrap_or_else(|err: String| {
|
.unwrap_or_else(|err: String| {
|
||||||
eprintln!("{}", err);
|
eprintln!("{}", err);
|
||||||
Box::new(Ctr::String("<prompt broken!>".to_string()))
|
Box::new(Ctr::String("<prompt broken!>".to_string()))
|
||||||
});
|
});
|
||||||
let d_ctr = *syms
|
let d_ctr = *syms
|
||||||
.call_symbol(&"CFG_RELISH_PROMPT_DELIMITER".to_string(), &Seg::new(), true)
|
.call_symbol(&PROMPT_DELIM_VNAME.to_string(), &Seg::new(), true)
|
||||||
.unwrap_or_else(|err: String| {
|
.unwrap_or_else(|err: String| {
|
||||||
eprintln!("{}", err);
|
eprintln!("{}", err);
|
||||||
Box::new(Ctr::String("<prompt broken!>".to_string()))
|
Box::new(Ctr::String("<prompt broken!>".to_string()))
|
||||||
|
|
@ -397,3 +408,47 @@ fn get_token_to_complete(line: &str, pos: usize) -> (String, bool, usize) {
|
||||||
|
|
||||||
return (res, is_str, start_idx)
|
return (res, is_str, start_idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* It was considered that a SIGWINCH handler would be a more
|
||||||
|
* elegant solution to this. Such a solution would need to
|
||||||
|
* modify the current libc based approach to use a state-enclosing
|
||||||
|
* closure as a signal handler. As of May 2023 there is no clear
|
||||||
|
* way of doing such a thing.
|
||||||
|
*
|
||||||
|
* Luckily this data is only used within Relish, so we can simply
|
||||||
|
* rely on it only being read during the evaluation phase of the REPL.
|
||||||
|
* This method will at least work for that. (ava)
|
||||||
|
*/
|
||||||
|
fn check_and_update_console_dimensions(
|
||||||
|
syms: &mut SymTable,
|
||||||
|
last_xdim: u16,
|
||||||
|
last_ydim: u16
|
||||||
|
) -> (u16, u16) {
|
||||||
|
let (xdim, ydim) = terminal_size().expect("Couldnt get console dimensions");
|
||||||
|
|
||||||
|
if xdim != last_xdim {
|
||||||
|
syms.insert(
|
||||||
|
String::from(CONSOLE_XDIM_VNAME),
|
||||||
|
Symbol::from_ast(
|
||||||
|
&String::from(CONSOLE_XDIM_VNAME),
|
||||||
|
&String::from("Length of current console"),
|
||||||
|
&Seg::from_mono(Box::new(Ctr::Integer(xdim.into()))),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ydim != last_ydim {
|
||||||
|
syms.insert(
|
||||||
|
String::from(CONSOLE_YDIM_VNAME),
|
||||||
|
Symbol::from_ast(
|
||||||
|
&String::from(CONSOLE_YDIM_VNAME),
|
||||||
|
&String::from("Height of current console"),
|
||||||
|
&Seg::from_mono(Box::new(Ctr::Integer(ydim.into()))),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
(xdim, ydim)
|
||||||
|
}
|
||||||
|
|
|
||||||
18
src/lib.rs
18
src/lib.rs
|
|
@ -23,7 +23,7 @@ mod stl;
|
||||||
mod sym;
|
mod sym;
|
||||||
|
|
||||||
pub mod ast {
|
pub mod ast {
|
||||||
pub use crate::run::{run, load_defaults, load_environment};
|
pub use crate::run::run;
|
||||||
pub use crate::eval::eval;
|
pub use crate::eval::eval;
|
||||||
pub use crate::lex::lex;
|
pub use crate::lex::lex;
|
||||||
pub use crate::segment::{Ctr, Seg, Type};
|
pub use crate::segment::{Ctr, Seg, Type};
|
||||||
|
|
@ -31,7 +31,21 @@ pub mod ast {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod stdlib {
|
pub mod stdlib {
|
||||||
pub use crate::stl::{dynamic_stdlib, static_stdlib};
|
pub use crate::stl::{};
|
||||||
|
pub use crate::stl::{
|
||||||
|
dynamic_stdlib, static_stdlib,
|
||||||
|
load_defaults, load_environment,
|
||||||
|
CONSOLE_XDIM_VNAME,
|
||||||
|
CONSOLE_YDIM_VNAME,
|
||||||
|
POSIX_CFG_VNAME,
|
||||||
|
MODENV_CFG_VNAME,
|
||||||
|
L_PROMPT_VNAME,
|
||||||
|
R_PROMPT_VNAME,
|
||||||
|
PROMPT_DELIM_VNAME,
|
||||||
|
CFG_FILE_VNAME,
|
||||||
|
RELISH_DEFAULT_CONS_HEIGHT,
|
||||||
|
RELISH_DEFAULT_CONS_WIDTH,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod aux {
|
pub mod aux {
|
||||||
|
|
|
||||||
108
src/run.rs
108
src/run.rs
|
|
@ -18,24 +18,11 @@
|
||||||
use crate::eval::eval;
|
use crate::eval::eval;
|
||||||
use crate::lex::lex;
|
use crate::lex::lex;
|
||||||
use crate::segment::{Ctr, Seg};
|
use crate::segment::{Ctr, Seg};
|
||||||
use crate::sym::{Args, SymTable, Symbol, ValueType};
|
use crate::sym::SymTable;
|
||||||
use std::path::{Path};
|
use std::path::Path;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
use std::env::{vars, var, current_dir};
|
use std::env::{var, current_dir};
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
fn l_prompt_default_callback(_: &Seg, _: &mut SymTable) -> Result<Ctr, String> {
|
|
||||||
Ok(Ctr::String(">".to_string()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn r_prompt_default_callback(_: &Seg, _: &mut SymTable) -> Result<Ctr, String> {
|
|
||||||
Ok(Ctr::String(String::new()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn prompt_delimiter_default_callback(_: &Seg, _: &mut SymTable) -> Result<Ctr, String> {
|
|
||||||
Ok(Ctr::String("λ ".to_string()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_paths() -> Vec<String> {
|
fn get_paths() -> Vec<String> {
|
||||||
Vec::from_iter(var("PATH")
|
Vec::from_iter(var("PATH")
|
||||||
|
|
@ -44,95 +31,6 @@ fn get_paths() -> Vec<String> {
|
||||||
.map(String::from))
|
.map(String::from))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_defaults(syms: &mut SymTable) {
|
|
||||||
syms.insert(
|
|
||||||
"CFG_RELISH_POSIX".to_string(),
|
|
||||||
Symbol {
|
|
||||||
name: String::from("CFG_RELISH_POSIX"),
|
|
||||||
args: Args::None,
|
|
||||||
conditional_branches: false,
|
|
||||||
docs: "variable holding whether or not POSIX job control functions are to be loaded.
|
|
||||||
checked at shell startup by configuration daemon. not used afterwards.
|
|
||||||
|
|
||||||
default value: false".to_string(),
|
|
||||||
value: ValueType::VarForm(Box::new(Ctr::Bool(false))),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
syms.insert(
|
|
||||||
"CFG_RELISH_ENV".to_string(),
|
|
||||||
Symbol {
|
|
||||||
name: String::from("CFG_RELISH_ENV"),
|
|
||||||
args: Args::None,
|
|
||||||
conditional_branches: false,
|
|
||||||
docs: "variable holding whether or not vars and other symbols should be linked to process environment variables.
|
|
||||||
If set/defined all calls to def will result in additions or subtractions from user environment variables.
|
|
||||||
checked at shell startup by configuration daemon. not used afterwards.
|
|
||||||
|
|
||||||
default value: 1 (set)
|
|
||||||
".to_string(),
|
|
||||||
value: ValueType::VarForm(Box::new(Ctr::Bool(true))),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
syms.insert(
|
|
||||||
"CFG_RELISH_L_PROMPT".to_string(),
|
|
||||||
Symbol {
|
|
||||||
name: String::from("default relish left prompt"),
|
|
||||||
args: Args::None,
|
|
||||||
conditional_branches: false,
|
|
||||||
docs: "function called to output prompt on left hand. this function is called with no arguments."
|
|
||||||
.to_string(),
|
|
||||||
value: ValueType::Internal(Rc::new(l_prompt_default_callback)),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
syms.insert(
|
|
||||||
"CFG_RELISH_R_PROMPT".to_string(),
|
|
||||||
Symbol {
|
|
||||||
name: String::from("default relish right prompt"),
|
|
||||||
args: Args::None,
|
|
||||||
conditional_branches: false,
|
|
||||||
docs: "function called to output prompt on right hand. this function is called with no arguments."
|
|
||||||
.to_string(),
|
|
||||||
value: ValueType::Internal(Rc::new(r_prompt_default_callback)),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
syms.insert(
|
|
||||||
"CFG_RELISH_PROMPT_DELIMITER".to_string(),
|
|
||||||
Symbol {
|
|
||||||
name: String::from("default relish prompt delimiter"),
|
|
||||||
args: Args::None,
|
|
||||||
conditional_branches: false,
|
|
||||||
docs: "function called to output prompt delimiter. this function is called with no arguments."
|
|
||||||
.to_string(),
|
|
||||||
value: ValueType::Internal(Rc::new(prompt_delimiter_default_callback)),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load_environment(syms: &mut SymTable) {
|
|
||||||
for (key, value) in vars() {
|
|
||||||
syms.insert(
|
|
||||||
key.clone(),
|
|
||||||
Symbol{
|
|
||||||
name: key,
|
|
||||||
args: Args::None,
|
|
||||||
conditional_branches: false,
|
|
||||||
docs: String::from("from env vars at time of load"),
|
|
||||||
value: ValueType::VarForm(Box::new(Ctr::String(value))),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn find_on_path(filename: String) -> Option<String> {
|
pub fn find_on_path(filename: String) -> Option<String> {
|
||||||
let mut prefixes = get_paths();
|
let mut prefixes = get_paths();
|
||||||
if let Ok(s) = current_dir() {
|
if let Ok(s) = current_dir() {
|
||||||
|
|
|
||||||
143
src/stl.rs
143
src/stl.rs
|
|
@ -20,6 +20,7 @@ use crate::run::{run_callback, RUN_DOCSTRING};
|
||||||
use crate::sym::{Args, SymTable, Symbol, ValueType};
|
use crate::sym::{Args, SymTable, Symbol, ValueType};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
use std::env::vars;
|
||||||
|
|
||||||
pub mod posix;
|
pub mod posix;
|
||||||
pub mod append;
|
pub mod append;
|
||||||
|
|
@ -29,6 +30,29 @@ pub mod decl;
|
||||||
pub mod math;
|
pub mod math;
|
||||||
pub mod strings;
|
pub mod strings;
|
||||||
|
|
||||||
|
pub const CONSOLE_XDIM_VNAME: &str = "_RELISH_WIDTH";
|
||||||
|
pub const CONSOLE_YDIM_VNAME: &str = "_RELISH_HEIGHT";
|
||||||
|
pub const POSIX_CFG_VNAME: &str = "CFG_RELISH_POSIX";
|
||||||
|
pub const MODENV_CFG_VNAME: &str = "CFG_RELISH_ENV";
|
||||||
|
pub const L_PROMPT_VNAME: &str = "CFG_RELISH_L_PROMPT";
|
||||||
|
pub const R_PROMPT_VNAME: &str = "CFG_RELISH_R_PROMPT";
|
||||||
|
pub const PROMPT_DELIM_VNAME: &str = "CFG_RELISH_PROMPT_DELIMITER";
|
||||||
|
pub const CFG_FILE_VNAME: &str = "RELISH_CFG_FILE";
|
||||||
|
pub const RELISH_DEFAULT_CONS_HEIGHT: i16 = 24;
|
||||||
|
pub const RELISH_DEFAULT_CONS_WIDTH: i16 = 80;
|
||||||
|
|
||||||
|
fn l_prompt_default_callback(_: &Seg, _: &mut SymTable) -> Result<Ctr, String> {
|
||||||
|
Ok(Ctr::String(">".to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn r_prompt_default_callback(_: &Seg, _: &mut SymTable) -> Result<Ctr, String> {
|
||||||
|
Ok(Ctr::String(String::new()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prompt_delimiter_default_callback(_: &Seg, _: &mut SymTable) -> Result<Ctr, String> {
|
||||||
|
Ok(Ctr::String("λ ".to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
/// static_stdlib
|
/// static_stdlib
|
||||||
/// inserts all stdlib functions that can be inserted without
|
/// inserts all stdlib functions that can be inserted without
|
||||||
/// any kind of further configuration data into a symtable
|
/// any kind of further configuration data into a symtable
|
||||||
|
|
@ -618,11 +642,12 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> {
|
||||||
pub fn dynamic_stdlib(syms: &mut SymTable, shell: Option<Rc<RefCell<posix::ShellState>>>) -> Result<(), String> {
|
pub fn dynamic_stdlib(syms: &mut SymTable, shell: Option<Rc<RefCell<posix::ShellState>>>) -> Result<(), String> {
|
||||||
//get CFG_RELISH_ENV from syms
|
//get CFG_RELISH_ENV from syms
|
||||||
let env_cfg_user_form = syms
|
let env_cfg_user_form = syms
|
||||||
.call_symbol(&"CFG_RELISH_ENV".to_string(), &Seg::new(), true)
|
.call_symbol(&MODENV_CFG_VNAME.to_string(), &Seg::new(), true)
|
||||||
.unwrap_or_else(|_: String| Box::new(Ctr::None))
|
.unwrap_or_else(|_: String| Box::new(Ctr::None))
|
||||||
.to_string()
|
.to_string()
|
||||||
.eq("true");
|
.eq("true");
|
||||||
|
|
||||||
|
// this also depends on the value of CFG_RELISH_ENV
|
||||||
syms.insert(
|
syms.insert(
|
||||||
"def".to_string(),
|
"def".to_string(),
|
||||||
Symbol {
|
Symbol {
|
||||||
|
|
@ -639,9 +664,10 @@ pub fn dynamic_stdlib(syms: &mut SymTable, shell: Option<Rc<RefCell<posix::Shell
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// This should be replaced by actual compiler conditionals in the future
|
||||||
if let Some(shell_state) = shell {
|
if let Some(shell_state) = shell {
|
||||||
let posix_cfg_user_form = syms
|
let posix_cfg_user_form = syms
|
||||||
.call_symbol(&"CFG_RELISH_POSIX".to_string(), &Seg::new(), true)
|
.call_symbol(&POSIX_CFG_VNAME.to_string(), &Seg::new(), true)
|
||||||
.unwrap_or_else(|_: String| Box::new(Ctr::None))
|
.unwrap_or_else(|_: String| Box::new(Ctr::None))
|
||||||
.to_string()
|
.to_string()
|
||||||
.eq("true");
|
.eq("true");
|
||||||
|
|
@ -664,3 +690,116 @@ pub fn dynamic_stdlib(syms: &mut SymTable, shell: Option<Rc<RefCell<posix::Shell
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn load_environment(syms: &mut SymTable) {
|
||||||
|
for (key, value) in vars() {
|
||||||
|
syms.insert(
|
||||||
|
key.clone(),
|
||||||
|
Symbol{
|
||||||
|
name: key,
|
||||||
|
args: Args::None,
|
||||||
|
conditional_branches: false,
|
||||||
|
docs: String::from("from env vars at time of load"),
|
||||||
|
value: ValueType::VarForm(Box::new(Ctr::String(value))),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_defaults(syms: &mut SymTable) {
|
||||||
|
syms.insert(
|
||||||
|
POSIX_CFG_VNAME.to_string(),
|
||||||
|
Symbol {
|
||||||
|
name: String::from(POSIX_CFG_VNAME),
|
||||||
|
args: Args::None,
|
||||||
|
conditional_branches: false,
|
||||||
|
docs: "variable holding whether or not POSIX job control functions are to be loaded.
|
||||||
|
checked at shell startup by configuration daemon. not used afterwards.
|
||||||
|
|
||||||
|
default value: false".to_string(),
|
||||||
|
value: ValueType::VarForm(Box::new(Ctr::Bool(false))),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
syms.insert(
|
||||||
|
MODENV_CFG_VNAME.to_string(),
|
||||||
|
Symbol {
|
||||||
|
name: String::from(MODENV_CFG_VNAME),
|
||||||
|
args: Args::None,
|
||||||
|
conditional_branches: false,
|
||||||
|
docs: "variable holding whether or not vars and other symbols should be linked to process environment variables.
|
||||||
|
If set/defined all calls to def will result in additions or subtractions from user environment variables.
|
||||||
|
checked at shell startup by configuration daemon. not used afterwards.
|
||||||
|
|
||||||
|
default value: 1 (set)
|
||||||
|
".to_string(),
|
||||||
|
value: ValueType::VarForm(Box::new(Ctr::Bool(true))),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
syms.insert(
|
||||||
|
L_PROMPT_VNAME.to_string(),
|
||||||
|
Symbol {
|
||||||
|
name: String::from(L_PROMPT_VNAME),
|
||||||
|
args: Args::None,
|
||||||
|
conditional_branches: false,
|
||||||
|
docs: "function called to output prompt on left hand. this function is called with no arguments."
|
||||||
|
.to_string(),
|
||||||
|
value: ValueType::Internal(Rc::new(l_prompt_default_callback)),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
syms.insert(
|
||||||
|
R_PROMPT_VNAME.to_string(),
|
||||||
|
Symbol {
|
||||||
|
name: String::from(R_PROMPT_VNAME),
|
||||||
|
args: Args::None,
|
||||||
|
conditional_branches: false,
|
||||||
|
docs: "function called to output prompt on right hand. this function is called with no arguments."
|
||||||
|
.to_string(),
|
||||||
|
value: ValueType::Internal(Rc::new(r_prompt_default_callback)),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
syms.insert(
|
||||||
|
PROMPT_DELIM_VNAME.to_string(),
|
||||||
|
Symbol {
|
||||||
|
name: String::from(PROMPT_DELIM_VNAME),
|
||||||
|
args: Args::None,
|
||||||
|
conditional_branches: false,
|
||||||
|
docs: "function called to output prompt delimiter. this function is called with no arguments."
|
||||||
|
.to_string(),
|
||||||
|
value: ValueType::Internal(Rc::new(prompt_delimiter_default_callback)),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
syms.insert(
|
||||||
|
String::from(CONSOLE_XDIM_VNAME),
|
||||||
|
Symbol::from_ast(
|
||||||
|
&String::from(CONSOLE_XDIM_VNAME),
|
||||||
|
&String::from("Length of current console"),
|
||||||
|
&Seg::from_mono(Box::new(
|
||||||
|
Ctr::Integer(RELISH_DEFAULT_CONS_WIDTH.into())
|
||||||
|
)),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
syms.insert(
|
||||||
|
String::from(CONSOLE_YDIM_VNAME),
|
||||||
|
Symbol::from_ast(
|
||||||
|
&String::from(CONSOLE_YDIM_VNAME),
|
||||||
|
&String::from("Height of current console"),
|
||||||
|
&Seg::from_mono(Box::new(
|
||||||
|
Ctr::Integer(RELISH_DEFAULT_CONS_HEIGHT.into())
|
||||||
|
)),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use crate::eval::eval;
|
use crate::eval::eval;
|
||||||
use crate::segment::{Ctr, Seg};
|
use crate::segment::{Ctr, Seg, Type};
|
||||||
|
use crate::stdlib::{CONSOLE_XDIM_VNAME, RELISH_DEFAULT_CONS_WIDTH};
|
||||||
use crate::sym::{SymTable, Symbol, UserFn, ValueType};
|
use crate::sym::{SymTable, Symbol, UserFn, ValueType};
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
|
|
@ -129,19 +130,76 @@ pub const ENV_DOCSTRING: &str = "takes no arguments
|
||||||
prints out all available symbols and their associated values";
|
prints out all available symbols and their associated values";
|
||||||
|
|
||||||
pub fn env_callback(_ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
|
pub fn env_callback(_ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
|
||||||
|
// get width of current output
|
||||||
|
let xdim: i128;
|
||||||
|
if let Ctr::Integer(dim) = *syms
|
||||||
|
.call_symbol(&CONSOLE_XDIM_VNAME.to_string(), &Seg::new(), true)
|
||||||
|
.unwrap_or_else(|_: String| Box::new(Ctr::None)) {
|
||||||
|
xdim = dim;
|
||||||
|
} else {
|
||||||
|
println!("{} contains non integer value, defaulting to {}",
|
||||||
|
CONSOLE_XDIM_VNAME, RELISH_DEFAULT_CONS_WIDTH);
|
||||||
|
xdim = RELISH_DEFAULT_CONS_WIDTH as i128;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut v_col_len = 0;
|
||||||
|
let mut f_col_len = 0;
|
||||||
let mut functions = vec![];
|
let mut functions = vec![];
|
||||||
println!("VARIABLES:");
|
let mut variables = vec![];
|
||||||
for (name, val) in syms.iter() {
|
for (name, val) in syms.iter() {
|
||||||
match val.value {
|
if let ValueType::VarForm(l) = &val.value {
|
||||||
ValueType::VarForm(_) => {
|
let token: String;
|
||||||
println!(" {}: {}", &name, val.value);
|
match l.to_type() {
|
||||||
|
Type::Lambda => token = format!("{}: <lambda>", name),
|
||||||
|
Type::Seg => token = format!("{}: <form>", name),
|
||||||
|
_ => token = format!("{}: {}", name, val.value.to_string()),
|
||||||
}
|
}
|
||||||
_ => functions.push(name.clone()),
|
|
||||||
|
if token.len() > v_col_len && token.len() < xdim as usize {
|
||||||
|
v_col_len = token.len();
|
||||||
|
}
|
||||||
|
|
||||||
|
variables.push(token);
|
||||||
|
} else {
|
||||||
|
if f_col_len < name.len() && name.len() < xdim as usize {
|
||||||
|
f_col_len = name.len();
|
||||||
|
}
|
||||||
|
functions.push(name.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("FUNCTIONS:");
|
|
||||||
|
let mut n_v_cols = xdim / v_col_len as i128;
|
||||||
|
// now decrement to make sure theres room for two spaces of padding
|
||||||
|
while n_v_cols > 1 && xdim % (v_col_len as i128) < (2 * n_v_cols) {
|
||||||
|
n_v_cols -= 1;
|
||||||
|
}
|
||||||
|
// again for functions
|
||||||
|
let mut n_f_cols = xdim / f_col_len as i128;
|
||||||
|
while n_f_cols > 1 && xdim & (f_col_len as i128) < (2 * n_f_cols) {
|
||||||
|
n_f_cols -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut col_iter = 0;
|
||||||
|
println!("VARIABLES:");
|
||||||
|
for var in variables {
|
||||||
|
print!("{:v_col_len$}", var);
|
||||||
|
col_iter += 1;
|
||||||
|
if col_iter % n_v_cols == 0 {
|
||||||
|
print!("\n");
|
||||||
|
} else {
|
||||||
|
print!(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("\nFUNCTIONS:");
|
||||||
|
col_iter = 0;
|
||||||
for func in functions {
|
for func in functions {
|
||||||
println!(" {}", func);
|
print!("{:f_col_len$}", func);
|
||||||
|
col_iter += 1;
|
||||||
|
if col_iter % n_f_cols == 0 {
|
||||||
|
print!("\n");
|
||||||
|
} else {
|
||||||
|
print!(" ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(Ctr::None)
|
Ok(Ctr::None)
|
||||||
}
|
}
|
||||||
|
|
@ -335,7 +393,7 @@ pub fn store_callback(ast: &Seg, syms: &mut SymTable, env_cfg: bool) -> Result<C
|
||||||
var_val_form = &outer_scope_val;
|
var_val_form = &outer_scope_val;
|
||||||
},
|
},
|
||||||
_ if !is_var => return Err("arg list must at least be a list".to_string()),
|
_ if !is_var => return Err("arg list must at least be a list".to_string()),
|
||||||
_ => unimplemented!(), // rustc is haunted
|
_ => unimplemented!(), // rustc is haunted and cursed
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_var {
|
if is_var {
|
||||||
|
|
@ -353,12 +411,18 @@ pub fn store_callback(ast: &Seg, syms: &mut SymTable, env_cfg: bool) -> Result<C
|
||||||
Symbol::from_ast(&name, &docs, &outer_seg, None),
|
Symbol::from_ast(&name, &docs, &outer_seg, None),
|
||||||
);
|
);
|
||||||
if env_cfg {
|
if env_cfg {
|
||||||
|
match var_val.to_type() {
|
||||||
|
Type::Lambda => {},
|
||||||
|
Type::Seg => {},
|
||||||
|
_ => {
|
||||||
let mut s = var_val.to_string();
|
let mut s = var_val.to_string();
|
||||||
if let Ctr::String(tok) = var_val {
|
if let Ctr::String(tok) = var_val {
|
||||||
s = tok;
|
s = tok;
|
||||||
}
|
}
|
||||||
env::set_var(name.clone(), s);
|
env::set_var(name.clone(), s);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return Ok(Ctr::None)
|
return Ok(Ctr::None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue