shell fully configurable
This commit is contained in:
parent
1ce5fd3454
commit
a711b32730
4 changed files with 117 additions and 29 deletions
17
Readme.org
17
Readme.org
|
|
@ -395,8 +395,12 @@ Errors during configuration are non-terminal. In such a case any defaults which
|
||||||
*** Configuration Values
|
*** Configuration Values
|
||||||
- CFG_RELISH_POSIX (default false): when true, enables POSIX style job control.
|
- CFG_RELISH_POSIX (default false): when true, enables POSIX style job control.
|
||||||
- CFG_RELISH_ENV (default true): when true, interpreter's variable table and environment variable table are kept in sync.
|
- CFG_RELISH_ENV (default true): when true, interpreter's variable table and environment variable table are kept in sync.
|
||||||
- CFG_RELISH_PROMPT (default (echo "λ ")): A *function* definition which is called in order to output the prompt for each loop of the REPL.
|
- CFG_RELISH_L_PROMPT (default 'λ'): a function that is called with no arguments to output the left hand of the prompt
|
||||||
This function will be reloaded each REPL loop and will be called by the interpreter with no arguments.
|
- CFG_RELISH_R_PROMPT (default ''): a function that is called with no arguments to output the right hand of the prompt
|
||||||
|
- CFG_RELISH_PROMPT_DELIMITER (default '>'): a function that is called with no arguments to output the delimiter separating prompt from user input
|
||||||
|
|
||||||
|
*** Prompt design
|
||||||
|
For an example of prompt design see file:snippets/mood-prompt.rls
|
||||||
|
|
||||||
*** Further configuration
|
*** Further configuration
|
||||||
Further configuration can be done by loading scripts that contain more functions and data to evaluate.
|
Further configuration can be done by loading scripts that contain more functions and data to evaluate.
|
||||||
|
|
@ -477,12 +481,16 @@ 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 Pre-alpha tasks
|
** TODO Pre-alpha tasks
|
||||||
- Shell prompt is fully configurable (History, L, R, and Delim)
|
- paths function
|
||||||
|
- add-path function
|
||||||
- Shell module
|
- Shell module
|
||||||
- Only loadable via POSIX config var
|
- Only loadable via POSIX config var
|
||||||
- Overload Load function to hook into this lib
|
- Overload Load function to hook into this lib
|
||||||
- arg processor because these are control flow
|
- arg processor because these are control flow
|
||||||
- Process launching with environment variables
|
- Process launching with environment variables
|
||||||
|
- "flag" function
|
||||||
|
- "switch" function
|
||||||
|
- "with" function (load with)
|
||||||
- Optional form of process which allows fd redirecting
|
- Optional form of process which allows fd redirecting
|
||||||
- Background processes (bg function)
|
- Background processes (bg function)
|
||||||
- Foreground process TTY (fg function)
|
- Foreground process TTY (fg function)
|
||||||
|
|
@ -492,6 +500,9 @@ Note: this section only tracks the state of incomplete TODO items. Having everyt
|
||||||
- make const all the error messages
|
- make const all the error messages
|
||||||
|
|
||||||
** TODO alpha tasks
|
** TODO alpha tasks
|
||||||
|
- History length configurable
|
||||||
|
- Search delim configurable
|
||||||
|
- Escape sequences in strings
|
||||||
- Rename to Flesh
|
- Rename to Flesh
|
||||||
- master branch -> main branch
|
- master branch -> main branch
|
||||||
- Create a dedicated community channel on matrix.sunnypup.io
|
- Create a dedicated community channel on matrix.sunnypup.io
|
||||||
|
|
|
||||||
15
snippets/mood-prompt.rls
Normal file
15
snippets/mood-prompt.rls
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
#!/bin/relish
|
||||||
|
|
||||||
|
(def __mood 'current mood' ':3')
|
||||||
|
|
||||||
|
(def CFG_RELISH_L_PROMPT 'mood left prompt'
|
||||||
|
() (concat "(" __mood ")" ))
|
||||||
|
|
||||||
|
(def CFG_RELISH_R_PROMPT 'mood right prompt'
|
||||||
|
() 'call set-mood to change prompt')
|
||||||
|
|
||||||
|
(def CFG_RELISH_PROMPT_DELIMITER 'mood prompt delim'
|
||||||
|
() '>')
|
||||||
|
|
||||||
|
(def set-mood 'set the little ascii face in your prompt'
|
||||||
|
(mood) (set (q __mood) mood))
|
||||||
|
|
@ -28,22 +28,22 @@ use std::borrow::Cow;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct CustomPrompt<'a>(&'a str);
|
pub struct CustomPrompt(String, String, String);
|
||||||
impl Prompt for CustomPrompt<'_> {
|
impl Prompt for CustomPrompt {
|
||||||
fn render_prompt_left(&self) -> Cow<str> {
|
fn render_prompt_left(&self) -> Cow<str> {
|
||||||
{
|
{
|
||||||
Cow::Owned(self.0.to_string())
|
Cow::Owned(self.0.to_owned())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_prompt_right(&self) -> Cow<str> {
|
fn render_prompt_right(&self) -> Cow<str> {
|
||||||
{
|
{
|
||||||
Cow::Owned(format!(""))
|
Cow::Owned(self.1.to_owned())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_prompt_indicator(&self, _edit_mode: PromptEditMode) -> Cow<str> {
|
fn render_prompt_indicator(&self, _edit_mode: PromptEditMode) -> Cow<str> {
|
||||||
Cow::Owned("> ".to_string())
|
Cow::Owned(self.2.to_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_prompt_multiline_indicator(&self) -> Cow<str> {
|
fn render_prompt_multiline_indicator(&self) -> Cow<str> {
|
||||||
|
|
@ -117,20 +117,7 @@ fn main() {
|
||||||
|
|
||||||
// repl :)
|
// repl :)
|
||||||
loop {
|
loop {
|
||||||
let s = *syms
|
let readline_prompt = make_prompt(&mut syms);
|
||||||
.call_symbol(&"CFG_RELISH_PROMPT".to_string(), &Seg::new(), true)
|
|
||||||
.unwrap_or_else(|err: String| {
|
|
||||||
eprintln!("{}", err);
|
|
||||||
Box::new(Ctr::String("<prompt broken!>".to_string()))
|
|
||||||
});
|
|
||||||
let p_str: String;
|
|
||||||
if let Ctr::String(s) = s {
|
|
||||||
p_str = s;
|
|
||||||
} else {
|
|
||||||
p_str = s.to_string();
|
|
||||||
}
|
|
||||||
let readline_prompt = CustomPrompt(p_str.as_str());
|
|
||||||
|
|
||||||
let user_doc = rl.read_line(&readline_prompt).unwrap();
|
let user_doc = rl.read_line(&readline_prompt).unwrap();
|
||||||
match user_doc {
|
match user_doc {
|
||||||
Signal::Success(line) => {
|
Signal::Success(line) => {
|
||||||
|
|
@ -156,3 +143,45 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_prompt(syms: &mut SymTable) -> CustomPrompt {
|
||||||
|
let l_ctr = *syms
|
||||||
|
.call_symbol(&"CFG_RELISH_L_PROMPT".to_string(), &Seg::new(), true)
|
||||||
|
.unwrap_or_else(|err: String| {
|
||||||
|
eprintln!("{}", err);
|
||||||
|
Box::new(Ctr::String("<prompt broken!>".to_string()))
|
||||||
|
});
|
||||||
|
let r_ctr = *syms
|
||||||
|
.call_symbol(&"CFG_RELISH_R_PROMPT".to_string(), &Seg::new(), true)
|
||||||
|
.unwrap_or_else(|err: String| {
|
||||||
|
eprintln!("{}", err);
|
||||||
|
Box::new(Ctr::String("<prompt broken!>".to_string()))
|
||||||
|
});
|
||||||
|
let d_ctr = *syms
|
||||||
|
.call_symbol(&"CFG_RELISH_PROMPT_DELIMITER".to_string(), &Seg::new(), true)
|
||||||
|
.unwrap_or_else(|err: String| {
|
||||||
|
eprintln!("{}", err);
|
||||||
|
Box::new(Ctr::String("<prompt broken!>".to_string()))
|
||||||
|
});
|
||||||
|
|
||||||
|
let l_str: String;
|
||||||
|
let r_str: String;
|
||||||
|
let d_str: String;
|
||||||
|
if let Ctr::String(s) = l_ctr {
|
||||||
|
l_str = s;
|
||||||
|
} else {
|
||||||
|
l_str = l_ctr.to_string();
|
||||||
|
}
|
||||||
|
if let Ctr::String(s) = r_ctr {
|
||||||
|
r_str = s;
|
||||||
|
} else {
|
||||||
|
r_str = r_ctr.to_string();
|
||||||
|
}
|
||||||
|
if let Ctr::String(s) = d_ctr {
|
||||||
|
d_str = s;
|
||||||
|
} else {
|
||||||
|
d_str = d_ctr.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomPrompt(l_str, r_str, d_str)
|
||||||
|
}
|
||||||
|
|
|
||||||
47
src/run.rs
47
src/run.rs
|
|
@ -25,8 +25,16 @@ use std::iter::FromIterator;
|
||||||
use std::env::{vars, var, current_dir};
|
use std::env::{vars, var, current_dir};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
fn prompt_default_callback(_: &Seg, _: &mut SymTable) -> Result<Ctr, String> {
|
fn l_prompt_default_callback(_: &Seg, _: &mut SymTable) -> Result<Ctr, String> {
|
||||||
Ok(Ctr::Symbol("λ".to_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> {
|
||||||
|
|
@ -70,15 +78,40 @@ default value: 1 (set)
|
||||||
);
|
);
|
||||||
|
|
||||||
syms.insert(
|
syms.insert(
|
||||||
"CFG_RELISH_PROMPT".to_string(),
|
"CFG_RELISH_L_PROMPT".to_string(),
|
||||||
Symbol {
|
Symbol {
|
||||||
name: String::from("default relish prompt"),
|
name: String::from("default relish left prompt"),
|
||||||
args: Args::None,
|
args: Args::None,
|
||||||
conditional_branches: false,
|
conditional_branches: false,
|
||||||
docs: "function called to output prompt. this function is called with no arguments.
|
docs: "function called to output prompt on left hand. this function is called with no arguments."
|
||||||
default value (<lambda>)"
|
|
||||||
.to_string(),
|
.to_string(),
|
||||||
value: ValueType::Internal(Rc::new(prompt_default_callback)),
|
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()
|
..Default::default()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue