onivim / libvim

libvim: The core Vim editing engine as a minimal C library
https://v2.onivim.io
MIT License
691 stars 34 forks source link

Passing commands one character at a time breaks keybinds #184

Open tristil opened 4 years ago

tristil commented 4 years ago

Describe the bug

If input is passed to vimInput one character at a time a multi-character keybind (for example inoremap jk <esc>) will fail. The first key will be swallowed up and the second will be inputted, without leaving insert mode.

To Reproduce

This test passes

diff --git a/src/apitest/insert_mode.c b/src/apitest/insert_mode.c
index bb87cfe01..ff8e3f68b 100644
--- a/src/apitest/insert_mode.c
+++ b/src/apitest/insert_mode.c
@@ -168,6 +168,19 @@ MU_TEST(insert_mode_ctrlv_newline)
   mu_check(line[0] == 13);
 }

+MU_TEST(insert_mode_exits_with_keybind)
+{
+  vimExecute("inoremap jk <esc>");
+  vimInput("i");
+  vimInput("jk");
+
+  mu_check((vimGetMode() & NORMAL) == NORMAL);
+
+  char_u *line = vimBufferGetLine(curbuf, vimCursorGetLine());
+  printf("LINE: %s\n", line);
+  mu_check(strcmp(line, "abc") == 0);
+}
+
 MU_TEST_SUITE(test_suite)
 {
   MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
@@ -182,6 +195,7 @@ MU_TEST_SUITE(test_suite)
   MU_RUN_TEST(insert_mode_ctrlv);
   MU_RUN_TEST(insert_mode_ctrlv_no_digit);
   MU_RUN_TEST(insert_mode_ctrlv_newline);
+  MU_RUN_TEST(insert_mode_exits_with_keybind);
 }

whereas this test fails

diff --git a/src/apitest/insert_mode.c b/src/apitest/insert_mode.c
index bb87cfe01..837cae897 100644
--- a/src/apitest/insert_mode.c
+++ b/src/apitest/insert_mode.c
@@ -168,6 +168,20 @@ MU_TEST(insert_mode_ctrlv_newline)
   mu_check(line[0] == 13);
 }

+MU_TEST(insert_mode_exits_with_keybind)
+{
+  vimExecute("inoremap jk <esc>");
+  vimInput("i");
+  vimInput("j");
+  vimInput("k");
+
+  mu_check((vimGetMode() & NORMAL) == NORMAL);
+
+  char_u *line = vimBufferGetLine(curbuf, vimCursorGetLine());
+  printf("LINE: %s\n", line);
+  mu_check(strcmp(line, "abc") == 0);
+}
+
 MU_TEST_SUITE(test_suite)
 {
   MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
@@ -182,6 +196,7 @@ MU_TEST_SUITE(test_suite)
   MU_RUN_TEST(insert_mode_ctrlv);
   MU_RUN_TEST(insert_mode_ctrlv_no_digit);
   MU_RUN_TEST(insert_mode_ctrlv_newline);
+  MU_RUN_TEST(insert_mode_exits_with_keybind);
 }

Expected behavior

Oni2 sends keystrokes one at a time to vimInput. Because of this, the above behavior is blocking implementing Spacemacs-like keybindings. I would like to see this fixed here or for some other solution for spooling keypress before sending to vimInput implemented on the Oni2 side.

glennsl commented 4 years ago

Related: https://github.com/onivim/oni2/issues/741, https://github.com/onivim/oni2/issues/382, https://github.com/onivim/libvim/pull/101

I think this is currently being worked on in https://github.com/onivim/editor-input though, if I understood @bryphe correctly. And if so the solution is in a layer above libvim.