diff options
Diffstat (limited to 'cli')
-rw-r--r-- | cli/tests/integration/repl_tests.rs | 22 | ||||
-rw-r--r-- | cli/tools/repl/editor.rs | 35 |
2 files changed, 57 insertions, 0 deletions
diff --git a/cli/tests/integration/repl_tests.rs b/cli/tests/integration/repl_tests.rs index 47d366091..a6c053675 100644 --- a/cli/tests/integration/repl_tests.rs +++ b/cli/tests/integration/repl_tests.rs @@ -804,3 +804,25 @@ fn pty_clear_function() { assert!(output.contains("3234")); }); } + +#[test] +fn pty_tab_handler() { + // If the last character is **not** whitespace, we show the completions + util::with_pty(&["repl"], |mut console| { + console.write_line("a\t\t"); + console.write_line("close();"); + let output = console.read_all_output(); + assert!(output.contains("addEventListener")); + assert!(output.contains("alert")); + assert!(output.contains("atob")); + }); + // If the last character is whitespace, we just insert a tab + util::with_pty(&["repl"], |mut console| { + console.write_line("a \t\t"); // last character is whitespace + console.write_line("close();"); + let output = console.read_all_output(); + assert!(!output.contains("addEventListener")); + assert!(!output.contains("alert")); + assert!(!output.contains("atob")); + }); +} diff --git a/cli/tools/repl/editor.rs b/cli/tools/repl/editor.rs index 502134ebc..cc095a603 100644 --- a/cli/tools/repl/editor.rs +++ b/cli/tools/repl/editor.rs @@ -23,6 +23,7 @@ use rustyline::EventHandler; use rustyline::KeyCode; use rustyline::KeyEvent; use rustyline::Modifiers; +use rustyline::{ConditionalEventHandler, Event, EventContext, RepeatCount}; use rustyline_derive::{Helper, Hinter}; use std::borrow::Cow; use std::path::PathBuf; @@ -369,6 +370,10 @@ impl ReplEditor { KeyEvent(KeyCode::Char('s'), Modifiers::CTRL), EventHandler::Simple(Cmd::Newline), ); + editor.bind_sequence( + KeyEvent::from('\t'), + EventHandler::Conditional(Box::new(TabEventHandler)), + ); ReplEditor { inner: Arc::new(Mutex::new(editor)), @@ -391,3 +396,33 @@ impl ReplEditor { Ok(()) } } + +/// A custom tab key event handler +/// It uses a heuristic to determine if the user is requesting completion or if they want to insert an actual tab +/// The heuristic goes like this: +/// - If the last character before the cursor is whitespace, the the user wants to insert a tab +/// - Else the user is requesting completion +struct TabEventHandler; +impl ConditionalEventHandler for TabEventHandler { + fn handle( + &self, + evt: &Event, + n: RepeatCount, + _: bool, + ctx: &EventContext, + ) -> Option<Cmd> { + debug_assert_eq!(*evt, Event::from(KeyEvent::from('\t'))); + if ctx.line().is_empty() + || ctx.line()[..ctx.pos()] + .chars() + .rev() + .next() + .filter(|c| c.is_whitespace()) + .is_some() + { + Some(Cmd::Insert(n, "\t".into())) + } else { + None // default complete + } + } +} |