How to assign a string ending in <CR> to a vimscript variable without it adding a <LF>?

macros, macvim, special-characters, vim

Solution

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`.

Problem

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?

Original source