Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 240
murftown Avatar asked Dec 06 '25 00:12

murftown


1 Answers

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.

like image 145
jgriego Avatar answered Dec 08 '25 15:12

jgriego



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!