Чому Посилання рядка перетворюється в нульовий символ всередині реєстру пошуку та в командному рядку повернення перевезення?


12

Якщо у мене є такий текст:

foo
bar

Я візуально вибираю його і копіюю.
Текст тепер зберігається в неназваному реєстрі, "і ось його вміст (вихід :reg "):

""   foo^Jbar^J

Відповідно до цієї діаграми , схоже, ^Jце позначення карет для стрічки каналів.

Якщо я хочу дублювати неназваний реєстр у aреєстрі, ввівши: :let @a = @"
Ось його вміст (вихід :reg a):

"a   foo^Jbar^J

Це не змінилося.

Якщо я тепер дублюю його в реєстрі пошуку, ввівши :let @/ = @", ось його вміст (вихід :reg /):

"/   foo^@bar^@

Згідно з попередньою діаграмою, схоже, ^@це позначення карет для нульового персонажа.
Чому подача рядків автоматично перетворюється в символ Null всередині реєстру пошуку (але не в aрегістрі)?

Якщо я вставляю неназваний реєстр у командному рядку (або всередині пошуку після /), ввівши :<C-R>", ось що вставляється:

:foo^Mbar^M

Знову ж таки, згідно з останньою діаграмою, ^Mсхоже, це є позначенням карет для повернення перевезення.
Чому канал каналу автоматично перетворюється на повернення перевезення у командному рядку?

Редагувати :

Зазвичай ви можете вставити буквальний керуючий символ, ввівши:
<C-V><C-{character in caret notation}>

Наприклад, ви можете вставити буквар <C-R>, ввівши <C-V><C-R>.
Ви можете зробити це для, здавалося б, будь-якого керуючого персонажа.
Однак я помітив, що я не в змозі вставити буквальний LF всередину буфера або в командному рядку, тому що якщо я набираю: <C-V><C-J>він вставляє ^@нульовий символ замість ^J.
Це з тієї ж причини LF перетворюється на NUL всередині реєстру пошуку?

Редагувати 2 :

В :h key-notation, ми можемо прочитати це:

<Nul>       zero            CTRL-@    0 (stored as 10) <Nul>
<NL>        linefeed        CTRL-J   10 (used for <Nul>)

stored as 10Частина на першій лінії і used for <Nul>на другій лінії може свідчити про те , що є якась - то перекриття між LF і NUL, і що вони можуть бути інтерпретовані як те ж саме. Але вони не можуть бути тим самим, тому що після виконання попередньої команди :let @/ = @", якщо я набираю nв звичайному режимі, щоб перейти до наступного появи двох рядків, fooі barзамість отримання позитивної відповідності, у мене з'являється таке повідомлення про помилку:

E486: Pattern not found: foo^@bar^@

Крім цього, посилання, схоже, пояснює, що NUL позначає кінець рядка, тоді як LF позначає кінець рядка в текстовому файлі.

І якщо NUL, stored as 10як говорить довідка, це той самий код, що і для LF, як Vim здатний зробити різницю між двома?

Редагувати 3 :

Можливо, LF та NUL кодуються одним і тим же десятковим кодом 10, як йдеться в довідці. І Vim робить різницю між двома завдяки контексту. Якщо він зустрічає символ, десятковий код якого 10знаходиться в буфері або будь-якому регістрі, крім регістрів пошуку та команд, він інтерпретує його як LF.
Але в реєстрі пошуку ( :reg /) він трактує це як NUL, оскільки в контексті пошуку Vim шукає лише рядок, де поняття end of line in a fileне має сенсу, оскільки рядок не є файлом (що дивно, оскільки ви можете як і раніше використовувати атом \nу шуканому шаблоні, але, можливо, це лише особливість двигуна регулярних виразів?). Тож воно автоматично трактується 10як NUL, оскільки це найближче поняття ( end of stringend of line).

Таким же чином, у командному рядку / регістрі команд ( :reg :) він інтерпретує код 10як CR, оскільки поняття end of line in a fileтут не має сенсу. Найближча концепція end of commandтак Vim тлумачить 10як CR, так як ударяти Enterшлях до кінця / виконати команду і CR такий же , як удари Enter, так як при вставці буквального з <C-V><Enter>, ^Mвідображаються.

Можливо тлумачення символу, код якого 10змінюється відповідно до контексту:

  • кінець рядка в буфері ( ^J)
  • кінець рядка в пошуку ( ^@)
  • закінчення команди в командному рядку ( ^M)

2
Іноді поява несподіваних NULL символів викликається базовою функцією C, яка обробляє рядки. Це пояснення того, як C обробляє рядки, з якими ви пов’язані, пояснює, що внутрішньо C розмежовує рядки з a NULL. NULLs зустрічаються досить рідко в тексті, що робить його хорошим персонажем для цієї мети. Наслідком цього є те, що якщо програма C (vim) намагалася передати "порожню" рядок у внутрішню функцію C
the_velour_fog

