Від :help 'foldexpr'
:
Він оцінюється для кожного рядка для отримання рівня його складки
foldexpr
Оцінюється, тому вона повинна бути VIML код; не згадується про "спеціальний синтаксис" тощо. Результат цієї оцінки контролює те, що Vim вважає складовим чи ні.
Можливі значення є
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
Це не повний перелік; лише ті, які використовуються у прикладах вашого запитання. Дивіться :help foldexpr
повний список.
Спочатку
Перший досить простий, коли ми додаємо пробіли та видалимо зворотні косої риски, які нам потрібні для роботи в :set
команді:
getline(v:lnum)[0] == "\t"
getline(v:lnum)
отримує весь рядок.
[0]
отримує перший персонаж цього
- і
== "\t"
перевіряє, чи це символ вкладки.
- У VimL немає "true" або "false", він просто використовує "0" для false, а "1" - для true. Отже, якщо цей рядок починається з вкладки, він складається в foldlevel 1. Якщо це не так, він не знаходиться в складці (0).
Якщо ви розширите це для підрахунку кількості вкладок, у вас було б складання на основі відступу (принаймні, коли expandtab
це не ввімкнено).
Третя
Третя насправді не така вже й складна, як перша; як у першому прикладі, ми спочатку хочемо зробити його більш читабельним:
getline(v:lnum) =~ '^\s*$' && getline(v:lnum + 1) =~ '\S' ? '<1' : 1
- Ми отримуємо весь рядок с
getline(v:lnum)
- Ми збігаються як регулярний вираз з
=~
до '^\s*$'
; ^
якір до початку, \s
означає будь-який символ пробілу, *
означає повторити попередній нуль або більше разів і $
прив’язувати до кінця. Таким чином, це регулярне вираження збігається (повертає істину) для порожніх рядків або рядків з лише пробілом.
getline(v:lnum + 1)
отримує наступний рядок.
- Ми співставляємо це з тим
\S
, що відповідає будь-якому символу без пробілу в будь-якому місці цієї лінії.
- Якщо ці 2 умови істинні, ми оцінюємо в
<1
іншому випадку 1
. Це робиться з «потрійним» , if
відомої з C і деяких інших мовах: condition ? return_if_true : return_if_false
.
<1
означає складку, що закінчується на цій лінії, і 1
означає складну.
Отже, якщо ми закінчуємо згин, якщо рядок порожній, а наступний рядок не порожній. Інакше ми перебуваємо на рівні 1. Або, як :h foldexpr
сказано:
Це зробить складку з абзаців, розділених порожніми рядками
Четверте
Четвертий поводиться так само, як і третій, але робить це дещо по-іншому. Розширено, це:
getline(v:lnum - 1) =~ '^\s*$' && getline(v:lnum) =~ '\S' ? '>1' : 1
Якщо попередній рядок - це порожній рядок, а поточний рядок - це порожній рядок, ми починаємо >1
згин на цьому рядку ( ), якщо ні, то встановлюємо рівень згину на 1.
Післямова
Тож логіка на всіх 3-х прикладах насправді досить проста. Більшість труднощів виникає у відсутності пробілів та деякому використанні зворотньої косої риски.
Я підозрюю, що виклик функції має деякі накладні витрати, і оскільки це оцінюється для кожного рядка, який ви хочете мати гідну продуктивність. Я не знаю, наскільки велика різниця у сучасних машинах, і я рекомендував би використовувати функцію (як у другому прикладі), якщо у вас не виникнуть проблеми з продуктивністю. Пам'ятайте про Кнут: "передчасна оптимізація - корінь усього зла" .
Це питання також є у StackOverflow , на який є дещо інша відповідь. Але моє, звичайно, краще ;-)