A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://learnbyexample.github.io/vim_reference/Macro.html below:

Macro - Vim Reference Guide

Macro

The . repeat command repeats only the last change. And it gets overwritten with every change. The q command allows you to record a sequence of commands and execute them later whenever you need. You can make it recursive, add a count prefix, combine it with Command-line mode commands and so on. Powerful indeed!

With so many built-in features, sometimes it isn't easy to choose. I prefer the substitute command to macros if both of them can be used for the given problem, especially if the processing doesn't require multiple lines to be considered at once for the solution. That said, macros are more flexible, having an inherent advantage of being able to easily integrate numerous Vim commands. Also, macros allow you to progress in smaller chunks, which might be easier compared to a complicated regexp based solution.

Documentation links:

Macro usage steps

Here's a rough overview of the q command usage. Working examples will be discussed in later sections.

  1. Press q to start the recording
  2. Use any alphanumeric character as the register to store the recording (for example, a)
  3. Execute command sequence to accomplish the required task
  4. Press q again to stop the recording
  5. Press @a (the register used in step 2) to execute the recorded command sequence

Command-line area will show recording @a after step 2 and this indicator vanishes after step 4.

Note that these registers are shared across recording, delete and yank commands. You'll see how this helps to modify a recording later, but you should also be careful not to mix them if you want separate recording and paste use cases. As mentioned earlier in the Normal mode chapter, uppercase registers will append to existing content in lowercase registers.

See also vi.stackexchange: Can I repeat a macro with the "dot operator"? (one of the solutions will allow you to use the . command to execute a macro immediately after recording as well).

Example 1

The qwceHello^[q macro recording clears text till the end of the word and inserts Hello. Here's a breakdown of this command sequence:

After you've recorded the macro, you can execute this command sequence anywhere else you need it. For example, if the cursor is on the fourth character of the text Hi-there and @w is pressed, you'll get Hi-Hello.

Modifying a macro

As mentioned earlier, registers are shared across recording, delete and yank commands. When you call a macro using @, the register content is treated as the sequence of commands to be executed. So, editing a register's content will automatically update the behavior of the macro as well. Knowing that you can modify a macro also helps if you make a mistake — you can choose to finish the recording and update later instead of restarting the recording.

Suppose you want to use 'Hello!' instead of Hello for the macro discussed in the previous section. Here's one possible way to make the changes:

After you've modified the register contents, check if it is working as expected. For example, if the cursor is on the fourth character of the text Hi-there and @w is pressed, you should now get Hi-'Hello'!.

In case you wish to create a new macro from scratch by just typing the required text instead of using the q command, you'll find Ctrl+v (or the Ctrl+q alias) useful to insert keys like Esc and Enter. To do so, press Ctrl+v followed by the required key. You'll get ^[ for Esc, ^M for Enter and so on.

let @w = "ce'Hello'!^[" adding this line to the vimrc file will load the "w register with the given text at startup.

Example 2

Suppose you forgot to add curly braces for single statement control structures in a Perl program:

# syntax error
if($word eq reverse $word)
    print "$word is a palindrome\n";

# corrected code
if($word eq reverse $word)
{
    print "$word is a palindrome\n";
}

qpo{^[jo}^[q is one way to do it:

Having a macro will help you apply this correction whenever you forget braces for single statement control structures.

Note that { and } will be indented based on style settings for that particular filetype.

Example 3

I used F`r[f`s]()^["*P macro to replace `:h &LTtopic>` with a hyperlink to the corresponding online help page for this ebook. Assume the cursor is somewhere within the :h &LTtopic> text portion surrounded by backticks (markdown formatting for inline code). This has to be changed to [:h &LTtopic>](link) (markdown formatting for hyperlinks).

Once the macro was recorded, I just had to select the url from the browser for each help topic and execute the macro. I used n to navigate in the markdown files after using :h as the search pattern.

Motion and Filter

If you have to apply the same macro for text portions that are next to each other, you can add motion commands at the end of the macro for reaching the next text portion. The motion command could be arrow motions, searching using / and so on. Doing so will allow you to use a count prefix to apply the macro for all the text portions in one shot. This assumes that you can easily count the number of text portions. For example, consider this Python snippet where you want to change single line definitions to multiple lines:

def square(n): return n ** 2
def cube(n): return n ** 3
def isodd(n): return n % 2 == 1

You can do a recording as usual, select these lines visually (or use a range) and then apply the macro using normal @d in Command-line mode. Or, you could add a motion to automatically go to the next line and use a count prefix as described below.

qd0f:lr^M>>o^[jq is one way to achieve this:

After recording, you can use 3@d on the first line to get the output as shown below:

def square(n):
    return n ** 2

def cube(n):
    return n ** 3

def isodd(n):
    return n % 2 == 1

Suppose the Python function definitions discussed above aren't next to each other but can be found anywhere in the Python script file. In such cases, if you are able to reliably identify the lines using a regexp filter, you can use the :g command.

Recursive recording

Suppose it isn't easy to count the number of text portions and filtering is complicated too. In such cases, you might be able to use recursive recording that continues to execute the macro until one of the steps fails. Similar to recursive function calls, you have to call the macro from within the recording. Consider this Python snippet where you want to change single line definitions to multiple lines:

def square(n): return n ** 2
def cube(n): return n ** 3
def isodd(n): return n % 2 == 1
print(square(12))

qr0f:lr^M>>o^[j@rq is one way to achieve this. The only addition here is @r at the end of the recording compared to the solution discussed in the previous section. For the fourth line with print() function, the macro will stop when it doesn't find the : character. It would've stopped even if a : was found, provided it was the last character, since the l motion would've failed.

Using @r on the first line of the above snippet would give the following output:

def square(n):
    return n ** 2

def cube(n):
    return n ** 3

def isodd(n):
    return n % 2 == 1

print(square(12))

Note that the register being used here must be empty before you start the recording, otherwise you might see some unwanted changes when you type @r while recording. To ensure this register is empty, you can use qrq (i.e. record an empty macro) before you record the recursive macro.

If the :s command is part of the recording and you do not want the macro to stop if the search pattern isn't found, you can use the e flag.

Here are some more examples:

Exercise

Given the following text:

# Introduction
# Normal mode
# Command Line mode
# Visual mode

Use a macro (or the substitute command if you prefer) to get the modified text as shown below:

* [Introduction](#introduction)
* [Normal mode](#normal-mode)
* [Command Line mode](#command-line-mode)
* [Visual mode](#visual-mode)
Further Reading

RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4