Contraer pliegues vim en una sola línea, similar a Atom o Sublime Text

13

Soy fanático de la forma en que Atom y Sublime Text manejan el plegado de líneas, donde la primera línea de cada pliegue es visible (completa con resaltado de sintaxis), y se agrega un marcador al final de la línea que indica el pliegue.

Vea la captura de pantalla a continuación que compara el plegado de sangría de Vim (arriba) versus el de Atom (abajo):Código Vim vs. Atom plegable

Vim dedica dos líneas para cada pliegue. La primera línea sirve como encabezado, y la segunda línea describe información sobre el pliegue (número de líneas y texto dentro del pliegue).

Atom solo usa una línea y usa un pequeño marcador al final de la línea para indicar el pliegue, junto con el color agregado a los números de línea a la izquierda. El estilo plegable de Atom usa menos espacio en la pantalla pero aún comunica toda la información que realmente necesito.

Soy parcial con el estilo de plegado Atom. Parece más limpio y más consistente, en mi opinión, particularmente cuando se enumeran múltiples métodos o atributos en una fila (como en la captura de pantalla anterior).

¿Hay alguna manera de aproximar aproximadamente el estilo de plegado de Atom en Vim?

Mike Hearn
fuente
1
Creo que es porque tus pliegues en realidad no comienzan con la línea que contiene los corchetes de apertura. Vim solo usa el texto del pliegue en la línea donde comienza el pliegue. Vea, por ejemplo, cómo la colocación de llaves
muru
Pero esto es Python, sin llaves ( from __future__ import braces) ... ¿Cómo configuró el plegado? ¿Y puede pegar este fragmento de código (u otro que demuestre el problema)? Vim se pliega en una sola línea, pero como mencionó muru, tus pliegues comienzan una línea tarde.
Martin Tournoij
@Carpetsmoker las llaves son solo para ilustrar dónde comienza el pliegue. El mismo efecto se puede ver en, por ejemplo, Haskell.
muru
@ MikeHearn Mi respuesta anterior fue completamente incorrecta. Lo actualicé para incluir una solución al problema.
Rico

Respuestas:

12

Dos líneas versus una línea

En Vim, todas las líneas dentro de un pliegue se contraerán en una sola línea, y la 'foldtext'opción determina la sinopsis de esas líneas (generalmente guiones, el número de líneas plegadas y el contenido de la primera (o todas) líneas).

En su ejemplo, en Vim solo {...}se pliega el bloque de parámetros; la línea de arriba (que usa los parámetros) no es parte del pliegue. En contraste, en el otro editor, esa línea que usa los parámetros pertenece al pliegue, y su texto de pliegue (para usar la terminología de Vim) es el contenido de esa línea más el marcador adjunto.

Adaptación

En Vim, los pliegues se pueden generar a través de diferentes medios (ver :help fold-methods), y depende 'filetype'del buffer. La dificultad de incluir la línea anterior en el pliegue depende de eso; consultar con :setlocal foldmethod?. Con el plegado de sangría , no hay nada en lo que pueda influir; Tienes que cambiar a otro método. Para el plegamiento de sintaxis , eso significaría adaptar las definiciones de sintaxis, y podría ser muy complicado. Tendrá mejor suerte si se usa una expresión , pero aún significaría comprender y cambiar la lógica. (Es poco probable que el autor del complemento de tipo de archivo haya proporcionado una configuración para influir en esto).

Resaltado de sintaxis de la línea plegada

Eso desafortunadamente no es posible en absoluto. Vim siempre usa el Foldedgrupo resaltado para toda la línea doblada. Puede ajustar eso mediante :highlightcomandos en su ~/.vimrc, pero se perderá la diferenciación individual de la sintaxis.

Ingo Karkat
fuente
5

Vim ya muestra pliegues como una sola línea. Sin embargo, en el indentplegado de Vim , todas las líneas que tienen la misma sangría se incluyen en un pliegue. Entonces, en su captura de pantalla, las líneas a las que se refiere como "encabezados" (por ejemplo, la que comienza collection_base_url) no están dentro de los pliegues.

Puede lograr algo similar al plegado de Atom utilizando 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

Esto define una expresión de pliegue (ver :help fold-expr) de la siguiente manera:

  • Para las líneas inmediatamente anteriores a las líneas con sangría, devuelve la sangría del bloque que sigue.
  • Para líneas sangradas, devuelve la sangría. (Dividido por el ancho de cambio para que cada nivel de sangría incremente el valor devuelto por 1)
  • Para las líneas al final de un bloque de líneas sangradas, devuelve una cadena "<N", donde N se establece en la sangría. Esto le dice a Vim que un pliegue de nivel N termina en esa línea.

Actualizar

@alxndr pregunta en los comentarios si es posible extender esto para incluir los correos electrónicos de Ruby enden los pliegues. Puede comenzar reemplazando la " Calculate indent levelsección con lo siguiente:

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

Tal como está, esta no es la solución más sólida (por ejemplo, fallará si la enddeclaración está en la misma línea, después de un punto y coma). Podría ajustar la expresión regular y el código circundante para abordar esto, pero como ahora está dentro del ámbito de analizar la sintaxis real del archivo, sospecho que las cosas podrían complicarse mucho más antes de tener una buena solución.

Rico
fuente
Gran enfoque ¿Podría esta respuesta ser generalizada para manejar también, por ejemplo, Ruby, con su exceso endpara terminar un bloque?
alxndr
1
@alxndr He editado mi respuesta con un poco de discusión.
Rich
@Rich: También encuentro que el pliegue de texto Sublime que solo muestra una marca ...al final de la línea como símbolo de un bloque de texto doblado es muy útil y hace menos distracción que tener que resaltar toda la primera línea del bloque de texto como en vim. Intenté su doblez anterior con el comportamiento de doblez predeterminado de vim, simple no funciona. ¿Cómo tener pliegues que den una marca al final de la primera línea del bloque de texto con python? ¿Debo abrir una nueva pregunta? Acabo de probar nuevamente tu pliegue, de hecho funciona muy bien con la línea de sangría. super gracias.
Tuyen Pham el
¡Esto es increíble! ¡He estado buscando algo que haga el modo org como plegar y esto ayuda mucho!
priomsrb