Fix the additional moves of normal mode hjkl (#510)

* Fix the additional moves of normal mode `hjkl`

Fixes nushell/nushell#6991

Allows using `l` to complete the history hint in normal mode

Support menu navigation with `hjkl` in vi normal mode

Adjusts tests

* Fix clippy

Parameter only used in recursion
This commit is contained in:
Stefan Holderbach 2022-11-05 23:07:57 +01:00 committed by GitHub
parent 307df231e1
commit 431d2ab656
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 45 additions and 24 deletions

View File

@ -143,10 +143,23 @@ pub enum Motion {
impl Motion {
pub fn to_reedline(&self, vi_state: &mut Vi) -> Vec<ReedlineOption> {
match self {
Motion::Left => vec![ReedlineOption::Event(ReedlineEvent::Left)],
Motion::Right => vec![ReedlineOption::Event(ReedlineEvent::Right)],
Motion::Up => vec![ReedlineOption::Event(ReedlineEvent::Up)],
Motion::Down => vec![ReedlineOption::Event(ReedlineEvent::Down)],
Motion::Left => vec![ReedlineOption::Event(ReedlineEvent::UntilFound(vec![
ReedlineEvent::MenuLeft,
ReedlineEvent::Left,
]))],
Motion::Right => vec![ReedlineOption::Event(ReedlineEvent::UntilFound(vec![
ReedlineEvent::HistoryHintComplete,
ReedlineEvent::MenuRight,
ReedlineEvent::Right,
]))],
Motion::Up => vec![ReedlineOption::Event(ReedlineEvent::UntilFound(vec![
ReedlineEvent::MenuUp,
ReedlineEvent::Up,
]))],
Motion::Down => vec![ReedlineOption::Event(ReedlineEvent::UntilFound(vec![
ReedlineEvent::MenuDown,
ReedlineEvent::Down,
]))],
Motion::NextWord => vec![ReedlineOption::Edit(EditCommand::MoveWordRightStart)],
Motion::NextBigWord => vec![ReedlineOption::Edit(EditCommand::MoveBigWordRightStart)],
Motion::NextWordEnd => vec![ReedlineOption::Edit(EditCommand::MoveWordRightEnd)],

View File

@ -406,24 +406,36 @@ mod tests {
}
#[rstest]
#[case(&['2', 'k'], ReedlineEvent::Multiple(vec![ReedlineEvent::Up, ReedlineEvent::Up]))]
#[case(&['k'], ReedlineEvent::Multiple(vec![ReedlineEvent::Up]))]
#[case(&['2', 'k'], ReedlineEvent::Multiple(vec![ReedlineEvent::UntilFound(vec![
ReedlineEvent::MenuUp,
ReedlineEvent::Up,
]), ReedlineEvent::UntilFound(vec![
ReedlineEvent::MenuUp,
ReedlineEvent::Up,
])]))]
#[case(&['k'], ReedlineEvent::Multiple(vec![ReedlineEvent::UntilFound(vec![
ReedlineEvent::MenuUp,
ReedlineEvent::Up,
])]))]
#[case(&['w'],
ReedlineEvent::Multiple(vec![ReedlineEvent::Edit(vec![EditCommand::MoveWordRightStart])]))]
#[case(&['W'],
ReedlineEvent::Multiple(vec![ReedlineEvent::Edit(vec![EditCommand::MoveBigWordRightStart])]))]
#[case(&['2', 'j'], ReedlineEvent::Multiple(vec![ReedlineEvent::Down, ReedlineEvent::Down]))]
#[case(&['j'], ReedlineEvent::Multiple(vec![ReedlineEvent::Down]))]
#[case(&['2', 'l'], ReedlineEvent::Multiple(vec![
ReedlineEvent::Right,
ReedlineEvent::Right
]))]
#[case(&['l'], ReedlineEvent::Multiple(vec![ReedlineEvent::Right]))]
#[case(&['2', 'h'], ReedlineEvent::Multiple(vec![
ReedlineEvent::Left,
ReedlineEvent::Left,
]))]
#[case(&['h'], ReedlineEvent::Multiple(vec![ReedlineEvent::Left]))]
ReedlineEvent::UntilFound(vec![
ReedlineEvent::HistoryHintComplete,
ReedlineEvent::MenuRight,
ReedlineEvent::Right,
]),ReedlineEvent::UntilFound(vec![
ReedlineEvent::HistoryHintComplete,
ReedlineEvent::MenuRight,
ReedlineEvent::Right,
]) ]))]
#[case(&['l'], ReedlineEvent::Multiple(vec![ReedlineEvent::UntilFound(vec![
ReedlineEvent::HistoryHintComplete,
ReedlineEvent::MenuRight,
ReedlineEvent::Right,
])]))]
#[case(&['0'], ReedlineEvent::Multiple(vec![ReedlineEvent::Edit(vec![EditCommand::MoveToLineStart])]))]
#[case(&['$'], ReedlineEvent::Multiple(vec![ReedlineEvent::Edit(vec![EditCommand::MoveToLineEnd])]))]
#[case(&['i'], ReedlineEvent::Multiple(vec![ReedlineEvent::Repaint]))]

View File

@ -581,21 +581,17 @@ impl Reedline {
fn handle_event(&mut self, prompt: &dyn Prompt, event: ReedlineEvent) -> Result<EventStatus> {
if self.input_mode == InputMode::HistorySearch {
self.handle_history_search_event(prompt, event)
self.handle_history_search_event(event)
} else {
self.handle_editor_event(prompt, event)
}
}
fn handle_history_search_event(
&mut self,
prompt: &dyn Prompt,
event: ReedlineEvent,
) -> io::Result<EventStatus> {
fn handle_history_search_event(&mut self, event: ReedlineEvent) -> io::Result<EventStatus> {
match event {
ReedlineEvent::UntilFound(events) => {
for event in events {
match self.handle_history_search_event(prompt, event)? {
match self.handle_history_search_event(event)? {
EventStatus::Inapplicable => {
// Try again with the next event handler
}