Vim in IntelliJ

Introduction

Vim (and NeoVim) has long been a program that has intrigued me; Editing text "at the speed of thought" is a powerful idea, especially for a programmer. Over the years, I'd picked up the basics of navigating and editing text within Vim, but its real power seemed to be behind a steep learning curve. I also mostly work in Android Studio these days, and I was very hesitant to give up that familiar environment for a terminal-based text editor.

Then I came across a plugin for IntelliJ IDEs, like Android Studio, called IdeaVim. IdeaVim emulates a Vim engine within the IDE, so you can do (almost) all of the same things you could do within Vim. After giving it a try, I've realized that it's a great way to bridge the gap. I can use the powerful Vim motions and commands while retaining the functions of my IDE.

In this post, I'll share the tips that I've picked up along the way, as well as how and why I've configured IdeaVim for my day-to-day use and how you can, too.

Getting started

The best way to get started, of course, is to just do it. The IdeaVim plugin can be installed through your IDEs settings.

I also recommend installing the Which-Key plugin. Which-Key displays your keybindings in a small window as you type them, which is extremely helpful for learning your keybindings. I'll show a few of the customizations I've made for Which-Key later.

Which-Key window displaying my configured keybinds.

Which-Key window.

Move the configuration file

If you like to keep your configuration files within the $XDG_CONFIG_HOME directory (~/.config for me), you may want to move the .ideavim file that the plugin creates into that directory.

mkdir ~/.config/ideavim
mv ~/.ideavim ~/.config/ideavim/ideavimrc

Learn Vim

If you're totally new to Vim, your first step should be to run the vimtutor1 command from your terminal. This will start up Vim and walk you through all of the important information you need to know to be able to use it, from moving around to editing text to running commands. And most importantly, how to exit Vim. 😉

While not necessary, I absolutely recommend picking up the book Practical Vim by Drew Neil2. This book is such a great reference for all the things you can do in Vim and I keep it within arm's reach. Any time I feel like I'm probably doing something inefficiently, I crack open the book and skip to the relevant chapter.

Another great reference is the Vim Cheat Sheet, which contains all of the most important motions and keybinds. I keep this one pinned in my browser so it's easy to reference.

Configuring Ideavim

The IdeaVim configuration file supports many of the same options as a normal Vim configuration file. In fact, you can even import your Vim configuration if you want to keep your Vim and IdeaVim configurations separate.

source ~/.vimrc

One thing to note, however, is that while IdeaVim does support Vimscript, it has some limitations and may not support everything you can do in Vimscript. I personally haven't needed to use Vimscript, though, so I haven't run into those limitations. Also, IdeaVim does not support Lua like NeoVim does.

Keybinding IDE actions

IdeaVim allows you to set keybindings that can trigger actions within the IDE. There are two ways to do this.

" the documented method - <Action>()
nmap <leader>df <Action>(ToggleDistractionFreeMode)
" my preferred method - :action X<CR>
nnoremap <leader>df :action ToggleDistractionFreeMode<CR>

Feel free to use either method, but I prefer to be able to use the non-recursive mapping which doesn't seem possible when using the <Action>() method.

If you're curious about what action IDs are available, display the actionlist.

:actionlist

You can also filter the actionlist with input.

:actionlist toggle

If there's a specific IDE action that you want the ID for, enable the IdeaVim: Track Action IDs setting. When you perform the IDE action, a notification will be displayed containing the ID of the action that was just performed. You can also copy the action ID from that notification and use it in your configuration.

Be sure to disable the setting afterward so you're not constantly getting notifications.

The Track Action IDs setting within the Actions poopup.

IdeaVim: Track Action IDs setting within the Actions popup.

The Action ID notification for toggling Distraction Free mode.

Action ID notification.

Config Walkthrough

With all of that out of the way, here's a look at how I have my own IdeaVim configuration set up.

You can view my ideavimrc in its entirety on GitHub. I still make changes to it frequently, so some of the configurations might be different than what you see here.

Leader

let mapleader = " "

Set the <Leader> key to <Space>.

Vim has a lot of keybindings, with many keys on the typical keyboard already assigned. It's typical to set your own custom keybindings behind the <Leader> key. In other words, whatever mapleader is set to, you press that key first, followed by the keys you want to bind. By default, Vim has the \ key set as the <Leader> key. <Space> is easier to hit for me, though.

Show mode/command

set showmode
set showcmd

Display the Vim mode and partial command in the status bar.

Line numbers

set number
set relativenumber

Display hybrid line numbers.

By setting both of these options, the actual line number will be displayed in the gutter for the line the cursor is on. Other lines are numbered in the gutter relative to the current line. This allows me to see the number of the current line I'm on while also giving me relative line numbers for Vim motions.

Screenshot showing hybrid line numbers in the gutter.

Hybrid line numbers in the gutter.

Scrolloff

set scrolloff=10

Ensure there are at least 10 lines between the cursor and the top/bottom of the screen.

set ignorecase
set smartcase

When performing a search in the file with / or ?, perform a case-insensitive search unless an uppercase letter is present.

set incsearch
set hlsearch

Highlight search matches as the predicate is being typed.

Keybind timeout

set notimeout

Remove the keybind timeout.

This is especially useful while you're learning and trying to remember the keybinds. Not having a timeout is also useful so the Which-Key window doesn't disappear after a short period of time.

IdeaVim-specific options

set ideajoin

