Neovim Tips & Tricks


This chapter compiles many of the best tips and tricks that the Neovim community has developed over the years to turbo-charge your Neovim workflow.

Filed In:shell

Neovim registers and command-line mode can be combined to a pretty decent REST API client. This tip shows how. First, open a new buffer and add the API request: Initial Conditions https://jsonplaceholder.typicode.com/todos/1 NORMAL Top 1:1 Now, yank the current line, which places the contents of the current line into register 0: Yank the API Request Stringyy https://jsonplaceholder.typicode.com/todos/1 NORMAL Top 1:1 Finally, lets build the command to call the API and insert the response. First, we learned previously that we can use the :read command to call a shell command and insert its output. The call signature is: :read !{cmd} [args] In this case we want to call a REST API, so lets use curl to call the API and receive the response. The command to achieve is: curl -s '{request}' where the -s option tells curl to operate in "silent mode". Finally, we could hard-code the request into the command, but we have already yanked it to register 0. We can retrieve register contents in command-line mode using C-R followed by the register name, so our complete command is: :read !curl -s '<C-r>0' Executing this command produces: Insert the API response https://jsonplaceholder.typicode.com/todos/1 { "userId": 1, "id": 1, "title": "delectus aut autem", "completed": false } NORMAL 88% 7:1 6 more lines if you find yourself using this often, consider creating a macro to save yourself a few keystrokes.
Filed In:shell

Vim's internal formatting features work great in many cases, but sometimes it can be helpful to send a buffer's content to an external program to perform the formatting, then replace the buffer contents with the result. For example, suppose we have the following JSON file in a buffer and want to sort the keys. Initial Conditions { "bananas": 12, "strawberries": 15, "apples": 34, "oranges": 24, "grapes": 33 } COMMAND Top 1:1 :%!jq -S . % We will demonstrate how to achieve this using a command-line mode command that calls jq , a popular command-line JSON processor. Obviously jq needs to be installed on a system for this to work. The command to execute is: :%!jq -S . % Let's break this down to review what is happening: To start, this follows the pattern: :[range]!{cmd} {args} where :% specifies the range as the entire file. Next, !{cmd} indicates that an external command is to be called with the specified range and arguments. In this case the external command to be called is: jq -S . % The details of this command are (mostly) outside the scope of Vim itself, but can be found by executing jq --help which indicates that the jq command is called with the format: jq [options] <jq filter> [file] where: [options] = -S (sort object keys) <jq filter> = . (pass all lines back to stdout) [file] = % (Vim inserts the current filename) Now, when we execute this command we get the following result: After External Formatting { "apples": 34, "bananas": 12, "grapes": 33, "oranges": 24, "strawberries": 15 } NORMAL Top 1:1 7 lines filtered which contains our sorted JSON object.
Filed In:shell

Sometimes it can be handy to get a quick diff of the changes that have been made to the current buffer since the previous save. This can be achieved with a simple command-line mode command. To demonstrate, let's start with the following buffer: Initial Conditions a = [ "one", "two", "three", "five", ] COMMAND Top 1:1 :%s/two/changed Now lets edit the buffer. To keep it simple we will make a single edit, changing "two" to "changed": Edit the Buffer a = [ "one", "changed", "three", "five", ] NORMAL 43% 3:5 Now, we can generate a simple diff with the command: :write !diff % - Let's review what this does. To start, this uses the :write command with the following call signature: :w[rite] !{cmd} Which passes the entire contents of the current buffer to the specified command via stdin . In this example we will use the diff shell command, which has the call signature: diff file1 file2 where our command defines file1 and file2 as: file1 = %, which contains the filename of the current file, and file2 = -, which tells diff to read stdin So, putting this all together, we pass the current buffer contents to the diff command, and generate the diff between the saved version of the current file (%) and the current buffer contents. Finally, the diff is passed back to Neovim: Generate the Diff a = [ "one", "changed", "three", "five", ] NORMAL 43% 3:5 :write !diff % - 3c3 < "two", --- > "changed", shell returned 1 The output window shows that the line containing "two" has been changed to "changed". diff also returns a status code if 1, meaning that the two files were different. This is definitely not the prettiest diff in the world, but is useful when a quick diff is required. Take a look at: diff --help to see what options are available to suit the output to your needs. For example, by leveraging diff's options one can format the same output as a side-by-side diff: :write !diff -yt -W 60 % - Alternate Output a = [ "one", "changed", "three", "five", ] NORMAL 43% 3:5 :write !diff -yt -W 60 % - a = [ a = [ "one", "one", "two", | "changed", "three", "three", "five", "five", ] ] shell returned 1
Filed In:shell

A common task when editing files is to remove duplicate lines. While this can be done manually, it is often easier to leverage Vim's command-line mode to leverage the uniq command. Suppose we have the following file in a buffer and want to remove duplicates: Initial Conditions bananas apples apples oranges apples COMMAND Top 1:1 :%!uniq The command to execute is: :%!uniq Let's break this down to review what is happening: To start, this follows the pattern: :[range]!{cmd} {args} where :% specifies the range as the entire file, although this can be replaced with a range specifying a subset of lines, or a visual selection . Next, !{cmd} indicates that an external command is to be called with the specified range and arguments. In this case the external command to be called is: uniq with (initially) no arguments. By default uniq takes input from stdin, so there is no need to specify the input source. Executing this command produces the following output: Execute uniq bananas apples oranges apples NORMAL Top 1:1 5 lines filtered which is not exactly what we were looking for. It turns out that by default uniq only detects adjacent repeating lines, so apple still appears twice in the output. If we take a look at the help page for uniq we see that the -u option can be used to print only unique lines, which is what we were looking for. Lets undo to get back to the original buffer, then try again using the -u argument: Execute uniq -u bananas oranges apples NORMAL Top 1:1 5 lines filtered That is more like it. We should note that uniq also offers the -d option, which performs the opposite function and returns only the duplicate lines. Starting from the original buffer we can execute this command to see the result: Execute uniq -d apples NORMAL Top 1:1 5 lines filtered