From Emacs to Neovim (Configuration)
May 23, 2024
Background
This is a continuation of my post @ “From Emacs to Neovim”. In this post, I am going to share some concrete configuration examples and concepts that have helped me with adapting to vim
configuration and bindings coming from an emacs
background.
Note that my current, primary tooling focus is:
- spacemacs distribution of
emacs
primarily for Clojure/ClojureScript development - neovim distribution of
vim
for simple file editing in the terminal - vscode-neovim for TypeScript/JavaScript development
Neovim configuration
My public dotfiles can be found @ https://github.com/mrrodriguez/nvim-dotfiles
So far, I have not worked much to customize neovim
for a “standalone IDE” type of experience. I have been using it for basic file editing with minimum customization over the default terminal-based nvim
defaults. I then utilize this same configuration via the vscode-neovim
extension for vscode
, which I will describe more below in its own section. Later on below, I’ll enumerate the references that I used for some of this setup.
I have chosen to setup the neovim
configuration in a way where I can mix both vimscript
configuration along with lua
configuration. I liked this setup since I have found docs and examples are often in one or the other. I haven’t spent a lot of time learning either one yet to know how to translate between the two.
I am particularly a fan of nvim-surround
to help supplement for some of the utility I am used to from using paredit. This is a tool that I have heavily relied upon in emacs
. nvim-surround
isn’t meant to serve the same purpose as paredit
, but it does cover the most significant use-case I have had for paredit
which is “slurping” and “barfing” (this is paredit
terminology) surrounding delimiters around chunks of text/words. For the rest of the “structural navigation” parts I like from paredit
, I’ve tried to adapt with the idiomatic vim
navigation defaults and it has worked well enough so far. I’m sure there are plugins I could look into improve up on this in the future.
I also did not want to have to always use the “escape” key (aka. ESC
) for returning to “normal” mode. This is very common in the vim
community. There are many possible choices that are common and there are pros and cons to read about on them. I liked using jk
which I set via:
:inoremap jk <Esc>
:inoremap kj <Esc>
:vnoremap jk <Esc>
:vnoremap kj <Esc>
Another thing I noticed was it would often be convenient if I could go from “normal” mode to “insert” mode to insert a single character and then immediately be back in “normal” mode. This is another popularly discussed vim
topic (which I mention in the references below). I did this via:
function! RepeatChar(char, count)
return repeat(a:char, a:count)
endfunction
nnoremap s :<C-U>exec "normal i".RepeatChar(nr2char(getchar()), v:count1)<CR>
nnoremap S :<C-U>exec "normal a".RepeatChar(nr2char(getchar()), v:count1)<CR>
Neovim references
I have found these sources to be valuable in getting started with this configuration:
- This is a good post on starting a new
neovim
configuration. - These are two good posts concerning how to mix
vimscript
andlua
configuration files: - This is the neovim Lua guide.
- This was a useful post describing the difference from using
runtime
vssource
in alua
script. - “Insert Single Character in Vim?”
- This is improved upon in “Insert a single character”
I haven’t worked with many plugins yet, but I have followed the popular recommendations to manage them with lazy.nvim. In my configuration files it can be seen how to use this to install nvim-surround.
VSCode configuration
There were a few configuration changes to vscode
that helped me with the vscode-neovim
integration. Later on below, I’ll enumerate the references that I used for some of these.
To use my neovim
configuration within vscode-neovim
I added this to my User settings.json
:
"vscode-neovim.neovimInitVimPaths.darwin": "/Users/mikerod/.config/nvim/init.lua"
Where this is my ~/.config/nvim
location of the same init file I use for neovim
.
Using macOS I needed to change the setting to allow for holding a key to repeat it via:
defaults write com.microsoft.VSCode ApplePressAndHoldEnabled -bool false
For the same reason discussed above concerning spacemacs
configuration, I wanted jk
to return to “normal” mode the same way ESC
does. To do this I added to the vscode
User settings.json
file:
"vscode-neovim.compositeKeys": {
"jk": {
"command": "vscode-neovim.escape"
}
},
More options are supported here and it can be more complex. The docs cover this well (which I’ll link below in references).
I think it useful to have the editor change to “normal” mode on “save”. This seems like a fairly common configuration people setup for vim
style editors. This is by adding this to the User keybindings.json
:
{
"command": "runCommands",
"key": "cmd+s",
"when": "editorTextFocus && neovim.init && neovim.mode == 'insert'",
"args": {
"commands": ["workbench.action.files.save", "vscode-neovim.escape"]
}
}
VSCode references
I have found these sources to be valuable in updating my vscode
configuration with a vscode-neovim
emphasis:
- “Integrate Neovim inside VSCode”
- “Composite escape keys”
- “In VSCode Neovim, press Ctrl+S to save file and switch to normal mode?”
- Note that there is a
"command": "runCommands"
now available so themulti-command
extension is not needed. My configuration example above utilizes this instead. - See “How can I run multiple commands with a single VS Code keybinding without an extension?”
- Note that there is a
Spacemacs configuration
My public dotfiles can be found @ https://github.com/mrrodriguez/emacs-dotfiles
spacemacs
already comes with a lot of vim
support via its use of evil-mode. I haven’t had to do too much configuration. There is also spacemacs
specific features that typically involve the minibuffer and I use them the standard way. The spacemacs
specific features are mostly expressed via a “leader key” which defaults to being the “space” key (aka. SPC
). This works well with dotspacemacs-editing-style
set to hybrid
or vim
.
I’ll enumerate some quick configuration conveniences here that I added to dotspacemacs/user-config
. Later on below, I’ll enumerate the references that I used for some of these.
In the same way as I mentioned in the neovim
section above I wanted the editor to return to “normal” mode (aka. evil-normal-state
in evil-mode
) on “save”. This is done via:
(add-hook 'after-save-hook #'evil-normal-state)
In the same way as I described in the neovim
section above, I wanted to use jk
keys to return to “normal” mode to not have to always use ESC
.
(setq-default evil-escape-key-sequence "jk")
In the same way as I described in the neovim
section above, I wanted to be able to “insert a single character”, but remain in “normal” mode after.
(evil-define-command my-evil-insert-char (count char)
(interactive "<c><C>")
(setq count (or count 1))
(insert (make-string count char)))
(evil-define-command my-evil-append-char (count char)
(interactive "<c><C>")
(setq count (or count 1))
(when (not (eolp))
(forward-char))
(insert (make-string count char)))
(define-key evil-normal-state-map (kbd "s") 'my-evil-insert-char)
(define-key evil-normal-state-map (kbd "S") 'my-evil-append-char)
Spacemacs references
I have found these sources to be valuable in updating my spacemacs
configuration with a vim
emphasis: