diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index 93cc5328..7328e729 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -234,6 +234,7 @@ pub struct Keymap { /// Always a Node #[serde(flatten)] root: KeyTrie, + /// Stores pending keys waiting for the next key #[serde(skip)] state: Vec, } @@ -250,6 +251,11 @@ impl Keymap { &self.root } + /// Returns list of keys waiting to be disambiguated. + pub fn pending(&self) -> &[KeyEvent] { + &self.state + } + /// Lookup `key` in the keymap to try and find a command to execute pub fn get(&mut self, key: KeyEvent) -> KeymapResult { let &first = self.state.get(0).unwrap_or(&key); @@ -292,6 +298,19 @@ impl Default for Keymap { #[serde(transparent)] pub struct Keymaps(pub HashMap); +impl Keymaps { + /// Returns list of keys waiting to be disambiguated in current mode. + pub fn pending(&self) -> &[KeyEvent] { + self.0 + .values() + .find_map(|keymap| match keymap.pending().is_empty() { + true => None, + false => Some(keymap.pending()), + }) + .unwrap_or_default() + } +} + impl Deref for Keymaps { type Target = HashMap; diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 78a54079..99b49309 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -10,6 +10,8 @@ use helix_core::{ coords_at_pos, graphemes::{ensure_grapheme_boundary, next_grapheme_boundary}, syntax::{self, HighlightEvent}, + unicode::segmentation::UnicodeSegmentation, + unicode::width::UnicodeWidthStr, LineEnding, Position, Range, }; use helix_view::{ @@ -627,7 +629,7 @@ impl EditorView { } _ => { // set the count - cxt.count = cxt.editor.count.take(); + cxt.count = cxt.editor.count; // TODO: edge case: 0j -> reset to 1 // if this fails, count was Some(0) // debug_assert!(cxt.count != 0); @@ -636,6 +638,9 @@ impl EditorView { cxt.selected_register = cxt.editor.selected_register.take(); self.handle_keymap_event(mode, cxt, event); + if self.keymaps.pending().is_empty() { + cxt.editor.count = None + } } } } @@ -795,8 +800,12 @@ impl Component for EditorView { info.render(area, surface, cx); } + let key_width = 15u16; // for showing pending keys + let mut status_msg_width = 0; + // render status msg if let Some((status_msg, severity)) = &cx.editor.status_msg { + status_msg_width = status_msg.width(); use helix_view::editor::Severity; let style = if *severity == Severity::Error { cx.editor.theme.get("error") @@ -812,6 +821,28 @@ impl Component for EditorView { ); } + if area.width.saturating_sub(status_msg_width as u16) > key_width { + let mut disp = String::new(); + if let Some(count) = cx.editor.count { + disp.push_str(&count.to_string()) + } + for key in self.keymaps.pending() { + let s = key.to_string(); + if s.graphemes(true).count() > 1 { + disp.push_str(&format!("<{}>", s)); + } else { + disp.push_str(&s); + } + } + surface.set_string( + area.x + area.width.saturating_sub(key_width), + area.y + area.height.saturating_sub(1), + disp.get(disp.len().saturating_sub(key_width as usize)..) + .unwrap_or(&disp), + cx.editor.theme.get("ui.text"), + ); + } + if let Some(completion) = &self.completion { completion.render(area, surface, cx); }