2
наприклад, someFunction(arg1, "")де arg 2 був, "" тобто "пункт між цитатами, який буквально нічого -" порожній ". NULL може з'явитися, тому що його" додали "базовою реалізацією C, оскільки вона розмежувала рядок. Я не знаю як би ви це перевірили - але це
враховується

1
Дивіться також обговорення \rта \nвідмінності в:substitute .
Jamessan

Відповіді:


4

По-перше, дякую за цю дуже всебічну та продуману публікацію.

Після деяких випробувань я прийшов до такого висновку:

  1. Контрольні символи відображаються за допомогою позначення каретки: ^Mдля <CR>(повернення каретки) та ^Jдля <LF>(лінія каналу). У буферах <EOL>(кінець рядка) відображаються у вигляді нових рядків екрана та вводяться клавішею Enter. <EOL>залежить від формату файлу буфера: <EOL> = <CR>|<LF>|<CR><LF>для mac|unix|dosвідповідно.

  2. Під час редагування буфера завжди встановлюється формат файлу. Щоб змінити формат файлу відкритого буфера, ви можете скористатися такою командою, яка перетворює <EOL>:

    :set f[ile]f[ormat]=mac|unix|dos
    

    Крім перетворення <EOL>, ця команда перетворюється <LF>на <CR>зміну формату файлу з macна unix|dos, і навпаки, <CR>у <LF>зміну формату файлу з unix|dosна mac. Щоб побачити реальні байти буфера, ви можете скористатися наступною командою, яка перетворює текстове подання буфера в його шістнадцяткове представлення, використовуючи зручний шестидесятковий редактор xxd:

    :%!xxd
    
  3. У регістрах (що показали з командою :reg[isters]або :di[splay]) <EOL>завжди відображаються в вигляді ^J(але не всі ^Jце <EOL>), незалежно від формату файлу буфера. Однак <EOL>вони зберігаються як слід. Щоб мати можливість відрізнити візуально реальне ^J(тобто <LF>) від інших ^J(тобто <EOL>) у регістрах, ви можете використовувати таку команду, яка відображає шістнадцяткові значення замість позначення каретки контрольних символів, відмінних від <EOL>:

    :set d[ispla]y=uhex
    
  4. У шаблонах пошуку та рядках підстановки:

    \r = newline different from <EOL> (<CR> if <EOL> = <CR><LF>|<LF>, <LF> if <EOL> = <CR>)
    \n = <EOL>
    
  5. Скрізь:

    <C-V><C-M>|<C-V><EOL> = newline different from <EOL>
    <C-V><C-J> = <NUL>
    

    Це показує, що коли формат файлу є dos, ввести неможливо <LF>, оскільки <EOL> = <CR><LF>і <C-V><C-M>|<C-V><EOL> = <CR>.

  6. У рядках заміщення:

    • новий рядок, відмінний від <EOL>, трактується як <EOL>;

    • <EOL>які інтерпретуються , як <NUL>.

    Отже, згідно з 4., :%s[ubstitute]/\r/\r/gзамінює кожен новий рядок, відмінний від <EOL>буфера на <EOL>, а :%s[ubstitute]/\n/\n/gкожний <EOL>у буфері замінює на <NUL>.

  7. В поле пошуку регістр /і регістр команд :, <EOL>які перетворюються в

    • новий рядок, відмінний від <EOL>вставленого з реєстру з /<C-R>{register}або :<C-R>{register}відповідно;

    • <NUL>коли вставляється з реєстру з :let @/=@{register}або :let @:=@{register}відповідно.

  8. В буферах, відрізняється від перекладу рядка <EOL>будуть перетворені , щоб <EOL>при вставці з регістра , використовуючи i<C-R>{register}.

Чому Посилання рядка перетворюється в нульовий символ всередині реєстру пошуку та в командному рядку повернення перевезення?

Перш ніж скопіювати <LF>з безіменного реєстру "в інші регістри, потрібно ввести його <LF>та внести до реєстру ". Якщо формат файлу є unix, ви можете зробити це, використовуючи yyпорожній рядок; якщо формат файлу є mac, ви можете зробити це за допомогою i<C-V><C-M><Esc>yl; якщо формат файлу є dos, ви не можете ввести <LF>(див. 5.).

Тепер ваше твердження частково неправильне, оскільки

  • ви не використовуєте один і той же метод для копіювання <LF>з реєстру "в регістр пошуку /та регістр команд :. Ви використовуєте :let @/=@"для копіювання в реєстр /і :<C-R>"для копіювання в реєстр :. Використання /<C-R>"і :<C-R>"відповідно дасть вам однаковий результат ( <CR>) в обох випадках;

  • перетворення, <LF>яке відбувається за допомогою двох ваших різних методів копіювання, відбувається лише тоді, коли формат файлу є unix. Якщо mac, <LF>це НЕ конвертуються при копіюванні в реєстрі /або реєстрі :, і якщо dosви не можете навіть вхід <LF>.

Правильне твердження дано 7. Але я справді не знаю причин, які стоять за цим.


Чому це так важко зрозуміти ... Я досліджував декілька публікацій про SO і vim-SE та vim help, але не повністю послідовний і все ще плутаний.
Violapterin
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.