REPL implementation based on contribution: https://github.com/cozodb/cozo/issues/31
parent
09cd9cb962
commit
2b4a0fc7a8
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022, The Cozo Project Authors.
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||||
|
* If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// This file is based on code contributed by https://github.com/rhn
|
||||||
|
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
use prettytable;
|
||||||
|
use rustyline;
|
||||||
|
|
||||||
|
use cozo;
|
||||||
|
use cozo::DbInstance;
|
||||||
|
|
||||||
|
struct Indented;
|
||||||
|
|
||||||
|
impl rustyline::hint::Hinter for Indented {
|
||||||
|
type Hint = String;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl rustyline::highlight::Highlighter for Indented {}
|
||||||
|
impl rustyline::completion::Completer for Indented {
|
||||||
|
type Candidate = String;
|
||||||
|
|
||||||
|
fn update(
|
||||||
|
&self,
|
||||||
|
_line: &mut rustyline::line_buffer::LineBuffer,
|
||||||
|
_start: usize,
|
||||||
|
_elected: &str,
|
||||||
|
) {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl rustyline::Helper for Indented {}
|
||||||
|
|
||||||
|
impl rustyline::validate::Validator for Indented {
|
||||||
|
fn validate(
|
||||||
|
&self,
|
||||||
|
ctx: &mut rustyline::validate::ValidationContext<'_>,
|
||||||
|
) -> rustyline::Result<rustyline::validate::ValidationResult> {
|
||||||
|
Ok(if ctx.input().starts_with(" ") {
|
||||||
|
if ctx.input().ends_with("\n") {
|
||||||
|
rustyline::validate::ValidationResult::Valid(None)
|
||||||
|
} else {
|
||||||
|
rustyline::validate::ValidationResult::Incomplete
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rustyline::validate::ValidationResult::Valid(None)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn repl_main(db: DbInstance) -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut exit = false;
|
||||||
|
let mut rl = rustyline::Editor::<Indented>::new()?;
|
||||||
|
rl.set_helper(Some(Indented));
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let readline = rl.readline("=> ");
|
||||||
|
match readline {
|
||||||
|
Ok(line) => {
|
||||||
|
match db.run_script(&line, Default::default()) {
|
||||||
|
Ok(out) => {
|
||||||
|
use prettytable::format;
|
||||||
|
let mut table = prettytable::Table::new();
|
||||||
|
let headers = out
|
||||||
|
.headers
|
||||||
|
.iter()
|
||||||
|
.map(prettytable::Cell::from)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
table.set_titles(prettytable::Row::new(headers));
|
||||||
|
let rows = out
|
||||||
|
.rows
|
||||||
|
.iter()
|
||||||
|
.map(|r| r.iter().map(|c| format!("{}", c)).collect::<Vec<_>>())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let rows = rows
|
||||||
|
.iter()
|
||||||
|
.map(|r| r.iter().map(prettytable::Cell::from).collect::<Vec<_>>());
|
||||||
|
for row in rows {
|
||||||
|
table.add_row(prettytable::Row::new(row));
|
||||||
|
}
|
||||||
|
table.set_format(*format::consts::FORMAT_NO_BORDER_LINE_SEPARATOR);
|
||||||
|
table.printstd();
|
||||||
|
}
|
||||||
|
Err(mut err) => {
|
||||||
|
if err.source_code().is_none() {
|
||||||
|
err = err.with_source_code(line.to_string());
|
||||||
|
}
|
||||||
|
eprintln!("{:?}", err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
rl.add_history_entry(line);
|
||||||
|
}
|
||||||
|
Err(rustyline::error::ReadlineError::Interrupted) => {
|
||||||
|
if exit {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
println!("Again to exit");
|
||||||
|
exit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(rustyline::error::ReadlineError::Eof) => break,
|
||||||
|
Err(e) => eprintln!("{:?}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in New Issue