De :help 'foldexpr'
:
Il est évalué pour chaque ligne pour obtenir son niveau de pli
Le foldexpr
est évalué, il doit donc être du code VimL; il n'est fait aucune mention de "syntaxe spéciale" ou similaire. Le résultat de cette évaluation contrôle ce que Vim considère comme un pli ou non.
Les valeurs possibles sont
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
Ce n'est pas la liste complète; juste ceux utilisés dans les exemples de votre question. Voir :help foldexpr
pour la liste complète.
Première
Le premier est assez simple une fois que nous avons ajouté des espaces et supprimé les barres obliques inverses dont nous avons besoin pour que cela fonctionne dans une :set
commande:
getline(v:lnum)[0] == "\t"
getline(v:lnum)
obtient la ligne entière.
[0]
obtient le premier caractère de cette
- et
== "\t"
vérifie s'il s'agit d'un caractère de tabulation.
- VimL n'a pas "vrai" ou "faux", il utilise simplement "0" pour faux et "1" pour vrai. Donc, si cette ligne commence par une tabulation, elle est pliée au niveau de pliage 1. Si ce n'est pas le cas, elle n'est pas dans un pli (0).
Si vous étendez ceci pour compter le nombre d'onglets, vous auriez un pliage basé sur l'indentation (au moins, lorsqu'il expandtab
n'est pas activé).
Troisième
Le troisième n'est vraiment pas beaucoup plus compliqué que le premier; comme avec le premier exemple, nous voulons d'abord le rendre plus lisible:
getline(v:lnum) =~ '^\s*$' && getline(v:lnum + 1) =~ '\S' ? '<1' : 1
- Nous obtenons toute la gamme avec
getline(v:lnum)
- Nous associons cela comme une expression rationnelle avec
=~
à '^\s*$'
; ^
ancres au début, \s
signifie n'importe quel caractère d'espacement, *
signifie répéter le zéro précédent ou plusieurs fois, et $
ancres à la fin. Donc, cette expression régulière correspond (renvoie vrai) pour les lignes vides ou les lignes avec uniquement des espaces.
getline(v:lnum + 1)
obtient la ligne suivante .
- Nous faisons correspondre cela à
\S
, ce qui correspond à tout caractère non blanc n'importe où sur cette ligne.
- Si ces 2 conditions sont vraies, nous évaluons à
<1
, sinon 1
. Cela se fait avec le "ternaire" if
connu de C et d'autres langages:condition ? return_if_true : return_if_false
.
<1
signifie qu'un pli se termine sur cette ligne et 1
signifie un niveau de pli.
Donc, si nous terminons un pli si la ligne est vide et la ligne suivante n'est pas vide. Sinon, nous sommes au niveau 1. Ou, comme le :h foldexpr
dit:
Cela fera un repli des paragraphes séparés par des lignes vides
Quatrième
Le quatrième se comporte de la même manière que le troisième, mais le fait d'une manière légèrement différente. Développé, c'est:
getline(v:lnum - 1) =~ '^\s*$' && getline(v:lnum) =~ '\S' ? '>1' : 1
Si la ligne précédente est une ligne vierge et que la ligne actuelle est une ligne non vide, nous commençons un pli sur cette ligne ( >1
), sinon, nous mettons le niveau de pli à 1.
Épilogue
Donc, la logique sur les 3 exemples est vraiment assez simple. La majeure partie de la difficulté vient du manque d'espace et d'une partie de l'utilisation de la barre oblique inverse.
Je soupçonne que l'appel d'une fonction a une surcharge, et puisque cela est évalué pour chaque ligne, vous voulez avoir une performance décente. Je ne sais pas à quel point la différence est grande sur les machines modernes, et je recommanderais d'utiliser une fonction (comme dans le 2ème exemple), sauf si vous avez des problèmes de performances. Rappelez-vous The Knuth: "l'optimisation prématurée est la racine de tout mal" .
Cette question se trouve également sur StackOverflow , qui a une réponse légèrement différente. Mais le mien est bien sûr meilleur ;-)