How to replay a recursive macro recording once? - vim

I started recording by typing qw.
Then, I pressed #w to replay the search,movement and replacement.
A couple of seconds after, I saw my replay in an infinite loop.
How can I only repaly my recording only once ?
Is this possible ? Should I use another vim command ?
Thanks in advance !

Usually search and replace is done with :s. For example, to replace all foo with bar
:%s/foo/bar/g
See :help :s for more info.
To end a macro, type q in normal mode. So, a macro to move right, delete the next three characters, and move down would be typed as follows
qql3xjq
Then to replay the macro, #q or 3#q to execute it three times (:help q). Adding #q to the macro would make it recursive.

Related

Undo ESC-keystroke in vim

I am using vim for quite some time now, but several times per day I accidentally encounter an inconvenience by hitting ESC too early.
Assume I am editing the following file:
I want to change 'house' in this line.
'house' should stay like this.
This 'house' should become 'home'
The other 'house' should also change.
I want to change house to home in all lines except the second one. (In this simple example it would easy to write a :s command and perform the task, but usually the task is more specific and manual replacements are quicker and less error prone.) I navigate to the first occurrence of house, press cw, type hone, and hit ESC. After hitting ESC I realize that by accident I typed the letter n instead of m.
I could navigate to the next occurrence of house and hit . to repeat the faulty replacement. In this case I have to fix all hones and replace the n by m afterwards.
I could fix the mistake immediately, but then I can not repeat the same house->home replacement, since . would repeat the n->m replacement.
All of this would be no problem, if I had spotted the mistake before hitting ESC. My question is, if there is a way to undo leaving the insert mode, such that . will repeat both actions? Or similarly, is there a way to tell . to repeat the last to operations?
(Of course this sounds like recording a macro, but since I end up in this situation by mistake, I have not started a macro recording.)
As far as I am concerned, there's no command history of vim in that you could repeat the last two operations.
However, there's a plugin that could help you accomplish that. It's called the RepeatLast.vim plugin to address this exact requirement. It provides a 2\. key binding. The cost for using that plugin and how the plugin actually works is that... it actually enables macro recording all the time. But if you could live with that, it should deal with this sort of situation pretty fine.

How can I repeat the last VIM macro?

I know how to repeat the last command in Vim. I use ..
But how can I repeat the last macro? It's a little non-comfortable to press #q everytime I want to repeat it.
I tried with . but it just repeats the last command from the macro.
Is there a shorter way of doing that?
Yes, you can use ## to replay the last used macro.
As a bonus, use #: to replay the last ex command. (And then that becomes the "last used macro" that can be repeated with ##.)
I find ## a bit hard to type and as I don't use , much - and it's close enough to .:
:map , ##

Vim repeat append something at end of word

In vim I frequently find myself wanting to append a suffix to an identifier in my source code, and to then repeat it on other identifiers using '.'.
i.e. to transform:
foo bar baz faz
to:
foo_old bar_old baz_old faz_old
I would like to be able to do:
ea_old<ESC>w.w.w.
instead of:
ea_old<ESC>wea_old<ESC>wea_old<ESC>wea_old<ESC>
In other words, I want appending text to the end of a word to appear as a repeatable command in the history. Anyone know how to do this?
I can do:
nmap <C-a> ea
to create a slightly more convenient way to append at the end of a word, but it only repeats the "a". Ideally I want to be able to repeat the whole "eaarbitrarytext" sequence.
I have the repeat.vim plugin installed and tinkered a bit, but I don't really know what I'm doing in vimscript.
Clarifying the requirement: I want to be able to jump around using arbitrary movement commands until my cursor is somewhere on the identifier, and then hit "." to repeat the appending of a suffix. The above example is intended to be a special case.
ea_oldESCe.e.e. should work for you.
Another possible solution would be to use the c flag on a search and replace command:
:.s/\<[[:alnum:]]\+\>/&_old/gc
Then all you have to do is press y to confirm each replacement. This would be faster if you have a lot of replacements to do and want to confirm each one manually. If, on the other hand, you want to add _old to every word on a line, you can remove the c:
:.s/\<[[:alnum:]]\+\>/&_old/g
My guess is that the OP took a very simple example to illustrate a more generic problem that can be re-formulated as "I would like to repeat an arbitrarily big sequence of commands very easily".
And for that, there is the q command. Pick your favourite register for recording, say "q", then:
qq -- starts recording
(do any complicated set of actions here...)
q -- stops the ercording
#q -- plays back the recording
And as I am myself using this very often when programming, I ended up mapping the actions above to F2, F3 and F4 respectively on my keyboard. This allows to repeat your set of actions in really 1 key stroke. In .vimrc:
nmap <F2> qq
nmap <F3> q
nmap <F4> #q
For this specific case, you can use search and replace: s/ /_old /g.

