improve REPL command completer

This commit is contained in:
vms 2020-08-09 14:48:18 +03:00
parent d68e0cd76e
commit f1fcc7ce42
5 changed files with 375 additions and 17 deletions

3
.gitignore vendored
View File

@ -9,6 +9,9 @@ target/
*.wasm
*.wat
# REPL history files
*.repl_history
# Temporary file of ipfs node example
/examples/ipfs_node/wasm/artifacts/ipfs_rpc_file

308
Cargo.lock generated
View File

@ -15,6 +15,15 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
[[package]]
name = "aho-corasick"
version = "0.7.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86"
dependencies = [
"memchr",
]
[[package]]
name = "ansi_term"
version = "0.11.0"
@ -145,6 +154,17 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "chrono"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c74d84029116787153e02106bf53e66828452a4b325cc8652b788b5967c0a0b6"
dependencies = [
"num-integer",
"num-traits",
"time",
]
[[package]]
name = "clap"
version = "2.33.2"
@ -154,7 +174,7 @@ dependencies = [
"ansi_term",
"atty",
"bitflags",
"strsim",
"strsim 0.8.0",
"textwrap",
"unicode-width",
"vec_map",
@ -309,6 +329,66 @@ dependencies = [
"syn",
]
[[package]]
name = "darling"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim 0.9.3",
"syn",
]
[[package]]
name = "darling_macro"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72"
dependencies = [
"darling_core",
"quote",
"syn",
]
[[package]]
name = "derive_builder"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2658621297f2cf68762a6f7dc0bb7e1ff2cfd6583daef8ee0fed6f7ec468ec0"
dependencies = [
"darling",
"derive_builder_core",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "derive_builder_core"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2791ea3e372c8495c0bc2033991d76b512cd799d07491fbd6890124db9458bef"
dependencies = [
"darling",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "digest"
version = "0.8.1"
@ -327,6 +407,17 @@ dependencies = [
"generic-array 0.14.3",
]
[[package]]
name = "dirs"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901"
dependencies = [
"libc",
"redox_users",
"winapi",
]
[[package]]
name = "dirs-next"
version = "1.0.1"
@ -354,6 +445,19 @@ version = "1.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
[[package]]
name = "env_logger"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3"
dependencies = [
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]]
name = "erased-serde"
version = "0.3.12"
@ -557,6 +661,12 @@ dependencies = [
"uuid",
]
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "frepl"
version = "0.1.0"
@ -572,6 +682,15 @@ dependencies = [
"wasmer-wasi-fl",
]
[[package]]
name = "fuzzy-matcher"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda28c4acb13182d935e0ab6bc12329d1d22134d69801d0836d1ae4b47054f2a"
dependencies = [
"thread_local",
]
[[package]]
name = "gcc"
version = "0.3.55"
@ -678,12 +797,27 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
[[package]]
name = "humantime"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
dependencies = [
"quick-error",
]
[[package]]
name = "id-arena"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005"
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "indexmap"
version = "1.5.0"
@ -837,6 +971,19 @@ dependencies = [
"serde",
]
[[package]]
name = "nix"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce"
dependencies = [
"bitflags",
"cc",
"cfg-if",
"libc",
"void",
]
[[package]]
name = "nix"
version = "0.15.0"
@ -874,6 +1021,25 @@ dependencies = [
"version_check",
]
[[package]]
name = "num-integer"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.13.0"
@ -962,6 +1128,12 @@ dependencies = [
"parity-wasm",
]
[[package]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quote"
version = "1.0.7"
@ -1081,6 +1253,24 @@ dependencies = [
"rust-argon2",
]
[[package]]
name = "regex"
version = "1.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
"thread_local",
]
[[package]]
name = "regex-syntax"
version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
[[package]]
name = "rust-argon2"
version = "0.7.0"
@ -1127,9 +1317,10 @@ dependencies = [
"memchr",
"nix 0.17.0",
"scopeguard",
"skim",
"unicode-segmentation",
"unicode-width",
"utf8parse",
"utf8parse 0.2.0",
"winapi",
]
@ -1226,6 +1417,37 @@ dependencies = [
"serde",
]
[[package]]
name = "shlex"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
[[package]]
name = "skim"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb226ef1f69c44352626532a14c0692be118eb9f93e91010150d165a9d693efa"
dependencies = [
"bitflags",
"chrono",
"clap",
"derive_builder",
"env_logger",
"fuzzy-matcher",
"lazy_static",
"log",
"nix 0.14.1",
"rayon",
"regex",
"shlex",
"time",
"timer",
"tuikit",
"unicode-width",
"vte",
]
[[package]]
name = "smallvec"
version = "1.4.1"
@ -1244,6 +1466,12 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "strsim"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
[[package]]
name = "subtle"
version = "2.2.3"
@ -1279,6 +1507,26 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab0e7238dcc7b40a7be719a25365910f6807bd864f4cce6b2e6b873658e2b19d"
[[package]]
name = "term"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42"
dependencies = [
"byteorder",
"dirs",
"winapi",
]
[[package]]
name = "termcolor"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
dependencies = [
"winapi-util",
]
[[package]]
name = "test-record"
version = "0.1.0"
@ -1315,6 +1563,15 @@ dependencies = [
"syn",
]
[[package]]
name = "thread_local"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
dependencies = [
"lazy_static",
]
[[package]]
name = "time"
version = "0.1.43"
@ -1325,6 +1582,15 @@ dependencies = [
"winapi",
]
[[package]]
name = "timer"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31d42176308937165701f50638db1c31586f183f1aab416268216577aec7306b"
dependencies = [
"chrono",
]
[[package]]
name = "toml"
version = "0.5.6"
@ -1334,6 +1600,20 @@ dependencies = [
"serde",
]
[[package]]
name = "tuikit"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "846bc187c93656d5ef5389809d1b6950fd1364906af5e9953a9de129c295c3a5"
dependencies = [
"bitflags",
"lazy_static",
"log",
"nix 0.14.1",
"term",
"unicode-width",
]
[[package]]
name = "typenum"
version = "1.12.0"
@ -1382,6 +1662,12 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "utf8parse"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d"
[[package]]
name = "utf8parse"
version = "0.2.0"
@ -1415,6 +1701,15 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]]
name = "vte"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f42f536e22f7fcbb407639765c8fd78707a33109301f834a594758bedd6e8cf"
dependencies = [
"utf8parse 0.1.1",
]
[[package]]
name = "walrus"
version = "0.17.0"
@ -1660,6 +1955,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"

