Add support for Ctrl-C aborting the current command on the CLI (#528) r=rnewman
This commit is contained in:
parent
9740cafdbd
commit
1fcc3d7e1b
1 changed files with 35 additions and 9 deletions
|
@ -14,6 +14,7 @@ use linefeed::{
|
||||||
DefaultTerminal,
|
DefaultTerminal,
|
||||||
Reader,
|
Reader,
|
||||||
ReadResult,
|
ReadResult,
|
||||||
|
Signal,
|
||||||
};
|
};
|
||||||
|
|
||||||
use self::InputResult::*;
|
use self::InputResult::*;
|
||||||
|
@ -51,11 +52,26 @@ pub struct InputReader {
|
||||||
in_process_cmd: Option<Command>,
|
in_process_cmd: Option<Command>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum UserAction {
|
||||||
|
// We've received some text that we should interpret as a new command, or
|
||||||
|
// as part of the current command.
|
||||||
|
TextInput(String),
|
||||||
|
// We were interrupted, if we have a current command we should clear it,
|
||||||
|
// otherwise we should exit. Currently can only be generated by reading from
|
||||||
|
// a terminal (and not by reading from stdin).
|
||||||
|
Interrupt,
|
||||||
|
// We hit the end of the file, there was an error getting user input, or
|
||||||
|
// something else happened that means we should exit.
|
||||||
|
Quit,
|
||||||
|
}
|
||||||
|
|
||||||
impl InputReader {
|
impl InputReader {
|
||||||
/// Constructs a new `InputReader` reading from `stdin`.
|
/// Constructs a new `InputReader` reading from `stdin`.
|
||||||
pub fn new() -> InputReader {
|
pub fn new() -> InputReader {
|
||||||
let r = match Reader::new("mentat") {
|
let r = match Reader::new("mentat") {
|
||||||
Ok(mut r) => {
|
Ok(mut r) => {
|
||||||
|
// Handle SIGINT (Ctrl-C)
|
||||||
|
r.set_report_signal(Signal::Interrupt, true);
|
||||||
r.set_word_break_chars(" \t\n!\"#$%&'(){}*+,-./:;<=>?@[\\]^`");
|
r.set_word_break_chars(" \t\n!\"#$%&'(){}*+,-./:;<=>?@[\\]^`");
|
||||||
Some(r)
|
Some(r)
|
||||||
},
|
},
|
||||||
|
@ -80,8 +96,16 @@ impl InputReader {
|
||||||
pub fn read_input(&mut self) -> Result<InputResult, cli::Error> {
|
pub fn read_input(&mut self) -> Result<InputResult, cli::Error> {
|
||||||
let prompt = if self.in_process_cmd.is_some() { MORE_PROMPT } else { DEFAULT_PROMPT };
|
let prompt = if self.in_process_cmd.is_some() { MORE_PROMPT } else { DEFAULT_PROMPT };
|
||||||
let line = match self.read_line(prompt) {
|
let line = match self.read_line(prompt) {
|
||||||
Some(s) => s,
|
UserAction::TextInput(s) => s,
|
||||||
None => return Ok(Eof),
|
UserAction::Interrupt if self.in_process_cmd.is_some() => {
|
||||||
|
self.in_process_cmd = None;
|
||||||
|
self.buffer.clear();
|
||||||
|
// Move to the next line, so that our next prompt isn't on top
|
||||||
|
// of the previous.
|
||||||
|
println!();
|
||||||
|
String::new()
|
||||||
|
},
|
||||||
|
_ => return Ok(Eof),
|
||||||
};
|
};
|
||||||
|
|
||||||
if !self.buffer.is_empty() {
|
if !self.buffer.is_empty() {
|
||||||
|
@ -142,14 +166,16 @@ impl InputReader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_line(&mut self, prompt: &str) -> Option<String> {
|
fn read_line(&mut self, prompt: &str) -> UserAction {
|
||||||
match self.reader {
|
match self.reader {
|
||||||
Some(ref mut r) => {
|
Some(ref mut r) => {
|
||||||
r.set_prompt(prompt);
|
r.set_prompt(prompt);
|
||||||
r.read_line().ok().and_then(|line|
|
r.read_line().ok().map_or(UserAction::Quit, |line|
|
||||||
match line {
|
match line {
|
||||||
ReadResult::Input(s) => Some(s),
|
ReadResult::Input(s) => UserAction::TextInput(s),
|
||||||
_ => None
|
ReadResult::Signal(Signal::Interrupt) =>
|
||||||
|
UserAction::Interrupt,
|
||||||
|
_ => UserAction::Quit,
|
||||||
})
|
})
|
||||||
|
|
||||||
},
|
},
|
||||||
|
@ -157,12 +183,12 @@ impl InputReader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_stdin(&self) -> Option<String> {
|
fn read_stdin(&self) -> UserAction {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
|
|
||||||
match stdin().read_line(&mut s) {
|
match stdin().read_line(&mut s) {
|
||||||
Ok(0) | Err(_) => None,
|
Ok(0) | Err(_) => UserAction::Quit,
|
||||||
Ok(_) => Some(s)
|
Ok(_) => UserAction::TextInput(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue