I have been playing around with vim macros lately (in MacVim at the moment), and sometimes I like to explicitly assign a macro into a register using e.g. :let @a='(macro keystrokes)'. This is generally working fine, but I found a weird behavior in which anytime I assign a string value that ends in Carriage Return / ^M, vim automatically adds a Linefeed / ^J to the end before putting it in the register, which affects the execution of the macro!
Example: Let's say I record a simple macro that gets into insert mode, types "hey", escapes out of insert mode, and then hits Enter twice to go down 2 lines. I record this into register @a by typing qaihey<Escape><Enter><Enter>q, which stores the following in @a:
ihey^[^M^M
So far so good, and executing the macro by typing @a does just what it's supposed to. Another perfectly ok way I can get this same macro into register @a would be by typing the whole thing (ihey<Ctrl-V><Escape><Ctrl-V><Enter><Ctrl-V><Enter>) into a buffer and then yanking it with "ay -- the end result is just the same. But here's the weird thing -- suppose I just wanted to assign that string directly into @a using a let statement:
:let @a='ihey^[^M^M'
Now if I type :reg to look at the value it says there's an extra ^J on the end for some reason:
"8 ...
"9 ...
"a ihey^[^M^M^J
"b ...
Having the extra ^J causes it to go down an extra line when I execute the macro, so it's actually changing the behavior.
Anybody know why this extra character is being added? Anyone know how I can get a string value ending with ^M into a register (or any variable), without having an extra ^J get added?
Some quick checking the vim help files says this:
:let @{reg-name} = {expr1} *:let-register* *:let-@* ... If the result of {expr1} ends in a <CR> or <NL>, the register will be linewise, otherwise it will be set to characterwise.
In other words, ending the string with a carriage return will make Vim interpret it as a line ending
Quick googling give this from the VimTips wiki:
Note however, that the above method using :let will not work as expected for any macros which you make ending in a < CR > or < NL > character (carriage return or newline). This is because, as documented in :help :let-@, Vim will treat the register as "linewise" under these conditions. The reason for this is to make registers set with :let act "the right way" when dealing with yanked/deleted text, but it can cause headaches when dealing with recorded macros. Possible workarounds include using the setreg() function or adding "no-op" commands to the end of the macro, such as a < ESC >. See the discussion on vim_dev about unexpected behavior of the :let command for details.
So you have a few options: use setreg() or add some kind of no-op sequence (< ESC >) to the string when you use let.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With