Today's Featured Neovim Tips & Tricks:expand_moreApplying a Normal-mode Command to a RangeeditingformattingNormal mode commands can be used to apply an operation over each line in a range . Suppose you are creating a list in python by yanking and pasting some content from another buffer . After pasting, the items are in place but are missing the trailing , required by python: Initial Conditions a = [ "one" "two" "three" ] NORMAL 33% 2:1 These could be manually added in various ways, but Vim's :normal command provides a handy solution by allowing a normal mode command to be applied to each line in a range. To demonstrate, we first create a visual selection: Select Visual Range v 2j a = [ "one" "two" "three" ] VISUAL 67% 4:1 Note that the range could have also been entered manually. Next create the command to execute. We would like to move the cursor to the end of each line, enter insert mode after the line, then enter the , character. Inserting after the line can be achieve with the A command, so the command to execute for each line is: A, and the complete command is: :normal A, Executing this command in our buffer provides the desired result: Execute the Command a = [ "one", "two", "three" , ] NORMAL 67% 4:12Formatting an Entire BufferformattingStarting with the cursor in the middle of an un-formatted buffer : Initial Conditions <div> <p>line one</p> <p>line two</p> <p>line three</p> </div> NORMAL 50% 3:1 The first step is to execute gg , which moves the cursor to the top of the buffer: Move to Top of Buffer g g < div> <p>line one</p> <p>line two</p> <p>line three</p> </div> NORMAL Top 1:1 Next, we execute = , which tells Vim to format the lines traversed by the associated motion. We follow this with G , which indicates that we want to apply formatting from the current line to the bottom of the file: Format the Entire Buffer = G < div> <p>line one</p> <p>line two</p> <p>line three</p> </div> NORMAL Top 1:1 5 lines indented The end result shows that the combination of gg and G includes all lines in the file. Moving LineseditingkeymapReorganizing lines in a buffer is a very common task. While a yank and paste sequence could be used for each line, there is a better way. The following keymaps allow a line or group of lines to be easily moved up or down using a single keystroke: -- single-line vim . keymap . set ( "n" , "<A-j>" , ":move .+1<CR>==" ) vim . keymap . set ( "n" , "<A-k>" , ":move .-2<CR>==" ) -- multi-line vim . keymap . set ( "v" , "<A-j>" , ":move '>+1<CR>gv=gv" ) vim . keymap . set ( "v" , "<A-k>" , ":move '<-2<CR>gv=gv" ) To see how they work, consider the following buffer: Initial Conditions a = [ "one", "three", "two", "four", "five", ] NORMAL Top 1:1 Note that the words are out of order, and we would like to fix that. We start by moving the cursor to the line that we want to move (i.e. the "target" line): Move to Target Line 2j a = [ "one", "three", "two", "four", "five", ] NORMAL 38% 3:1 With this keymap, hitting A-J allows us to easily move the currently down one position, swapping its position with the line below it: Move Current Line <A-j> a = [ "one", "two", "three", "four", "five", ] NORMAL 50% 4:1 To get a better idea about what happened, consider the command that executed when we hit A-J : :move .+1<CR>== The :move command has a call signature: :m[ove] {address} and moves the current line (or selected lines) to the line below the specified address. In this case, the specified address is .+1 , which we learned in the ranges chapter means "the line below the current line". The carriage return causes the preceding command to execute, which is follows by == , which formats (indents) the line after it is moved. Let's see how this works with a visual selection . First, let's move the cursor so that the selection spans three lines: Select Multiple Lines v 2j a = [ "one", "two", "three", "four", "five", ] VISUAL 75% 6:1 Note that although the selection only touches the third line, the entire line is included in the block of lines to move. Now, move these lines up: Move Multiple Lines <A-k> a = [ "one", "three", "four", "five", "two", ] VISUAL 62% 5:1 3 lines indented The selected lines have each move up one line, and the line containing "two" (which has previously been above the selection) is now located below the selection. Search and Replace in Multiple FileseditingworkflowWe learned how to search and replace within a single file, this tip discussed how to extend that capability to multiple files. As a first step, let's define the pattern and replacements text we want to execute on a single file: Initial Conditions a = [ "one", "two", "three", "five", ] COMMAND Top 1:1 :%s/five/four/n As a simple example, let's change all occurrences of five to four . The command to do this is: :%s/five/four Let's test it on one file to be sure it works. We will add the n flag so that we can see the results but not execute the changes themselves: Test the Pattern a = [ "one", "two", "three", " five ", ] NORMAL Top 1:1 1 match on 1 line OK, that looks correct. Now that we have built the command we want to run, the next step is to define the list of files over which we will execute this command. This is done using the :args command. Suppose we want to execute this command over all python files in the current working directory. We can populate those paths in the arglist using: :args ./*.py we can verify the paths that we inserted into the arglist using: :args Now that the arglist has been populated, we can execute our command on each of the files in the list by calling :argdo and passing our search and replace command from above as an argument: :argdo %s/five/four Execute the Command a = [ "one", "two", "three", " four", ] NORMAL 71% 5:5
Applying a Normal-mode Command to a RangeeditingformattingNormal mode commands can be used to apply an operation over each line in a range . Suppose you are creating a list in python by yanking and pasting some content from another buffer . After pasting, the items are in place but are missing the trailing , required by python: Initial Conditions a = [ "one" "two" "three" ] NORMAL 33% 2:1 These could be manually added in various ways, but Vim's :normal command provides a handy solution by allowing a normal mode command to be applied to each line in a range. To demonstrate, we first create a visual selection: Select Visual Range v 2j a = [ "one" "two" "three" ] VISUAL 67% 4:1 Note that the range could have also been entered manually. Next create the command to execute. We would like to move the cursor to the end of each line, enter insert mode after the line, then enter the , character. Inserting after the line can be achieve with the A command, so the command to execute for each line is: A, and the complete command is: :normal A, Executing this command in our buffer provides the desired result: Execute the Command a = [ "one", "two", "three" , ] NORMAL 67% 4:12
Formatting an Entire BufferformattingStarting with the cursor in the middle of an un-formatted buffer : Initial Conditions <div> <p>line one</p> <p>line two</p> <p>line three</p> </div> NORMAL 50% 3:1 The first step is to execute gg , which moves the cursor to the top of the buffer: Move to Top of Buffer g g < div> <p>line one</p> <p>line two</p> <p>line three</p> </div> NORMAL Top 1:1 Next, we execute = , which tells Vim to format the lines traversed by the associated motion. We follow this with G , which indicates that we want to apply formatting from the current line to the bottom of the file: Format the Entire Buffer = G < div> <p>line one</p> <p>line two</p> <p>line three</p> </div> NORMAL Top 1:1 5 lines indented The end result shows that the combination of gg and G includes all lines in the file.
Moving LineseditingkeymapReorganizing lines in a buffer is a very common task. While a yank and paste sequence could be used for each line, there is a better way. The following keymaps allow a line or group of lines to be easily moved up or down using a single keystroke: -- single-line vim . keymap . set ( "n" , "<A-j>" , ":move .+1<CR>==" ) vim . keymap . set ( "n" , "<A-k>" , ":move .-2<CR>==" ) -- multi-line vim . keymap . set ( "v" , "<A-j>" , ":move '>+1<CR>gv=gv" ) vim . keymap . set ( "v" , "<A-k>" , ":move '<-2<CR>gv=gv" ) To see how they work, consider the following buffer: Initial Conditions a = [ "one", "three", "two", "four", "five", ] NORMAL Top 1:1 Note that the words are out of order, and we would like to fix that. We start by moving the cursor to the line that we want to move (i.e. the "target" line): Move to Target Line 2j a = [ "one", "three", "two", "four", "five", ] NORMAL 38% 3:1 With this keymap, hitting A-J allows us to easily move the currently down one position, swapping its position with the line below it: Move Current Line <A-j> a = [ "one", "two", "three", "four", "five", ] NORMAL 50% 4:1 To get a better idea about what happened, consider the command that executed when we hit A-J : :move .+1<CR>== The :move command has a call signature: :m[ove] {address} and moves the current line (or selected lines) to the line below the specified address. In this case, the specified address is .+1 , which we learned in the ranges chapter means "the line below the current line". The carriage return causes the preceding command to execute, which is follows by == , which formats (indents) the line after it is moved. Let's see how this works with a visual selection . First, let's move the cursor so that the selection spans three lines: Select Multiple Lines v 2j a = [ "one", "two", "three", "four", "five", ] VISUAL 75% 6:1 Note that although the selection only touches the third line, the entire line is included in the block of lines to move. Now, move these lines up: Move Multiple Lines <A-k> a = [ "one", "three", "four", "five", "two", ] VISUAL 62% 5:1 3 lines indented The selected lines have each move up one line, and the line containing "two" (which has previously been above the selection) is now located below the selection.
Search and Replace in Multiple FileseditingworkflowWe learned how to search and replace within a single file, this tip discussed how to extend that capability to multiple files. As a first step, let's define the pattern and replacements text we want to execute on a single file: Initial Conditions a = [ "one", "two", "three", "five", ] COMMAND Top 1:1 :%s/five/four/n As a simple example, let's change all occurrences of five to four . The command to do this is: :%s/five/four Let's test it on one file to be sure it works. We will add the n flag so that we can see the results but not execute the changes themselves: Test the Pattern a = [ "one", "two", "three", " five ", ] NORMAL Top 1:1 1 match on 1 line OK, that looks correct. Now that we have built the command we want to run, the next step is to define the list of files over which we will execute this command. This is done using the :args command. Suppose we want to execute this command over all python files in the current working directory. We can populate those paths in the arglist using: :args ./*.py we can verify the paths that we inserted into the arglist using: :args Now that the arglist has been populated, we can execute our command on each of the files in the list by calling :argdo and passing our search and replace command from above as an argument: :argdo %s/five/four Execute the Command a = [ "one", "two", "three", " four", ] NORMAL 71% 5:5