Pengganti dengan vimscript murni (tanpa `: s`)

12

Saya memiliki yang berikut di vimrc saya:

func! AddSpaceBeforeEqual()
  s/\([a-z)_0-9"'\[\]]\)=/\1 =/ge
endfunc

Saya menggunakan vint untuk lint vimrc saya, dan mendapat peringatan berikut:

ProhibitCommandWithUnintendedSideEffect Hindari perintah dengan efek samping yang tidak diinginkan. Hindari penggunaan: s [ubstitute] saat memindahkan kursor dan mencetak pesan kesalahan. Fungsi yang disukai (seperti pencarian ()) lebih cocok untuk skrip. Untuk banyak perintah vim, ada fungsi yang melakukan hal yang sama dengan efek samping yang lebih sedikit. Lihat: fungsi bantu () untuk daftar fungsi bawaan. Panduan Gaya Vimscript Google

Namun, saya tidak berpikir bahwa mereka adalah cara untuk melakukan substitusi tanpa menggunakan :sperintah.

Misalnya, search()fungsi memberikan garis yang cocok dengan pola, tetapi tidak ada cara untuk melakukan substitusi. The substitute()Fungsi beroperasi pada string, dan tidak menggantikan pada seluruh file.

Haruskah saya menerapkan metode pengganti sendiri, atau apakah itu cara yang lebih cerdas untuk menulis ulang fungsi saya?

edi9999
sumber

Jawaban:

10

Alasannya memperingatkan Anda tentang efek samping yang tidak diinginkan adalah karena :substitutememindahkan kursor dan menimpa pencarian sebelumnya (jika digunakan di luar fungsi) . Namun, ini tidak berarti Anda tidak boleh menggunakannya, karena Anda dapat membalikkan efek samping :substitute. Sebagai contoh, berikut adalah fungsi yang saya buat yang menggunakan perintah pengganti untuk menghapus trailing spasi:

function! StripTrailingWhitespace()
    " Save cursor position
    let l:save = winsaveview()
    " Remove trailing whitespace
    %s/\s\+$//e
    " Move cursor to original position
    call winrestview(l:save)
    echo "Stripped trailing whitespace"
endfunction

Perhatikan bahwa Anda juga bisa menggunakan :markperintah untuk menyimpan posisi kursor, tetapi itu juga berarti Anda akan menimpa tanda yang Anda putuskan untuk digunakan. Saya belum pernah menggunakan vint sebelumnya, tetapi satu tip pada linter adalah Anda dapat menerima peringatan mereka dengan sebutir garam. Dalam hal ini, memang benar yang :substitutememiliki efek samping, tetapi mereka adalah efek samping yang dapat dicegah. Plus, sebenarnya tidak ada cara yang lebih baik untuk melakukan pencarian dan mengganti file.

Pohon cemara
sumber
6
Istilah pencarian yang terakhir digunakan secara otomatis dikembalikan setelah meninggalkan fungsi, jadi simpan & pulihkan yang seharusnya tidak diperlukan saat menggunakannya di dalam fungsi. Lihat:help function-search-undo
Martin Tournoij
1
alih-alih menggunakan winsaveview () / winrestview () alih-alih cursor ()
Christian Brabandt
9

Berikut ini adalah implementasi sederhana dari fungsi Anda, ditulis dengan substitute():

function! AddSpaceBeforeEqualInWholeBuffer()
    let l = 1
    for line in getline(1,"$")
        call setline(l, substitute(line, '\([^= ]\)=', '\1 =', "g"))
        let l = l + 1
    endfor
endfunction

Sesuaikan pola pencarian sesuai selera.

romainl
sumber
1

The :sperintah adalah pendekatan Vimscript murni.

Dugaan saya adalah peringatan hanya berarti, bahwa kursor kemungkinan besar akan salah posisi setelah penggunaannya (yang Anda dapat mengelak dengan menggunakan winsaveview()fungsi sebelum dan perintah winrestview()setelah penggunaannya). Anda juga harus menjaga kemungkinan kesalahan yang mungkin terjadi. Ini biasanya ditangani dengan menggunakan ebendera. Juga kita perlu mengurus beberapa pengaturan seperti gdefaultpengaturan, yang membalikkan arti gbendera.

Orang perlu mengurus hal-hal spesifik itu dan itu mungkin merupakan akar penyebab dari peringatan itu. Tetapi itu tidak berarti menghindari penggunaan :sperintah. Tidak apa-apa menggunakan :sperintah, jika Anda ingin mengganti sesuatu di buffer saat ini.

(Catatan, seseorang tentu saja dapat mengulangi semua baris dan menggunakan pendekatan pencarian () / getline () / setline (). Tapi itu biasanya lebih lambat.)

Christian Brabandt
sumber