Réduire les plis vim en une seule ligne, semblable à Atom ou Sublime Text

13

Je suis fan de la façon dont Atom et Sublime Text gèrent le pliage de ligne, où la première ligne de chaque pli est visible (avec mise en évidence de la syntaxe), et un marqueur est ajouté à la fin de la ligne qui indique le pli.

Voir la capture d'écran ci-dessous comparant le pliage en retrait de Vim (en haut) à celui d'Atom (en bas):Pliage de code Vim vs Atom

Vim consacre deux lignes pour chaque pli. La première ligne sert d'en-tête et la deuxième ligne décrit certaines informations sur le pli (nombre de lignes et texte à l'intérieur du pli).

Atom n'utilise qu'une seule ligne et utilise un petit marqueur à la fin de la ligne pour indiquer le pli, ainsi que la couleur ajoutée aux numéros de ligne à gauche. Le style de pliage d'Atom utilise moins d'espace d'écran mais communique toujours toutes les informations dont j'ai vraiment besoin.

Je suis amateur du style de pliage Atom. Cela semble plus propre et plus cohérent, à mon avis, en particulier lors de la liste de plusieurs méthodes ou attributs dans une rangée (comme dans la capture d'écran ci-dessus).

Existe-t-il un moyen d'approcher approximativement le style de pliage d'Atom dans Vim?

Mike Hearn
la source
1
Je pense que c'est parce que vos plis ne commencent pas réellement par la ligne contenant les crochets d'ouverture. Vim utilise uniquement le texte du pli sur la ligne où le pli commence. Voir, par exemple, comment le placement de l'accolade l'affecte dans C: imgur.com/3h70dPf,wfCLPm7
muru
Mais c'est Python, pas d'accolades impliquées ( from __future__ import braces) ... Comment avez-vous configuré le pliage? Et pouvez-vous coller cet extrait de code (ou un autre qui illustre le problème)? Vim se replie sur une seule ligne, mais comme Muru l'a mentionné, vos plis commencent une ligne en retard.
Martin Tournoij
@Carpetsmoker les accolades sont uniquement à titre d'illustration de l'endroit où le pli commence. Le même effet peut être observé sur, disons, Haskell.
muru
@MikeHearn Ma réponse précédente était complètement incorrecte. Je l'ai mis à jour pour inclure une solution au problème.
Rich

Réponses:

12

Deux lignes contre une ligne

Dans Vim, toutes les lignes d'un pli seront réduites en une seule ligne, et l' 'foldtext'option détermine ensuite le synopsis de ces lignes (généralement des tirets, le nombre de lignes pliées et le contenu de la première (ou de toutes) les lignes).

Dans votre exemple, dans Vim, seul le {...}bloc de paramètres lui-même est plié; la ligne ci-dessus (qui utilise les paramètres) ne fait pas partie du pli. En revanche, dans l'autre éditeur, cette ligne utilisant les paramètres appartient au pli, et son texte de pliage (pour utiliser la terminologie Vim) est le contenu de cette ligne plus le marqueur ajouté.

L'adaptation

Dans Vim, les plis peuvent être générés par différents moyens (voir :help fold-methods), et dépendent 'filetype'du tampon. La difficulté d'inclure la ligne ci-dessus dans le pli en dépend; vérifier avec :setlocal foldmethod?. Avec le pliage en retrait , vous ne pouvez rien influencer; vous devez passer à une autre méthode. Pour le pliage de syntaxe , cela signifierait adapter les définitions de syntaxe, et pourrait être très délicat. Vous aurez plus de chance si une expression est utilisée, mais cela signifierait quand même comprendre et changer la logique. (Il est peu probable que l'auteur du plugin de type de fichier ait fourni une configuration pour influencer cela.)

Mise en évidence de la syntaxe de la ligne pliée

Ce n'est malheureusement pas possible du tout. Vim utilise toujours le Foldedgroupe de surbrillance pour toute la ligne pliée. Vous pouvez modifier cela via des :highlightcommandes dans votre ~/.vimrc, mais la différenciation individuelle de la syntaxe sera perdue.

Ingo Karkat
la source
5

Vim affiche déjà les plis sur une seule ligne. Cependant, dans le indentpliage de Vim , toutes les lignes qui ont le même retrait sont incluses dans un pli. Ainsi, dans votre capture d'écran, les lignes que vous appelez "en-têtes" (par exemple, celle qui commence collection_base_url) ne sont pas dans les plis.

Vous pouvez obtenir quelque chose de similaire au pliage d'Atom en utilisant 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

Cela définit une expression de repli (voir :help fold-expr) comme suit:

  • Pour les lignes précédant immédiatement les lignes en retrait, il renvoie l'indentation du bloc qui suit.
  • Pour les lignes en retrait, il renvoie l'indentation. (Divisé par la largeur de décalage, chaque niveau d'indentation incrémente la valeur renvoyée de 1)
  • Pour les lignes à la fin d'un bloc de lignes en retrait, il renvoie une chaîne "<N", où N est défini sur le retrait. Cela indique à Vim qu'un pli de niveau N se termine sur cette ligne.

Mise à jour

@alxndr demande dans les commentaires s'il est possible d'étendre ceci pour inclure les excentriques de Ruby enddans les plis. Vous pouvez commencer par remplacer la " Calculate indent levelsection par ce qui suit:

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

En l'état, ce n'est pas la solution la plus robuste (par exemple, elle échouera si l' endinstruction est sur la même ligne, après un point-virgule). Vous pouvez modifier l'expression régulière et le code environnant pour résoudre ce problème, mais comme vous êtes maintenant dans le domaine de l'analyse de la syntaxe réelle du fichier, je soupçonne que les choses pourraient devenir beaucoup plus compliquées avant d'avoir une bonne solution.

Riches
la source
Excellente approche. Cette réponse pourrait-elle être généralisée pour gérer également, disons Ruby, avec son dépassement endpour terminer un bloc?
alxndr
1
@alxndr J'ai édité ma réponse avec une discussion.
Rich
@Rich: Je trouve également que le texte Sublime fold ne montre qu'une marque ...à la fin de la ligne comme symbole d'un bloc de texte plié très utile et fait moins de distraction que de mettre en évidence toute la première ligne du bloc de texte comme dans vim. J'ai essayé votre pli ci-dessus avec le comportement de pli par défaut de vim, simple ne fonctionne pas. Comment avoir un pli qui donne une marque à la fin de la première ligne du bloc de texte avec python? Dois-je ouvrir une nouvelle question? Je viens de tester à nouveau votre pli, il fonctionne en effet très bien avec la ligne de retrait. Merci beaucoup.
Tuyen Pham
Ceci est incroyable! Je cherchais quelque chose qui fonctionne en mode org comme le pliage et cela aide beaucoup!
priomsrb