Mengapa Umpan Baris dikonversi menjadi karakter Null di dalam register pencarian dan menjadi Pengembalian Carriage di baris perintah?


12

Jika saya memiliki teks berikut:

foo
bar

Saya secara visual memilih dan menyalinnya.
Teks sekarang disimpan dalam register tanpa nama "dan di sini adalah isinya (keluaran dari :reg "):

""   foo^Jbar^J

Menurut bagan ini , tampaknya ^Jadalah notasi tanda untuk Line Feed.

Jika saya ingin menduplikasi register yang tidak disebutkan namanya dalam aregister dengan mengetik: :let @a = @"
Ini isinya (output dari :reg a):

"a   foo^Jbar^J

Itu tidak berubah.

Jika sekarang saya menggandakannya dalam register pencarian dengan mengetik :let @/ = @", berikut isinya (keluaran dari :reg /):

"/   foo^@bar^@

Menurut grafik sebelumnya, nampaknya ^@adalah tanda sisipan untuk karakter Null.
Mengapa Umpan Baris dikonversi secara otomatis menjadi karakter Null di dalam register pencarian (tetapi bukan aregister)?

Jika saya memasukkan register yang tidak disebutkan namanya pada baris perintah (atau di dalam pencarian setelah /), dengan mengetik :<C-R>", inilah yang dimasukkan:

:foo^Mbar^M

Sekali lagi, menurut grafik terakhir, ^Mtampaknya notasi tanda sisipan untuk Pengembalian Carriage.
Mengapa Umpan Garis diubah secara otomatis menjadi Pengembalian Carriage di baris perintah?

Edit :

Biasanya Anda dapat memasukkan karakter kontrol literal dengan mengetik:
<C-V><C-{character in caret notation}>

Misalnya, Anda bisa memasukkan literal <C-R>dengan mengetik <C-V><C-R>.
Anda dapat melakukannya untuk setiap karakter kontrol yang tampaknya.
Namun saya perhatikan bahwa saya tidak dapat memasukkan LF literal ke dalam buffer atau pada baris perintah, karena jika saya mengetik: <C-V><C-J>itu menyisipkan ^@, karakter nol, alih-alih ^J.
Apakah karena alasan yang sama LF diubah menjadi NUL di dalam register pencarian?

Edit 2 :

Di :h key-notation, kita bisa membaca ini:

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

Bagian stored as 10pada baris pertama dan used for <Nul>pada baris kedua dapat menunjukkan bahwa ada semacam tumpang tindih antara LF dan NUL, dan bahwa mereka dapat ditafsirkan sebagai hal yang sama. Tetapi mereka tidak bisa menjadi hal yang sama, karena setelah menjalankan perintah sebelumnya :let @/ = @", jika saya mengetik ndalam mode normal untuk mendapatkan kemunculan berikutnya dari 2 baris foodan bar, alih-alih mendapatkan kecocokan positif, saya memiliki pesan kesalahan berikut:

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

Selain itu tautan ini tampaknya menjelaskan bahwa NUL menunjukkan akhir suatu string, sedangkan LF menunjukkan akhir suatu baris dalam file teks.

Dan jika NUL adalah stored as 10seperti kata bantuan, yang merupakan kode yang sama dengan LF, bagaimana Vim dapat membuat perbedaan antara 2?

Edit 3 :

Mungkin LF dan NUL dikodekan dengan kode desimal yang sama 10,, seperti kata bantuan. Dan Vim membuat perbedaan antara 2 berkat konteksnya. Jika memenuhi karakter yang kode desimalnya ada 10di buffer atau register apa pun, kecuali pencarian dan register perintah, itu menafsirkannya sebagai LF.
Tetapi dalam register pencarian ( :reg /) ia mengartikannya sebagai NUL karena dalam konteks pencarian, Vim hanya mencari string di mana konsep end of line in a filetidak masuk akal karena string bukan file (yang aneh karena Anda dapat masih menggunakan atom \ndalam pola yang dicari, tapi mungkin itu hanya fitur mesin regex?). Jadi itu secara otomatis mengartikan 10sebagai NUL karena itu konsep terdekat ( end of stringend of line).

Dan dengan cara yang sama, pada baris perintah / register perintah ( :reg :) ia mengartikan kode 10sebagai CR, karena konsep end of line in a filetidak masuk akal di sini. Konsep terdekat end of commandbegitu Vim mengartikan 10sebagai CR, karena memukul Enteradalah cara untuk mengakhiri / mengeksekusi perintah dan CR sama dengan memukul Enter, karena ketika Anda memasukkan yang literal dengan <C-V><Enter>, ^Mditampilkan.

Mungkin interpretasi karakter yang kode-nya 10berubah sesuai dengan konteksnya:

  • akhir baris dalam buffer ( ^J)
  • akhir string dalam pencarian ( ^@)
  • akhir perintah pada baris perintah ( ^M)

2
Terkadang kemunculan NULL karakter yang tidak terduga disebabkan oleh fungsi C yang mendasarinya yaitu menangani string. Ini penjelasan tentang bagaimana C memproses string yang Anda terkait dengan menjelaskan bahwa secara internal C delimits string dengan NULL. NULLS jarang terjadi dalam teks sehingga membuatnya menjadi karakter yang baik untuk tujuan ini. Konsekuensi dari ini adalah bahwa jika program C (vim) mencoba untuk meneruskan string "kosong" ke fungsi C internal
the_velour_fog

