86

I'm trying to map Alt key in the following way:

:map <A-j> j
:map <A-k> k

but it doesn't work (bell is rang on Alt + j/Alt + k).

What am I missing?

I'm using Terminal on OSX, the same happens on remote Linux.


On Ctrl + v, Alt + j, I've got: ?~H~F ( when encoding=utf-8).

On Ctrl + v, Alt + k, I've got: ?~Z (˚ when encoding=utf-8).

Running vim without plugins (-u NONE) doesn't make any difference.

4
  • 1
    Does Alt (press, not hold) and then j work? With xterm at least I need to set metaSendsEscape to true to get these sequences to work... I don't know if you have the same problem, and I don't use OSX so I can't test... Commented Mar 3, 2015 at 23:16
  • @Carpetsmoker Pressing Alt, release, then j or any other key works as normal. I've checked and found the option 'Use option as meta key', enabled it and it works now. So setting metaSendsEscape did the trick, thanks.
    – kenorb
    Commented Mar 3, 2015 at 23:41
  • 5
    This question was previously answered (with a better response) here: stackoverflow.com/questions/6778961/… Commented Oct 5, 2016 at 7:55
  • Your Alt-j and Alt-k was intercepted by your operating system or your Terminal emulator or both. The intercepted action (Find?) as defined in your_os->system->settings->keybindings or your_terminal->settings->keymaps will tell you where the keystroke sunk. Delete all entries and vim once again receives your keystroke. Commented Jun 5, 2022 at 1:42

8 Answers 8

95

That's how I do it on Linux or Cygwin:

First check what chars are sent by your terminal when you press ALT+J:

