11

I often use extremely long macros when handling repetitive editing and refactoring. Whenever possible I write these as ex-mode commands rather than recording them as macros, because they are easier to edit interactively that way (with the command window).

However, sometimes I need to add in a couple of normal mode commands, e.g. to yank just part of a line rather than a whole line for later use in my macro, or to line some text up the way I want it.

Is there a way to continue an ex mode command after norm is included?

(For an actual example of the kind of complexity I'm talking about:)

:'a+s/\_^\s*\(\S*\)::\_[^>]*>\s*\("[^"]*"\)\s*;\_s*\_$/    "\1", \2,/ | m 'a- | norm f,50a ^[d44|

Is there a way I can add more text on the end and have it execute as an ex mode command?

2
  • 1
    Do you want to prevent the :normal command from consuming the rest of the line? If so you could wrap it inside a string that you could execute with the :execute command: :exe 'norm f,50a ^[d44|' | other Ex command.
    – saginaw
    Mar 2, 2016 at 0:54
  • :execute will only pass the string as an argument to :normal, and so the latter won't see what's after on the command line, allowing you to add other Ex commands. There's just a thing to pay attention to, if the string contains non literal control characters like \e for <Esc> you have to use double quotes to allow Vim to interpret them, otherwise single quotes prevent the interpretation of anything inside the string.
    – saginaw
    Mar 2, 2016 at 1:10

1 Answer 1

13

If you have a sequence of keystrokes that you want to execute in normal mode from the command line, you can use the :normal command.

However, by default the :normal command can't be followed by another command because as the help says:

    This command cannot be followed by another command,
    since any '|' is considered part of the command.

So, if you want to add another Ex command after :normal, you can wrap the whole :normal command inside a string, and then make the :execute command execute the latter. It could give something like:

:exe 'norm {your keystrokes}' | Other Ex command

Contrary to :normal, :execute won't consider the pipe as a part of its argument. It will consider it as a command termination, and will only execute what is inside the string.
:normal won't see what's after on the command line, it will only see what's left in the string.
Thus you should be able to add another Ex command afterwards without :normal typing it in normal mode.

There's just a little thing to pay attention to:
if you surround your string with single quotes, Vim won't interpret anything inside it, which can be a problem if you want :normal to hit control characters such as <Esc>, <CR>, <Tab> or <C-V> by writing special characters, respectively: \e, \r, \t and \<C-V>.
These special characters are described in :help expr-quote.
In this case you could use double quotes instead of single quotes to surround the string, so that Vim can interpret them correctly.
If your control characters are literal (that is if you see their caret notation: ^[ for Escape, ^M for Enter, ^I for Tab, ^V for <C-V>), you shouldn't need the double quotes.

When you record a macro, the latter stores your control characters as literal ones, it doesn't use the kind of special characters described in :h expr-quote, so you shouldn't need the double quotes. And if you want to edit a macro by adding a literal control character yourself, you can prefix it with <C-V> (see :h i_ctrl-v for more info). For example, to add a literal escape inside the register where your macro is stored or inside the sequence of keystrokes passed as an argument to :normal, you could hit <C-V><Esc>.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.