2
misalnya di someFunction(arg1, "")mana arg 2 adalah "" "item antara tanda kutip, yang secara harfiah tidak ada -" kosong ". sebuah NULL dapat muncul, karena itu" ditambahkan "oleh implementasi C yang mendasari karena membatasi string. Saya tidak tahu bagaimana Anda akan memeriksa ini - tetapi terlintas dalam pikiran sebagai kemungkinan penyebab
the_velour_fog

Jawaban:


4

Pertama, terima kasih untuk posting yang sangat komprehensif dan penuh perhatian ini.

Setelah beberapa pengujian, saya sampai pada kesimpulan ini:

  1. Karakter kontrol ditampilkan menggunakan notasi caret: ^Mfor <CR>(carriage return) dan ^Juntuk <LF>(line feed). Dalam buffer, <EOL>(end-of-line) ditampilkan sebagai baris layar baru dan dimasukkan dengan tombol enter. <EOL>tergantung pada format file dari buffer: <EOL> = <CR>|<LF>|<CR><LF>untuk mac|unix|dosmasing - masing.

  2. Saat mengedit buffer, format file selalu diatur. Untuk mengubah format file buffer yang dibuka, Anda dapat menggunakan perintah berikut yang mengonversi <EOL>:

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

    Selain mengkonversi <EOL>, perintah ini bertobat <LF>untuk <CR>ketika mengubah format file dari macke unix|dos, dan sebaliknya, <CR>untuk <LF>saat mengubah format file dari unix|doske mac. Untuk melihat byte sebenarnya dari buffer, Anda dapat menggunakan perintah berikut yang mengubah representasi tekstual dari buffer menjadi representasi heksadesimal menggunakan editor heksadesimal nyaman xxd:

    :%!xxd
    
  3. Dalam register (menunjukkan dengan perintah :reg[isters]atau :di[splay]), <EOL>selalu ditampilkan sebagai ^J(tetapi tidak semua ^Jyang <EOL>), terlepas dari format file dari buffer. Namun <EOL>yang disimpan sebagaimana mestinya. Untuk dapat membedakan visual nyata ^J(yaitu <LF>) dari yang lain ^J(yaitu <EOL>) di register, Anda dapat menggunakan perintah berikut yang menampilkan nilai heksadesimal alih-alih notasi tanda kuret dari karakter kontrol yang berbeda dari <EOL>:

    :set d[ispla]y=uhex
    
  4. Dalam pola pencarian dan string pengganti:

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

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

    Ini menunjukkan bahwa ketika format file adalah dos, tidak mungkin untuk memasukkan <LF>, karena <EOL> = <CR><LF>dan <C-V><C-M>|<C-V><EOL> = <CR>.

  6. Dalam string pengganti:

    • baris baru yang berbeda dari <EOL>yang diartikan sebagai <EOL>;

    • <EOL>yang ditafsirkan sebagai <NUL>.

    Jadi, menurut 4., :%s[ubstitute]/\r/\r/gmengganti setiap baris baru yang berbeda dari <EOL>dalam buffer dengan <EOL>, sedangkan :%s[ubstitute]/\n/\n/gmenggantikan setiap <EOL>baris dalam buffer dengan <NUL>.

  7. Dalam pencarian mendaftar /dan perintah mendaftar :, <EOL>yang dikonversi ke

    • baris baru berbeda dari <EOL>ketika dimasukkan dari register dengan /<C-R>{register}atau :<C-R>{register}masing - masing;

    • <NUL>ketika dimasukkan dari register dengan :let @/=@{register}atau :let @:=@{register}masing - masing.

  8. Dalam buffer, baris baru yang berbeda dari <EOL>yang dikonversi ke <EOL>saat dimasukkan dari register menggunakan i<C-R>{register}.

Mengapa Umpan Baris dikonversi menjadi karakter Null di dalam register pencarian dan menjadi Pengembalian Carriage di baris perintah?

Sebelum menyalin <LF>dari register tanpa nama "ke register lain, Anda perlu memasukkan <LF>dan memasukkannya ke dalam register ". Jika format file adalah unix, Anda dapat melakukannya dengan menggunakan yybaris kosong; jika format file adalah mac, Anda dapat melakukannya dengan menggunakan i<C-V><C-M><Esc>yl; jika format file adalah dos, Anda tidak dapat memasukkan <LF>(lih. 5.).

Sekarang sebagian pernyataan Anda salah, karena

  • Anda tidak menggunakan metode yang sama untuk menyalin <LF>dari register "ke register pencarian /dan register perintah :. Anda menggunakan :let @/=@"untuk menyalin ke dalam register /dan :<C-R>"untuk menyalin ke dalam register :. Menggunakan /<C-R>"dan :<C-R>"masing - masing akan memberi Anda hasil yang sama ( <CR>) dalam kedua kasus;

  • konversi <LF>yang terjadi dengan dua metode salin berbeda hanya terjadi ketika format file unix. Jika mac, <LF>ini tidak diubah ketika disalin ke register /atau register :, dan jika dosAnda tidak dapat bahkan masukan <LF>.

Pernyataan yang benar diberikan oleh 7. Tapi saya benar-benar tidak tahu alasan di baliknya.


Mengapa ini sangat sulit untuk dipahami ... Saya telah meneliti melalui beberapa posting di SO dan vim-SE dan bantuan vim, tetapi tidak sepenuhnya konsisten, dan masih bingung.
Violapterin
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.