Dari :help 'foldexpr'
:
Itu dievaluasi untuk setiap baris untuk mendapatkan tingkat lipatannya
The foldexpr
dievaluasi, sehingga perlu kode VimL; tidak disebutkan "sintaks khusus" atau sejenisnya. Hasil evaluasi ini mengontrol apa yang dianggap Vim sebagai lipatan atau tidak.
Nilai yang mungkin adalah
0 the line is not in a fold
1, 2, .. the line is in a fold with this level
"<1", "<2", .. a fold with this level ends at this line
">1", ">2", .. a fold with this level starts at this line
Ini bukan daftar lengkap; hanya yang digunakan dalam contoh di pertanyaan Anda. Lihat :help foldexpr
daftar lengkapnya.
Pertama
Yang pertama cukup sederhana setelah kita menambahkan beberapa spasi dan menghapus garis miring terbalik yang kita perlukan agar ini berfungsi dalam :set
perintah:
getline(v:lnum)[0] == "\t"
getline(v:lnum)
mendapat seluruh baris.
[0]
mendapat karakter pertama dari itu
- dan
== "\t"
memeriksa apakah itu karakter tab.
- VimL tidak memiliki "true" atau "false", ia hanya menggunakan "0" untuk false, dan "1" untuk true. Jadi jika baris ini dimulai dengan sebuah tab, itu dilipat di foldlevel 1. Jika tidak, itu tidak dalam flip (0).
Jika Anda ingin memperluas ini untuk menghitung jumlah tab Anda akan memiliki lipatan berbasis lekukan (setidaknya, ketika expandtab
tidak diaktifkan).
Ketiga
Yang ketiga benar-benar tidak jauh lebih rumit dari yang pertama; seperti contoh pertama, pertama-tama kita ingin membuatnya lebih mudah dibaca:
getline(v:lnum) =~ '^\s*$' && getline(v:lnum + 1) =~ '\S' ? '<1' : 1
- Kami mendapat seluruh garis dengan
getline(v:lnum)
- Kami cocok bahwa sebagai regexp dengan
=~
untuk '^\s*$'
; ^
jangkar ke awal, \s
berarti karakter spasi putih, *
berarti mengulangi nol sebelumnya atau lebih banyak kali, dan $
jangkar ke akhir. Jadi regexp ini cocok (mengembalikan true) untuk baris kosong atau baris dengan spasi kosong saja .
getline(v:lnum + 1)
mendapat baris berikutnya .
- Kami mencocokkan ini dengan
\S
, yang cocok dengan karakter non-spasi putih mana pun di baris ini.
- Jika 2 kondisi ini benar, kami mengevaluasi
<1
, jika tidak 1
,. Hal ini dilakukan dengan "terner" if
diketahui dari C dan beberapa bahasa lain: condition ? return_if_true : return_if_false
.
<1
berarti lipatan berakhir pada garis ini, dan 1
berarti lipatan tingkat satu.
Jadi, Jika kita mengakhiri lipatan jika garis kosong dan baris berikutnya tidak kosong. Kalau tidak, kita berada di foldlevel 1. Atau, seperti yang :h foldexpr
dikatakan:
Ini akan membuat lipatan paragraf dipisahkan oleh garis kosong
Keempat
Yang keempat berperilaku sama dengan yang ketiga, tetapi melakukannya dengan cara yang sedikit berbeda. Diperluas, ini:
getline(v:lnum - 1) =~ '^\s*$' && getline(v:lnum) =~ '\S' ? '>1' : 1
Jika garis sebelumnya adalah garis kosong, dan garis saat ini adalah garis tidak-kosong, kita mulai lipatan pada garis ini ( >1
), jika tidak, kita mengatur lipatan tingkat ke 1.
Kata penutup
Jadi logika pada ketiga contoh ini sangat sederhana. Sebagian besar kesulitan datang dalam kurangnya ruang dan beberapa penggunaan backslash.
Saya menduga bahwa memanggil fungsi memiliki beberapa overhead, dan karena ini dievaluasi untuk setiap baris Anda ingin memiliki kinerja yang layak. Saya tidak tahu seberapa besar perbedaannya pada mesin-mesin modern, dan saya sarankan Anda menggunakan fungsi (seperti pada contoh ke-2) kecuali Anda memiliki masalah kinerja. Remember The Knuth: "optimasi prematur adalah akar dari semua kejahatan" .
Pertanyaan ini juga ada di StackOverflow , yang memiliki jawaban yang sedikit berbeda. Tapi milikku tentu saja lebih baik ;-)