diff options
author | Vincent Ambo <mail@tazj.in> | 2022-08-11T21·27+0300 |
---|---|---|
committer | tazjin <tazjin@tvl.su> | 2022-08-26T17·19+0000 |
commit | 7c803a7e72564807cd9029a829109d795b9beb6d (patch) | |
tree | 761838b0a52a9eb2faafc6027ad019ce7e4bcce2 | |
parent | d14db8dcaae3c6d624ce17417ac58a44a6f5983c (diff) |
feat(tvix/eval): use rustyline crate for REPL r/4505
This is a substantially nicer experience, immediately granting us history, proper exiting and so on. Change-Id: Iba4cb1713b9ac53d0799722bdbe2cd0e94a2f527 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6171 Reviewed-by: grfn <grfn@gws.fyi> Tested-by: BuildkiteCI
-rw-r--r-- | tvix/eval/src/main.rs | 68 |
1 files changed, 49 insertions, 19 deletions
diff --git a/tvix/eval/src/main.rs b/tvix/eval/src/main.rs index 41d9ed36bd5d..0c4d082783e2 100644 --- a/tvix/eval/src/main.rs +++ b/tvix/eval/src/main.rs @@ -1,8 +1,6 @@ -use std::{ - env, fs, - io::{self, Write}, - mem, process, -}; +use std::{env, fs, path::PathBuf, process}; + +use rustyline::{error::ReadlineError, Editor}; fn main() { let mut args = env::args(); @@ -21,26 +19,58 @@ fn main() { fn run_file(file: &str) { let contents = fs::read_to_string(file).expect("failed to read the input file"); - run(contents); + match tvix_eval::interpret(&contents) { + Ok(result) => println!("=> {} :: {}", result, result.type_of()), + Err(err) => eprintln!("{}", err), + } +} + +fn state_dir() -> Option<PathBuf> { + let mut path = dirs::data_dir(); + path.as_mut().map(|p| p.push("tvix")); + path } fn run_prompt() { - let mut line = String::new(); + let mut rl = Editor::<()>::new().expect("should be able to launch rustyline"); + + let history_path = match state_dir() { + Some(mut path) => { + path.push("history.txt"); + rl.load_history(&path).ok(); + + Some(path) + } + + None => None, + }; loop { - print!("> "); - io::stdout().flush().unwrap(); - io::stdin() - .read_line(&mut line) - .expect("failed to read user input"); - run(mem::take(&mut line)); - line.clear(); + let readline = rl.readline("tvix-repl> "); + match readline { + Ok(line) => { + if line.is_empty() { + continue; + } + + match tvix_eval::interpret(&line) { + Ok(result) => { + println!("=> {} :: {}", result, result.type_of()); + rl.add_history_entry(line); + } + Err(err) => println!("{}", err), + } + } + Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => break, + + Err(err) => { + eprintln!("error: {}", err); + break; + } + } } -} -fn run(code: String) { - match tvix_eval::interpret(&code) { - Ok(result) => println!("=> {} :: {}", result, result.type_of()), - Err(err) => eprintln!("{}", err), + if let Some(path) = history_path { + rl.save_history(&path).unwrap(); } } |