Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with [keys.insert] mappings such as j = { f = "normal_mode" } #2612

Open
nitish-17 opened this issue May 30, 2022 · 9 comments · May be fixed by #8486
Open

Issue with [keys.insert] mappings such as j = { f = "normal_mode" } #2612

nitish-17 opened this issue May 30, 2022 · 9 comments · May be fixed by #8486
Labels
A-helix-term Area: Helix term improvements C-bug Category: This is a bug

Comments

@nitish-17
Copy link
Contributor

Summary

I'm using jf to exit insert mode. When I insert anything that ends with j (not jj) and try to exit insert mode with jf I end up inserting jf and remain in insert mode. To overcome this I usually end up pressing escape key twice to exit insert mode which is not ideal.

Reproduction Steps

context:
I'm using jf to exit insert mode.

I tried this:

  • tried to inset hij and exit insert mode with jf

I expected this to happen:

  • insert hij and end up in normal mode

Instead, this happened:

  • inset hijjf and end up in insert mode

Helix log

No response

Platform

Linux

Terminal Emulator

gnome terminal

Helix Version

helix 22.03 (d4e45fd)

@nitish-17 nitish-17 added the C-bug Category: This is a bug label May 30, 2022
@the-mikedavis the-mikedavis added the A-helix-term Area: Helix term improvements label May 30, 2022
@n0s4
Copy link
Contributor

n0s4 commented Jun 5, 2022

I guess the solution would be when the next key doesn't match the keybind, instead of inserting it you check again to see if it's the start of another key combination?

@the-mikedavis
Copy link
Member

That might work but I like the current system where a key not found in a pending key sequence cancels the sequence (see here).

Kakoune has an interesting way of approaching this: https://github.com/mawww/kakoune/wiki/Avoid-the-escape-key#jk-to-escape. It maps k to a hook that deletes the preceeding jk sequence if it exists, and if it existed it goes to normal mode. I don't think we can create a similar keybinding without scripting support for config though.

@kverb
Copy link

kverb commented Jun 11, 2022

In vim, this type of exiting insert mode has a timeout. So, while there's a short (but configurable) inconvenience if you want to end your insertion on 'j', it's at least possible. I was a bit surprised to find that helix's helpful little keymap sequence hint window just persists indefinitely, waiting for the next key.

fwiw, this is my first day with helix and I am truly delighted so far.

@aldanor
Copy link

aldanor commented Oct 11, 2022

This was the first (and only major) problem I've hit with Helix so far.

Wonder if anyone has viable solutions for it? If the text your editing in insert mode ends with the first letter of your jj/jk/fd/kj/whatever, what do you do?

E.g., I have f-d as exit-to-normal-mode sequence.

  • Typing buffd in vim would result in buf whereas in Helix it results in buffd.
  • Having an alternative escape sequence like j-k doesn't help either (since on the first f you will already enter the sequence mode and j will just cancel it).
  • The only way out seems to be reaching out to Esc which is not nice.

@zeeklop
Copy link

zeeklop commented Oct 20, 2022

Glad to not be the only one with this issue. I use jj to escape insert mode. On VIM there is a timeout implemented for these kind of commands. If I press j once, it waits for a couple of seconds. After the timeout is done, j is inserted in the document. If I press another key (not bound to j) then j and the new key are inserted.

The key bound to the command get inserted in the document but if the next key executes a command then that key is removed and the command executed

vim_escape_insert

@geometryolife
Copy link

Previously, I used Neovim to use kj to exit insert mode, but in the past few days with Helix, I have become very accustomed to using C-[ to exit insert mode.

@eugenesvk
Copy link

eugenesvk commented May 14, 2023

Have you tried nested binding like this?

[keys.insert] #
  'j'	= {f='normal_mode','j'={'f'=[':insert-output /bin/echo -n j','move_char_right','normal_mode']}}
  # 'hij' + 'jf' cleanly exits after typing 'hij' instead of typing an extra jf
  # the char movement was needed because otherwise you end up 1 char left with insert and with append-output at the end of the line you get an insert at the wrong line

(though this is missing a proper text insertion API, check #2797)

@zeeklop

it waits for a couple of seconds

that's also bad

The proper way to do this type of switching is like this:

  • no delay: the character appears immediately, so there is no typing interference
  • clean up on mode switch (the previously inserted letter completely disappears leaving no dirty/undo etc. trace)
  • cancel after some delay

(as implemented in https://github.com/NeoVintageous/NeoVintageous)

See this short demo

modelInsertExit.mov

Although an even better solution would be to have an on-hold functionality since you'd not use that in regular typing, so you don't have this conflict in the first place, then you could have a clean

  • (tap) i enters Insert mode
  • (hold)i exits Insert mode or another alternative that doesn't depend on any delays
  • (hold)i(tap)j exits Insert mode (the way this differentiates from typing ij is tracking key releases, if j is released first, then it's was a (hold)i, otherwise it's just a regular typing sequence where the earlier typed key is always released earlier)

just like you can have the same with other modes

(though this suggestion was unfortunately shot down #1494)

@eugenesvk
Copy link

Another workaround is to use a good keyboard remapping tool (like Karabiner on a Mac) to implement the workaround I use for the lack of on-hold functionality: basically, make some key like i

  • insert i on release instead of on press
  • simulate some other shortcut on hold
  • map ↑ shortcut to enter normal mode in Helix

However, this is limited by:

  • the lack of Helix GUI (so you'd need to use it for the whole terminal as an app filter for remapping)
  • inability of Helix to communicate its mode switches to other apps (so you'd need to have a mechanism that doesn't negatively affect non-insert modes) Communicate mode switch to external apps #6081

(you can also do it for a key chord like jf, but I think it's more bug-prone due to the aforementioned limitations)

Mac example:
Helix config

[keys.insert] #
  'A-}'	= 'normal_mode' # some unused inconvenient shortcut, ideally free in any mode

Goku Karabiner config snippet

:applications {:wezterm	["^com\\.github\\.wez\\.wezterm$"]}
:main [
 {:des "  🠿i⃣  ⟶ Normal Mode ⇧⎇] (@WezTerm instead of @Helix)" :rules [:wezterm
  [:i         nil nil
   {:alone {:key :i :halt true} :delayed{:canceled[:i]} :held{:key :⇧⎇】 :repeat false}
    :params{:alone 254 :held 255 :delay 255} }]
  ]}
]

@kmicklas
Copy link
Contributor

Is there any opposition from the maintainers to having proper support for this? It's a dealbreaker for me to use Helix, but I'm happy to try to implement it if it's desired.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-helix-term Area: Helix term improvements C-bug Category: This is a bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants