If I have the following text:
foo
bar
I visually select it and copy it.
The text is now stored in the unnamed register "
and here is its contents (output of :reg "
):
"" foo^Jbar^J
According to this chart, it seems ^J
is the caret notation for a Line Feed.
If I want to duplicate the unnamed register in the a
register by typing: :let @a = @"
Here is its contents (output of :reg a
):
"a foo^Jbar^J
It didn't change.
If I now duplicate it in the search register by typing :let @/ = @"
, here is its contents (output of :reg /
):
"/ foo^@bar^@
According to the previous chart, it seems ^@
is the caret notation for a Null character.
Why is a Line Feed automatically converted into a Null character inside the search register (but not the a
register)?
If I insert the unnamed register on the command line (or inside a search after /
), by typing :<C-R>"
, here is what is inserted:
:foo^Mbar^M
Again, according to the last chart, ^M
seems to be the caret notation for a Carriage Return.
Why is a Line Feed automatically converted into a Carriage Return on the command line?
Edit:
Usually you can insert a literal control character by typing:
<C-V><C-{character in caret notation}>
For example, you can insert a literal <C-R>
by typing <C-V><C-R>
.
You can do it for seemingly any control character.
However I've noticed that I'm unable to insert a literal LF inside a buffer or on the command line, because if I type: <C-V><C-J>
it inserts ^@
, a null character, instead of ^J
.
Is it for the same reason a LF is converted into NUL inside the search register?
Edit 2:
In :h key-notation
, we can read this:
<Nul> zero CTRL-@ 0 (stored as 10) <Nul>
<NL> linefeed CTRL-J 10 (used for <Nul>)
The stored as 10
part on the first line and used for <Nul>
on the second line could indicate that there's some sort of overlap between a LF and a NUL, and that they could be interpreted as the same thing. But they can't be the same thing, because after executing the previous command :let @/ = @"
, if I type n
in normal mode to get to the next occurrence of the 2 lines foo
and bar
, instead of getting a positive match, I have the following error message:
E486: Pattern not found: foo^@bar^@
Besides this link seems to explain that a NUL denotes the end of a string, whereas a LF denotes the end of a line in a text file.
And if a NUL is stored as 10
as the help says, which is the same code as for a LF, how is Vim able to make the difference between the 2?
Edit 3:
Maybe a LF and a NUL are coded with the same decimal code, 10
, as the help says. And Vim makes the difference between the 2 thanks to the context. If it meets a character whose decimal code is 10
in a buffer or any register, except the search and command registers, it interprets it as a LF.
But in the search register (:reg /
) it interprets it as a NUL because in the context of a search, Vim only searches for a string where the concept of end of line in a file
doesn't make sense because a string is not a file (which is weird since you can still use the atom \n
in a searched pattern, but maybe that's only a feature of the regex engine?). So it automatically interprets 10
as a NUL because it's the nearest concept (end of string
≈ end of line
).
And in the same way, on the command line / command register (:reg :
) it interprets the code 10
as a CR, because the concept of end of line in a file
doesn't make sense here. The nearest concept is end of command
so Vim interprets 10
as a CR, because hitting Enter
is the way to end/execute a command and a CR is the same as hitting Enter
, since when you insert a literal one with <C-V><Enter>
, ^M
is displayed.
Maybe the interpretation of the character whose code is 10
changes according to the context:
- end of line in a buffer (
^J
) - end of string in a search (
^@
) - end of command on the command line (
^M
)
NULL
characters is caused by the underlying C function that is handling the strings. This explanation of how C processes strings that you linked to explains that internally C delimits strings with aNULL
.NULL
s occur rarely enough in text that it makes it a good character for this purpose. A consequence of this is that if the C program (vim) tried to pass an "empty" string into an internal C functionsomeFunction(arg1, "")
where arg 2 was""
i.e. "the item between the quotes, which is literally nothing - an "empty". a NULL can appear, because it was "added" by the underlying C implementation as it delimited the string. I don't know how you would check for this - but it comes to mind as a possible cause.\r
and\n
difference in:substitute
.