Collapse vim wird ähnlich wie Atom oder Sublime Text zu einer einzelnen Zeile gefaltet

13

Ich bin ein Fan der Art und Weise, wie Atom und Sublime Text das Falten von Linien handhaben, wobei die erste Linie jeder Falte sichtbar ist (einschließlich Hervorhebung der Syntax) und eine Markierung an das Ende der Linie angehängt wird, die die Falte angibt.

Siehe den Screenshot unten, in dem Vims Einrückung (oben) mit der von Atom (unten) verglichen wird:Vim vs. Atom Code falten

Vim reserviert zwei Zeilen für jede Falte. Die erste Zeile dient als Überschrift und die zweite Zeile beschreibt einige Informationen zur Falte (Anzahl der Zeilen und Text innerhalb der Falte).

Atom verwendet nur eine Zeile und verwendet einen kleinen Marker am Ende der Zeile, um die Falte sowie die Farbe zu kennzeichnen, die den Zeilennummern auf der linken Seite hinzugefügt wird. Atoms Faltstil verbraucht weniger Platz auf dem Bildschirm, vermittelt aber dennoch alle Informationen, die ich wirklich brauche.

Ich bin ein Teil des Atom-Faltstils. Meiner Meinung nach wirkt es sauberer und konsistenter, insbesondere wenn mehrere Methoden oder Attribute hintereinander aufgelistet werden (wie im obigen Screenshot).

Gibt es eine Möglichkeit, den Faltstil von Atom in Vim grob anzunähern?

Mike Hearn
quelle
1
Ich denke, das liegt daran, dass deine Falten nicht mit der Linie beginnen, die die öffnenden Klammern enthält. Vim verwendet nur den Falztext in der Zeile, in der der Falz beginnt. In C: imgur.com/3h70dPf,wfCLPm7
muru
Aber das ist Python, keine geschweiften Klammern ( from __future__ import braces) ... Wie haben Sie das Falten konfiguriert? Und können Sie diesen Codeausschnitt einfügen (oder einen anderen, der das Problem demonstriert)? Vim faltet sich zu einer einzelnen Linie, aber wie Muru sagte, beginnen Ihre Falten eine Linie zu spät.
Martin Tournoij
@Carpetsmoker Die Klammern dienen nur zur Veranschaulichung, wo die Falte beginnt. Der gleiche Effekt ist beispielsweise bei Haskell zu beobachten.
Muru
@MikeHearn Meine vorherige Antwort war völlig falsch. Ich habe es aktualisiert, um eine Lösung für das Problem aufzunehmen.
Rich

Antworten:

12

Zwei Zeilen gegen eine Zeile

In Vim werden alle Linien innerhalb einer Falte zu einer einzigen Linie zusammengefasst, und die 'foldtext'Option bestimmt dann die Zusammenfassung dieser Linien (normalerweise Bindestriche, die Anzahl der gefalteten Linien und den Inhalt der ersten (oder aller) Linien).

In Ihrem Beispiel wird in Vim nur der {...}Parameterblock selbst gefaltet. Die Zeile darüber (die die Parameter verwendet) ist nicht Teil der Falte. Im Gegensatz dazu gehört in dem anderen Editor diese Zeile, die die Parameter verwendet, zur Falte, und ihr Falttext (um die Vim-Terminologie zu verwenden) ist der Inhalt dieser Zeile plus der angehängte Marker.

Anpassung

In Vim können Falten auf unterschiedliche Weise erzeugt werden (siehe :help fold-methods) und hängen 'filetype'vom Puffer ab. Die Schwierigkeit, die obige Linie in die Falte aufzunehmen, hängt davon ab; erkundigen Sie sich bei :setlocal foldmethod?. Beim Falten von Einzügen gibt es nichts, was Sie beeinflussen können. Sie müssen zu einer anderen Methode wechseln. Für Syntax Folding würde dies bedeuten, dass die Syntaxdefinitionen angepasst werden, und könnte sehr schwierig sein. Sie werden mehr Glück haben, wenn ein Ausdruck verwendet wird, aber es würde immer noch bedeuten, die Logik zu verstehen und zu ändern. (Es ist unwahrscheinlich, dass der Autor des Dateityp-Plugins eine Konfiguration bereitgestellt hat, um dies zu beeinflussen.)