How to provide parameter in vim macro

Is it possible to provide some parameter when recording a macro in vim via prompt or some other ways?
Edit:
I have such code:
foo
bar
And I would like to surround each with ruby block:
expect do
foo
end.to raise_error(CustomClass)
expect do
foo
end.to raise_error(OtherCustomClass)
So, it is easy to create a macro that will result with:
expect do
foo
end.to raise_error()
expect do
foo
end.to raise_error()
But it will be nice to have prompt that will be used to set raise_error method parameter. In each use of macro this parameter will be different.
While I agree with everyone else that if you need this feature, you're probably going about things inefficiently, it is possible to insert a variable text string into a document as part of a macro. The trick is to store the text you want to use in your macro in a register.
yank some text into a named register, for example "xyw to yank a word into the x register
record your macro, qq, when you want to place the variable text, put it, for example "xp to put the text in the x register into the document where the cursor is
now, when you play your q macro, #q, it will use whatever is currently in the x register, so you can yank different text into the x register, play your q macro, and the newly yanked text will be used.
If you are talking about recording a macro with qx...q, this is not possible.
However you could still do : :let #y = substitute(#x, 'old_pattern', 'replacement', 'g') and then use #y.
You could also define a function:
function Play(myArg)
execute 'normal sequence_of_characters' . a:myArg . 'other_sequence_of_characters'
endfunction
call Play('foo')
Very particularly in the OP's situation, where you really only have precisely two variable pieces of content, I find the easiest method to be a bastardisation of #mkomitee's approach above.
Instead of manually saving the two ‘parameters’ into registers before each usage of the macro, I prefer to type the “first parameter,” visual-select it, evaluate the macro, then type the “second parameter.” To achieve this, I start the macro with a deletion command (a simple d, assuming you're always going to invoke the macro in visual-mode, for instance); then finish it with a command that switches to insert mode (like c or i), and finally, while still in insert mode, a Ctrl-O q to cause the macro to also leave Vim in insert mode when it's done.
As a slightly simple example, if the two “parameters” are single words, here's the keystrokes to create (and then invoke) a macro to manipulate widget.snog() to a parameterised widgetFoo.fooSnog(bar):
foob qq "zdw — we're now recording to the q register, with the first ‘argument’ in z
‸
"aP — prefix-paste from a fixed register used elsewhere in the document
widget.snog()‸
^ea␣Ctrl-rEscb~hx — paste the first arg, and capitalize
widget‸Foo.snog()
2w~b"zP — capitalize existing word, then paste the first arg again
widgetFoo.fo‸oSnog()
$Ctrl-Oq — move to the last position, enter insert-mode, and end the macro
widgetFoo.fooSnog(‸)
After finishing the first instance with bar, we can now use it several times:
obazEscb — set up our first ‘argument’,
widgetFoo.fooSnog(bar)
‸baz
#qquuxEsc — invoke the macro, and finish with the second one
widgetFoo.fooSnog(bar)
widgetBaz.bazSnog(quux‸)
ocorgeEscb##graultEsc — repeat a third time
widgetFoo.fooSnog(bar)
widgetBaz.bazSnog(quux)
widgetCorge.corgeSnog(grault‸)
ogarplyEscb##waldoEsc — … and so on
widgetFoo.fooSnog(bar)
widgetBaz.bazSnog(quux)
widgetCorge.corgeSnog(grault)
widgetGarply.garplySnog(waldo‸)
Of course, it looks laborious, typed out in such a long fashion — but it's surprisingly few key-strokes in practice, and very easy to train into your fingers.
tl;dr: type the first argument; enter macro-recording before deleting it into a register; manipulate your text as desired; then leave vim in insert-mode at the position of the second argument with Ctrl-Oq.
If you need to generate a code, which is the case, the best way for this is to use vim snippets. You can configure snippet to put cursor where you need when you [tab].

How do I repeat the last n changes in Vim?

Doing . repeats the last change. Doing 2. repeats the last change two times.
But imagine I want to repeat the change before the last one. How do I do it in Vim?
Don't think you can, see :help . However, what you can do is to record a macro for your edits, you have a lot of registers to choose from {0-9a-zA-Z"} (uppercase to append).
Then use e.g. #u for edit 1, #t for edit 2 and so on.
Great tips about recording from Best of VIM Tips
" Recording (BEST TIP of ALL)
qq # record to q
your complex series of commands
q # end recording
#q to execute
## to Repeat
5## to Repeat 5 times
qQ#qq : Make an existing recording q recursive *N*
" editing a register/recording
"qp :display contents of register q (normal mode)
<ctrl-R>q :display contents of register q (insert mode)
" you can now see recording contents, edit as required
"qdd :put changed contacts back into q
#q :execute recording/register q
Have a look at these for more hints for repeating:
:& last substitute
:%& last substitute every line
:%&gic last substitute every line confirm
g% normal mode repeat last substitute
g& last substitute on all lines
## last recording
#: last command-mode command
:!! last :! command
:~ last substitute
:help repeating
I wrote the RepeatLast.vim plugin to address this exact requirement. It provides a 5\. key binding to repeat the last 5 changes (including movements) and 2\D to drop/forget the last 2 actions.
It works by enabling macro recording all the time, which may not be desirable for everyone. But if you can live with that, it works in 99% of use cases.
Latest version: https://github.com/joeytwiddle/RepeatLast.vim (Please feedback!)
Caveats:
Please :set ch=2 so that the first line of output won't be hidden by the "recording" message.
The 1% of times it fails to work as intended are usually due to:
Difficulties triggering the CursorHold event slowly without losing
fast-repeated keystrokes
Undesirable recording of [Space] and
[Enter] keys when the user is responding to a prompt.
Training your q muscle to pre-emptively record macros might be a better approach in the long term. ;-)
Based on Fredrick Phil's answer, here is an example:
Recording your macro
The following shows how to record a macro to delete everything in and including a quoted string and store in register d. The command to delete a string is da". So to store this command in macro register d we can simply do this:
qdda"q
Notice it starts and ends with a q. The second character is the register, in this case d for delete. But we could have given it any letter or number. The remaining characters da" is our command.
Using our macro
Now that our macro is recorded we can invoke it by using the # symbol followed by the register:
#d
Repeating the last macro command
To use the most recently invoked macro command again:
##
Unrelated info:
In this example, we used da" which stands for delete a quoted string. (If you instead wanted to delete everything inside the quoted string, but not the quotation marks themselves you can instead use di" instead.).
Record Your "Edits"
yes! you can do this in vim! 😎
One of Vim's most useful features is its ability to record what you type for later playback. This is most useful for repeated jobs that cannot easily be done with .
To start recording
press q in normal mode followed by a letter (a to z)
That starts recording keystrokes to the specified register. Vim displays recording in the status line
Type any normal mode commands, or enter insert mode and type text
To stop recording
ending in normal mode, come to normal mode if you are not, and press q
ending in insert mode, press Ctrl+O, this will temporarily get you into normal mode, and then press q
To playback your keystrokes/recording
press # followed by the letter previously chosen
Typing ## repeats the last playback
References
Vim Fandom: Recording keys for repeated jobs
Vim Fandom: Macros
Quora - How do you stop recording a Vim macro when in insert mode?

Resources