The Essential IdeaVim Remaps. Reaching the mouseless productivity... | by Amine Elhattami | Towards Data Science

I’ve been using IdeaVim for both machine learning and general software projects for a while now. During my journey, I’ve compiled a list of essential remaps to take your mouseless development to the next level without sacrificing the robust features that Jetbrains IDEs provide. So if you’re more focused on the code you’re producing and not which airline theme you should use, then this blog post is for you. This is also for the machine learning crowd that still use Jupyter notebooks and want to step up their dev environment game but are discouraged by Vim’s steep learning curve.
A few years back, I was using Vim/NeoVim as my daily driver and I decided to switch to IdeaVim because I came to the realization that I was spending valuable time working on my .vimrc. As you will see in this post, you still need to do some configuration. However, it’s mainly setting shortcuts compared to building an “IDE” on top of Vim. IdeaVim isn’t perfect, but it provided me the level of flexibility I needed especially since I wasn’t a Vim power user. If you’re interested about why I switched to IdeaVim in more details, check out this article.
If you’re new to IdeaVim, check out my previous post to see how to set it up and to understand how IdeaVim shortcuts work. Also, I understand that it can be overwhelming to remember all the shortcuts. This was the same for me when I started. I’ve tried multiple tricks to memorize them but the ones that helped the most are:
Make the key bindings your own. While on the journey of perfecting your configuration you’ll end up collecting remaps from multiple sources like this one, and sometimes the key binding won’t make sense to you or it might be already used. So go ahead and change it.
Follow the same method to create shortcuts. For example, you can choose to use CTRL and the first letter of the action the shortcut does. Example, mapping CTRL t to launch the terminal. Occasionally some actions will start with the same letter, and this is when you can introduce the <leader> key or just any key like gd for go to definition.
Keep the list of shortcuts that you always forget somewhere visible. I use a Post-it on my monitor, and it works!
Remember that learning Vim style key binding will always be valuable. Since even if you choose to use another IDE, it will probably have some kind of vim emulation. For example, I use PyCharm and CLion for development and NeoVim for editing configuration files on the fly and I have roughly the same key binding in all three. So I only need to remember one set of shortcuts, which is a major advantage. Moreover, you will be thanking yourself next time you have to edit a server config, were vi is the only option.
Finally, I’m sharing some screen casts here because seeing is believing.
I’ve decided to split the list into sections to provide more details on each, and if you’re only looking for specific remaps.
As a reference, I included the full config at the bottom of the post. However, I recommend that you copy/paste each part instead and try each remap to see what it does.
Throughout this blog post, you’ll see snippets that need to be appended to your .ideavimrc file. Once saved, it needs to be reloaded to apply the changes. The following defines two remaps:\e to open the file and \r to reload it. Moreover, the set clipboard command enables using the system clipboard from IdeaVim and vice-versa.
set clipboard+=unnamedset clipboard+=ideaputnnoremap \e :e ~/.ideavimrc<CR>nnoremap \r :action IdeaVim.ReloadVimRc.reload<CR>
Note that for remaps that I don’t use while coding, like the one above. I try to use the same prefix (in this case \) since I don’t want to waste useful key bindings.
Or rather the lack of the escape button. This one is handy for those cursed with the older MacBook touch bar. Since you need to hit <ESC> pretty much all time, having the tactile feedback of a physical button is a must (at least for me). The following remaps CTRL c to <ESC>.
map <C-c> <Esc>
Moreover, I set the CAPSLOCK as a CTRL key from the system preferences. I find it very useful since your fingers don’t need to leave the home row. You can even set the CAPSLOCK key to act as <ESC> if hit once and as CTRL if held.
If you aren’t familiar with Vim, see the leader key as a mapping prefix that you set once. Let’s say you have <leader>c in your config and you’ve mapped the leader to SPACE like the snippet below, then your mapping is SPACE c.
let mapleader=" "
The advantage of using the leader key is that if you decide that SPACE isn’t practical anymore, the change needs to happen in one place only.
As I mentioned in a previous post, I’m a big fan of Vim’s clean interface. Yet, I keep getting asked why someone would hide all the useful widgets the IDE offers. My response is that I like to treat my development interface like my desk. I try to keep the bare minimum on top, because every item is constantly fighting for my attention. Also, having visible widgets can ‘trick’ you to use the mouse instead of using a shortcut. Always remember:
You can’t click on what you can’t see.
nnoremap <c-z> :action ToggleDistractionFreeMode<CR>
With all the command line tools that I use daily, having a shortcut for the terminal is a must.
nnoremap <c-t> :action ActivateTerminalToolWindow<CR>nnoremap <leader>t :action Terminal.OpenInTerminal<CR>
The Terminal.OpenInTerminal action let you open a new terminal directly in the parent folder of the current file in the editor. This is very useful with deeply nested folder structures, since it avoids having to cd to the right folder.
While programming, I rely on navigation remaps a lot, because I’m constantly creating splits and moving from one buffer (or tab) to another.
nnoremap <c-\> :action SplitVertically<CR>nnoremap <c--> :action SplitHorizontally<CR>nnoremap <c-=> :action Unsplit<CR>nnoremap <c-m> :action MoveEditorToOppositeTabGroup<CR>sethandler <c-j> a:vimsethandler <c-k> a:vimnnoremap <c-h> <c-w>hnnoremap <c-l> <c-w>lnnoremap <c-j> <c-w>jnnoremap <c-k> <c-w>knnoremap <TAB> :action PreviousTab<CR>nnoremap <s-TAB> :action NextTab<CR>nnoremap <Leader>en :action EditSourceInNewWindow<CR>nnoremap <Leader>n :action NextWindow<CR>nnoremap <Leader>q :action CloseContent<CR>nnoremap <Leader>qa :action CloseAllEditors<CR>
The sethandler command sets IdeaVim as the handler of the specified shortcut. This can be done via the settings UI. However, I like to keep everything in one place as much as possible.
An essential remap list would be irrelevant if it excluded editing source code. Looking at my config, I can count 30 plus remaps that I found here and there. However, while writing this post, I’ve selected the ones that I use the most. This shows that you don’t need an extensive list. You just need to keep the ones you use, so feel free to pick and choose.
set ideajoinset idearefactormode=keepvnoremap < <gvvnoremap > >gvnnoremap [[ :action MethodUp<CR>nnoremap ]] :action MethodDown<CR>nnoremap zc :action CollapseRegion<CR>nnoremap zo :action ExpandRegion<CR>nnoremap <leader>zc :action CollapseAllRegions<CR>nnoremap <leader>zo :action ExpandAllRegions<CR>nnoremap <leader>c :action CommentByLineComment<CR>nnoremap <leader>r :action Refactorings.QuickListPopupAction<CR>nnoremap <Leader>=  :action ReformatCode<CR>nnoremap <leader>o :action OptimizeImports<CR>nnoremap <c-r> :action RecentFiles<CR>nnoremap <leader>l :action RecentLocations<CR>nnoremap <leader>h  :action LocalHistory.ShowHistory<CR>nnoremap ge :action GotoNextError<CR>nnoremap gE :action GotoPreviousError<CR>
For refactoring, I went with the quick list since I find it easier this way. However, you can map each of the specific refactoring actions using the appropriate ID .i.e. ExtractMethod, RenameElement, ChangeSignature, etc. Use the :actionlist command to find the full action ID list.
I enjoy the search functionality of Jetbrains IDEs. It just works and has a close to perfect intellisense. Especially while working on a new large code base, where I’m still learning where things are.
set incsearchnnoremap <c-/> :action FindInPath<CR>nnoremap <c-a> :action GotoAction<CR>nnoremap <c-f> :action GotoFile<CR>nnoremap <leader>u :action FindUsages<CR>nnoremap <leader>s :action GotoRelated<CR>nnoremap <leader>h :action CallHierarchy<CR>nnoremap <leader>b :action ShowNavBar<CR>nnoremap <c-s> :action FileStructurePopup<CR>nnoremap <c-o> :action GotoSymbol<CR>nnoremap gc :action GotoClass<CR>nnoremap gi :action GotoImplementation<CR>nnoremap gd :action GotToDeclaration<CR>nnoremap gp :action GotToSuperMethod<CR>nnoremap gt :action GotoTest<CR>nnoremap gb :action Back<CR>nnoremap gf :action Forward<CR>
For the in file search, I like to use Vim’s default search command /. Since it provides all I need. However, you can always map the Find action.
In any Jetbrains IDEs, pretty much anything that isn’t the editor is a tool window. So having a good set of shortcuts to manage them comes very handy.
First in your .ideavimrc you need to set the shortcuts that gets triggered from the editor.
nnoremap <c-p> :action JumpToLastWindow<CR>nnoremap <c-x> :action HideAllWindows<CR>
Second, from the IDE settings set the ones that get triggered from the tool windows:
Go to ‘keymap’ and find ‘Other’, then ‘Tool Windows View Mode’ and map ‘Dock Pinned’, ‘Float’ and ‘Window’. In my case I used ALT d, ALT f and ALT w respectively. Note that these mappings won’t interfere with the ones in your .ideavimrc.
Still in ‘keymap’, find ‘Main Menu’, then ‘Window’, after that ‘Hide Active Tool Window’ and map ‘Hide Active Tool Window’. In my case I used ALT h.
In ‘Tools’ find ‘Terminal’ and uncheck ‘Override IDE shortcuts’
One last comment, whenever you want to go back to the editor just hit <ESC>. However, due to a bug in IdeaVim you can’t use <ESC> to return to the editor from the run console only. A workaround is to set a second shortcut for ‘Focus Editor’ from the IDE settings other than <ESC>, in my case I use F1.
My configuration for running and debugging is very straight forward as you can see bellow.
nnoremap ,r :action ContextRun<CR>nnoremap ,c :action RunClass<CR>nnoremap ,f :action ChooseRunConfiguration<CR>nnoremap ,t :action ActivateRunToolWindow<CR>nnoremap ,u :action Rerun<CR>
I choose to map ContextRun instead of the Run action, because the latter runs the previously selected configuration instead of running the code at the cursor. The RunClass action name is misleading but it’s used to run the current file. Moreover, since you can reach the ActivateDebugConfiguration by holding SHIFT when using ActivateRunConfiguration defined above. I decided not to map it.
All commands above apply to runing tests. Just place the cursor on the test you want to run and hit the shortcut. I also like using the RerunFailedTest which does what it says.
nnoremap ,f :action RerunFailedTests<CR>
As for debugging, multiple actions can be remapped. However, I only use the shortcuts for basic cases. For anything more advanced, I’m sticking with the mouse for now. Relying mainly on shortcuts feels slower or maybe I’m not that fast on a keyboard. Also, if you look at the Vimspector project (one of the most promising debugging plugins), you can see that they added buttons to Vim’s interface. So I might not be the only one with this opinion.
nnoremap ,b :action ToggleLineBreakpoint<CR>nnoremap ,d :action ContextDebug<CR>nnoremap ,n :action ActivateDebugToolWindow<CR>
One downside of running and debugging using the IDE is that you will need to use the mouse to create a configuration if you’re using some advanced settings like environmental variables or interpreter options. You can still run your code from the terminal, but you will lose some nice features like the test runner and the debugger. This is wasn’t a deal breaker for me since it is a set and forget setting.
""" Editing and Reloading the Configset clipboard+=unnamedset clipboard+=ideaputnnoremap \e :e ~/.ideavimrc<CR>nnoremap \r :action IdeaVim.ReloadVimRc.reload<CR>""" The Escape buttonmap <C-c> <Esc>""" The Leader Keylet mapleader=" """" Distraction Free Modennoremap <c-z> :action ToggleDistractionFreeMode<CR>""" Terminalnnoremap <c-t> :action ActivateTerminalToolWindow<CR>nnoremap <leader>t :action Terminal.OpenInTerminal<CR>""" Navigationnnoremap <c-\> :action SplitVertically<CR>nnoremap <c--> :action SplitHorizontally<CR>nnoremap <c-=> :action Unsplit<CR>nnoremap <c-m> :action MoveEditorToOppositeTabGroup<CR>sethandler <c-j> a:vimsethandler <c-k> a:vimnnoremap <c-h> <c-w>hnnoremap <c-l> <c-w>lnnoremap <c-j> <c-w>jnnoremap <c-k> <c-w>knnoremap <TAB> :action PreviousTab<CR>nnoremap <s-TAB> :action NextTab<CR>nnoremap <Leader>en :action EditSourceInNewWindow<CR>nnoremap <Leader>n :action NextWindow<CR>nnoremap <Leader>q :action CloseContent<CR>nnoremap <Leader>qa :action CloseAllEditors<CR>""" Editing source codeset ideajoinset idearefactormode=keepvnoremap < <gvvnoremap > >gvnnoremap [[ :action MethodUp<CR>nnoremap ]] :action MethodDown<CR>nnoremap zc :action CollapseRegion<CR>nnoremap zo :action ExpandRegion<CR>nnoremap <leader>zc :action CollapseAllRegions<CR>nnoremap <leader>zo :action ExpandAllRegions<CR>nnoremap <leader>c :action CommentByLineComment<CR>nnoremap <leader>r :action Refactorings.QuickListPopupAction<CR>nnoremap <Leader>=  :action ReformatCode<CR>nnoremap <leader>o :action OptimizeImports<CR>nnoremap <c-r> :action RecentFiles<CR>nnoremap <leader>l :action RecentLocations<CR>nnoremap <leader>h  :action LocalHistory.ShowHistory<CR>nnoremap ge :action GotoNextError<CR>nnoremap gE :action GotoPreviousError<CR>nnoremap <leader>s :write<CR>""" Searching and Source Code Navigationset incsearchnnoremap <c-/> :action FindInPath<CR>nnoremap <c-a> :action GotoAction<CR>nnoremap <c-f> :action GotoFile<CR>nnoremap <leader>u :action FindUsages<CR>nnoremap <leader>s :action GotoRelated<CR>nnoremap <leader>h :action CallHierarchy<CR>nnoremap <leader>b :action ShowNavBar<CR>nnoremap <c-s> :action FileStructurePopup<CR>nnoremap <c-o> :action GotoSymbol<CR>nnoremap gc :action GotoClass<CR>nnoremap gi :action GotoImplementation<CR>nnoremap gd :action GotToDeclaration<CR>nnoremap gp :action GotToSuperMethod<CR>nnoremap gt :action GotoTest<CR>nnoremap gb :action Back<CR>nnoremap gf :action Forward<CR>""" Tool windowsnnoremap <c-p> :action JumpToLastWindow<CR>nnoremap <c-x> :action HideAllWindows<CR>""" Running and Debuggingnnoremap ,r :action ContextRun<CR>nnoremap ,c :action RunClass<CR>nnoremap ,f :action ChooseRunConfiguration<CR>nnoremap ,t :action ActivateRunToolWindow<CR>nnoremap ,u :action Rerun<CR>nnoremap ,f :action RerunFailedTests<CR>nnoremap ,b :action ToggleLineBreakpoint<CR>nnoremap ,d :action ContextDebug<CR>nnoremap ,n :action ActivateDebugToolWindow<CR>
I re-iterate this again, I’m not sponsored by Jetbrains; However, this as part of my desire to share my journey hoping it might help someone.
I still believe that IdeaVim isn’t perfect, but up until now it provided me enough flexibility that I’m happy to continue using it.
Finally, I’m currently relying on a set of plugins to supercharge my configuration and will be sharing them soon, so make sure to follow me!
Follow me on Twitter, where I regularly tweet about software development and machine learning.