De :help 'foldexpr'
:
É avaliado para cada linha para obter seu nível de dobra
O foldexpr
é avaliado, portanto, ele precisa ser código VimL; não há menção a "sintaxe especial" ou algo parecido. O resultado dessa avaliação controla o que o Vim considera uma dobra ou não.
Valores possíveis são
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
Esta não é a lista completa; apenas os usados nos exemplos da sua pergunta. Veja :help foldexpr
a lista completa.
Primeiro
O primeiro é bastante simples quando adicionamos alguns espaços e removemos as barras invertidas necessárias para que isso funcione em um :set
comando:
getline(v:lnum)[0] == "\t"
getline(v:lnum)
recebe a linha inteira.
[0]
recebe o primeiro personagem disso
- e
== "\t"
verifica se esse é um caractere de tabulação.
- O VimL não possui "true" ou "false", apenas usa "0" para false e "1" para true. Portanto, se essa linha começar com uma guia, ela será dobrada no nível da dobra 1. Caso contrário, ela não estará na dobra (0).
Se você expandir isso para contar o número de guias, terá dobras baseadas em recuo (pelo menos quando expandtab
não estiver ativado).
Terceiro
O terceiro, na verdade, não é muito mais complicado que o primeiro; como no primeiro exemplo, primeiro queremos torná-lo mais legível:
getline(v:lnum) =~ '^\s*$' && getline(v:lnum + 1) =~ '\S' ? '<1' : 1
- Temos toda a linha com
getline(v:lnum)
- Nós combinamos isso como uma expressão regular com
=~
to '^\s*$'
; ^
âncoras no início, \s
significa qualquer caractere de espaço em branco, *
significa repetir o zero anterior ou mais vezes e $
ancora no final. Portanto, esse regexp corresponde (retorna true) para linhas em branco ou linhas com apenas espaço em branco.
getline(v:lnum + 1)
obtém a próxima linha.
- Nós combinamos isso com
\S
, que corresponde a qualquer caractere que não seja um espaço em branco em qualquer lugar desta linha.
- Se essas 2 condições forem verdadeiras, avaliamos como
<1
, caso contrário 1
,. Isso é feito com o "ternário" if
conhecido a partir de C e outras linguagens: condition ? return_if_true : return_if_false
.
<1
significa que uma dobra termina nessa linha e significa uma dobra no 1
nível.
Portanto, se encerrarmos uma dobra, se a linha estiver em branco e a próxima linha não estiver em branco. Caso contrário, estamos no nível de dobra 1. Ou, como :h foldexpr
diz:
Isso fará uma dobra de parágrafos separados por linhas em branco
Quarto
O quarto se comporta da mesma forma que o terceiro, mas de uma maneira ligeiramente diferente. Expandido, é:
getline(v:lnum - 1) =~ '^\s*$' && getline(v:lnum) =~ '\S' ? '>1' : 1
Se a linha anterior for uma linha em branco e a linha atual for uma linha não em branco, iniciaremos uma dobra nessa linha ( >1
); caso contrário, definiremos o nível de dobra como 1.
Posfácio
Portanto, a lógica dos três exemplos é realmente bastante simples. A maior parte da dificuldade está na falta de espaços e em parte do uso da barra invertida.
Suspeito que chamar uma função tenha alguma sobrecarga, e como isso é avaliado para cada linha que você deseja ter um desempenho decente. Porém, não sei quão grande é a diferença nas máquinas modernas e recomendo que você use uma função (como no segundo exemplo), a menos que tenha problemas de desempenho. Lembre-se de Knuth: "a otimização prematura é a raiz de todo mal" .
Esta pergunta também está no StackOverflow , que tem uma resposta um pouco diferente. Mas o meu é obviamente melhor ;-)