Modern Vim: Tips and Techniques for Efficient Editing
Vim is a powerful and versatile text editor that offers a wide range of features and customization options. In this article, we will explore some useful tips and techniques from the book “Modern Vim” to help you become more efficient and productive in your Vim editing.
Introduction
Vim has a unique set of keyboard shortcuts and commands that can enhance your editing experience. Here are some key concepts and shortcuts to keep in mind:
<C-p>
represents pressing the Control key followed by the letter “p.”Operators are commands used to perform actions on text. Some common operators include:
1
2
3
4
5
6
7
8
9
10
11
12
13`c` for change
`d` for delete
`y` for yank (copy)
`~` for swapping case
`gu` for making text lowercase
`gU` for making text uppercase
`!` for filtering text through an external program
`=` for text formatting
`gq` for text formatting with line wrapping
`>` for shifting text right
`<` for shifting text left
`zf` for defining a fold
`g@` for calling a function set with the 'operatorfunc' optionThe
Meta
key:- On macOS, it refers to the Option key.
- On Windows, it refers to the Alt key.
Getting Modern Vim
To get the most out of Vim, it’s recommended to use Neovim and the neovim-remote tool developed by Marco Hinz. This tool allows remote control of Neovim processes.
Installing Plugins
Plugins are a great way to extend Vim’s functionality. Here are some insights on managing plugins:
Understanding Scripts, Plugins, and Packages:
- You can manually load a script using the
:source {path}
command, where{path}
is the location of the script. - Vim automatically sources scripts located in specific locations on disk when it starts up.
- Your
vimrc
file is one of the first scripts to be loaded, making it an ideal place to configure your startup settings. - Prior to recent versions of Vim, managing the
runtimepath
to include plugins was not convenient. However, you can now use the:set runtimepath+=$VIMCONFIG/arbitrary/demo-plugin
command to add a plugin to theruntimepath
. - Pressing
<C-]>
will jump to the specified anchor in Vim’s documentation, and you can use<C-o>
to quickly jump back to the previous location. These commands allow you to navigate Vim’s documentation similar to interacting with a web page. - After installing a new plugin, you only need to run
:helptags
once. Vim will then use the generated tags file to find the documentation for that plugin.
- You can manually load a script using the
Installing Plugins to Your Package:
- Note that if you install a new plugin into the
start
directory while Vim is running, you won’t be able to use it immediately. Restarting Vim will add the new plugin to theruntimepath
and make it available. - The unimpaired plugin comes with documentation, but Vim doesn’t know where to find the appropriate files. You can fix this issue by running the
:helptags ALL
command (:help :helptags
). - You can suppress error messages by running
:silent helptags ALL
. - By default, optional plugins are not loaded. Use the
:packadd
command to activate a plugin (e.g.,:packadd vim-scriptease
).
- Note that if you install a new plugin into the
Managing Plugins with minpac:
- Typing
:call minpac#update()
can be cumbersome. You can create custom commands to make it more convenient:command! PackUpdate call minpac#update()
command! PackClean call minpac#clean()
- Typing
Opening Files
Efficiently opening and navigating files is crucial for an effective editing workflow. Let’s explore two techniques:
Finding Files Using Fuzzy Path Matching:
- You can use
<C-x>
,<C-v>
, or<C-t>
to open a file in a horizontal split, vertical split, or new tab, respectively. - The
rg --files
command (Ripgrep) filters out files ignored by Git, Mercurial, and Subversion repositories.
- You can use
Finding Files Semantically:
Open files in separate windows using the
-O
flag. For example:vim -O file1.txt file2.txt
You can define file-to-type mappings in a
.projections.json
file. For instance:"app/models/*.js": { "type": "model" }
Vim provides navigation commands specific to file types, such as:
- ```
:Etype
- Opens the specified type in the current window:Stype
- Opens the specified type in a horizontal split:Vtype
- Opens the specified type in a vertical split:Ttype
- Opens the specified type in a new tabpage1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
- These navigation commands are my preferred way to navigate codebases, and you can add navigation commands as needed for different file types.
- Jumping to an Alternate File:
- The Projectionist plugin allows you to create links between related files. Once you specify the relationship between a file and its alternate file, you can follow the link by running the `:A` command.
## Working with the Quickfix List
The quickfix list is a powerful feature in Vim that allows you to efficiently handle build errors, linting results, and file search results. Let's explore some techniques:
- Running a Build and Navigating Failures:
- The Dispatch plugin, introduced in 2013, provides asynchronous command execution in Vim when it didn't natively support it. Make sure to check out the plugin's release and the "dispatch.vim" screencast.
- Linting the Current File:
- Learn about the Asynchronous Linting Engine (ALE), a powerful plugin for linting code in Vim.
- You can use the `]w` and `[w` mappings to quickly navigate between warnings. Error messages are displayed at the bottom of the screen as you access each warning.
- Neomake is another linting plugin that runs asynchronously. It supports running commands across the entire project, not just on individual files.
- Searching Files with Grep-Alikes:
- The `:Grepper` command provides a powerful way to search for patterns in files. For example, running `:Grepper -cword` with the word "Waldo" under the cursor will prompt you for search options.
## Neovim's Built-In Terminal Emulator
Neovim comes with a built-in terminal emulator that allows you to interact with programs running in the terminal. Let's dive into some terminal-related techniques:
- Grokking Terminal Mode:
- Neovim introduces a new mode called Terminal mode, where you can interact with programs running in the built-in terminal emulator.
- Use the `:terminal` command to open a terminal buffer.
- When you create a terminal buffer, you start in normal mode. Pressing `i` switches to terminal mode, indicated by the
`-- TERMINAL --` prompt in the bottom left corner. Press `<C-><C-n>` to switch back to normal mode.
- Running Programs in a Terminal Buffer:
- Use the `:read !{cmd}` command to capture the output of a command in an existing buffer.
- The `:terminal {cmd}` command is a new feature in Neovim. It runs the specified command in a new terminal buffer. You can abbreviate it as `:te {cmd}`.
- To switch between a terminal buffer and a regular buffer, use `<C-^>` (`:h ctrl-^`).
- Try stopping a process in the terminal buffer using the `:bwipeout!` command (e.g., `:5bwipeout` to stop the top process).
- When you exit Neovim, any running processes in terminal buffers are also closed.
- Note that if you suspend Neovim (`<C-z>`), all processes running in terminal buffers will be suspended as well. They will resume when you resume Neovim.
- Managing Windows That Contain Terminal Buffers:
- Opening a terminal buffer with the `:terminal` command takes over the current window and hides the buffer that was previously displayed. This behavior is similar to the `:edit {file}` command.
- If you use `:te`, it creates a buffer. However, `:te` does not create a buffer.
- Use the `tnoremap` command to create mappings that work only in terminal mode. With these mappings, you can switch to another window by pressing `<M-h>`, `<M-j>`, `<M-k>`, or `<M-l>` regardless of whether you are in normal mode or terminal mode.
- Using Normal Mode Commands in a Terminal Buffer:
- You can use the `yi`` command to copy the text within backticks to Vim's unnamed register and then paste it using `p` in the terminal at the cursor position.
- You can prepend a named register (e.g., `"a`) or use special registers like `"*` to reference the system clipboard when using yank and put commands.
- The terminal buffer is now hidden, but you can quickly switch back to it using `<C-^>` (`:h ctrl-^`).
- Sending Commands to a Terminal Buffer:
- Activate the window containing the terminal buffer running the web server and run the following command:
- `:echo b:terminal_job_id`
- This tells us that the job ID is 1, which we can use as the first argument when calling `jobsend({job}, {data})`.
- To restart the web server, run the command:
- `:call jobsend(1, "\<C-c>npm run server\<CR>")`
## Sessions
Sessions in Vim allow you to save and restore your editing environment. Let's explore session-related techniques:
- Saving and Restoring Sessions:
- After opening the `app.js` and `app-test.js` files in adjacent windows, use the `:mksession!` command (`:h :mksession`) to save the session.
- Restart Vim with the `-S` flag to load the session:
- `vim -S`
- If you like the idea of automatically recording sessions, consider installing Tim Pope's Obsession plugin. You can install it in your bundle directory:
- `cd $VIMCONFIG/pack/bundle/start`
- `git clone https://github.com/tpope/vim-obsession.git`
- Making Undo Persist Between Sessions:
- By default, undo history is not preserved between sessions. However, you can use autocommands to disable the undofile for files matching specific patterns. For example, the following is an example script that disables persistent undo in all files in the `/tmp` directory:
- `--forget-undo-in-tmpfile.vim`
- ```
augroup vimrc
autocmd!
autocmd BufWritePre /tmp/* setlocal noundofile
augroup END
- ```
Restarting Terminal Processes When Resuming a Session:
- You can rename a terminal buffer using the
:file {name}
command (:help :file_f
). Activate the window containing the terminal buffer running the web server and run::file term://PORT=3001 npm run server
- You can rename a terminal buffer using the
Configuring Vim
Customizing Vim’s behavior can greatly enhance your editing experience. Here’s a technique to respond to events using autocommands:
- Using Autocommands to Respond to Events:
- Vim triggers the
BufReadPost
command (:h BufReadPost
) after reading a file into a buffer. If the file path matches the pattern defined in our autocommand, Vim executes the specified{command}
. Since we use a wildcard*
in this example, the autocommand applies to all buffers. - Sometimes, there might be more suitable events. For such cases, you can achieve similar results by listening to the
FileType
event (:h FileType
).autocmd BufWritePre /tmp/* setlocal noundofile
- The autocommand we defined is triggered by the
User
event with the patternProjectionistActivate
. TheUser
event doesn’t trigger automatically, but you can trigger such events yourself::doautocmd User ProjectionistActivate
- Vim triggers the
In this article, we’ve explored various tips and techniques from “Modern Vim” to help you enhance your Vim editing skills. By incorporating these techniques into your workflow, you can become a more efficient and productive Vim user.