created June 20, 2006 · complexity intermediate · author Eric Arnold · version 5.7
There is often a question as to why newlines aren't doing what the user expects inside Vim script.
When \n is stored in a Vim variable/register/etc, it is stored as a NULL, and then translated back to a real newline under circumstances such as "put".
Try inserting a newline in insert mode, i.e. ^V^J (or ^Q^J if you're using the mswin behavior). You will see a <00> show up.
Now try these to help understand further:
let @a = "a" . "\n" . "b" or let @a = "a" . "\x0a" . "b"
and put it into the buffer using "ap or :put a
You should see:
"put" is especially smart about translating the newlines from NULLs back to 0x0a. Now do:
call setline(".", @a) or call append("$", @a)
You should see:
It's not a happy reality, since NULLs and newlines cannot cooexist in Vim script strings in various circumstances.
In Vim 7 you have the option of giving a list to setline() and append(), which solves the line break ambiguity:
call setline(".", [ 'a', 'b' ] )
I'm now using lists everywhere I can, in preference to concatenated strings with newline separators. I usually split() any such strings I find into a list for easier manipulation. This sidesteps all the usual pitfalls trying to handle line breaks manually as embedded characters.
A useful function in this context:
:echo strtrans(@a) a^@b
Another question: Why does s/\r/\r/ change <CR> to <NL>?
This is because Ex commands (as opposed to function calls) are trying to be extra smart about linebreaks. In this case:
let @a = substitute( "a\rb", '\r', '\r', 'g' ) call setline( "$", @a ) a<0d>b
You can see that Vim is still storing the carriage return, but is getting translated on the back end, in this case by the s/\r/\r/ command. I think the \r case is treated specially by the Ex s/ command, since :put a doesn't put 'a' and 'b' on different lines.
The moral of the story is: find out what works, and remember it, because trying to apply universal rules won't work.