Add history recall to repl.
This commit is contained in:
parent
f1458e79e0
commit
389bb9bf66
25
CHANGELOG.md
25
CHANGELOG.md
@ -29,9 +29,32 @@ New features
|
|||||||
Enhancements
|
Enhancements
|
||||||
------------
|
------------
|
||||||
|
|
||||||
* `rhai-repl` tool has a few more commands, such as `strict` to turn on/off _Strict Variables Mode_ and `optimize` to turn on/off script optimization.
|
|
||||||
* Default features for dependencies (such as `ahash/std` and `num-traits/std`) are no longer required.
|
* Default features for dependencies (such as `ahash/std` and `num-traits/std`) are no longer required.
|
||||||
* The `no_module` feature now eliminates large sections of code via feature gates.
|
* The `no_module` feature now eliminates large sections of code via feature gates.
|
||||||
|
* Debug display of `AST` is improved.
|
||||||
|
|
||||||
|
REPL tool changes
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
The REPL bin tool, `rhai-rpl`, has been enhanced.
|
||||||
|
|
||||||
|
### Build changes
|
||||||
|
|
||||||
|
* The `rustyline` feature is now required in order to build `rhai-repl`.
|
||||||
|
* Therefore, `rhai-repl` is no longer automatically built when using a simple `cargo build` with default features.
|
||||||
|
|
||||||
|
### Line editor
|
||||||
|
|
||||||
|
* `rhai-repl` now uses [`rustyline`](https://crates.io/crates/rustyline) as a line editor with history.
|
||||||
|
* Shift-Enter can now be used to enter multiple lines without having to attach the `\` continuation character the end of each line.
|
||||||
|
|
||||||
|
### New commands
|
||||||
|
|
||||||
|
* `strict` to turn on/off _Strict Variables Mode_.
|
||||||
|
* `optimize` to turn on/off script optimization.
|
||||||
|
* `history` to print lines history.
|
||||||
|
* `!!`, `!`_num_ and `!`_text_ to recall a history line.
|
||||||
|
* `keys` to print all key bindings.
|
||||||
|
|
||||||
|
|
||||||
Version 1.4.1
|
Version 1.4.1
|
||||||
|
@ -44,9 +44,13 @@ fn print_error(input: &str, mut err: EvalAltResult) {
|
|||||||
/// Print help text.
|
/// Print help text.
|
||||||
fn print_help() {
|
fn print_help() {
|
||||||
println!("help => print this help");
|
println!("help => print this help");
|
||||||
println!("keys => print list of key bindings");
|
|
||||||
println!("quit, exit => quit");
|
println!("quit, exit => quit");
|
||||||
|
println!("keys => print list of key bindings");
|
||||||
println!("history => print lines history");
|
println!("history => print lines history");
|
||||||
|
println!("!! => repeat the last history line");
|
||||||
|
println!("!<#> => repeat a particular history line");
|
||||||
|
println!("!<text> => repeat the last history line starting with some text");
|
||||||
|
println!("!?<text> => repeat the last history line containing some text");
|
||||||
println!("scope => print all variables in the scope");
|
println!("scope => print all variables in the scope");
|
||||||
println!("strict => toggle on/off Strict Variables Mode");
|
println!("strict => toggle on/off Strict Variables Mode");
|
||||||
#[cfg(not(feature = "no_optimize"))]
|
#[cfg(not(feature = "no_optimize"))]
|
||||||
@ -311,6 +315,10 @@ fn main() {
|
|||||||
|
|
||||||
// REPL loop
|
// REPL loop
|
||||||
let mut input = String::new();
|
let mut input = String::new();
|
||||||
|
let mut replacement = None;
|
||||||
|
let mut replacement_index = 0;
|
||||||
|
let mut history_offset = 1;
|
||||||
|
|
||||||
let mut main_ast = AST::empty();
|
let mut main_ast = AST::empty();
|
||||||
let mut ast_u = AST::empty();
|
let mut ast_u = AST::empty();
|
||||||
let mut ast = AST::empty();
|
let mut ast = AST::empty();
|
||||||
@ -318,6 +326,20 @@ fn main() {
|
|||||||
print_help();
|
print_help();
|
||||||
|
|
||||||
'main_loop: loop {
|
'main_loop: loop {
|
||||||
|
if let Some(replace) = replacement.take() {
|
||||||
|
input = replace;
|
||||||
|
if rl.add_history_entry(input.clone()) {
|
||||||
|
history_offset += 1;
|
||||||
|
}
|
||||||
|
if input.contains('\n') {
|
||||||
|
println!("[{}] ~~~~", replacement_index);
|
||||||
|
println!("{}", input);
|
||||||
|
println!("~~~~");
|
||||||
|
} else {
|
||||||
|
println!("[{}] {}", replacement_index, input);
|
||||||
|
}
|
||||||
|
replacement_index = 0;
|
||||||
|
} else {
|
||||||
input.clear();
|
input.clear();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@ -336,8 +358,11 @@ fn main() {
|
|||||||
}
|
}
|
||||||
Ok(line) => {
|
Ok(line) => {
|
||||||
input += line.trim_end();
|
input += line.trim_end();
|
||||||
if !input.is_empty() {
|
if !input.is_empty() && !input.starts_with('!') && input.trim() != "history"
|
||||||
rl.add_history_entry(input.clone());
|
{
|
||||||
|
if rl.add_history_entry(input.clone()) {
|
||||||
|
history_offset += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -350,6 +375,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let script = input.trim();
|
let script = input.trim();
|
||||||
|
|
||||||
@ -371,10 +397,10 @@ fn main() {
|
|||||||
"history" => {
|
"history" => {
|
||||||
for (i, h) in rl.history().iter().enumerate() {
|
for (i, h) in rl.history().iter().enumerate() {
|
||||||
match &h.split('\n').collect::<Vec<_>>()[..] {
|
match &h.split('\n').collect::<Vec<_>>()[..] {
|
||||||
[line] => println!("[{}] {}", i + 1, line),
|
[line] => println!("[{}] {}", history_offset + i, line),
|
||||||
lines => {
|
lines => {
|
||||||
for (x, line) in lines.iter().enumerate() {
|
for (x, line) in lines.iter().enumerate() {
|
||||||
let number = format!("[{}]", i + 1);
|
let number = format!("[{}]", history_offset + i);
|
||||||
if x == 0 {
|
if x == 0 {
|
||||||
println!("{} {}", number, line.trim_end());
|
println!("{} {}", number, line.trim_end());
|
||||||
} else {
|
} else {
|
||||||
@ -447,6 +473,57 @@ fn main() {
|
|||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
"!!" => {
|
||||||
|
if let Some(line) = rl.history().last() {
|
||||||
|
replacement = Some(line.clone());
|
||||||
|
replacement_index = history_offset + rl.history().len() - 1;
|
||||||
|
} else {
|
||||||
|
eprintln!("No lines history!");
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_ if script.starts_with("!?") => {
|
||||||
|
let text = script[2..].trim();
|
||||||
|
if let Some((n, line)) = rl
|
||||||
|
.history()
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.enumerate()
|
||||||
|
.find(|&(_, h)| h.contains(text))
|
||||||
|
{
|
||||||
|
replacement = Some(line.clone());
|
||||||
|
replacement_index = history_offset + (rl.history().len() - 1 - n);
|
||||||
|
} else {
|
||||||
|
eprintln!("History line not found: {}", text);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_ if script.starts_with('!') => {
|
||||||
|
if let Ok(num) = script[1..].parse::<usize>() {
|
||||||
|
if num >= history_offset {
|
||||||
|
if let Some(line) = rl.history().get(num - history_offset) {
|
||||||
|
replacement = Some(line.clone());
|
||||||
|
replacement_index = num;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let prefix = script[1..].trim();
|
||||||
|
if let Some((n, line)) = rl
|
||||||
|
.history()
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.enumerate()
|
||||||
|
.find(|&(_, h)| h.trim_start().starts_with(prefix))
|
||||||
|
{
|
||||||
|
replacement = Some(line.clone());
|
||||||
|
replacement_index = history_offset + (rl.history().len() - 1 - n);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eprintln!("History line not found: {}", &script[1..]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user