From 2513b67ed4afe87fc71a38f9253356ab182c45de Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Tue, 27 Jul 2021 10:26:42 +0530 Subject: [PATCH 1/2] Show pending keys and counts in status line --- helix-term/src/keymap.rs | 16 ++++++++++++++++ helix-term/src/ui/editor.rs | 29 ++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index 93cc53289d71..416f4152b452 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,14 @@ impl Keymap { &self.root } + /// Returns list of keys waiting to be disambiguated. + pub fn pending(&self) -> Option<&Vec> { + match self.state.is_empty() { + true => None, + false => Some(&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 +301,13 @@ 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) -> Option<&Vec> { + self.0.values().find_map(|keymap| keymap.pending()) + } +} + impl Deref for Keymaps { type Target = HashMap; diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 78a54079d7f5..207a3cee5ca3 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -10,6 +10,7 @@ use helix_core::{ coords_at_pos, graphemes::{ensure_grapheme_boundary, next_grapheme_boundary}, syntax::{self, HighlightEvent}, + unicode::width::UnicodeWidthStr, LineEnding, Position, Range, }; use helix_view::{ @@ -627,7 +628,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 +637,9 @@ impl EditorView { cxt.selected_register = cxt.editor.selected_register.take(); self.handle_keymap_event(mode, cxt, event); + if self.keymaps.pending().is_none() { + cxt.editor.count = None + } } } } @@ -810,6 +814,29 @@ impl Component for EditorView { status_msg, style, ); + } else { + let mut disp = String::new(); + if let Some(count) = cx.editor.count { + disp.push_str(&count.get().to_string()) + } + if let Some(keys) = self.keymaps.pending() { + for key in keys { + let s = key.to_string(); + if s.width() > 1 { + disp.push_str(&format!("<{}>", s)); + } else { + disp.push_str(&s); + } + } + } + let width = 10usize; + surface.set_string( + area.x + area.width.saturating_sub(width as u16), + area.y + area.height.saturating_sub(1), + disp.get(disp.len().saturating_sub(width)..) + .unwrap_or(&disp), + cx.editor.theme.get("ui.text"), + ); } if let Some(completion) = &self.completion { From e54e807bc32a2b173bbe2294006be09d5ade46d1 Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Tue, 27 Jul 2021 21:19:33 +0530 Subject: [PATCH 2/2] Refactor pending key display --- helix-term/src/keymap.rs | 17 ++++++++++------- helix-term/src/ui/editor.rs | 32 ++++++++++++++++++-------------- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index 416f4152b452..7328e7292a23 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -252,11 +252,8 @@ impl Keymap { } /// Returns list of keys waiting to be disambiguated. - pub fn pending(&self) -> Option<&Vec> { - match self.state.is_empty() { - true => None, - false => Some(&self.state), - } + pub fn pending(&self) -> &[KeyEvent] { + &self.state } /// Lookup `key` in the keymap to try and find a command to execute @@ -303,8 +300,14 @@ pub struct Keymaps(pub HashMap); impl Keymaps { /// Returns list of keys waiting to be disambiguated in current mode. - pub fn pending(&self) -> Option<&Vec> { - self.0.values().find_map(|keymap| keymap.pending()) + 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() } } diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 207a3cee5ca3..99b493092321 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -10,6 +10,7 @@ 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, }; @@ -637,7 +638,7 @@ impl EditorView { cxt.selected_register = cxt.editor.selected_register.take(); self.handle_keymap_event(mode, cxt, event); - if self.keymaps.pending().is_none() { + if self.keymaps.pending().is_empty() { cxt.editor.count = None } } @@ -799,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") @@ -814,26 +819,25 @@ impl Component for EditorView { status_msg, style, ); - } else { + } + + 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.get().to_string()) + disp.push_str(&count.to_string()) } - if let Some(keys) = self.keymaps.pending() { - for key in keys { - let s = key.to_string(); - if s.width() > 1 { - disp.push_str(&format!("<{}>", s)); - } else { - disp.push_str(&s); - } + 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); } } - let width = 10usize; surface.set_string( - area.x + area.width.saturating_sub(width as u16), + area.x + area.width.saturating_sub(key_width), area.y + area.height.saturating_sub(1), - disp.get(disp.len().saturating_sub(width)..) + disp.get(disp.len().saturating_sub(key_width as usize)..) .unwrap_or(&disp), cx.editor.theme.get("ui.text"), );