Show pending keys in status line (#515)

* Show pending keys and counts in status line

* Refactor pending key display
pull/518/head
Gokul Soumya 3 years ago committed by GitHub
parent 581a3d42c8
commit 1493313750
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -234,6 +234,7 @@ pub struct Keymap {
/// Always a Node /// Always a Node
#[serde(flatten)] #[serde(flatten)]
root: KeyTrie, root: KeyTrie,
/// Stores pending keys waiting for the next key
#[serde(skip)] #[serde(skip)]
state: Vec<KeyEvent>, state: Vec<KeyEvent>,
} }
@ -250,6 +251,11 @@ impl Keymap {
&self.root &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 /// Lookup `key` in the keymap to try and find a command to execute
pub fn get(&mut self, key: KeyEvent) -> KeymapResult { pub fn get(&mut self, key: KeyEvent) -> KeymapResult {
let &first = self.state.get(0).unwrap_or(&key); let &first = self.state.get(0).unwrap_or(&key);
@ -292,6 +298,19 @@ impl Default for Keymap {
#[serde(transparent)] #[serde(transparent)]
pub struct Keymaps(pub HashMap<Mode, Keymap>); pub struct Keymaps(pub HashMap<Mode, Keymap>);
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 { impl Deref for Keymaps {
type Target = HashMap<Mode, Keymap>; type Target = HashMap<Mode, Keymap>;

@ -10,6 +10,8 @@ use helix_core::{
coords_at_pos, coords_at_pos,
graphemes::{ensure_grapheme_boundary, next_grapheme_boundary}, graphemes::{ensure_grapheme_boundary, next_grapheme_boundary},
syntax::{self, HighlightEvent}, syntax::{self, HighlightEvent},
unicode::segmentation::UnicodeSegmentation,
unicode::width::UnicodeWidthStr,
LineEnding, Position, Range, LineEnding, Position, Range,
}; };
use helix_view::{ use helix_view::{
@ -627,7 +629,7 @@ impl EditorView {
} }
_ => { _ => {
// set the count // set the count
cxt.count = cxt.editor.count.take(); cxt.count = cxt.editor.count;
// TODO: edge case: 0j -> reset to 1 // TODO: edge case: 0j -> reset to 1
// if this fails, count was Some(0) // if this fails, count was Some(0)
// debug_assert!(cxt.count != 0); // debug_assert!(cxt.count != 0);
@ -636,6 +638,9 @@ impl EditorView {
cxt.selected_register = cxt.editor.selected_register.take(); cxt.selected_register = cxt.editor.selected_register.take();
self.handle_keymap_event(mode, cxt, event); 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); info.render(area, surface, cx);
} }
let key_width = 15u16; // for showing pending keys
let mut status_msg_width = 0;
// render status msg // render status msg
if let Some((status_msg, severity)) = &cx.editor.status_msg { if let Some((status_msg, severity)) = &cx.editor.status_msg {
status_msg_width = status_msg.width();
use helix_view::editor::Severity; use helix_view::editor::Severity;
let style = if *severity == Severity::Error { let style = if *severity == Severity::Error {
cx.editor.theme.get("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 { if let Some(completion) = &self.completion {
completion.render(area, surface, cx); completion.render(area, surface, cx);
} }

Loading…
Cancel
Save