This product is so deep that I can’t even say how powerful it is. I’ve actually used the very first version of vi (pronounced “vee-eye”) when Bill Joy did the first cut, Wikipedia says it was in the very first BSD version, but that’s a longer story that doesn’t provide the whole story on how Unix/32V from Bell Labs actually arrived in Berkeley. Let’s just say that as a nobody, I did see Tom London nearly loose his mind talking with John Reiser 🙂
In any case, vi has moved far, far ahead. First with vim and now with Neovim. Neovim I just switched to this week and having a python backend really does help. And then there are all the many utilities like fzf for fuzzy finding files and ripgrep for search that I’ve yet to integrate.
And this might all get superseded by an IDE that I can use daily, personally, my money is on JupyterLab. Why use this same package for all these years. In a word, speed. All the vi variants are super fast and although a pain to learn (like superhuman for instance), being model between edit and select mode means no more chording (you don’t need CTRL-ALT-SHIFT X for instance because you don’t need an escape from edit mode).
Although I’ve been using it for a long, long, long time, there are still new commands and tricks (I think they’ve been added lately, the original command set was really small, it had to be). But here are some of the latest tips and tricks.
The biggest extensions are semantic which moves vi from an editor to a full IDE. That is teaching vi how to understand the structure of the file and
- being able to statically lint to get bugs out early (a huge feature!)
- beautify the code so it follows standards
- and also change the code (so if you change the name of a variable, it goes everywhere and being to have string completion that is smart).
- The biggest of course to get to full IDE is to dynamically run and debug code, but I’ll leave that for another post).
I have no doubt there are more, but a short list where I’m assuming you have coc.vim (which is a port of Visual Studio Code completions) and the proper key remappings (see below). Note that there is an older set of linter tools that you can use with ALE or just directly, so there is a transition, use CoC for linting, beautifying and if there isn’t a linter, go to ALE.
Vi has a logical if obtuse selection method, you basically have a command set like y
for yank and then you add movement commands to it:
- So for instance
yy
by convention means yank a whole row. - If you stick a number in front, this is how mand so
3yy
means hank three lines. - And then any movement command works after that, so
3y}
means yank 3 paragraphs down yG
means yank all the way to the end because aG
by itself moves you to the bottom, and by convention, if you put a number in front, it is not repeat but which like to go to, soy234G
means yank from cursor to line 234
Now there are some real conveniences such as :%s/Old_string/new_string/
just works and is way shorter than the older g/Old_string/s//new_string
However, vi/vim/neovim all allow a very obtuse command language that lives in ~/.exrc
, ~/.vimrc
or ~/.config/nvim/init.vim
respectively. And with that you can extend things like crazy. By convention g
or go gives you a whole new layer of commands:
The biggest extension is a whole new set of g
commands because g wasn’t used in the original command set. While you can lots of meta keys, the best thing about vi is the way it handles the 26 letters of the alphabet and gives it obvious meanings.
gf
This means go to a file where you take the name under the cursor and move there.gq
Does rewrapping, sogqq
means rewrap as there is no automatic wrapping dynamically
The nice thing is that you can add extensions to that easily, so for instance if you install Code of Completion, then you can add going to definitions, types and files like this in your profile and it’s pretty self-explanatory, but it is really convenient to do a gd
to get to the definition of a variable.
nmap <silent> gd <Plug>(coc-definition)
nmap <silent> gy <Plug>(coc-type-definition)
nmap <silent> gi <Plug>(coc-implementation)
nmap <silent> gr <Plug>(coc-references)
The second extension is the use of the so-called leader escape. Eventually, you run out of keys, so you need more. While some editors just add more command keys, so you end up remembering if it is SHIFT-CMD-o or SHIFT-OPTION-CMD, in vi, you just add another prefix key. Personally I find that much easier to remember. By default this is the backslash \
although lots of people bind it to comma instead. So some convenient ones are which means \rn
will rename the variable under your cursor and \f
will run an external formatter like autopep8
or black
or yapf
for you.
nmap <leader>rn <Plug>(coc-rename)
nmap <leader>f <Plug>(coc-format-selected)
Finally, if you use Vim Awesome you get these additional commands and completions which I’ve not had any time to absorb.
Vi spelling and folding
This normally doesn’t make much sense with source code, but you can turn it on for txt or md files with:
# For things that are mark down or set turn on spelling
autocmd FileType md,markdown,txt setlocal spell spelllang=en_us
# Do the same for git commits
autocmd BufRead COMMIT_EDITMSG setlocal spell spelllang=en_us
# Create your own private dictionary
set spell spelllang=en_us
Now the say you use it is a little (?!) unintuitive, but:
-
]s
means go to next misspelling, [s
is back. When you land on the wordz=
, to get a suggestionz
w to add it to your Private dictionaryzu
w if you make a mistake to remove it from you dictionary
Then if your syntax editor supports it, you can hide text under headings. This is great for YAML and other files and long code files. This is called folding with a bunch of different methods that you set with set foldmethod=
:
- Marker. If you put in some special likes like
// {{{
you create a manual fold - Indent. This was designed for python since it uses indents to determine scope. So a command like `autocommand BugnewFile, BufRead *.py set fold
Comment out a line
A surprisingly useful feature is when you want to just comment out a section which NerdCommenter does well:
\cc
comments out the current line. This works with Python but does *not* with nvim/init.vim so you are warned\ci
inverts the state of the comment\cn
let’s you select a block to comment out in visual mode for a block
Ripgrep
Ok this is a tool that I’ve just started using, but I have used grep
for years, but a brew install ripgrep
is a revelation. As Marius Schulz says picking the right defaults is the real magic so you don’t have to worry about quoting and -R
:
# find all TODO's in your source
rg '// TODO'
# edit all the files with TODO's
vi $(rg // TODO)
# see two lines around TODO
rg '// TODO' -C 2
# Look for TODO's in python files
rg -t py '// TODO'
FZF
This fuzzy finds anything so you can use it for easy searched. The main limitation is that is assumes you are just looking from the current working directory down so you need to first cd ~
for instance and then run fzf. It will then create an index and then be super fast from then on
# install with all the goodies
brew install fzf
$(brew prefix)/opt/fzf ins
# Initialize it
cd ~; fzf
# Make sure you have completions done and type a tab
vi **
# if you want to find a directory and then a tab
cd **
Then there are some commands it turbocharges, so Ctrl-R for looking through history is now run by fzf and you can change directories with Alt-C. That’s actually a bit of pain since on Mac keyboards, Alt-C is a c with a diacritical
. You can do this slightly bizarre thing which is to hold the ESC key and press C.