Add support for line editing, history and keyboard shortcuts in skysh (#142)

* Add line editing and history support

* Enable screen to be cleared by running clear
next
Sayan Nandan 3 years ago committed by GitHub
parent 885e2f2c42
commit f1beb7b1e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

3
.gitignore vendored

@ -6,4 +6,5 @@ snapstore.bin
snapstore.partmap
/snapshots
/.idea
.DS_Store
.DS_Store
.sky_history

151
Cargo.lock generated

@ -97,12 +97,64 @@ dependencies = [
"yaml-rust",
]
[[package]]
name = "crossterm"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c36c10130df424b2f3552fcc2ddcd9b28a27b1e54b358b45874f88d1ca6888c"
dependencies = [
"bitflags",
"crossterm_winapi",
"lazy_static",
"libc",
"mio",
"parking_lot",
"signal-hook",
"winapi",
]
[[package]]
name = "crossterm_winapi"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0da8964ace4d3e4a044fd027919b2237000b24315a37c916f61809f1ff2140b9"
dependencies = [
"winapi",
]
[[package]]
name = "devtimer"
version = "4.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "907339959a92f6b98846570500c0a567c9aecbb3871cef00561eb5d20d47b7c1"
[[package]]
name = "dirs-next"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
dependencies = [
"cfg-if",
"dirs-sys-next",
]
[[package]]
name = "dirs-sys-next"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
dependencies = [
"libc",
"redox_users",
"winapi",
]
[[package]]
name = "endian-type"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
[[package]]
name = "env_logger"
version = "0.8.3"
@ -131,6 +183,16 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "fs2"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "fs_extra"
version = "1.2.0"
@ -360,6 +422,27 @@ dependencies = [
"winapi",
]
[[package]]
name = "nibble_vec"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43"
dependencies = [
"smallvec",
]
[[package]]
name = "nix"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a"
dependencies = [
"bitflags",
"cc",
"cfg-if",
"libc",
]
[[package]]
name = "ntapi"
version = "0.3.6"
@ -540,6 +623,16 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "radix_trie"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd"
dependencies = [
"endian-type",
"nibble_vec",
]
[[package]]
name = "rand"
version = "0.8.3"
@ -589,6 +682,16 @@ dependencies = [
"bitflags",
]
[[package]]
name = "redox_users"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
dependencies = [
"getrandom",
"redox_syscall",
]
[[package]]
name = "regex"
version = "1.4.6"
@ -606,6 +709,29 @@ version = "0.6.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581"
[[package]]
name = "rustyline"
version = "8.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e1b597fcd1eeb1d6b25b493538e5aa19629eb08932184b85fef931ba87e893"
dependencies = [
"bitflags",
"cfg-if",
"dirs-next",
"fs2",
"libc",
"log",
"memchr",
"nix",
"radix_trie",
"scopeguard",
"smallvec",
"unicode-segmentation",
"unicode-width",
"utf8parse",
"winapi",
]
[[package]]
name = "ryu"
version = "1.0.5"
@ -649,6 +775,17 @@ dependencies = [
"serde",
]
[[package]]
name = "signal-hook"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e31d442c16f047a671b5a71e2161d6e68814012b7f5379d269ebd915fac2729"
dependencies = [
"libc",
"mio",
"signal-hook-registry",
]
[[package]]
name = "signal-hook-registry"
version = "1.3.0"
@ -714,8 +851,10 @@ version = "0.5.1"
dependencies = [
"bytes",
"clap",
"crossterm",
"libsky",
"openssl",
"rustyline",
"tokio",
"tokio-openssl",
]
@ -841,6 +980,12 @@ dependencies = [
"serde",
]
[[package]]
name = "unicode-segmentation"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796"
[[package]]
name = "unicode-width"
version = "0.1.8"
@ -853,6 +998,12 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "utf8parse"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372"
[[package]]
name = "vcpkg"
version = "0.2.11"

@ -12,4 +12,6 @@ tokio = {version = "1.5.0", features = ["full"]}
bytes = "1.0.1"
clap = {version = "2.33.3", features=["yaml"]}
openssl = { version = "0.10.33", features = ["vendored"] }
tokio-openssl = "0.6.1"
tokio-openssl = "0.6.1"
rustyline = "8.0.0"
crossterm = "0.19.0"

@ -27,15 +27,20 @@
use crate::protocol;
use clap::load_yaml;
use clap::App;
use std::io::stdout;
use libsky::terrapipe::ADDR;
use crossterm::{execute, cursor};
use crossterm::terminal::{Clear, ClearType};
use protocol::{Con, Connection, SslConnection};
use std::io::{self, prelude::*};
use readline::config::Configurer;
use readline::{error::ReadlineError, Editor};
use rustyline as readline;
use std::process;
const MSG_WELCOME: &'static str = "Skytable v0.5.1";
#[macro_use]
macro_rules! end_con_with_loop {
($con:ident) => {
macro_rules! close_con {
($con:expr) => {
if let Err(e) = $con.shutdown().await {
eprintln!(
"Failed to gracefully terminate connection with error '{}'",
@ -43,7 +48,10 @@ macro_rules! end_con_with_loop {
);
std::process::exit(0x100);
}
break;
};
($con:expr, $err:expr) => {
eprintln!("An error occurred while reading your input: '{}'", $err);
close_con!($con)
};
}
@ -97,29 +105,33 @@ pub async fn start_repl() {
con.execute_query(eval_expr.to_string()).await;
return;
}
let mut editor = Editor::<()>::new();
editor.set_auto_add_history(true);
editor.set_history_ignore_dups(true);
let _ = editor.load_history(".sky_history");
println!("{}", MSG_WELCOME);
loop {
print!("skysh>");
io::stdout()
.flush()
.expect("Couldn't flush buffer, this is a serious error!");
let mut rl = String::new();
io::stdin()
.read_line(&mut rl)
.expect("Couldn't read line, this is a serious error!");
if rl.trim().to_uppercase() == "EXIT" {
println!("Goodbye!");
end_con_with_loop!(con);
}
if rl.len() == 0 {
// The query was empty, so let it be
continue;
}
tokio::select! {
_ = con.execute_query(rl) => {},
_ = tokio::signal::ctrl_c() => {
end_con_with_loop!(con);
match editor.readline("skysh> ") {
Ok(line) => match line.to_lowercase().as_str() {
"exit" => break,
"clear" => {
let mut stdout = stdout();
execute!(stdout, Clear(ClearType::All)).expect("Failed to clear screen");
execute!(stdout, cursor::MoveTo(0, 0)).expect("Failed to move cursor to origin");
drop(stdout); // aggressively drop stdout
continue;
}
_ => con.execute_query(line).await,
},
Err(ReadlineError::Interrupted) => break,
Err(err) => {
close_con!(con, err);
}
}
}
if let Err(e) = editor.save_history(".sky_history") {
eprintln!("Failed to save history with error: '{}'", e);
}
close_con!(con);
println!("Goodbye!");
}

Loading…
Cancel
Save