От :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 , который имеет немного другой ответ. Но мой, конечно, лучше ;-)