Skip to content

Commit 6cca737

Browse files
Automatically track pseudo-pending text (#4077)
This change automatically tracks pending text for for commands which use on-next-key callbacks. For example, `t` will await the next key event and "t" will be shown in the bottom right-hand corner to show that we're in a pending state. Previously, the text for these on-next-key commands needed to be hard-coded into the command definition which had some drawbacks: * It was easy to forget to write and clear the pending text. * If a command was remapped in a custom config, the pending text would still show the old key. With this change, pending text is automatically tracked based on the key events that lead to the command being executed. This works even when the command is remapped in config and when the on-next-key callback is nested under some key sequence (for example `mi`).
1 parent 9124c23 commit 6cca737

File tree

3 files changed

+43
-49
lines changed

3 files changed

+43
-49
lines changed

helix-term/src/commands.rs

Lines changed: 33 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,27 +1091,18 @@ fn extend_next_long_word_end(cx: &mut Context) {
10911091
extend_word_impl(cx, movement::move_next_long_word_end)
10921092
}
10931093

1094-
fn will_find_char<F>(
1095-
cx: &mut Context,
1096-
search_fn: F,
1097-
inclusive: bool,
1098-
extend: bool,
1099-
pseudo_pending: &str,
1100-
) where
1094+
fn will_find_char<F>(cx: &mut Context, search_fn: F, inclusive: bool, extend: bool)
1095+
where
11011096
F: Fn(RopeSlice, char, usize, usize, bool) -> Option<usize> + 'static,
11021097
{
11031098
// TODO: count is reset to 1 before next key so we move it into the closure here.
11041099
// Would be nice to carry over.
11051100
let count = cx.count();
11061101

1107-
cx.editor.pseudo_pending = Some(pseudo_pending.to_string());
1108-
11091102
// need to wait for next key
11101103
// TODO: should this be done by grapheme rather than char? For example,
11111104
// we can't properly handle the line-ending CRLF case here in terms of char.
11121105
cx.on_next_key(move |cx, event| {
1113-
cx.editor.pseudo_pending = None;
1114-
11151106
let ch = match event {
11161107
KeyEvent {
11171108
code: KeyCode::Enter,
@@ -1214,35 +1205,35 @@ fn find_prev_char_impl(
12141205
}
12151206

12161207
fn find_till_char(cx: &mut Context) {
1217-
will_find_char(cx, find_next_char_impl, false, false, "t")
1208+
will_find_char(cx, find_next_char_impl, false, false)
12181209
}
12191210

12201211
fn find_next_char(cx: &mut Context) {
1221-
will_find_char(cx, find_next_char_impl, true, false, "f")
1212+
will_find_char(cx, find_next_char_impl, true, false)
12221213
}
12231214

12241215
fn extend_till_char(cx: &mut Context) {
1225-
will_find_char(cx, find_next_char_impl, false, true, "t")
1216+
will_find_char(cx, find_next_char_impl, false, true)
12261217
}
12271218

12281219
fn extend_next_char(cx: &mut Context) {
1229-
will_find_char(cx, find_next_char_impl, true, true, "f")
1220+
will_find_char(cx, find_next_char_impl, true, true)
12301221
}
12311222

12321223
fn till_prev_char(cx: &mut Context) {
1233-
will_find_char(cx, find_prev_char_impl, false, false, "T")
1224+
will_find_char(cx, find_prev_char_impl, false, false)
12341225
}
12351226

12361227
fn find_prev_char(cx: &mut Context) {
1237-
will_find_char(cx, find_prev_char_impl, true, false, "F")
1228+
will_find_char(cx, find_prev_char_impl, true, false)
12381229
}
12391230

12401231
fn extend_till_prev_char(cx: &mut Context) {
1241-
will_find_char(cx, find_prev_char_impl, false, true, "T")
1232+
will_find_char(cx, find_prev_char_impl, false, true)
12421233
}
12431234

12441235
fn extend_prev_char(cx: &mut Context) {
1245-
will_find_char(cx, find_prev_char_impl, true, true, "F")
1236+
will_find_char(cx, find_prev_char_impl, true, true)
12461237
}
12471238

12481239
fn repeat_last_motion(cx: &mut Context) {
@@ -4392,7 +4383,6 @@ fn select_textobject(cx: &mut Context, objtype: textobject::TextObject) {
43924383

43934384
cx.on_next_key(move |cx, event| {
43944385
cx.editor.autoinfo = None;
4395-
cx.editor.pseudo_pending = None;
43964386
if let Some(ch) = event.char() {
43974387
let textobject = move |editor: &mut Editor| {
43984388
let (view, doc) = current!(editor);
@@ -4441,33 +4431,31 @@ fn select_textobject(cx: &mut Context, objtype: textobject::TextObject) {
44414431
}
44424432
});
44434433

4444-
if let Some((title, abbrev)) = match objtype {
4445-
textobject::TextObject::Inside => Some(("Match inside", "mi")),
4446-
textobject::TextObject::Around => Some(("Match around", "ma")),
4434+
let title = match objtype {
4435+
textobject::TextObject::Inside => "Match inside",
4436+
textobject::TextObject::Around => "Match around",
44474437
_ => return,
4448-
} {
4449-
let help_text = [
4450-
("w", "Word"),
4451-
("W", "WORD"),
4452-
("p", "Paragraph"),
4453-
("c", "Class (tree-sitter)"),
4454-
("f", "Function (tree-sitter)"),
4455-
("a", "Argument/parameter (tree-sitter)"),
4456-
("o", "Comment (tree-sitter)"),
4457-
("t", "Test (tree-sitter)"),
4458-
("m", "Closest surrounding pair to cursor"),
4459-
(" ", "... or any character acting as a pair"),
4460-
];
4461-
4462-
cx.editor.autoinfo = Some(Info::new(
4463-
title,
4464-
help_text
4465-
.into_iter()
4466-
.map(|(col1, col2)| (col1.to_string(), col2.to_string()))
4467-
.collect(),
4468-
));
4469-
cx.editor.pseudo_pending = Some(abbrev.to_string());
44704438
};
4439+
let help_text = [
4440+
("w", "Word"),
4441+
("W", "WORD"),
4442+
("p", "Paragraph"),
4443+
("c", "Class (tree-sitter)"),
4444+
("f", "Function (tree-sitter)"),
4445+
("a", "Argument/parameter (tree-sitter)"),
4446+
("o", "Comment (tree-sitter)"),
4447+
("t", "Test (tree-sitter)"),
4448+
("m", "Closest surrounding pair to cursor"),
4449+
(" ", "... or any character acting as a pair"),
4450+
];
4451+
4452+
cx.editor.autoinfo = Some(Info::new(
4453+
title,
4454+
help_text
4455+
.into_iter()
4456+
.map(|(col1, col2)| (col1.to_string(), col2.to_string()))
4457+
.collect(),
4458+
));
44714459
}
44724460

44734461
fn surround_add(cx: &mut Context) {

helix-term/src/ui/editor.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use super::statusline;
3333
pub struct EditorView {
3434
pub keymaps: Keymaps,
3535
on_next_key: Option<Box<dyn FnOnce(&mut commands::Context, KeyEvent)>>,
36+
pseudo_pending: Vec<KeyEvent>,
3637
last_insert: (commands::MappableCommand, Vec<InsertEvent>),
3738
pub(crate) completion: Option<Completion>,
3839
spinners: ProgressSpinners,
@@ -56,6 +57,7 @@ impl EditorView {
5657
Self {
5758
keymaps,
5859
on_next_key: None,
60+
pseudo_pending: Vec::new(),
5961
last_insert: (commands::MappableCommand::normal_mode, Vec::new()),
6062
completion: None,
6163
spinners: ProgressSpinners::default(),
@@ -839,6 +841,7 @@ impl EditorView {
839841
event: KeyEvent,
840842
) -> Option<KeymapResult> {
841843
let mut last_mode = mode;
844+
self.pseudo_pending.extend(self.keymaps.pending());
842845
let key_result = self.keymaps.get(mode, event);
843846
cxt.editor.autoinfo = self.keymaps.sticky().map(|node| node.infobox());
844847

@@ -1316,6 +1319,11 @@ impl Component for EditorView {
13161319
}
13171320

13181321
self.on_next_key = cx.on_next_key_callback.take();
1322+
match self.on_next_key {
1323+
Some(_) => self.pseudo_pending.push(key),
1324+
None => self.pseudo_pending.clear(),
1325+
}
1326+
13191327
// appease borrowck
13201328
let callback = cx.callback.take();
13211329

@@ -1416,8 +1424,8 @@ impl Component for EditorView {
14161424
for key in self.keymaps.pending() {
14171425
disp.push_str(&key.key_sequence_format());
14181426
}
1419-
if let Some(pseudo_pending) = &cx.editor.pseudo_pending {
1420-
disp.push_str(pseudo_pending.as_str())
1427+
for key in &self.pseudo_pending {
1428+
disp.push_str(&key.key_sequence_format());
14211429
}
14221430
let style = cx.editor.theme.get("ui.text");
14231431
let macro_width = if cx.editor.macro_recording.is_some() {

helix-view/src/editor.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -677,7 +677,6 @@ pub struct Editor {
677677

678678
pub idle_timer: Pin<Box<Sleep>>,
679679
pub last_motion: Option<Motion>,
680-
pub pseudo_pending: Option<String>,
681680

682681
pub last_completion: Option<CompleteAction>,
683682

@@ -758,7 +757,6 @@ impl Editor {
758757
idle_timer: Box::pin(sleep(conf.idle_timeout)),
759758
last_motion: None,
760759
last_completion: None,
761-
pseudo_pending: None,
762760
config,
763761
auto_pairs,
764762
exit_code: 0,

0 commit comments

Comments
 (0)