Skip to content

Commit

Permalink
Handle suffixes of cancelled keymaps in insert mode
Browse files Browse the repository at this point in the history
  • Loading branch information
kmicklas committed Oct 12, 2023
1 parent 574f821 commit 021ff44
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 19 deletions.
43 changes: 26 additions & 17 deletions helix-term/src/ui/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -857,28 +857,37 @@ impl EditorView {
}

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)
let mut stack = vec![event];

while let Some(event) = stack.pop() {
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)
}
}
}
KeymapResult::Cancelled(pending) => {
for ev in pending {
match ev.char() {
Some(ch) => commands::insert::insert_char(cx, ch),
None => {
if let KeymapResult::Matched(command) =
self.keymaps.get(Mode::Insert, ev)
{
command.execute(cx);
}
KeymapResult::Cancelled(pending) => {
let mut pending = pending.into_iter();
if let Some(first) = pending.next() {
// Note that since this is the first pending key, we know
// it can't map to a command by itself.
match first.char() {
// The first key is both the start of a menu and a regular
// insert key. The user may have intended to type it as an
// insert, and then execute the remaining suffix of keys.
Some(ch) => commands::insert::insert_char(cx, ch),
// If the first key is not a character to insert, then we
// assume the user intended to enter a command menu, so we
// should just discard pending keys if they don't match.
None => continue,
}
}

stack.extend(pending.rev());
}
_ => unreachable!(),
}
_ => unreachable!(),
}
}
}
Expand Down
1 change: 1 addition & 0 deletions helix-term/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ mod test {
mod auto_indent;
mod auto_pairs;
mod commands;
mod insert_keymap_suffix;
mod languages;
mod movement;
mod prompt;
Expand Down
2 changes: 0 additions & 2 deletions helix-term/tests/test/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,8 +300,6 @@ impl AppBuilder {
self
}

// Remove this attribute once `with_config` is used in a test:
#[allow(dead_code)]
pub fn with_config(mut self, mut config: Config) -> Self {
let keys = replace(&mut config.keys, helix_term::keymap::default());
merge_keys(&mut config.keys, keys);
Expand Down
36 changes: 36 additions & 0 deletions helix-term/tests/test/insert_keymap_suffix.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use super::*;

#[tokio::test(flavor = "multi_thread")]
async fn insert_keymap_suffix() -> anyhow::Result<()> {
test_with_config(
AppBuilder::new().with_config(config()),
("#[|]#", "iselffd", "self#[|]#"),
)
.await?;

Ok(())
}

#[tokio::test(flavor = "multi_thread")]
async fn insert_keymap_suffix_non_char() -> anyhow::Result<()> {
test_with_config(
AppBuilder::new().with_config(config()),
("#[|]#", "i<F1>ua", "a#[|]#"),
)
.await?;

Ok(())
}

fn config() -> Config {
let config = r#"
[keys.insert]
f.d = "normal_mode"
F1.j = "insert_newline"
"#;
Config::load(
Ok(config.to_owned()),
Err(helix_term::config::ConfigLoadError::default()),
)
.unwrap()
}

0 comments on commit 021ff44

Please sign in to comment.