Lipat dengan pola pencarian regex

13

Saya mendapat file teks biasa dengan kolom nilai yang dipisahkan spasi. Seperti ini:

AU 3030 .... ... ....  
AU 3031 .... ... ....  
AU 3032 .... ... .... 
AU 3033 .... ... .... 
IT 48100 ... .. .....
IT 40100 ... .. .....
IT 48123 ... .. .....
UK 3333 ... ... ..... 
UK 4444 ... ... .....
UK 5555 ... ... .....

Saya juga mendapat regex ini yang akan cocok dengan baris yang berdekatan dengan nilai yang sama di kolom pertama (anggap file diurutkan pada kolom pertama) kecuali yang terakhir:

/^\(\([A-Z0-9]\+\)\s\+.*\n\)\(\2\)\@=

(atau untuk membuatnya kurang "berbulu"):

/^\v([A-Z0-9]+)\s+.*\n(\1)@=

Apakah mungkin untuk melipat garis di atas garis yang tidak cocok? Memiliki hasil ini:

+-- 4 lines AU ....
+-- 3 lines IT ....
+-- 3 lines UK ....
guido
sumber

Jawaban:

14

Lakukan set foldmethod=exprdan gunakan 'foldexpr'untuk mengatur ekspresi skrip vim yang akan menentukan titik awal lipat.

set foldmethod=expr
set foldexpr=get(split(getline(v:lnum-1)),0,'')!=get(split(getline(v:lnum)),0,'')?'>1':'='

Ini terlihat lebih rumit daripada itu, karena kita tidak dapat dengan mudah menggunakan spasi di :set, tetapi dengan spasi, dan baris baru atau 2, sepertinya:

get(split(getline(v:lnum - 1)), 0, '') != get(split(getline(v:lnum)), 0, '')
    \ ? '>1'
    \ : '='

Gambaran

Pada dasarnya ini membandingkan kata pertama dari setiap baris dengan baris sebelumnya. Jika kata-katanya berbeda maka garis mulai lipatan >1,. Kalau tidak, ia akan mempertahankan tingkat lipatan yang sama =,.

Kemuliaan Rincian

  • set foldmethod=expr untuk memberitahu Vim untuk menggunakan ekspresi skrip vim untuk menentukan lipatan
  • 'foldexpr' opsi menahan ekspresi skrip vim
  • Mengevaluasi kondisi dengan terner yang kembali >1ketika lipatan harus dimulai dan =ketika tingkat lipatan harus dilanjutkan
  • v:lnumadalah baris saat ini yang 'foldexpr'sedang berjalan untuk memperbarui lipatan
  • Dapatkan konten baris saat ini ( v:lnum) dan baris sebelumnya ( v:lnum - 1) melaluigetline()
  • Pisahkan setiap baris menjadi kata-kata melalui split()
  • Gunakan get()untuk mendapatkan indeks pertama dari kata-kata yang baru dipisah
  • Gunakan nilai default ''jika ada baris kosong. misalnyaget(words, 0, '')
  • Bandingkan kata pertama dari baris saat ini dengan kata pertama dari baris sebelumnya di bagian kondisi terner

Catatan: metode ini mungkin memiliki beberapa masalah kinerja dengan dokumen yang sangat besar

Untuk bantuan lebih lanjut lihat:

:h 'foldmethod'
:h 'foldexpr'
:h getline(
:h v:lnum
:h split(
:h get(
Peter Rincker
sumber