From 66fb1e67c09c653b1577336dac27e6f6b162e7b6 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Sun, 3 Mar 2024 23:22:30 +0100 Subject: [PATCH] add fallback onNextKey adds a variant of on_next_key callbacks that are only called when no other mapping matches a key --- helix-term/src/commands.rs | 21 ++++++++++++++++-- helix-term/src/ui/editor.rs | 44 +++++++++++++++++++++++++++---------- 2 files changed, 51 insertions(+), 14 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 6a35e812b..788d10f04 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -87,6 +87,11 @@ use ignore::{DirEntry, WalkBuilder, WalkState}; pub type OnKeyCallback = Box; +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub enum OnKeyCallbackKind { + PseudoPending, + Fallback, +} pub struct Context<'a> { pub register: Option, @@ -94,7 +99,7 @@ pub struct Context<'a> { pub editor: &'a mut Editor, pub callback: Vec, - pub on_next_key_callback: Option, + pub on_next_key_callback: Option<(OnKeyCallback, OnKeyCallbackKind)>, pub jobs: &'a mut Jobs, } @@ -120,7 +125,19 @@ pub fn on_next_key( &mut self, on_next_key_callback: impl FnOnce(&mut Context, KeyEvent) + 'static, ) { - self.on_next_key_callback = Some(Box::new(on_next_key_callback)); + self.on_next_key_callback = Some(( + Box::new(on_next_key_callback), + OnKeyCallbackKind::PseudoPending, + )); + } + + #[inline] + pub fn on_next_key_fallback( + &mut self, + on_next_key_callback: impl FnOnce(&mut Context, KeyEvent) + 'static, + ) { + self.on_next_key_callback = + Some((Box::new(on_next_key_callback), OnKeyCallbackKind::Fallback)); } #[inline] diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 5179be4f4..530dd8b5b 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -1,5 +1,5 @@ use crate::{ - commands::{self, OnKeyCallback}, + commands::{self, OnKeyCallback, OnKeyCallbackKind}, compositor::{Component, Context, Event, EventResult}, events::{OnModeSwitch, PostCommand}, handlers::completion::CompletionItem, @@ -37,7 +37,7 @@ pub struct EditorView { pub keymaps: Keymaps, - on_next_key: Option, + on_next_key: Option<(OnKeyCallback, OnKeyCallbackKind)>, pseudo_pending: Vec, pub(crate) last_insert: (commands::MappableCommand, Vec), pub(crate) completion: Option, @@ -918,8 +918,10 @@ 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) + if !self.on_next_key(OnKeyCallbackKind::Fallback, cx, event) { + if let Some(ch) = event.char() { + commands::insert::insert_char(cx, ch) + } } } KeymapResult::Cancelled(pending) => { @@ -1015,7 +1017,10 @@ fn command_mode(&mut self, mode: Mode, cxt: &mut commands::Context, event: KeyEv // set the register cxt.register = cxt.editor.selected_register.take(); - self.handle_keymap_event(mode, cxt, event); + let res = self.handle_keymap_event(mode, cxt, event); + if matches!(&res, Some(KeymapResult::NotFound)) { + self.on_next_key(OnKeyCallbackKind::Fallback, cxt, event); + } if self.keymaps.pending().is_empty() { cxt.editor.count = None } else { @@ -1091,7 +1096,7 @@ fn handle_non_key_input(&mut self, cxt: &mut commands::Context) { modifiers: KeyModifiers::empty(), }; // dismiss any pending keys - if let Some(on_next_key) = self.on_next_key.take() { + if let Some((on_next_key, _)) = self.on_next_key.take() { on_next_key(cxt, null_key_event); } self.handle_keymap_event(cxt.editor.mode, cxt, null_key_event); @@ -1314,6 +1319,24 @@ fn handle_mouse_event( _ => EventResult::Ignored(None), } } + fn on_next_key( + &mut self, + kind: OnKeyCallbackKind, + ctx: &mut commands::Context, + event: KeyEvent, + ) -> bool { + if let Some((on_next_key, kind_)) = self.on_next_key.take() { + if kind == kind_ { + on_next_key(ctx, event); + true + } else { + self.on_next_key = Some((on_next_key, kind_)); + false + } + } else { + false + } + } } impl Component for EditorView { @@ -1365,10 +1388,7 @@ fn handle_event( let mode = cx.editor.mode(); - if let Some(on_next_key) = self.on_next_key.take() { - // if there's a command waiting input, do that first - on_next_key(&mut cx, key); - } else { + if !self.on_next_key(OnKeyCallbackKind::PseudoPending, &mut cx, key) { match mode { Mode::Insert => { // let completion swallow the event if necessary @@ -1418,8 +1438,8 @@ fn handle_event( self.on_next_key = cx.on_next_key_callback.take(); match self.on_next_key { - Some(_) => self.pseudo_pending.push(key), - None => self.pseudo_pending.clear(), + Some((_, OnKeyCallbackKind::PseudoPending)) => self.pseudo_pending.push(key), + _ => self.pseudo_pending.clear(), } // appease borrowck