In order to do this I go to console and run sed -n l (you can also use cat for it). Then I press ALT+J and see that the chars on the screen are ^[j .

I replace ^[ with \e (because that's what is sent by my terminal when I press esc) and the final string for me is \ej.

Then I write it to my .vimrc:

execute "set <M-j>=\ej"
nnoremap <M-j> j

And the mapping works.

12
  • 9
    I can't find the documentation for the :set <M-j>=\ej part. What should I search for? Commented Jun 3, 2015 at 1:05
  • 1
    Thanks for the answer, this was the only solution that has worked for me w/ Iterm + vim Commented Jun 22, 2015 at 14:33
  • 3
    Nah, this doesn't work. Sometimes ESC-J will act as ALT-J Commented Oct 4, 2016 at 5:15
  • 5
    @EvgeniSergeev See :help :set-termcap
    – Rich
    Commented Feb 15, 2018 at 22:10
  • 4
    I like your "check what chars are sent by your terminal" part. Smart!
    – Bruce
    Commented Feb 3, 2021 at 10:56
21

With help of Carpetsmoker, it seems that Terminal wasn't configured to 'Use Alt/option as meta key' (this is especially common for GUI Terminals).

For Terminal on OSX, it's in Preferences -> Settings -> Keyboard tab -> 'Use option as meta key'. Check: How can I change Terminal to use option as meta key? (Mavericks).

For XTerm, check: Configuring XTerm to Default to Meta Sends Escape which says:

Add this line anywhere in your personal .Xdefaults file (~/.Xdefaults):

xterm*metaSendsEscape: true

Then reload the config with xrdb. Without this step the changes in .Xdefaults won't take effect until the next X restart:

xrdb -l ~/.Xdefaults

Then standard mappings with Alt key like:

:map <A-j> j
:map <A-k> k

works fine.

For help, see: :h :map-alt-keys.

1
  • 4
    May also want to look at :h :map-alt-keys as another source of information Commented Mar 4, 2015 at 17:02
15

Similar to Kossak's answer but a bit simpler, by mapping literal key presses.

Either in normal mode after pressing :, or inserted into your .vimrc, map the input directly by starting the mapping:

nnoremap 

then hitting Ctrl + V then the keystroke to record, e.g. Alt + . This will show as something like this:

nnoremap ^[[1;3D

but each ^[ is a single, literal escape character and syntax highlighting should show this. Replace the literal escape(s) with the text <Esc>, and append the command you wish to use:

nnoremap <Esc>[1;3D <C-w>h

I know OP was mapping Alt + letters, but I used arrows to show how do it for something that may not be mapped by default.

4
  • Worked like a charm, thanks a lot!
    – aryndin
    Commented Oct 24, 2019 at 9:11
  • 1
    This is exactly what I was looking for. I didn't know exactly what vim was interpreting my desired key combo as, and this shows you. Thanks! Commented Nov 25, 2020 at 22:55
  • Doesn't work with my Danish layout. Commented Feb 15, 2021 at 21:06
  • @SebastianNielsen What, exactly "doesn't work"? This should be layout independent because you're mapping raw keypresses regardless of what they are. If you can't send SYN on a Danish keyboard, then first figure that out.
    – Walf
    Commented Feb 16, 2021 at 0:07
4

If Control+V followed by ALT-x shows ^[x (type in terminal) you can fix it with this small script from vim.wikia.com:

for i in range(97,122)
  let c = nr2char(i)
  exec "map \e".c." <M-".c.">"
  exec "map! \e".c." <M-".c.">"
endfor

Add to .vimrc for all alt key mappings.

1
  • 1
    Generally this is a bad idea, as then the <esc> key itself will be delayed.
    – user202729
    Commented Feb 17, 2023 at 2:49
3

This works for me on Ubuntu 16.04 xfce terminal (and alacritty rust terminal)

Set ultisnip snippet trigger to Meta-/ (just like emacs snippet)

let g:UltiSnipsExpandTrigger="^[/"

Here's now I type ^[/ in vim

In insert mode Ctrl-V Alt-/

(Meta is the Alt key on my PC keyboard)

2

I'm using Terminal on OSX, the same happens on remote Linux.

I don't know about Terminal, but if you are on OSX, your mappings should work out of the box, provided that you use a recent Vim version, and a recent iTerm2 terminal.

You need at least the Vim patch 8.1.2134. Having the patch 8.1.2194 also helps, because it automatically enables the modifyOtherKeys feature on which Vim relies to let the user map various chords.

For iterm2, I think you need at least the version 3.4.0. From the changelog:

  • Modifier keys in vim should work better now. CSI u mode is no longer enabled by a control sequence. Instead, a "modifyOtherKeys" mode has been added which is compatible with xterm.

On Linux, xterm also supports the modifyOtherKeys feature.


You are not limited to meta chords. You can map many other chords, like <C-;> for example:

vim -Nu NONE +'nno <c-;> :echo "c-; was hit"<cr>'

For more info, see :h modifyOtherKeys.

1
  • I'm on 8.2.2300, and I couldn't make nnoremap <A-j> :echo "alt-j"<CR> work on macOS on either Terminal.app or Alacritty :( oh well, I don't tend to use those chords anyway
    – D. Ben Knoble
    Commented Mar 7, 2021 at 17:53
1

You have another option. NeoVim works with M-x out of the box when you have terminal sending ESC + sequence, which mostly every terminal could.

As a summary for other answers, I think your two options are

  1. Turning using "opt as meta" off, using the actual sent code in mapping
  2. Turning using "opt as meta" on, using <esc>x type of sequence for mapping.

There are some answers stating that just turning on opt as meta would make <A-x>/<M-x> work. That is not true. At least, it will not work on macOS.

1
  • 1
    Welcome to Vi and Vim! I've edited your post for some formatting, and also edited out the opinion-based parts to focus on the core facts.
    – D. Ben Knoble
    Commented Mar 7, 2021 at 17:46
1

I couldn't get any of the solutions in this thread to work on macOS because it has special characters mapped to <alt><letter>.

I ended up just mapping to the special characters. So <A-J><M-J> gets mapped to å. It doesn't work in insert mode because the special character will still get inserted, but I spend more time in normal mode anyway.

It's been the simplest working solution for me thus far.

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.