Syntaxhervorhebung der gefalteten Linie

Das ist leider gar nicht möglich. Vim verwendet immer die FoldedMarkierungsgruppe für die gesamte gefaltete Linie. Sie können dies über :highlightBefehle in Ihrem System anpassen ~/.vimrc, aber die individuelle Unterscheidung der Syntax geht verloren.

Ingo Karkat
quelle
5

Vim zeigt Falten bereits als einzelne Linie an. Bei der indentFaltung von Vim werden jedoch alle Linien mit demselben Einzug in eine Faltung eingeschlossen. In Ihrem Screenshot befinden sich die Zeilen, die Sie als "Überschriften" bezeichnen (z. B. die, die beginnt collection_base_url), nicht innerhalb der Falten.

Sie können mit Vim's etwas erreichen, das der Faltung von Atom ähnlich ist 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

Dies definiert einen Fold-Ausdruck (siehe :help fold-expr) wie folgt:

  • Für Zeilen, die unmittelbar vor eingerückten Zeilen stehen, wird der Einzug des nachfolgenden Blocks zurückgegeben.
  • Bei eingerückten Zeilen wird der Einzug zurückgegeben. (Geteilt durch die Verschiebungsbreite, erhöht jede Einrückungsstufe den zurückgegebenen Wert um 1.)
  • Für Zeilen am Ende eines Blocks eingerückter Zeilen wird eine Zeichenfolge zurückgegeben "<N", wobei N auf den Einzug gesetzt wird. Dies sagt Vim, dass eine Falte von Level N in dieser Zeile endet .

Aktualisieren

@alxndr fragt in den Kommentaren, ob es möglich ist, dies zu erweitern, um Rubys ausgeprägte ends in die Falten einzuschließen . Sie könnten damit beginnen, den " Calculate indent levelAbschnitt durch Folgendes zu ersetzen :

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

Dies ist jedoch nicht die robusteste Lösung (z. B. schlägt sie fehl, wenn sich die endAnweisung nach einem Semikolon in derselben Zeile befindet). Sie könnten den regulären Ausdruck und den umgebenden Code optimieren, um dies zu beheben, aber da Sie sich jetzt im Bereich des Parsens der tatsächlichen Syntax der Datei befinden, ist zu vermuten, dass die Dinge viel komplizierter werden könnten, bevor Sie eine gute Lösung finden.

Reich
quelle
Toller Ansatz. Könnte diese Antwort verallgemeinert werden, um auch sagen zu können, dass Ruby endeinen Block beenden soll?
Alxndr
1
@alxndr Ich habe meine Antwort mit einer Diskussion bearbeitet.
Rich
@Rich: Ich finde auch Sublime Textfalten, die nur eine Markierung ...am Zeilenende als Symbol eines gefalteten Textblocks zeigen, sehr nützlich und lenken weniger ab, als die gesamte erste Zeile des Textblocks wie in vim hervorheben zu müssen. Ich habe dein Fold oben mit dem Standard-Fold-Verhalten von vim ausprobiert, simple geht nicht. Wie kann man mit Python eine Falte haben, die am Ende der ersten Zeile des Textblocks eine Markierung gibt? Soll ich eine neue Frage öffnen? Ich teste einfach nochmal deine Falte, es funktioniert ja sehr gut mit Einrückungslinie. super danke
Tuyen Pham
Das ist großartig! Ich habe nach etwas gesucht, das im Org-Modus funktioniert, wie z. B. Falten, und das hilft sehr!
Priomsrb