diff --git a/src/main.rs b/src/main.rs index a8312b3..3583f1d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -56,8 +56,11 @@ mod runner; use anyhow::{Context, Result}; use clap::Parser; use crossterm::{ + event::{KeyboardEnhancementFlags, PopKeyboardEnhancementFlags, PushKeyboardEnhancementFlags}, execute, - terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, + terminal::{ + self, disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, + }, }; use std::io; use tui::{backend::CrosstermBackend, Terminal}; @@ -126,6 +129,17 @@ fn main() -> anyhow::Result<()> { fn configure_terminal() -> Result>, anyhow::Error> { enable_raw_mode().context("Unable to enable raw mode")?; let mut stdout = io::stdout(); + if matches!(terminal::supports_keyboard_enhancement(), Ok(true)) { + execute!( + stdout, + PushKeyboardEnhancementFlags( + KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES + | KeyboardEnhancementFlags::REPORT_ALTERNATE_KEYS + ) + ) + .context("Unable to push keyboard enhancement flags")?; + } + execute!(stdout, EnterAlternateScreen).context("Unable to enter alternate screen")?; let backend = CrosstermBackend::new(stdout); let terminal = Terminal::new(backend).context("Unable to create terminal")?; @@ -138,6 +152,11 @@ fn restore_terminal( mut terminal: Terminal>, ) -> Result<(), anyhow::Error> { disable_raw_mode().context("Unable to disable raw mode")?; + if matches!(terminal::supports_keyboard_enhancement(), Ok(true)) { + execute!(terminal.backend_mut(), PopKeyboardEnhancementFlags) + .context("Unable to pop keyboard enhancement flags")?; + } + execute!(terminal.backend_mut(), LeaveAlternateScreen) .context("Unable to leave alternate screen")?; terminal.show_cursor().context("Unable to show cursor")?; diff --git a/src/runner.rs b/src/runner.rs index 7a87218..00fb710 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -12,7 +12,7 @@ //! And test statistics are returned from the runner. use anyhow::{Context, Result}; -use crossterm::event::{self, Event, KeyCode}; +use crossterm::event::{self, Event, KeyCode, KeyModifiers}; use mockall::automock; use std::time::{Duration, Instant}; use tui::{ @@ -71,6 +71,18 @@ impl Runner { } } + /// Removes the last word from user input + fn remove_last_word(&mut self) { + let mut words = self.input.split_whitespace().collect::>(); + words.pop(); + + self.input = words.join(" "); + + if !self.input.is_empty() { + self.input.push(' '); + } + } + /// Method that runs the test. /// /// It renders the application using the `tui` crate and reacts to user input. @@ -129,6 +141,13 @@ impl Runner { _ => {} }, InputMode::Editing => match key.code { + // Crossterm returns `ctrl+w` or ``ctrl+h` when `ctrl+backspace` is pressed + // see: https://github.com/crossterm-rs/crossterm/issues/504 + KeyCode::Char('h') | KeyCode::Char('w') + if key.modifiers.contains(KeyModifiers::CONTROL) => + { + self.remove_last_word(); + } KeyCode::Char(c) => { self.input.push(c); @@ -147,6 +166,12 @@ impl Runner { self.raw_valid_characters_count += 1; } } + KeyCode::Backspace + if key.modifiers.contains(KeyModifiers::ALT) + | key.modifiers.contains(KeyModifiers::CONTROL) => + { + self.remove_last_word(); + } KeyCode::Backspace => { self.input.pop(); }