Handle line join commands (Shift+J) using IntelliJ's "smart join" feature.

set ideaput

Handle paste commands using IntelliJ's paste implementation rather than performing a simple text insertion.

set ideamarks

Handle Vim global marks using IntelliJ's bookmarks.

Plugins

set highlightedyank

Highlight yanked text for an instant.

set commentary

Add Vim functionality for commenting text and lines using gcc (normal mode) and gc (visual mode).

Disable arrow keys

nnoremap <Left>  :echo "Use h to move!"<CR>
nnoremap <Down>  :echo "Use j to move!"<CR>
nnoremap <Up>    :echo "Use k to move!"<CR>
nnoremap <Right> :echo "Use l to move!"<CR>

Print a notice to myself reminding me to use the appropriate movement keys if/when I use an arrow key for movement in normal mode. D'oh!

Paging up/down

nnoremap <C-d> <C-d>zz
nnoremap <C-u> <C-u>zz

When paging up/down, center the cursor in the middle of the screen.

Search highlighting

nnoremap / :set hlsearch<CR>/
nnoremap ? :set hlsearch<CR>?
nnoremap <Esc> :set nohlsearch<CR>

Enable search highlighting when performing a search and clear highlighting when I press <Esc> in normal mode.

Splits

nnoremap <C-h>  <C-w>h
nnoremap <C-j>  <C-w>j
nnoremap <C-k>  <C-w>k
nnoremap <C-l>  <C-w>l

Move the cursor to the split left/below/above/right.

nnoremap <C-w>m :action MoveEditorToOppositeTabGroup<CR>

Move a tab to another split.

nnoremap <C-w>M :action MaximizeEditorInSplit<CR>

Maximize the active split.

nnoremap <C-w>O :action ChangeSplitOrientation<CR>

Switch the split orientation between horizontal and vertical.

nnoremap <C-w>u :action Unsplit<CR>

Merge all splits into one, keeping open tabs.

Diagnostics

nnoremap [d :action GotoPreviousError<CR>
nnoremap ]d :action GotoNextError<CR>

Navigate between diagnostic messages and errors in the file.

Yanking

nnoremap <leader>y   :%y<CR>
nnoremap <leader>Y   :%y+<CR>

Yank the entire file, either to a register or the system clipboard.

Display modes

nnoremap <leader>df  :action ToggleDistractionFreeMode<CR>
nnoremap <leader>dp  :action TogglePresentationMode<CR>

Enter Distraction Free or Presentation modes.

Presentation mode is especially useful when I'm pair-programming with someone because the high resolution of my screen tends to make it difficult for others to see my screen clearly. Presentation mode will make everything larger.

Files

nnoremap <leader>ff  :action GotoFile<CR>
nnoremap <leader>fr  :action RecentFiles<CR>

Open a popup to navigate to a different file.

nnoremap <leader>fb  :action NewScratchBuffer<CR>
nnoremap <leader>fs  :action NewScratchFile<CR>

Create a new scratch buffer or scratch file.

Goto

nnoremap <leader>gd  :action GotoDeclaration<CR>
nnoremap <leader>gi  :action GotoImplementation<CR>
nnoremap <leader>gt  :action GotoTest<CR>
nnoremap <leader>gy  :action GotoTypeDeclaration<CR>

Go to declarations, implementations, or tests.

nnoremap <leader>gl  :action RecentLocations<CR>

Display a popup allowing me to navigate to any of the recent locations my cursor has been.

I use this often to navigate back to where I was before I started looking up type definitions or implementations.

nnoremap <leader>gs  :action FileStructurePopup<CR>

Display a popup of the file structure allowing me to navigate directly to a class method or function.

Project actions

nnoremap <leader>pr  :action Run<CR>

Run the project.

nnoremap <leader>ps  :action Android.SyncProject<CR>

Sync the project. Typically a Gradle sync, for me.

Information popups

nnoremap <leader>sa  :action ShowIntentionActions<CR>
nnoremap <leader>sh  :action ShowHoverInfo<CR>
nnoremap <leader>si  :action QuickImplementations<CR>
nnoremap <leader>st  :action QuickTypeDefinition<CR>
nnoremap <leader>su  :action ShowUsages<CR>

Display popups containing declarations, implementations, or usages.

Refactoring

nnoremap <leader>rf  :action ReformatCode<CR>

Reformat the code using IntelliJ's formatter.

nnoremap <leader>rr  :action RenameElement<CR>

Rename a symbol throughout the project.

nnoremap <leader>rs  :action ChangeSignature<CR>

Refactor a function signature to add/remove/change arguments.

IdeaVim

nnoremap <leader>R   :action IdeaVim.ReloadVimRc.reload<CR>

Reload the IdeaVim configuration.

Which-Key

let g:WhichKey_DefaultDelay = 0

Display the Which-Key window immediately.

let g:WhichKey_FontSize = 16

Set the font size of the Which-Key window to a larger size than my typical editor font size.

let g:WhichKey_SortCaseSensitive = "false"

Sort the keybindings within the Which-Key window according to case.

Final Thoughts

For those like myself who work in an IntelliJ IDE very often, IdeaVim is a great way to keep your familiar environment while adding the power of Vim motions and commands.

Whether you eventually make the full switch to Vim (or NeoVim), or you stay with IdeaVim, there is no "right" choice. Go with what works for you.

Personally, I still plan to switch to NeoVim eventually. For now, IdeaVim is keeping me happy and productive.

Footnotes