2

I use the right alt key as a compose key on my system, to easily draw diacritics and accent characters.

In Vim, I unlock alt key mappings with this (from stackoverflow):

" Allow <alt> key mappings
let c='a'
while c <= 'z'
  let d=toupper(c)
  exec "set <A-".c.">=\e".c
  exec "imap \e".c." <A-".c.">"
  exec "set <A-".d.">=\e".d
  exec "imap \e".d." <A-".d.">"
  let c = nr2char(1+char2nr(c))
endw

So I can set these mappings:

inoremap <M-j> <down>
inoremap <M-k> <up>
inoremap <M-h> <left>
inoremap <M-l> <right>

With this set of mappings, conflicts occur, and I can no longer type some accent characters like ê, è or ì. The cursor moves instead, on typing the e or i.
â, é, í, ï ç and ø still work, though (for example).

How can I resolve this conflict?

Setup: Vim 8.2, terminal (Gnome Terminal and Terminator) and GUI.
Neovim (terminal and GUI) is not affected by the problem.

3
  • Are you using the GUI? If not, which terminal are you using? And which Vim version? Does this help?
    – user938271
    Commented Jul 16, 2020 at 12:39
  • I edited my question and I'm taking a look at your link right now.
    – Biggybi
    Commented Jul 16, 2020 at 12:44
  • I was able to set a workaround with your link, by using four <F3x> mappings for my moves :) I'll accept your answer if you bother writing one.
    – Biggybi
    Commented Jul 16, 2020 at 13:01

1 Answer 1

3

If you use the GUI, you don't need anything special, but you need at least the patch 8.2.0851. Remove all of your code, except the mappings:

inoremap <M-h> <left>
inoremap <M-j> <down>
inoremap <M-k> <up>
inoremap <M-l> <right>

If you use Vim in a terminal which supports the modifyOtherKeys feature (typically xterm and maybe iterm), again, you don't need anything special, but you need at least the patch 8.1.2134. The feature should be enabled by default, but if that's not the case, you can enable it by setting the terminal options 't_TI' and 't_TE':

                   ┌ 1 = enables this feature for keys excluding keys with well-known behavior
                   │ 2 = enables this feature for all keys (see `man xterm /^\s*modifyOtherKeys`)
                   │
let &t_TI = "\e[>4;2m"
let &t_TE = "\e[>4;m"

You can check whether the modifyOtherKeys feature is enabled by pressing in insert mode C-S-v followed by C-v.

If Vim inserts this key code:

^[[27;5;118~

Then it's enabled; otherwise, if you just get:

^V

Then it's disabled.

Note that for the test to succeed, you need to make sure that you don't have any terminal key binding on C-S-v. If you have one, try to disable it temporarily.


If you use Vim in a terminal which does not support the modifyOtherKeys feature, the issue is that <M-h> is encoded as è internally which can cause the unexpected behavior you reported in your question:

:echo "\<M-h>"
è

See this answer for more info.

But there exists a workaround; try this:

exe "set <F31>=\eh"
exe "set <F32>=\ej"
exe "set <F33>=\ek"
exe "set <F34>=\el"

inoremap <F31> <left>
inoremap <F32> <down>
inoremap <F33> <up>
inoremap <F34> <right>

The function keys used here are somewhat arbitrary. Although, you can't go beyond <F37>:

:set <F38>
E846: Key code not set: <F38>

And you probably don't want to use <F1> to <F12>, as those are usually present on a keyboard and could be easily typed interactively. You can also use the shift modifier:

      vv
:set <S-F37>

but not the other ones:

      vv
:set <C-F37>
E518: Unknown option: <C-F37>

It works by telling Vim a lie:

exe "set <F31>=\eh"

This tells Vim that whenever it sees the sequence Esc + h in the typeahead buffer, it must translate it into <F31>; which is wrong, but bear with me.

From then, whenever you need to refer to <M-h> in a mapping, you write <F31>. As an example, you don't write this:

inoremap <M-h> <left>
         ^---^
           ✘

But this:

inoremap <F31> <left>
         ^---^
           ✔

Now, when you try to insert è, here's what happens:

typeahead | executed
--------------------
è         |
          | è

è is not remapped in the typeahead buffer because you don't have any mapping whose lhs is <M-h> nor è.

You may wonder how it's possible for a mapping triggered by <M-h> to still work even if you no longer write the latter explicitly. It turns out you don't need the Vim key code <M-h> to make Vim execute something when you press M-h in the terminal.

Consider the previous code:

exe "set <F31>=\eh"
inoremap <F31> <left>

And suppose you press <M-h>; here's what happens:

typeahead | executed
--------------------
<esc>h    |
<F31>     |
<left>    |
          | <left>

If you don't like this <F31> hack, visit your terminal's bug tracker, and check whether someone opened a ticket to ask for the modifyOtherKeys feature. If no one did, consider opening one. When your terminal supports the feature, get rid of the hack.

Since you mentioned using sometimes gnome-terminal, I had a look at the gnome bug tracker and found this ticket.

If the developers need some technical documentation, they can find one here. If you need some short user documentation, see here.


For more info, see:

1
  • 1
    Thanks for such a detailed answer, that is awesome!
    – Biggybi
    Commented Jul 16, 2020 at 13:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.