Dlaczego przesunięcie wiersza jest konwertowane na znak Null w rejestrze wyszukiwania i na znak powrotu karetki w wierszu poleceń?

12

Jeśli mam następujący tekst:

foo
bar

Wybieram go wizualnie i kopiuję.
Tekst jest teraz przechowywany w rejestrze bez nazwy "i oto jego zawartość (wynik :reg "):

""   foo^Jbar^J

Zgodnie z tym wykresem wydaje się, że ^Jjest to notacja karetki dla przesuwania linii.

Jeśli chcę powielić rejestr nienazwany w arejestrze, wpisując: :let @a = @"
Oto jego zawartość (wynik :reg a):

"a   foo^Jbar^J

Nie zmieniło się.

Jeśli teraz powielę go w rejestrze wyszukiwania, wpisując :let @/ = @", oto jego zawartość (wynik :reg /):

"/   foo^@bar^@

Zgodnie z poprzednim wykresem wydaje się, że ^@jest to znak karetki dla znaku Null.
Dlaczego wysuw wiersza jest automatycznie konwertowany na znak Null w rejestrze wyszukiwania (ale nie w arejestrze)?

Jeśli wstawię nienazwany rejestr w wierszu polecenia (lub w środku wyszukiwania po /), wpisując :<C-R>", oto co jest wstawiane:

:foo^Mbar^M

Ponownie, zgodnie z ostatnią tabelą, ^Mwydaje się być notacją karetki zwrotu powozu.
Dlaczego wiersz wiersza jest automatycznie przekształcany w wiersz powrotu karetki w wierszu polecenia?

Edytuj :

Zwykle można wstawić dosłowny znak kontrolny, wpisując:
<C-V><C-{character in caret notation}>

Na przykład możesz wstawić literał <C-R>, pisząc <C-V><C-R>.
Możesz to zrobić dla pozornie dowolnej postaci kontrolnej.
Zauważyłem jednak, że nie jestem w stanie wstawić dosłownego pliku LF do bufora lub wiersza poleceń, ponieważ jeśli napiszę: <C-V><C-J>wstawi ^@, zamiast znaku null ^J.
Czy z tego samego powodu LF jest konwertowany na NUL w rejestrze wyszukiwania?

Edycja 2 :

W :h key-notationmożemy przeczytać to:

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

stored as 10Część na pierwszej linii, a used for <Nul>na drugiej linii może wskazywać, że istnieje jakiś rodzaj zachodzenia między LF i NUL, i że mogą być interpretowane jako samo. Ale nie mogą być tym samym, ponieważ po wykonaniu poprzedniego polecenia :let @/ = @", jeśli piszę nw trybie normalnym, aby przejść do następnego wystąpienia 2 linii fooi barzamiast uzyskania pozytywnego dopasowania, pojawia się następujący komunikat o błędzie:

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

Poza tym ten link wydaje się wyjaśniać, że NUL oznacza koniec łańcucha, podczas gdy LF oznacza koniec linii w pliku tekstowym.

A jeśli NUL jest, stored as 10jak mówi pomoc, czyli taki sam kod jak dla LF, w jaki sposób Vim może rozróżnić 2?

Edycja 3 :

Być może LF i NUL są kodowane tym samym kodem dziesiętnym 10, jak mówi pomoc. A Vim robi różnicę między tymi 2 dzięki kontekstowi. Jeśli napotka znak, którego kod dziesiętny znajduje się 10w buforze lub dowolnym rejestrze, z wyjątkiem rejestrów wyszukiwania i poleceń, interpretuje go jako LF.
Ale w rejestrze wyszukiwania ( :reg /) interpretuje to jako NUL, ponieważ w kontekście wyszukiwania Vim szuka tylko ciągu znaków, w którym koncepcja end of line in a filenie ma sensu, ponieważ ciąg nie jest plikiem (co jest dziwne, ponieważ można nadal używasz atomu \nw szukanym wzorze, ale może to tylko funkcja silnika wyrażeń regularnych?). Więc automatycznie interpretuje 10jako NUL, ponieważ jest to najbliższa koncepcja ( end of stringend of line).

I w ten sam sposób, w wierszu poleceń / register register ( :reg :) interpretuje kod 10jako CR, ponieważ pojęcie end of line in a filetutaj nie ma sensu. Najbliższa koncepcja jest end of commandtaka, że ​​Vim interpretuje 10jako CR, ponieważ uderzanie Enterjest sposobem na zakończenie / wykonanie polecenia, a CR jest tym samym co uderzanie Enter, ponieważ po wstawieniu dosłownego za pomocą <C-V><Enter>, ^Mwyświetla się.

Może interpretacja znaku, którego kod 10zmienia się zgodnie z kontekstem:

  • koniec linii w buforze ( ^J)
  • koniec ciągu w wyszukiwaniu ( ^@)
  • koniec polecenia w wierszu polecenia ( ^M)
saginaw
źródło
2
Czasami pojawienie się nieoczekiwanych NULL znaków jest spowodowane podstawową funkcją C, która obsługuje ciągi znaków. To objaśnienie, w jaki sposób C przetwarza ciągi, które łączysz, wyjaśnia, że ​​wewnętrznie C rozgranicza ciągi za pomocą NULL. NULLs występują w tekście rzadko, co sprawia, że ​​jest to dobry znak do tego celu. Konsekwencją tego jest to, że jeśli program C (vim) próbował przekazać „pusty” ciąg do wewnętrznej funkcji C
the_velour_fog
2
np. someFunction(arg1, "")gdzie arg 2 to "" np. „pozycja między cudzysłowami, która jest dosłownie niczym -„ pusta ”. Może pojawić się wartość NULL, ponieważ została„ dodana ”przez podstawową implementację języka C, ponieważ rozgraniczała ciąg. Nie wiem jak byś to sprawdził - ale wydaje się, że to możliwa przyczyna.
the_velour_fog
1
Zobacz także dyskusję \ri \nróżnice w:substitute .
jamessan 10.10.16

