Recolher dobras do vim em uma única linha, semelhante ao texto Atom ou Sublime

13

Sou fã da maneira como o Atom e o Sublime Text lidam com a dobra de linhas, onde a primeira linha de cada dobra é visível (completa com destaque de sintaxe) e um marcador é anexado ao final da linha que indica a dobra.

Veja a captura de tela abaixo comparando a dobradura de travessão do Vim (em cima) com a do Atom (em baixo):Dobragem de código Vim vs. Atom

O Vim dedica duas linhas para cada dobra. A primeira linha serve como cabeçalho e a segunda linha descreve algumas informações sobre a dobra (número de linhas e texto dentro da dobra).

O Atom usa apenas uma linha e usa um pequeno marcador no final da linha para indicar a dobra, juntamente com a cor adicionada aos números de linha à esquerda. O estilo dobrável do Atom usa menos espaço na tela, mas ainda comunica todas as informações que realmente preciso.

Sou parcial com o estilo de dobramento Atom. Parece mais limpo e consistente, na minha opinião, principalmente ao listar vários métodos ou atributos em uma linha (como na captura de tela acima).

Existe uma maneira de aproximar aproximadamente o estilo de dobramento do Atom no Vim?

Mike Hearn
fonte
1
Acho que é porque suas dobras não começam com a linha que contém os colchetes de abertura. O Vim usa apenas o texto da dobra na linha em que a dobra começa. Veja, por exemplo, como colocação de cinta afeta-lo em C: imgur.com/3h70dPf,wfCLPm7
Muru
Mas este é Python, sem chaves ( from __future__ import braces) ... Como você configurou a dobragem? E você pode colar esse trecho de código (ou outro que demonstre o problema)? O Vim dobra para uma única linha, mas, como o muru mencionou, suas dobras começam uma linha tarde.
Martin Tournoij
@Carpetsmoker os aparelhos são apenas para ilustração de onde a dobra começa. O mesmo efeito pode ser visto em, digamos, Haskell.
muru
@ MikeHearn Minha resposta anterior estava completamente incorreta. Atualizei-o para incluir uma solução para o problema.
24515 Rich

Respostas:

12

Duas linhas vs. uma linha

No Vim, todas as linhas dentro de uma dobra serão recolhidas em uma única linha, e a 'foldtext'opção determina a sinopse dessas linhas (geralmente traços, o número de linhas dobradas e o conteúdo das primeiras (ou todas) linhas).

No seu exemplo, no Vim, apenas o {...}próprio bloco de parâmetros é dobrado; a linha acima (que usa os parâmetros) não faz parte da dobra. Por outro lado, no outro editor, essa linha usando os parâmetros pertence à dobra e seu texto da dobra (para usar a terminologia do Vim) é o conteúdo dessa linha mais o marcador anexado.

Adaptação

No Vim, as dobras podem ser geradas por diferentes meios (consulte :help fold-methods) e dependem 'filetype'do buffer. A dificuldade de incluir a linha acima na dobra depende disso; verifique com :setlocal foldmethod?. Com a dobradura de indentação , não há nada que você possa influenciar; você precisa mudar para outro método. Para dobrar sintaxe , isso significaria adaptar as definições de sintaxe e poderia ser muito complicado. Você terá mais sorte se uma expressão for usada, mas isso ainda significaria entender e alterar a lógica. (É improvável que o autor do plugin do tipo de arquivo tenha fornecido uma configuração para influenciar isso.)

Destaque de sintaxe da linha dobrada

Infelizmente, isso não é possível. O Vim sempre usa o Foldedgrupo de destaque para toda a linha dobrada. Você pode ajustá-lo através de :highlightcomandos no seu ~/.vimrc, mas a diferenciação individual da sintaxe será perdida.

Ingo Karkat
fonte
5

O Vim já exibe dobras como uma única linha. No entanto, nas indentdobras de Vim , todas as linhas que têm o mesmo recuo são incluídas em uma dobra. Portanto, na sua captura de tela, as linhas às quais você se refere como "cabeçalhos" (por exemplo, a que está começando collection_base_url) não estão dentro das dobras.

Você pode obter algo semelhante à dobra do Atom usando o Vim foldexpr foldmethod:

" Finds the indent of a line. The indent of a blank line is the indent of the
" first non-blank line above it.
function! FindIndent(line_number, indent_width)
    " Regular expression for a "blank" line
    let regexp_blank = "^\s*$"

    let non_blank_line = a:line_number
    while non_blank_line > 0 && getline(non_blank_line) =~ regexp_blank
        let non_blank_line = non_blank_line - 1
    endwhile
    return indent(non_blank_line) / a:indent_width
endfunction

" 'foldexpr' for Atom-style indent folding
function! AtomStyleFolding(line_number)
    let indent_width = &shiftwidth

    " Find current indent
    let indent = FindIndent(a:line_number, indent_width)

    " Now find the indent of the next line
    let indent_below = FindIndent(a:line_number + 1, indent_width)

    " Calculate indent level
    if indent_below > indent
        return indent_below
    elseif indent_below < indent
        return "<" . indent
    else
        return indent
    endif
endfunction

set foldexpr=AtomStyleFolding(v:lnum)
set foldmethod=expr

Isso define uma expressão de dobra (consulte :help fold-expr) da seguinte maneira:

  • Para linhas imediatamente anteriores às linhas recuadas, ele retorna o recuo do bloco a seguir.
  • Para linhas recuadas, ele retorna o recuo. (Dividido pela largura de turno para que cada nível de recuo aumente o valor retornado em 1)
  • Para linhas no final de um bloco de linhas recuadas, ele retorna uma string "<N", onde N é definido como recuo. Isso diz ao Vim que uma dobra do nível N termina nessa linha.

Atualizar

@alxndr pergunta nos comentários se é possível estender isso para incluir os ends ultrapassados ​​de Ruby dentro das dobras. Você pode começar substituindo a " Calculate indent levelseção pelo seguinte:

if indent_below > indent
    return indent_below
elseif getline(a:line_number) =~ '^\s*end\s*$'
    return "<" . (indent + 1)
else
    return indent
endif

Como é, essa não é a solução mais robusta (por exemplo, ela falhará se a endinstrução estiver na mesma linha, após ponto e vírgula). Você pode ajustar a expressão regular e o código ao redor para resolver isso, mas como agora você está analisando a sintaxe real do arquivo, suspeito que as coisas possam ficar muito mais complicadas antes de você ter uma boa solução.

Rico
fonte
Ótima abordagem. Essa resposta poderia ser generalizada para também manipular, digamos, o Ruby, com o seu desatualizado endpara terminar um bloco?
Alxndr
1
@alxndr Eu editei minha resposta com alguma discussão.
Ricos
@ Rich: Também acho a dobra de texto sublime que mostra apenas uma marca ...no final da linha como símbolo de um bloco de texto dobrado muito útil e faz menos distrações do que é necessário destacar toda a primeira linha do bloco de texto como no vim. Eu tentei sua dobra acima com o comportamento de dobra padrão do vim, simples não funciona. Como ter dobra que dê uma marca no final da primeira linha do bloco de texto com python? Devo abrir uma nova pergunta? Acabei de testar novamente sua dobra, é realmente trabalhar muito bem com a linha de recuo. super Obrigado.
Tuyen Pham
Isso é incrível! Eu estive procurando por algo que funcione no modo org, como dobrar e isso ajuda muito!
Priomsrb 02/04/19