From 957453e8ed4f42adfbe68e5b51c5bcc5eaea5360 Mon Sep 17 00:00:00 2001 From: Ken Micklas Date: Sun, 8 Oct 2023 10:38:09 +0100 Subject: [PATCH] Handle suffixes of cancelled keymaps in insert mode --- helix-term/src/ui/editor.rs | 48 +++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index dd6fff087bee3..0328e1d81b29b 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -29,7 +29,7 @@ use helix_view::{ keyboard::{KeyCode, KeyModifiers}, Document, Editor, Theme, View, }; -use std::{mem::take, num::NonZeroUsize, path::PathBuf, rc::Rc, sync::Arc}; +use std::{collections::VecDeque, mem::take, num::NonZeroUsize, path::PathBuf, rc::Rc, sync::Arc}; use tui::{buffer::Buffer as Surface, text::Span}; @@ -857,28 +857,40 @@ impl EditorView { } fn insert_mode(&mut self, cx: &mut commands::Context, event: KeyEvent) { - if let Some(keyresult) = self.handle_keymap_event(Mode::Insert, cx, event) { - match keyresult { - KeymapResult::NotFound => { - if let Some(ch) = event.char() { - commands::insert::insert_char(cx, ch) + let mut queue = VecDeque::from([event]); + + while let Some(event) = queue.pop_front() { + if let Some(keyresult) = self.handle_keymap_event(Mode::Insert, cx, event) { + match keyresult { + KeymapResult::NotFound => { + if let Some(ch) = event.char() { + commands::insert::insert_char(cx, ch) + } } - } - KeymapResult::Cancelled(pending) => { - for ev in pending { - match ev.char() { - Some(ch) => commands::insert::insert_char(cx, ch), - None => { - if let KeymapResult::Matched(command) = - self.keymaps.get(Mode::Insert, ev) - { - command.execute(cx); - } + KeymapResult::Cancelled(pending) => { + let mut pending = pending.into_iter(); + if let Some(first) = pending.next() { + // Note that since this is the first pending key, we know + // it can't map to a command by itself. + match first.char() { + // The first key is both the start of a menu and a regular + // insert key. The user may have intended to type it as an + // insert, and then execute the remaining suffix of keys. + Some(ch) => commands::insert::insert_char(cx, ch), + // If the first key is not a character to insert, then we + // assume the user intended to enter a command menu, so we + // should just discard pending keys if they don't match. + None => continue, } } + + // Sadly VecDeque has no extend_front method. + for event in pending.rev() { + queue.push_front(event); + } } + _ => unreachable!(), } - _ => unreachable!(), } } }