Skip to content

Commit e337549

Browse files
authored
From Emacs to Neovim (Part 2) (#20)
1 parent 5f4a83e commit e337549

File tree

2 files changed

+190
-10
lines changed

2 files changed

+190
-10
lines changed

_posts/2024-05-20-emacs-to-neovim.markdown

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,34 @@ date: 2024-05-20
66
tags: [emacs, neovim, spacemacs, vim, vscode, vscode-neovim, vi, editor, development, programming]
77
---
88

9+
### Update: 2024-05-22
10+
11+
I continue this discussion into a "Part 2" post @ ["From Emacs to Neovim (Configuration)"]({% post_url 2024-05-23-emacs-to-neovim-part-2 %}) where some concrete configuration examples are provided.
12+
913
# Background
1014

11-
I have been using emacs for around 15 years with a "traditional" configuration and key bindings setup. I’ve primarily used it for Clojure/ClojureScript development. Occasionally, I have also used it for XML, HTML, JSON, CSS, C/C++, Ruby, Python, JavaScript, and Common Lisp.
15+
I have been using `emacs` for around 15 years with a "traditional" configuration and key bindings setup. I’ve primarily used it for Clojure/ClojureScript development. Occasionally, I have also used it for XML, HTML, JSON, CSS, C/C++, Ruby, Python, JavaScript, and Common Lisp.
1216

13-
About 6 years ago I started to use the [spacemacs distribution](https://www.spacemacs.org). This was done after seeing several of my coworkers using it. I thought that this would be useful due to the general knowledge sharing of common configuration advice and best practices. The defaults worked well when getting started with spacemacs to replace my existing emacs setup. My previous setup was something I had configured in an ad hoc fashion over several years with no particular setup framework in mind. Notably, I did not use `evil-mode` bindings at all. The `helm` search buffer and `magit` key sequences were the closest I had to something like vim bindings (eg. mnemonic key sequences in a "non-insert" mode).
17+
About 6 years ago I started to use the [spacemacs distribution](https://www.spacemacs.org). This was done after seeing several of my coworkers using it. I thought that this would be useful due to the general knowledge sharing of common configuration advice and best practices. The defaults worked well when getting started with `spacemacs` to replace my existing `emacs` setup. My previous setup was something I had configured in an ad hoc fashion over several years with no particular setup framework in mind. Notably, I did not use `evil-mode` bindings at all. The `helm` search buffer and `magit` key sequences were the closest I had to something like `vim` bindings (eg. mnemonic key sequences in a "non-insert" mode).
1418

15-
I recently have been working more with languages such as TypeScript/JavaScript and Golang. This has made me curious if I could find better and/or more supported tooling available if I was willing to venture beyond the emacs editor. A natural fit for both seemed to be [vscode](https://code.visualstudio.com). I knew I wanted powerful editing capabilities like I was familiar with already via emacs. I tried some emacs key emulators/extensions in other IDEs before. I did not find them to be sufficient though. Without the elisp, the minibuffer, the "kill ring", among many other specifics to the emacs editor, the integration didn't seem powerful or similar enough to real emacs.
19+
I recently have been working more with languages such as TypeScript/JavaScript and Golang. This has made me curious if I could find better and/or more supported tooling available if I was willing to venture beyond the `emacs` editor. A natural fit for both seemed to be [vscode](https://code.visualstudio.com). I knew I wanted powerful editing capabilities like I was familiar with already via `emacs`. I tried some `emacs` key emulators/extensions in other IDEs before. I did not find them to be sufficient though. Without the elisp, the minibuffer, the "kill ring", among many other specifics to the `emacs` editor, the integration didn't seem powerful or similar enough to real `emacs`.
1620

1721
# The idea
1822

19-
Lately, I've seen and heard a lot more about [neovim](https://neovim.io) as an editor. It seems to have brought a new surge in popularity vim. I have been curoius about vim for some time. I knew a little bit about how it "philosophically" differed from emacs and was intrigued.
23+
Lately, I've seen and heard a lot more about [neovim](https://neovim.io) as an editor. It seems to have brought a new surge in popularity `vim`. I have been curoius about `vim` for some time. I knew a little bit about how it "philosophically" differed from `emacs` and was intrigued.
2024

21-
Since I was using spacemacs, I thought this may be an interesting opportunity to explore vim via `evil-mode`. My plan was to ease into it by using spacemacs ["hybrid editing style"](https://develop.spacemacs.org/doc/DOCUMENTATION.html#hybrid) which uses `evil-mode` for all vim modes (called "states" in spacemacs) other than "insert". This was really convenient for me to be (somewhat) efficient and productive as I learned. Along with this, I did neovim tutorials and read docs to get started learning more of the vim side. I gradually applied these ideas/concepts more to my hybrid editing style spacemacs setup.
25+
Since I was using `spacemacs`, I thought this may be an interesting opportunity to explore `vim` via `evil-mode`. My plan was to ease into it by using `spacemacs` ["hybrid editing style"](https://develop.spacemacs.org/doc/DOCUMENTATION.html#hybrid) which uses `evil-mode` for all `vim` modes (called "states" in `spacemacs`) other than "insert". This was really convenient for me to be (somewhat) efficient and productive as I learned. Along with this, I did neovim tutorials and read docs to get started learning more of the `vim` side. I gradually applied these ideas/concepts more to my hybrid editing style `spacemacs` setup.
2226

2327
# Learning process
2428

25-
It was difficult for a week of dedicated focus on learning vim keys while doing my day to day work. This definitely made me slower for a short period. By about 3 weeks, I felt much more proficient and efficient. After that, I only had some lingering inefficient movement annoyances I knew I’d need to investigate and improve over time. Basically, the thought is to wait until the annoyance/inefficiency becomes frequent enough to be [worth the time investment to address](https://xkcd.com/1205).
29+
It was difficult for a week of dedicated focus on learning `vim` keys while doing my day to day work. This definitely made me slower for a short period. By about 3 weeks, I felt much more proficient and efficient. After that, I only had some lingering inefficient movement annoyances I knew I’d need to investigate and improve over time. Basically, the thought is to wait until the annoyance/inefficiency becomes frequent enough to be [worth the time investment to address](https://xkcd.com/1205).
2630

27-
From there, I started using vscode for TypeScript with the [vscode-neovim](https://github.com/vscode-neovim/vscode-neovim) extension. I was impressed by how well this extension blended well within vscode. I was also able to find a lot of good resources available when troubleshooting and learning about the extension. The ability to use my actual neovim configuration files from within vscode in non-trivial ways was great too.
31+
From there, I started using vscode for TypeScript with the [vscode-neovim](https://github.com/vscode-neovim/vscode-neovim) extension. I was impressed by how well this extension blended well within vscode. I was also able to find a lot of good resources available when troubleshooting and learning about the extension. The ability to use my actual `neovim` configuration files from within vscode in non-trivial ways was great too.
2832

2933
# Outcome
3034

31-
I still use spacemacs with hybrid mode bindings while doing Clojure/ClojureScript and various other data files and languages I may lightly use. I still prefer "insert" mode (aka. spacemacs "insert state") to be done with emacs traditional bindings. To me, it is a "better" insert mode experience compared to vim bindings within emacs. However, I now find myself using a lot less insert mode than I used to.
35+
I still use `spacemacs` with hybrid mode bindings while doing Clojure/ClojureScript and various other data files and languages I may lightly use. I still prefer "insert" mode (aka. `spacemacs` "insert state") to be done with `emacs` traditional bindings. To me, it is a "better" insert mode experience compared to `vim` bindings within `emacs`. However, I now find myself using a lot less insert mode than I used to.
3236

33-
When I switch to vscode with the vscode-neovim extension, I can quickly adapt to that IDE environment. I can even toggle back and forth throughout the day without a struggle. Overall, the switch to vim bindings seems to be a worthwhile investment. I also use neovim now when I want to quickly open/edit text files from the terminal. My general thought is that you can get more “range”/"reach" out of vim bindings due to the extensions available in popular IDEs and other text editors (including in the terminal which is "the default" for neovim). To me, the editing efficiencies are just as powerful and efficient when compared to my traditional emacs experiences.
37+
When I switch to `vscode` with the `vscode-neovim` extension, I can quickly adapt to that IDE environment. I can even toggle back and forth throughout the day without a struggle. Overall, the switch to `vim` bindings seems to be a worthwhile investment. I also use `neovim` now when I want to quickly open/edit text files from the terminal. My general thought is that you can get more “range”/"reach" out of `vim` bindings due to the extensions available in popular IDEs and other text editors (including in the terminal which is "the default" for `neovim`). To me, the editing efficiencies are just as powerful and efficient when compared to my traditional `emacs` experiences.
3438

35-
I will post a follow-up to this post to discuss some helpful resources and/or plugins/extensions/configuration that helped me transition from my traditional emacs setup concepts to vim concepts (via neovim specifically).
39+
I have posted a follow-up to this post @ ["From Emacs to Neovim (Configuration)"]({% post_url 2024-05-23-emacs-to-neovim-part-2 %}). In this I discuss some helpful resources and/or plugins/extensions/configuration that helped me transition from my traditional `emacs` setup concepts to `vim` concepts (via `neovim` specifically).
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
---
2+
layout: post
3+
title: "From Emacs to Neovim (Configuration)"
4+
author: Mike Rodriguez
5+
date: 2024-05-23
6+
tags: [emacs, neovim, spacemacs, vim, vscode, vscode-neovim, vi, editor, development, programming]
7+
---
8+
9+
# Background
10+
11+
This is a continuation of my post @ ["From Emacs to Neovim"]({% post_url 2024-05-20-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.
12+
13+
Note that my current, primary tooling focus is:
14+
* [spacemacs distribution](https://www.spacemacs.org) of `emacs` primarily for Clojure/ClojureScript development
15+
* [neovim distribution](https://neovim.io) of `vim` for simple file editing in the terminal
16+
* [vscode-neovim](https://github.com/vscode-neovim/vscode-neovim) for TypeScript/JavaScript development
17+
18+
# Neovim configuration
19+
20+
My public dotfiles can be found @ <https://github.com/mrrodriguez/nvim-dotfiles>
21+
22+
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](#neovim-references), I'll enumerate the references that I used for some of this setup.
23+
24+
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.
25+
26+
I am particularly a fan of `nvim-surround` to help supplement for some of the utility I am used to from using [paredit](https://paredit.org). 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.
27+
28+
-----
29+
30+
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:
31+
32+
```vimscript
33+
:inoremap jk <Esc>
34+
:inoremap kj <Esc>
35+
:vnoremap jk <Esc>
36+
:vnoremap kj <Esc>
37+
```
38+
39+
-----
40+
41+
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:
42+
43+
```vimscript
44+
function! RepeatChar(char, count)
45+
return repeat(a:char, a:count)
46+
endfunction
47+
nnoremap s :<C-U>exec "normal i".RepeatChar(nr2char(getchar()), v:count1)<CR>
48+
nnoremap S :<C-U>exec "normal a".RepeatChar(nr2char(getchar()), v:count1)<CR>
49+
```
50+
51+
#### Neovim references
52+
53+
I have found these sources to be valuable in getting started with this configuration:
54+
* [This is a good post](https://builtin.com/software-engineering-perspectives/neovim-configuration) on starting a new `neovim` configuration.
55+
* These are two good posts concerning how to mix `vimscript` and `lua` configuration files:
56+
* ["Is it possible to use init.vim and init.lua together?"](https://www.reddit.com/r/neovim/comments/zfimqo/is_it_possible_to_use_initvim_and_initlua_together)
57+
* ["How to handle init.lua examples if you use init.vim?"](https://www.reddit.com/r/neovim/comments/1913nyw/how_to_handle_initlua_examples_if_you_use_initvim)
58+
* [This is the neovim Lua guide](https://neovim.io/doc/user/lua-guide.html).
59+
* [This was a useful post](https://github.com/vscode-neovim/vscode-neovim/issues/819#issuecomment-1035983972) describing the difference from using `runtime` vs `source` in a `lua` script.
60+
* ["Insert Single Character in Vim?"](https://superuser.com/a/581669)
61+
* This is improved upon in ["Insert a single character"](https://vim.fandom.com/wiki/Insert_a_single_character)
62+
63+
I haven't worked with many plugins yet, but I have followed the popular recommendations to manage them with [lazy.nvim](https://github.com/folke/lazy.nvim). In my configuration files it can be seen how to use this to install [nvim-surround](https://github.com/kylechui/nvim-surround).
64+
65+
# VSCode configuration
66+
67+
There were a few configuration changes to `vscode` that helped me with the `vscode-neovim` integration. [Later on below](#vscode-references), I'll enumerate the references that I used for some of these.
68+
69+
-----
70+
71+
To use my `neovim` configuration within `vscode-neovim` I added this to my User `settings.json`:
72+
73+
```json
74+
"vscode-neovim.neovimInitVimPaths.darwin": "/Users/mikerod/.config/nvim/init.lua"
75+
```
76+
77+
Where this is my `~/.config/nvim` location of the same init file I use for `neovim`.
78+
79+
-----
80+
81+
Using macOS I needed to change the setting to allow for holding a key to repeat it via:
82+
83+
```sh
84+
defaults write com.microsoft.VSCode ApplePressAndHoldEnabled -bool false
85+
```
86+
87+
-----
88+
89+
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:
90+
91+
```json
92+
"vscode-neovim.compositeKeys": {
93+
"jk": {
94+
"command": "vscode-neovim.escape"
95+
}
96+
},
97+
```
98+
99+
More options are supported here and it can be more complex. The docs cover this well (which I'll link below in references).
100+
101+
-----
102+
103+
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`:
104+
105+
```json
106+
{
107+
"command": "runCommands",
108+
"key": "cmd+s",
109+
"when": "editorTextFocus && neovim.init && neovim.mode == 'insert'",
110+
"args": {
111+
"commands": ["workbench.action.files.save", "vscode-neovim.escape"]
112+
}
113+
}
114+
```
115+
116+
#### VSCode references
117+
118+
I have found these sources to be valuable in updating my `vscode` configuration with a `vscode-neovim` emphasis:
119+
120+
* ["Integrate Neovim inside VSCode"](https://medium.com/@shaikzahid0713/integrate-neovim-inside-vscode-5662d8855f9d)
121+
* ["Composite escape keys"](https://github.com/vscode-neovim/vscode-neovim/blob/02d13f0e119afbec8f68fe5add0f2c2a1072ec49/README.md#composite-escape-keys)
122+
* ["In VSCode Neovim, press Ctrl+S to save file and switch to normal mode?"](https://stackoverflow.com/a/77769949/924604)
123+
* Note that there is a `"command": "runCommands"` now available so the `multi-command` extension is not needed. My configuration example above utilizes this instead.
124+
* See ["How can I run multiple commands with a single VS Code keybinding without an extension?"](https://stackoverflow.com/a/75808372/924604)
125+
126+
# Spacemacs configuration
127+
128+
My public dotfiles can be found @ <https://github.com/mrrodriguez/emacs-dotfiles>
129+
130+
`spacemacs` already comes with a lot of `vim` support via its use of [evil-mode](https://github.com/emacs-evil/evil). 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`.
131+
132+
I'll enumerate some quick configuration conveniences here that I added to `dotspacemacs/user-config`. [Later on below](#spacemacs-references), I'll enumerate the references that I used for some of these.
133+
134+
-----
135+
136+
In the same way as I mentioned in the `neovim` [section above](#vscode-configuration) I wanted the editor to return to "normal" mode (aka. `evil-normal-state` in `evil-mode`) on "save". This is done via:
137+
138+
```lisp
139+
(add-hook 'after-save-hook #'evil-normal-state)
140+
```
141+
142+
-----
143+
144+
In the same way as I described in the `neovim` [section above](#neovim-configuration), I wanted to use `jk` keys to return to "normal" mode to not have to always use `ESC`.
145+
146+
```lisp
147+
(setq-default evil-escape-key-sequence "jk")
148+
```
149+
150+
-----
151+
152+
In the same way as I described in the `neovim` [section above](#neovim-configuration), I wanted to be able to "insert a single character", but remain in "normal" mode after.
153+
154+
```lisp
155+
(evil-define-command my-evil-insert-char (count char)
156+
(interactive "<c><C>")
157+
(setq count (or count 1))
158+
(insert (make-string count char)))
159+
160+
(evil-define-command my-evil-append-char (count char)
161+
(interactive "<c><C>")
162+
(setq count (or count 1))
163+
(when (not (eolp))
164+
(forward-char))
165+
(insert (make-string count char)))
166+
167+
(define-key evil-normal-state-map (kbd "s") 'my-evil-insert-char)
168+
(define-key evil-normal-state-map (kbd "S") 'my-evil-append-char)
169+
```
170+
171+
#### Spacemacs references
172+
173+
I have found these sources to be valuable in updating my `spacemacs` configuration with a `vim` emphasis:
174+
175+
* ["Single character insert for Evil"](https://www.reddit.com/r/emacs/comments/7ogu7a/comment/ds9py2s/?utm_source=reddit&utm_medium=web2x&context=3)
176+
* ["Spacemacs : insert single character in normal mode"](https://emacs.stackexchange.com/questions/32450/spacemacs-insert-single-character-in-normal-mode)

0 commit comments

Comments
 (0)