Baeldung Pro – Linux – NPI EA (cat = Baeldung on Linux)
announcement - icon

Learn through the super-clean Baeldung Pro experience:

>> Membership and Baeldung Pro.

No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.

Partner – Orkes – NPI EA (tag=Kubernetes)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

1. Introduction

Let’s be honest: we love our customizations! Whether it’s the quirky, fun look and feel we cherish on our workstations or just the extra speed and efficiency they might bring, we strive to stamp our identity on our systems.

Vim and NeoVim, as text editors, offer us flexibility and extensibility, particularly in the area of custom key mappings, which enable us to optimize our workflow. However, customizing specific keys in these editors can be tricky, especially if it’s the Alt key (usually called a Meta key).

In this tutorial, we’ll explore the different ways to map the Alt key in Vim and NeoVim and how to keep abreast with key notations.

2. Why Do We Map Keys?

Customizations, which key mappings are a part of, can add several benefits to our user experience. Aside from improving workflow efficiency and adding a personal feel, we map keys for other reasons. For one, key mappings can help us overcome terminal limitations and incorporate underutilized keys. We could also use key mappings to ensure consistency across different platforms and environments and enhance modal navigation.

However, mapping the Alt key is different from mapping other keys. This is because the terminal handles this key differently.

3. Understanding the Alt Key Challenge

The Alt key behaves differently across terminal emulators, often conflicting with escape sequences. This is because many terminals read it as a prefix to another key combination, like sending an escape sequence before a character.

To fully understand how the terminal reads the Alt key, we must first check what is sent when we type that key. A good way to check this is to use the sed command. Let’s say we want to see what happens when we press the Alt+j combination:

$ sed -n l
^[j

As we can see, executing the command moves our cursor to the next line, and the output of the Alt keystroke appears as ^[. So we know that our GNOME terminal reads the Alt key as ^[. Remember that it might not be the same for other terminal emulators.

We could also use the showkey command to get similar results:

$ showkey -a

Press any keys - Ctrl-D will terminate this program

^[ 	 27 0033 0x1b
j 	106 0152 0x6a
^[ 	 27 0033 0x1b
l 	108 0154 0x6c

In this case, we sent Alt+j and Alt+l sequences to the terminal. We can see what was returned as the Alt key.

4. Mapping the Alt Key

Now that we know how to check what our terminal returns as the Alt key and we’ve identified its character, we can go ahead and map this character.

There are several ways to map the Alt key. Let’s examine some of them.

4.1. Configuring the .vimrc File Using a Simple Set of Commands

We can map the ^[ character along with our desired key. Let’s say we want the Alt+j combo to output just j. First, we check how our terminal handles the Esc character:

$ sed -n l
\e

Then, we map the Alt sequence with the new character by appending the following lines to our .vimrc file:

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

Let’s break down this code:

  • execute “set <M-j>=\ej”: The execute command runs the string that follows it as if it were a command. In this case, we’re setting the Meta key combination <M-j> to be recognized as \ej, which represents its escape sequence in many terminals.
  • nnoremap <M-j> j: After configuring Vim to recognize the Alt+j key combination, this line sets the parameters of the mapping. n means this mapping occurs in normal mode, nore means this mapping is non-recursive and shouldn’t invoke other mappings of j within this one, <M-j> is our key combination, and j is the action assigned to the combination, which in Vim normal mode moves the cursor down one line.

After saving, we can see that the mapping now works. However, certain terminals read the Esc character as the Alt key as well:

$ sed -n l 
^[j

In this case, we’ve got to employ a more rooted approach.

4.2. Using the nr2char() Function

To ensure that Vim recognizes our Meta keys, we can use the nr2char() function in our .vimrc file:

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

Let’s break down what this code does and how it ensures the recognition of our Meta keys:

  • for i in range(97, 122): First, we create a for loop that iterates over a range of values from 97 to 122. These values correspond to lowercase characters in ASCII, i.e., ASCII 97 represents a, and ASCII 122 represents z.
  • let c = nr2char(i): Then, we assign the character value of these ASCII numerals to variable c using the nr2char(i) function. This means that if i = 98, which resolves to b, then c = b.
  • exec “map \e”.c.” <M-“.c.”>”: This line uses the exec command to generate a normal mode mapping in Vim. As previously mentioned, \e is the escape sequence that Vim uses to represent the Alt key in the terminal environment, so \e + c will represent Alt+c. The result of this command is that the Alt+<letter> combination, for example, Alt+j, will be mapped to <M-j>, which is Vim’s notation for representing a Meta key followed by j.
  • exec “map! \e”.c.” <M-“.c.”>”: This line is similar to the previous one, except it uses map! instead of map. map! is used for insert mode and command-line mode. It means that the same Alt+<letter> combination will be mapped in insert mode or when typing in the command line.
  • endfor: Marks the end of the for loop.

In summary, this code creates mappings for Vim’s normal mode (map) as well as insert and command-line (map!) mode. Specifically, it means that Vim can now recognize Meta key combinations:

:imap <M-j> Home
:imap <M-k> Is
:imap <M-l> Best

This creates mappings for the Alt key for insert mode. Next, we can test the mappings by typing each key combination:

HomeIsBest

We can see that Vim recognizes our key mappings.

4.3. Lua-Based Alt Key Mapping in Neovim

To set up key mappings in NeoVim using Lua, we can append the following code to our init.lua file:

-- Map ALT+j to the function hello()
function hello()
    print("Is it me you're looking for?")
end
vim.keymap.set('n', '<M-j>', hello)

This defines a Lua function named hello(), which, when called, executes the print() function and outputs “Is it me you’re looking for?” in NeoVim’s command-line area. Let’s look at the key mapping itself:

  • vim.keymap.set() is a NeoVim Lua function used to set key mappings. It offers a cleaner and more flexible way than Vimscript’s traditional :map or :nmap commands.
  • ‘n’ specifies that this key mapping applies to normal mode.
  • ‘<M-j>’ represents the Meta (Alt) + j key combination.
  • hello() is the function that will be executed when we press the Alt+j key combination.

We can try the key combination now in our NeoVim command-line area:

Is it me you're looking for?

Our key mapping works!

5. Key Notations in Vim and NeoVim

We can go ahead and create other key combinations using the Meta keys. We can check key notations in Vim using the :help command:

:help key-notation

key-notation key-codes keycodes
These names for keys are used in the documentation.  They can also be used
with the ":map" command (insert the key name by pressing CTRL-K and then the
key you want the name for).

notation        meaning             equivalent  decimal value(s)
-----------------------------------------------------------------------
<Nul>           zero                    CTRL-@    0 (stored as 10) <Nul>
<BS>            backspace               CTRL-H    8     backspace
<Tab>           tab                     CTRL-I    9     tab Tab
                                                        linefeed
<NL>            linefeed                CTRL-J   10 (used for <Nul>)
<FF>            formfeed                CTRL-L   12     formfeed
<CR>            carriage return         CTRL-M   13     carriage-return
<Return>        same as <CR>                            <Return>
<Enter>         same as <CR>                            <Enter>
...

Also, we can check what a hotkey does in NeoVim by executing the :map <key_combination> command:

:map <M-j>
hello

This returns the mapping of a particular hotkey combination. The Lua documentation provides more information on the different Lua modes.

6. Conclusion

In this article, we discussed mapping the Alt key in Vim and NeoVim. Using showkey or sed, we discovered how to check what our terminal returns when we input the Alt key.

Then, we explored the different ways we can map this key in Vim and NeoVim. Configuring the .vimrc file, we identified the nr2char() function as one way to ensure that Vim recognizes the Meta keys. For NeoVim, we explored the Lua-based key mapping configuration.

Lastly, we discussed documentation that can help us keep abreast with key notations and mappings in Vim and NeoVim.