diff --git a/src/input.rs b/src/input.rs index 9620c36..39e3744 100644 --- a/src/input.rs +++ b/src/input.rs @@ -7,6 +7,7 @@ use console::{Key, Term, measure_text_width}; use termcolor::{Buffer, WriteColor}; use crate::ctrlc; +use crate::keys::{CTRL_U, CTRL_W}; use crate::{Theme, theme}; /// Trait for implementing autocompletion features for text inputs. @@ -200,9 +201,6 @@ pub struct Input<'a> { suggestions_scroll_offset: usize, } -const CTRL_U: char = '\u{15}'; -const CTRL_W: char = '\u{17}'; - impl<'a> Input<'a> { /// Creates a new input with the given title. pub fn new>(title: S) -> Self { diff --git a/src/keys.rs b/src/keys.rs new file mode 100644 index 0000000..a088615 --- /dev/null +++ b/src/keys.rs @@ -0,0 +1,6 @@ +// Ctrl-N/Ctrl-P are the readline/emacs bindings for next/previous line +pub(crate) const CTRL_N: char = '\u{e}'; +pub(crate) const CTRL_P: char = '\u{10}'; + +pub(crate) const CTRL_U: char = '\u{15}'; +pub(crate) const CTRL_W: char = '\u{17}'; diff --git a/src/lib.rs b/src/lib.rs index 932c9a5..4207579 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,6 +22,7 @@ mod dialog; mod event; mod height; mod input; +mod keys; mod list; mod multiselect; mod option; diff --git a/src/list.rs b/src/list.rs index d0e31ee..a6817d6 100644 --- a/src/list.rs +++ b/src/list.rs @@ -4,6 +4,7 @@ use console::{Key, Term}; use std::io::Write; use termcolor::{Buffer, WriteColor}; +use crate::keys::{CTRL_N, CTRL_P}; use crate::{Theme, ctrlc, theme}; /// Display a list of options @@ -152,17 +153,19 @@ impl<'a> List<'a> { }; if self.filtering { match key { + Key::ArrowDown | Key::Char(CTRL_N) => self.handle_down()?, + Key::ArrowUp | Key::Char(CTRL_P) => self.handle_up(), Key::Enter => self.handle_stop_filtering(true)?, Key::Escape => self.handle_stop_filtering(false)?, Key::Backspace => self.handle_filter_backspace()?, - Key::Char(c) => self.handle_filter_key(c)?, + Key::Char(c) if !c.is_control() => self.handle_filter_key(c)?, _ => {} } } else { self.term.hide_cursor()?; match key { - Key::ArrowUp | Key::Char('k') => self.handle_up(), - Key::ArrowDown | Key::Char('j') => self.handle_down()?, + Key::ArrowDown | Key::Char('j') | Key::Char(CTRL_N) => self.handle_down()?, + Key::ArrowUp | Key::Char('k') | Key::Char(CTRL_P) => self.handle_up(), Key::ArrowLeft | Key::Char('h') => self.handle_left()?, Key::ArrowRight | Key::Char('l') => self.handle_right()?, Key::Char('/') if self.filterable => self.handle_start_filtering(), diff --git a/src/multiselect.rs b/src/multiselect.rs index 2420c7e..7c844a6 100644 --- a/src/multiselect.rs +++ b/src/multiselect.rs @@ -8,6 +8,7 @@ use fuzzy_matcher::skim::SkimMatcherV2; use itertools::Itertools; use termcolor::{Buffer, WriteColor}; +use crate::keys::{CTRL_N, CTRL_P}; use crate::theme::Theme; use crate::{DemandOption, ctrlc, theme}; @@ -199,8 +200,8 @@ impl<'a, T> MultiSelect<'a, T> { }; if self.filtering { match key { - Key::ArrowDown => self.handle_down()?, - Key::ArrowUp => self.handle_up()?, + Key::ArrowDown | Key::Char(CTRL_N) => self.handle_down()?, + Key::ArrowUp | Key::Char(CTRL_P) => self.handle_up()?, Key::ArrowLeft => self.handle_left()?, Key::ArrowRight => self.handle_right()?, Key::Enter => { @@ -212,14 +213,14 @@ impl<'a, T> MultiSelect<'a, T> { Key::Escape => self.handle_stop_filtering(false)?, Key::Backspace => self.handle_filter_backspace()?, key if key == self.toggle_key => self.handle_toggle(), - Key::Char(c) => self.handle_filter_key(c)?, + Key::Char(c) if !c.is_control() => self.handle_filter_key(c)?, _ => {} } } else { self.term.hide_cursor()?; match key { - Key::ArrowDown | Key::Char('j') => self.handle_down()?, - Key::ArrowUp | Key::Char('k') => self.handle_up()?, + Key::ArrowDown | Key::Char('j') | Key::Char(CTRL_N) => self.handle_down()?, + Key::ArrowUp | Key::Char('k') | Key::Char(CTRL_P) => self.handle_up()?, Key::ArrowLeft | Key::Char('h') => self.handle_left()?, Key::ArrowRight | Key::Char('l') => self.handle_right()?, key if key == self.toggle_key || key == Key::Char('x') => self.handle_toggle(), diff --git a/src/select.rs b/src/select.rs index 1441132..a8cb805 100644 --- a/src/select.rs +++ b/src/select.rs @@ -1,6 +1,7 @@ use std::io; use std::io::Write; +use crate::keys::{CTRL_N, CTRL_P}; use crate::theme::Theme; use crate::{DemandOption, ctrlc, theme}; use console::{Alignment, Key, Term}; @@ -174,8 +175,8 @@ impl<'a, T> Select<'a, T> { }; if self.filtering { match key { - Key::ArrowDown => self.handle_down()?, - Key::ArrowUp => self.handle_up()?, + Key::ArrowDown | Key::Char(CTRL_N) => self.handle_down()?, + Key::ArrowUp | Key::Char(CTRL_P) => self.handle_up()?, Key::ArrowLeft => self.handle_left()?, Key::ArrowRight => self.handle_right()?, Key::Enter if !self.visible_options().is_empty() => { @@ -183,13 +184,13 @@ impl<'a, T> Select<'a, T> { } Key::Escape => self.handle_stop_filtering(false)?, Key::Backspace => self.handle_filter_backspace()?, - Key::Char(c) => self.handle_filter_key(c)?, + Key::Char(c) if !c.is_control() => self.handle_filter_key(c)?, _ => {} } } else { match key { - Key::ArrowDown | Key::Char('j') => self.handle_down()?, - Key::ArrowUp | Key::Char('k') => self.handle_up()?, + Key::ArrowDown | Key::Char('j') | Key::Char(CTRL_N) => self.handle_down()?, + Key::ArrowUp | Key::Char('k') | Key::Char(CTRL_P) => self.handle_up()?, Key::ArrowLeft | Key::Char('h') => self.handle_left()?, Key::ArrowRight | Key::Char('l') => self.handle_right()?, Key::Char('/') if self.filterable => self.handle_start_filtering(),