View File

@ -19,7 +19,7 @@ clap = "2.33.1"
serde_json = "1.0.57"
wasmer-wasi = { package = "wasmer-wasi-fl", version = "0.17.0"}
rustyline = "6.1.2"
rustyline = { version = "6.1.2", features = ["with-fuzzy"] }
rustyline-derive = "0.3.1"
rustop = "1.1.0"
uuid = { version = "0.8.1", features = ["v4"] }

View File

@ -40,6 +40,9 @@ use rustyline::{Cmd, CompletionType, Config, Context, EditMode, Editor, KeyPress
use rustyline_derive::Helper;
use std::borrow::Cow::{self, Borrowed, Owned};
use std::collections::HashSet;
const HISTORY_FILE_PATH: &str = ".repl_history";
pub(crate) type Result<T> = std::result::Result<T, anyhow::Error>;
@ -52,22 +55,28 @@ fn main() -> Result<()> {
let config = Config::builder()
.history_ignore_space(true)
.completion_type(CompletionType::List)
.completion_type(CompletionType::Fuzzy)
.edit_mode(EditMode::Emacs)
.output_stream(OutputStreamType::Stdout)
.build();
let h = MyHelper {
let repl_hinter = REPLHinter {
commands_hints: commands_hints(),
history_hinter: HistoryHinter {},
};
let repl_helper = REPLHelper {
completer: FilenameCompleter::new(),
highlighter: MatchingBracketHighlighter::new(),
hinter: HistoryHinter {},
hinter: repl_hinter,
colored_prompt: "".to_owned(),
validator: MatchingBracketValidator::new(),
};
let mut rl = Editor::with_config(config);
rl.set_helper(Some(h));
rl.set_helper(Some(repl_helper));
rl.bind_sequence(KeyPress::Meta('N'), Cmd::HistorySearchForward);
rl.bind_sequence(KeyPress::Meta('P'), Cmd::HistorySearchBackward);
let _ = rl.load_history("history.txt");
let _ = rl.load_history(HISTORY_FILE_PATH);
println!("Welcome to the Fluence FaaS REPL:");
@ -75,7 +84,7 @@ fn main() -> Result<()> {
let mut count = 1;
loop {
let p = format!("{}> ", count);
let p = format!("\n{}> ", count);
rl.helper_mut().expect("No helper").colored_prompt = format!("\x1b[1;32m{}\x1b[0m", p);
let readline = rl.readline(&p);
match readline {
@ -99,19 +108,29 @@ fn main() -> Result<()> {
count += 1;
}
if let Err(e) = rl.save_history(HISTORY_FILE_PATH) {
eprintln!("failed to save history: {}", e);
}
Ok(())
}
#[derive(Helper)]
struct MyHelper {
struct REPLHelper {
completer: FilenameCompleter,
highlighter: MatchingBracketHighlighter,
validator: MatchingBracketValidator,
hinter: HistoryHinter,
hinter: REPLHinter,
colored_prompt: String,
}
impl Completer for MyHelper {
/// Tries to find hint from history if its failed from supported command list.
struct REPLHinter {
commands_hints: HashSet<String>,
history_hinter: HistoryHinter,
}
impl Completer for REPLHelper {
type Candidate = Pair;
fn complete(
@ -124,13 +143,33 @@ impl Completer for MyHelper {
}
}
impl Hinter for MyHelper {
impl Hinter for REPLHelper {
fn hint(&self, line: &str, pos: usize, ctx: &Context<'_>) -> Option<String> {
self.hinter.hint(line, pos, ctx)
if pos < line.len() {
return None;
}
if let Some(hint) = self.hinter.history_hinter.hint(line, pos, ctx) {
return Some(hint);
}
self.hinter
.commands_hints
.iter()
.filter_map(|hint| {
// expect hint after word complete, like redis cli, add condition:
// line.ends_with(" ")
if pos > 0 && hint.starts_with(&line[..pos]) {
Some(hint[pos..].to_owned())
} else {
None
}
})
.next()
}
}
impl Highlighter for MyHelper {
impl Highlighter for REPLHelper {
fn highlight<'l>(&self, line: &'l str, pos: usize) -> Cow<'l, str> {
self.highlighter.highlight(line, pos)
}
@ -156,7 +195,7 @@ impl Highlighter for MyHelper {
}
}
impl Validator for MyHelper {
impl Validator for REPLHelper {
fn validate(
&self,
ctx: &mut validate::ValidationContext<'_>,
@ -168,3 +207,15 @@ impl Validator for MyHelper {
self.validator.validate_while_typing()
}
}
fn commands_hints() -> HashSet<String> {
let mut set = HashSet::new();
set.insert(String::from("load"));
set.insert(String::from("unload"));
set.insert(String::from("call"));
set.insert(String::from("envs"));
set.insert(String::from("fs"));
set.insert(String::from("interface"));
set.insert(String::from("help"));
set
}