58

I'm running Vim on a gnome terminal. But the alt key mappings are not working. For example:

:imap <A-i> <Esc>

It works fine in GVim. But when I run the same command with Vim in the gnome terminal it does nothing.

I'm using Windows 7, The problem is with the terminal, right?

Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
Jesse
  • 1,449
  • 2
  • 15
  • 20
  • Your `Alt-i` keystroke was intercepted by the operating system itself or the terminal emulator window's GUI keybindings, it performed an action that had no visible effect, and so vim does not receive the Alt-i keystroke at all. To remedy you have to review your OS system settings -> keybindings. Then review your Terminal Emulator's system->keymaps. There you will find an entry for Alt-i. Delete that entry and now vim can receive your keystroke. – Eric Leschinski Jun 05 '22 at 00:37

6 Answers6

107

The problem

There are two ways for a terminal emulator to send an Alt key (usually called a Meta key as actual terminals didn't have Alt). It can either send 8 bit characters and set the high bit when Alt is used, or it can use escape sequences, sending Alt-a as <Esc>a. Vim expects to see the 8 bit encoding rather than the escape sequence.

Some terminal emulators such as xterm can be set to use either mode, but Gnome terminal doesn't offer any such setting. To be honest in these days of Unicode editing, the 8-bit encoding is not such a good idea anyway. But escape sequences are not problem free either; they offer no way of distinguishing between <Esc>j meaning Alt-j vs pressing Esc followed by j.

In earlier terminal use, typing Escj was another way to send a Meta on a keyboard without a Meta key, but this doesn't fit well with vi's use of Esc to leave insert mode.

The solution

It is possible to work around this by configuring vim to map the escape sequences to their Alt combinations.

Add this to your .vimrc:

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

set timeout ttimeoutlen=50

Alt-letter will now be recognised by vi in a terminal as well as by gvim. The timeout settings are used to work around the ambiguity with escape sequences. Esc and j sent within 50ms will be mapped to <A-j>, greater than 50ms will count as separate keys. That should be enough time to distinguish between Meta encoding and hitting two keys.

If you don't like having timout set, which times out for other mapped key sequences (after a second by default), then you can use ttimeout instead. ttimeout applies only to key codes and not other mappings.

set ttimeout ttimeoutlen=50
Elias Dorneles
  • 22,556
  • 11
  • 85
  • 107
jpnp
  • 1,390
  • 1
  • 10
  • 9
  • 1
    Thank you so much for this! You finally fixed a problem that's been bothering me for so long! – Eli Gundry Jun 22 '12 at 17:53
  • How to modify it for ? I mean - for uppercase keys? – Arnis Lapsa Jul 10 '12 at 13:06
  • 3
    Change the let to 'A' and the while condition to 'Z' to map upper case keys. Do both if you want. – jpnp Jul 10 '12 at 22:07
  • 5
    I have found with this setup, if I'm in Cmdline-mode or Visual-mode that if I press escape it'll either execute a mapping or insert multibyte characters. I fixed this by allowing myself to leave these modes by pressing escape twice with these settings: `vnoremap ` and `cnoremap ` – Eli Gundry Jul 20 '12 at 19:26
  • Is there a workaround that works with having timeout disabled? I don't like timeout, and vim will wait indefinitely for me to complete (for example) a sequence starting with . – trusktr Oct 13 '13 at 10:26
  • 1
    @trusktr Yes you can set ttimeout. Will add to answer. – jpnp Dec 07 '13 at 10:09
  • 8
    If you are using vim within tmux and can't figure out why the above isn't working, it's because tmux inserts a wait after ESC and will itself interpret keycodes. Put `set -sg escape-time 0` in your .tmux.conf to disable this behavior. – cledoux Apr 06 '15 at 15:09
  • I found this solution very helpful. I would had trouble using it because I was interested in the keybinding, which isn't affected in your while loop. It was easy enough to add, by repeating the loop from '0' to '9'. – Jeffeb3 Jan 14 '16 at 16:51
  • Is it possible to make a similar hack work in tmux (so that you can use the alt key in tmux)? – George Feb 11 '16 at 16:04
  • Unfortunately, this breaks macros in vim for me. – Samir Alajmovic Feb 03 '18 at 12:55
8

For Gnome-terminal, use the following instead:

imap ^[i <Esc>

^[i should be typed by pressing Ctrl-v Alt-i

Attention: You need to yank and put in Vim when you want to copy it elsewhere. If you just copy the mapping in an editor like gedit, the mapping will probably be broken.

EDIT here is an example which makes Alt-k add an empty line above the cursor, and Alt-j add an empty line after the current line.

" Alt-j/k to add a blank line
if has('gui_running')
    " the following two lines do not work in vim, but work in Gvim
    nnoremap <silent><A-j> :set paste<CR>m`o<Esc>``:set nopaste<CR>
    nnoremap <silent><A-k> :set paste<CR>m`O<Esc>``:set nopaste<CR>
else
    " these two work in vim
    " shrtcut with alt key: press Ctrl-v then Alt-k
    " ATTENTION: the following two lines should not be 
    " edited under other editors like gedit. ^[k and ^[j will be broken!
    nnoremap ^[k :set paste<CR>m`O<Esc>``:set nopaste<CR>
    nnoremap ^[j :set paste<CR>m`o<Esc>``:set nopaste<CR>
endif
ying17zi
  • 492
  • 6
  • 15
2

The same thing happens to me. I searched on Google with "gnome terminal alt key", and found that someone asked almost the same question: "How to disable the alt-hotkey behavior on gnome terminal?" in the first link found. (The second link is just this question)

So, maybe you can try that:

Edit > Keyboard Shortcuts, and uncheck "Enable menu access keys"
Community
  • 1
  • 1
aptx4869
  • 380
  • 3
  • 8
  • Dunno if that's one of those weird ubuntu upstream edits on gnome-terminal but debian's version didn't quite have that, simply going to edit->preferences->shortcuts and disabling them all worked for me – Dmitri DB Sep 13 '16 at 23:31
2

Try

<m-i>

Or, if typing alti inserts a character (like in my case, it inserts a carret: ˆ) just map to that character:

:inoremap ˆ <esc>

Be careful, because this one wouldn't work (at least in my system, MacOS 10.6). The caret waits for a letter, because it's not exactly a caret, it is a circumflex.

sidyll
  • 57,726
  • 14
  • 108
  • 151
2

It may be that the shortcuts are actually from the Gnome Desktop. Try looking at the Gnome Keyboard Shortcuts tool (System menu, Preferences, Keyboard Shortcuts), which lets you view and modify the shortcuts defined on Gnome Desktop. If the key combination is assigned to a function on Gnome Desktop, then remove it and then that key combo should filter down to Vim properly.

Or you may be right that it is a problem of the terminal. Not all terminals support all key combos. Your problem may be the one described in the Vim help docs at :h map-alt-keys. The docs provide a workaround, but not a very good one.

Herbert Sitz
  • 21,858
  • 9
  • 50
  • 54
  • Since the alt shortcut works with GVim, I think it is not a keyboard issue. Maybe the problem is really the terminal. Do you know if there are alternative terminals for Ubuntu witch I could try? – Jesse Jul 21 '11 at 19:16
  • Here's list of terminal alternatives for Ubuntu: http://www.howtogeek.com/howto/ubuntu/set-the-default-terminal-emulator-on-ubuntu-linux/ – Herbert Sitz Jul 22 '11 at 00:15
1

Take a look at section 1.10 of http://vimdoc.sourceforge.net/htmldoc/map.html. It seems to indicate that gnome-terminal automatically escapes the Alt modifier, so that it doesn't switch the byte sent in the way that Vim is expecting. The document seems to indicate that there isn't really a way around this except for using a different terminal (such as xterm).

This is certainly frustrating because so far as I can tell Linux machines are also incapable of using the D (Mac's Command or Linux's Super) bindings, so at least as far as the terminal goes, we are limited to Shift and Ctrl modifiers, which is frustrating if we want to ensure that we can use all the commands we use in Gvim on terminal Vim (at least without switching terminals, towards which I'm perhaps overly stubborn - gnome-terminal is just so much prettier). I've been looking for a way around this but have been unable to find anything.

metasoarous
  • 2,854
  • 1
  • 23
  • 24