Dobrando pelo padrão de pesquisa regex

13

Eu tenho um arquivo de texto sem formatação com colunas de valores separadas por espaço em branco. Como isso:

AU 3030 .... ... ....  
AU 3031 .... ... ....  
AU 3032 .... ... .... 
AU 3033 .... ... .... 
IT 48100 ... .. .....
IT 40100 ... .. .....
IT 48123 ... .. .....
UK 3333 ... ... ..... 
UK 4444 ... ... .....
UK 5555 ... ... .....

Também recebi esse regex que corresponderá a qualquer linha adjacente com o mesmo valor na primeira coluna (suponha que o arquivo esteja classificado na primeira coluna), exceto a última:

/^\(\([A-Z0-9]\+\)\s\+.*\n\)\(\2\)\@=

(ou para torná-lo menos "cabeludo"):

/^\v([A-Z0-9]+)\s+.*\n(\1)@=

É possível dobrar linhas sobre a linha que não correspondeu? Tendo este resultado:

+-- 4 lines AU ....
+-- 3 lines IT ....
+-- 3 lines UK ....
guido
fonte

Respostas:

14

Faça set foldmethod=expre use 'foldexpr'para definir uma expressão de script vim que definirá os pontos de início da dobra.

set foldmethod=expr
set foldexpr=get(split(getline(v:lnum-1)),0,'')!=get(split(getline(v:lnum)),0,'')?'>1':'='

Isso parece mais complicado do que é, porque não podemos usar espaços com facilidade :set, mas com espaços e uma nova linha ou 2, parece:

get(split(getline(v:lnum - 1)), 0, '') != get(split(getline(v:lnum)), 0, '')
    \ ? '>1'
    \ : '='

Visão geral

Basicamente, isso compara a primeira palavra de cada linha com a linha anterior. Se as palavras forem diferentes, então a linha é o início da dobra >1,. Caso contrário, ele mantém o mesmo nível de dobra =,.

Glória dos Detalhes

  • set foldmethod=expr dizer ao Vim para usar uma expressão de script vim para determinar as dobras
  • 'foldexpr' A opção mantém a expressão de script vim
  • Avaliando a condição com um ternário que retorna >1quando uma dobra deve começar e =quando o nível da dobra deve continuar
  • v:lnumé a linha atual que 'foldexpr'está sendo executada para atualizar as dobras
  • Obtenha o conteúdo da linha atual ( v:lnum) e da linha anterior ( v:lnum - 1) viagetline()
  • Divida cada linha em palavras por split()
  • Use get()para obter o primeiro índice das palavras recém-divididas
  • Use um valor padrão ''no caso de uma linha em branco. por exemploget(words, 0, '')
  • Compare a primeira palavra da linha atual com a primeira palavra da linha anterior na parte da condição do ternário

Nota: este método pode ter alguns problemas de desempenho com documentos muito grandes

Para obter mais ajuda, consulte:

:h 'foldmethod'
:h 'foldexpr'
:h getline(
:h v:lnum
:h split(
:h get(
Peter Rincker
fonte