Odpowiedzi:

5

Po pierwsze, dziękuję za ten bardzo obszerny i przemyślany post.

Po kilku testach doszedłem do tego wniosku:

  1. Znaki kontrolne są wyświetlane za pomocą notacji karetki: ^Mdla <CR>(powrót karetki) i ^Jdla <LF>(przesunięcie wiersza). W buforach <EOL>(koniec linii) są wyświetlane jako nowe linie ekranu i są wprowadzane za pomocą klawisza Enter. <EOL>zależy od formatu pliku bufora: <EOL> = <CR>|<LF>|<CR><LF>dla mac|unix|dosodpowiednio.

  2. Podczas edycji bufora format pliku jest zawsze ustawiony. Aby zmienić format pliku otwartego bufora, możesz użyć następującego polecenia, które konwertuje <EOL>:

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

    Oprócz konwertowania <EOL>to polecenie konwertuje <LF>na <CR>przy zmianie formatu pliku z macna unix|dosi odwrotnie <CR>na <LF>przy zmianie formatu pliku z unix|dosna mac. Aby zobaczyć rzeczywiste bajty bufora, możesz użyć następującego polecenia, które przekształca tekstową reprezentację bufora na jego reprezentację szesnastkową za pomocą wygodnego edytora szesnastkowego xxd:

    :%!xxd
    
  3. W rejestrach (wykazali za pomocą polecenia :reg[isters]lub :di[splay]) <EOL>zawsze są wyświetlane jako ^J(ale nie wszystkie ^J<EOL>), niezależnie od formatu pliku bufora. Jednak <EOL>przechowywane tak, jak powinny. Aby móc odróżnić wizualnie rzeczywiste ^J(tj. <LF>) Od innych ^J(tj. <EOL>) W rejestrach, możesz użyć następującego polecenia, które wyświetla wartości szesnastkowe zamiast notacji znakowej znaków kontrolnych innych niż <EOL>:

    :set d[ispla]y=uhex
    
  4. W wzorach wyszukiwania i ciągach podstawień:

    \r = newline different from <EOL> (<CR> if <EOL> = <CR><LF>|<LF>, <LF> if <EOL> = <CR>)
    \n = <EOL>
    
  5. Wszędzie:

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

    To pokazuje, że gdy format pliku dosjest niemożliwy, nie można go wprowadzić <LF>, ponieważ <EOL> = <CR><LF>i <C-V><C-M>|<C-V><EOL> = <CR>.

  6. W ciągach podstawienia:

    • nowa linia inna niż <EOL>interpretowane jako <EOL>;

    • <EOL>interpretowane jako <NUL>.

    Tak więc, zgodnie z 4., :%s[ubstitute]/\r/\r/gzamienia każdą nową <EOL>linię inną niż w buforze na <EOL>, a :%s[ubstitute]/\n/\n/gzastępuje każdą <EOL>w buforze na <NUL>.

  7. W poszukiwaniu rejestru /ewidencji i poleceń :, <EOL>konwertowane do

    • nowa linia różni się od <EOL>po wstawieniu z rejestru z /<C-R>{register}lub :<C-R>{register}odpowiednio;

    • <NUL>po wstawieniu z rejestru za pomocą :let @/=@{register}lub :let @:=@{register}odpowiednio.

  8. W buforach nowa linia inna niż <EOL>jest konwertowana na <EOL>po wstawieniu z rejestru za pomocą i<C-R>{register}.

Dlaczego przesunięcie wiersza jest konwertowane na znak Null w rejestrze wyszukiwania i na znak powrotu karetki w wierszu poleceń?

Przed skopiowaniem <LF>z nienazwanego rejestru "do innych rejestrów, musisz wprowadzić <LF>i umieścić go w rejestrze ". Jeśli format pliku to unix, możesz to zrobić, używając yypustej linii; jeśli format pliku to mac, możesz to zrobić za pomocą i<C-V><C-M><Esc>yl; jeśli format pliku to dos, nie można wprowadzić danych <LF>(porównaj 5.).

Teraz twoje stwierdzenie jest częściowo błędne

  • nie używasz tej samej metody do kopiowania <LF>z rejestru "do rejestru wyszukiwania /i rejestru poleceń :. Używasz :let @/=@"do kopiowania do rejestru /i :<C-R>"do kopiowania do rejestru :. Użycie /<C-R>"i :<C-R>"odpowiednio da ci ten sam wynik ( <CR>) w obu przypadkach;

  • konwersje, <LF>które odbywają się za pomocą dwóch różnych metod kopiowania, zachodzą tylko wtedy, gdy format pliku jest unix. Jeśli tak mac, nie<LF> jest konwertowany po skopiowaniu do rejestru lub rejestru , a jeśli tak , nie można nawet wprowadzić danych ./:dos<LF>

Właściwe stwierdzenie podaje 7. Ale tak naprawdę nie znam powodów.

Maggyero
źródło
Dlaczego to jest tak trudne do zrozumienia ... Przeszukałem kilka postów na temat SO i vim-SE i pomocy vim, ale nie do końca spójne i wciąż zdezorientowane.
Violapterin