От :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. Поэтому, если эта строка начинается с вкладки, она складывается на уровне 1 сгиба. Если нет, она не в сгибе (0).
Если бы вы расширили это, чтобы подсчитать количество вкладок, у вас будет сворачивание на основе отступов (по крайней мере, когда expandtabне включено).
В третьих
Третий действительно не намного сложнее, чем первый; как и в первом примере, мы сначала хотим сделать его более читабельным:
getline(v:lnum) =~ '^\s*$' && getline(v:lnum + 1) =~ '\S' ? '<1' : 1
- Мы получаем всю строку с
getline(v:lnum)
- Мы сопоставляем это как регулярное выражение с
=~to '^\s*$'; ^привязки к началу, \sозначает любой символ пробела, *означает повторение предыдущего нуля или более раз и $привязку к концу. Таким образом, это регулярное выражение соответствует (возвращает true) для пустых строк или строк только с пробелами .
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.
Послесловие
Таким образом, логика на всех трех примерах действительно проста. Большая часть трудностей заключается в недостатке пробелов и использовании обратной косой черты.
Я подозреваю, что вызов функции имеет некоторые издержки, и, поскольку он оценивается для каждой строки, вы хотите иметь достойную производительность. Я не знаю, насколько велика разница на современных машинах, и рекомендую использовать функцию (как во втором примере), если у вас нет проблем с производительностью. Помните Кнута: «преждевременная оптимизация - корень всего зла» .
Этот вопрос также на StackOverflow , который имеет немного другой ответ. Но мой, конечно, лучше ;-)