diff --git a/cli/tools/repl/editor.rs b/cli/tools/repl/editor.rs index 2ff9ee0b4b..86d4ce4f94 100644 --- a/cli/tools/repl/editor.rs +++ b/cli/tools/repl/editor.rs @@ -372,6 +372,7 @@ pub struct ReplEditor { inner: Arc>>, history_file_path: PathBuf, errored_on_history_save: Arc, + should_exit_on_interrupt: Arc, } impl ReplEditor { @@ -395,6 +396,13 @@ impl ReplEditor { KeyEvent(KeyCode::Tab, Modifiers::NONE), EventHandler::Conditional(Box::new(TabEventHandler)), ); + let should_exit_on_interrupt = Arc::new(AtomicBool::new(false)); + editor.bind_sequence( + KeyEvent(KeyCode::Char('r'), Modifiers::CTRL), + EventHandler::Conditional(Box::new(ReverseSearchHistoryEventHandler { + should_exit_on_interrupt: should_exit_on_interrupt.clone(), + })), + ); let history_file_dir = history_file_path.parent().unwrap(); std::fs::create_dir_all(history_file_dir).with_context(|| { @@ -408,6 +416,7 @@ impl ReplEditor { inner: Arc::new(Mutex::new(editor)), history_file_path, errored_on_history_save: Arc::new(AtomicBool::new(false)), + should_exit_on_interrupt, }) } @@ -426,6 +435,31 @@ impl ReplEditor { eprintln!("Unable to save history file: {}", e); } } + + pub fn should_exit_on_interrupt(&self) -> bool { + self.should_exit_on_interrupt.load(Relaxed) + } + + pub fn set_should_exit_on_interrupt(&self, yes: bool) { + self.should_exit_on_interrupt.store(yes, Relaxed); + } +} + +/// Command to reverse search history , same as rustyline default C-R but that resets repl should_exit flag to false +struct ReverseSearchHistoryEventHandler { + should_exit_on_interrupt: Arc, +} +impl ConditionalEventHandler for ReverseSearchHistoryEventHandler { + fn handle( + &self, + _: &Event, + _: RepeatCount, + _: bool, + _: &EventContext, + ) -> Option { + self.should_exit_on_interrupt.store(false, Relaxed); + Some(Cmd::ReverseSearchHistory) + } } /// A custom tab key event handler diff --git a/cli/tools/repl/mod.rs b/cli/tools/repl/mod.rs index 8fcae505ee..b594055805 100644 --- a/cli/tools/repl/mod.rs +++ b/cli/tools/repl/mod.rs @@ -91,7 +91,6 @@ pub async fn run(flags: Flags, repl_flags: ReplFlags) -> Result { let worker = worker.into_main_worker(); let mut repl_session = ReplSession::initialize(ps.clone(), worker).await?; let mut rustyline_channel = rustyline_channel(); - let mut should_exit_on_interrupt = false; let helper = EditorHelper { context_id: repl_session.context_id, @@ -154,7 +153,7 @@ pub async fn run(flags: Flags, repl_flags: ReplFlags) -> Result { .await; match line { Ok(line) => { - should_exit_on_interrupt = false; + editor.set_should_exit_on_interrupt(false); editor.update_history(line.clone()); let output = repl_session.evaluate_line_and_get_output(&line).await; @@ -167,10 +166,10 @@ pub async fn run(flags: Flags, repl_flags: ReplFlags) -> Result { println!("{}", output); } Err(ReadlineError::Interrupted) => { - if should_exit_on_interrupt { + if editor.should_exit_on_interrupt() { break; } - should_exit_on_interrupt = true; + editor.set_should_exit_on_interrupt(true); println!("press ctrl+c again to exit"); continue; }