Kakoune: [feature request] timing-tolerant escaping from insert

Created on 6 Oct 2020  路  6Comments  路  Source: mawww/kakoune

Steps

Open a tmux session. Open kakoune. Start an insertion. Press esc, then immediately press h to move the cursor backwards.

Outcome

The insert doesn't end, and an h appears in the buffer.

Expected

It should end the insertion and move the cursor backwards.

I try the same thing in vim and it works fine, so it isn't tmux's fault.

EDIT

That was the original "bug", which turns out not to be a bug, really. The feature request is here: https://github.com/mawww/kakoune/issues/3780#issuecomment-704447679

bug

Most helpful comment

When you press <esc> followed by h, your terminal sends the bytes 0x1B (ESC) and 0x68 (h).

When you press <a-h>, most terminals also send the bytes 0x1B and 0x68.

Kakoune has a lot of Alt-based key-bindings, so since most terminals indicate the Alt modifier by sending a 0x1b prefix byte, Kakoune has to work with that and uses a timeout to figure out whether the 0x1B 0x68 bytes were sent at the same time (<a-h>) or separately (<esc>h).

tmux does the same thing, but it tends to make matters worse because its default timeout is so long. When running Kakoune locally, it often runs with an effective timeout of 0, meaning you can type <esc>h quite quickly and still have those keys processed individually. tmux's timeout of 500ms means you always have to wait at least that long between keystrokes to ensure Kakoune understands them correctly.

Vim cheats because as far as I can tell, it only supports Alt-based key-bindings if the terminal indicates Alt by setting the most significant bit of the byte, i.e. that send <a-h> as 0xE8 rather than 0x1B 0x68. This is a rare behaviour these days, and growing rarer, because it interferes with UTF-8 support. As a result, Vim will always process 0x1B 0x68 as <esc>h regardless of timing, and many terminals will be unable to trigger an <a-h> key-binding in their default configuration - some will be unable to trigger it at all.

That's not a big deal for Vim because it has so few Alt-based key-bindings to begin with. Kakoune, however, has a lot of Alt-based key-bindings, and for them to work reliably, Kakoune has to understand the 0x1B 0x68 encoding and deal with the ambiguity that introduces.

All 6 comments

I assume by "Press ," you mean "press <esc>,"

I can't reproduce that behaviour here, but it probably is tmux's fault, because Vim cheats.

https://github.com/mawww/kakoune/blob/master/doc/pages/faq.asciidoc#why-does-leaving-insert-mode-take-more-than-half-a-second-in-tmux

Vim isn't cheating. It has the same information kakoune does and it does the right thing somehow. Changing the escape timeout to 25ms works for local connections but won't work for network connections, when there can be latency spikes of more than 200 milliseconds depending on how good your network connection is. That's why the default timeout is 500ms.

When you press <esc> followed by h, your terminal sends the bytes 0x1B (ESC) and 0x68 (h).

When you press <a-h>, most terminals also send the bytes 0x1B and 0x68.

Kakoune has a lot of Alt-based key-bindings, so since most terminals indicate the Alt modifier by sending a 0x1b prefix byte, Kakoune has to work with that and uses a timeout to figure out whether the 0x1B 0x68 bytes were sent at the same time (<a-h>) or separately (<esc>h).

tmux does the same thing, but it tends to make matters worse because its default timeout is so long. When running Kakoune locally, it often runs with an effective timeout of 0, meaning you can type <esc>h quite quickly and still have those keys processed individually. tmux's timeout of 500ms means you always have to wait at least that long between keystrokes to ensure Kakoune understands them correctly.

Vim cheats because as far as I can tell, it only supports Alt-based key-bindings if the terminal indicates Alt by setting the most significant bit of the byte, i.e. that send <a-h> as 0xE8 rather than 0x1B 0x68. This is a rare behaviour these days, and growing rarer, because it interferes with UTF-8 support. As a result, Vim will always process 0x1B 0x68 as <esc>h regardless of timing, and many terminals will be unable to trigger an <a-h> key-binding in their default configuration - some will be unable to trigger it at all.

That's not a big deal for Vim because it has so few Alt-based key-bindings to begin with. Kakoune, however, has a lot of Alt-based key-bindings, and for them to work reliably, Kakoune has to understand the 0x1B 0x68 encoding and deal with the ambiguity that introduces.

Ah, now I understand. tmux queues the <esc> until it receives the h, then sends both at once. Kakoune sees this and thinks based on timing that it must be <a-h>. Kakoune, when it fails to find the <a-h> keybinding in insert mode, just ignores the esc and h. Therefore, I can keep the long tmux timeout if I add insert mode bindings for <a-X> for the common actions after insertion and map them to <esc>X.

It would be nice, though, if I didn't have to make those bindings. Could there be a kakoune feature that when in insert mode retries "\eX" as <esc>X if <a-X> is unbound?

It would be nice, though, if I didn't have to make those bindings. Could there be a kakoune feature that when in insert mode retries "\eX" as <esc>X if <a-X> is unbound?

That would be quite ugly to implement, as keys are parsed by the clients, and mappings are only known by the server. I dont think its reasonable to have such a long timout by default in tmux, network latency is not really relevant because a <a-x> keystroke would generate the bytes \033x and it would be extremely unlikely for those two bytes to be sent in separate packets, so they would still end-up appearing at the same time on Kakounes input buffer.

It is far more likely for a separate <esc> and x to end-up buffered together than split apart, so by having a long timeout tmux is making the likely error case even more likely. I imagine there must be a good reason for that, but I cannot find it myself.

it would be extremely unlikely for those two bytes to be sent in separate packets, so they would still end-up appearing at the same time on Kakounes input buffer.

That's a good point, @mawww .

Was this page helpful?
0 / 5 - 0 ratings

Related issues

MasterOfTheTiger picture MasterOfTheTiger  路  4Comments

lenormf picture lenormf  路  4Comments

akkartik picture akkartik  路  3Comments

alexherbo2 picture alexherbo2  路  3Comments

fennewald picture fennewald  路  3Comments