2023-02-17 21:00:07 -08:00
|
|
|
/* relish: versatile lisp shell
|
|
|
|
|
* Copyright (C) 2021 Aidan Hahn
|
|
|
|
|
*
|
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
2023-03-01 11:38:02 -08:00
|
|
|
use crate::segment::{Ctr, Seg, Type};
|
2023-03-20 19:00:30 -07:00
|
|
|
use crate::run::{run_callback, RUN_DOCSTRING};
|
2023-03-06 15:29:01 -08:00
|
|
|
use crate::sym::{Args, SymTable, Symbol, ValueType};
|
2023-05-23 22:06:11 +00:00
|
|
|
use crate::error::Traceback;
|
2023-02-27 17:30:49 -08:00
|
|
|
use std::rc::Rc;
|
2023-03-24 18:14:33 -07:00
|
|
|
use std::cell::RefCell;
|
2023-05-21 23:53:00 +00:00
|
|
|
use std::env::vars;
|
2023-02-17 21:00:07 -08:00
|
|
|
|
2023-03-24 18:14:33 -07:00
|
|
|
pub mod posix;
|
2023-02-27 22:53:54 -08:00
|
|
|
pub mod append;
|
2023-03-02 09:43:12 -08:00
|
|
|
pub mod boolean;
|
2023-03-03 14:29:53 -08:00
|
|
|
pub mod control;
|
2023-03-06 15:29:01 -08:00
|
|
|
pub mod decl;
|
2023-03-06 19:05:34 -08:00
|
|
|
pub mod math;
|
2023-03-08 11:39:54 -08:00
|
|
|
pub mod strings;
|
2023-02-17 21:00:07 -08:00
|
|
|
|
2023-05-21 23:53:00 +00:00
|
|
|
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;
|
|
|
|
|
|
2023-05-23 22:06:11 +00:00
|
|
|
fn l_prompt_default_callback(_: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
|
2023-05-21 23:53:00 +00:00
|
|
|
Ok(Ctr::String(">".to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-23 22:06:11 +00:00
|
|
|
fn r_prompt_default_callback(_: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
|
2023-05-21 23:53:00 +00:00
|
|
|
Ok(Ctr::String(String::new()))
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-23 22:06:11 +00:00
|
|
|
fn prompt_delimiter_default_callback(_: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
|
2023-05-21 23:53:00 +00:00
|
|
|
Ok(Ctr::String("λ ".to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-27 22:53:54 -08:00
|
|
|
/// static_stdlib
|
|
|
|
|
/// inserts all stdlib functions that can be inserted without
|
|
|
|
|
/// any kind of further configuration data into a symtable
|
|
|
|
|
pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> {
|
2023-05-25 23:08:44 +00:00
|
|
|
append::add_list_lib(syms);
|
|
|
|
|
strings::add_string_lib(syms);
|
|
|
|
|
decl::add_decl_lib_static(syms);
|
|
|
|
|
control::add_control_lib(syms);
|
|
|
|
|
boolean::add_bool_lib(syms);
|
|
|
|
|
math::add_math_lib(syms);
|
2023-03-20 19:00:30 -07:00
|
|
|
|
|
|
|
|
syms.insert(
|
2023-03-27 14:34:07 -07:00
|
|
|
"call".to_string(),
|
2023-03-20 19:00:30 -07:00
|
|
|
Symbol {
|
2023-03-27 14:34:07 -07:00
|
|
|
name: String::from("call"),
|
2023-03-20 19:00:30 -07:00
|
|
|
args: Args::Strict(vec![Type::String]),
|
|
|
|
|
conditional_branches: false,
|
|
|
|
|
docs: RUN_DOCSTRING.to_string(),
|
|
|
|
|
value: ValueType::Internal(Rc::new(run_callback)),
|
|
|
|
|
..Default::default()
|
2023-03-22 22:53:29 -07:00
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
2023-02-27 17:30:49 -08:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-27 22:53:54 -08:00
|
|
|
/// dynamic_stdlib
|
|
|
|
|
/// takes configuration data and uses it to insert dynamic
|
|
|
|
|
/// callbacks with configuration into a symtable
|
2023-03-24 18:14:33 -07:00
|
|
|
pub fn dynamic_stdlib(syms: &mut SymTable, shell: Option<Rc<RefCell<posix::ShellState>>>) -> Result<(), String> {
|
2023-03-01 11:14:42 -08:00
|
|
|
//get CFG_RELISH_ENV from syms
|
2023-03-01 11:38:02 -08:00
|
|
|
let env_cfg_user_form = syms
|
2023-05-21 23:53:00 +00:00
|
|
|
.call_symbol(&MODENV_CFG_VNAME.to_string(), &Seg::new(), true)
|
2023-05-23 22:06:11 +00:00
|
|
|
.unwrap_or_else(|_: Traceback| Box::new(Ctr::None))
|
2023-03-01 11:14:42 -08:00
|
|
|
.to_string()
|
2023-03-18 23:00:55 -07:00
|
|
|
.eq("true");
|
2023-03-01 11:14:42 -08:00
|
|
|
|
2023-05-25 23:08:44 +00:00
|
|
|
decl::add_decl_lib_dynamic(syms, env_cfg_user_form);
|
2023-02-27 17:30:49 -08:00
|
|
|
|
2023-05-21 23:53:00 +00:00
|
|
|
// This should be replaced by actual compiler conditionals in the future
|
2023-03-24 18:14:33 -07:00
|
|
|
if let Some(shell_state) = shell {
|
|
|
|
|
let posix_cfg_user_form = syms
|
2023-05-21 23:53:00 +00:00
|
|
|
.call_symbol(&POSIX_CFG_VNAME.to_string(), &Seg::new(), true)
|
2023-05-23 22:06:11 +00:00
|
|
|
.unwrap_or_else(|_: Traceback| Box::new(Ctr::None))
|
2023-03-24 18:14:33 -07:00
|
|
|
.to_string()
|
|
|
|
|
.eq("true");
|
|
|
|
|
|
|
|
|
|
if posix_cfg_user_form {
|
|
|
|
|
posix::load_posix_shell(syms, shell_state);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-27 22:53:54 -08:00
|
|
|
Ok(())
|
2023-02-27 17:30:49 -08:00
|
|
|
}
|
2023-05-21 23:53:00 +00:00
|
|
|
|
|
|
|
|
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,
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
}
|