2011-05-11 15 views
8

me gustaría establecer dos métodos para doblarDos métodos de plegado al mismo tiempo

  1. :set foldmethod=indent y conservar todas sus características
  2. comentarios de encubrimiento con

    :set foldmethod=marker

    :set foldmarker=/*,*/

Descubrí que esto no es posible. ¿Es posible lograr el plegado deseado y configurar esto en .vimrc o utilizar algún script o complemento para esto?

Respuesta

8

No es posible tener diferentes tipos de métodos de plegado en el mismo buffer. ¿Cómo es que Vim sabe que hay algunos comentarios al mismo nivel de sangrado que otro texto que desea tratar como de un nivel diferente (más numerado)?

Estoy seguro de que puede lograr lo que desea estableciendo foldmethod en 'expr'. Esta es la forma más flexible de hacer pliegues en Vim, pero puede complicarse (y/o ralentizarse) según lo que desee. Aunque creo que funcionaría con bastante facilidad para su caso de uso.

Primero, en algún lugar de vimrc o vimscripts necesita asegurarse de que foldexpr se está definiendo para el tipo de archivo en cuestión.

set foldexpr=MyFoldLevel(v:lnum) 
set foldmethod=expr 
" and for last code example 
let b:previous_level = 0 

y luego tienes que dar cuerpo a su función foldexpr de manera que asigna los niveles de una manera que resulta en un comportamiento que desea. Algo como el siguiente código podría estar a punto de funcionar en casos en que cada línea de comentario tenga el símbolo de prefijo (es decir, no en su caso), pero espero que necesite algunos ajustes. h: fold-expr sería un buen lugar para buscar ayuda:

function! MyFoldLevel(linenum) 
    " assign levels based on spaces indented and tabstop of 4 
    let level = indent(a:linenum)/4 
    if getline(a:linenum) =~ [put line-based comment prefix pattern here] 
     let level = 20 
    endif 
endfunction 

tendría que ser modificado para asignar un nivel más alto para las líneas entre el inicio comentario y al final marcadores de la manera deseada:

function! MyFoldLevel(linenum) 
    let linetext = getline(a:linenum) 
    if linetext =~ [put line-based comment prefix pattern here] 
     let level = 20 
    elseif linetext =~ '^\s*/\*' 
     let level = 20 
    elseif linetext =~ '^\s*\*/' 
     let level = 21 
    else 
     if b:previous_level == 20 
      let level = 20 
     else 
      "assuming code is space-indented with tabstop of 4 
      let level = indent(a:linenum)/4 
     endif 
    endif 

    let b:previous_level = level 
    return level 

endfunction 

I don' T esperar que las funciones de foldmethod que he escrito funcionen exactamente como están escritas. Pero señalan el camino a algo que funcionaría.

Tenga en cuenta que el uso del nivel de '20' para los comentarios es solo un nivel arbitrario que les permite ser plegados, mientras que todos los códigos sangrados (presumiblemente de nivel inferior) podrían ser visibles. '21' para la última línea de la sección de comentarios es solo para diferenciarlo de las líneas anteriores de comentarios que tienen un nivel de 20, para saber que la siguiente línea debe tratarse como una línea de código regular.

Además, las operaciones clave como 'zc' y 'zo' no funcionarán del todo bien en los comentarios cuando se establecen en un nivel mucho más alto que el código circundante. Quisiera usar el comando directo como :set foldlevel=21 para mostrar todas las líneas de comentarios.

No es bonito, y espero que se pueda simplificar un poco, pero algo como esto es lo que creo que se requiere para lo que quiere.

En realidad, pensando en esto un poco más, creo que desearía que la primera línea de cualquier bloque de comentarios estuviera en el mismo nivel que si fuera una línea sin comentario, solo las líneas de comentario posteriores en el mismo bloque necesitarían ser de un nivel superior para que se "doble" en la línea de comentario inicial.En el código que di, si funciona o está a punto de funcionar, creo que vim doblaría las líneas de comentarios detrás de la línea anterior sin comentario, que no es lo que quieres, pero desafortunadamente no tener más tiempo para dedicar a este pequeño rompecabezas. . . He hecho este tipo de plegado personalizado bastantes veces y generalmente siempre tengo un poco de prueba y error para obtener exactamente lo que quiero.

+0

¿Es posible mapear 'zo' comando para 'zo' comando pulsa 21 veces? Me di cuenta de que zo presionado más veces no tiene efectos secundarios. ¿Se ralentiza demasiado? – xralf

1

Plegado basado en sintaxis puede ser una mejor manera de obtener lo que desea que el método basado en expr que sugerí en una respuesta diferente a su pregunta. Consulte :h fold-syn para obtener más información. Creo que puede haber algunas buenas soluciones que ya existen para el plegado basado en c. No saben lo bueno que es, pero aquí es un archivo c-sintaxis con soporte para basada en la sintaxis de plegado: http://www.vim.org/scripts/script.php?script_id=234 y otro: http://www.vim.org/scripts/script.php?script_id=925

las soluciones anteriores son completamente basado en la sintaxis, no implican usando sangrías para determinar los niveles de pliegue. Pero podría modificar el plegado basado en sintaxis para hacer el plegado principal por regiones con sangría si quisiera. Si aplica sangría basada en elementos sintácticos, el resultado puede ser el mismo de todos modos.

He aquí un consejo que muestra cómo acaba de doblar los comentarios de c-estilo (no el código real) http://vim.wikia.com/wiki/Fold_C-style_comments

0

Tengo las mismas peticiones como la suya, aquí está mi solución no es perfecto

mi par fabricante es # < === === y #> (o #region y #endregion como en PyCharm)

let b:inBlock=0 
let b:lastLineNum=0 
let b:lastLevel=0 
let b:lastGoodLine=0 
let b:lastGoodBlock=0 
let b:startFoldingMark='^\s*.\?#<==*\|^\s*.\?#region' 
let b:endFoldingMark='^\s*.\?#=*=>\|^\s*.\?#endregion' 
function! MyFold(linenum) 
    let linetext = getline(a:linenum) 
    let level  = indent(a:linenum) /&shiftwidth 
    "the first line have 0 fold level 
    if (a:linenum == 1) 
     if linetext =~ b:startFoldingMark 
      let b:inBlock = 1 
      let b:lastLineNum=a:linenum 
      let b:lastGoodLine=0 
      let b:lastGoodBlock=0 
      let b:lastLevel=level 
      return level 
     endif 
     let b:inBlock=0 
     let b:lastInBlock=0 
     let b:lastLineNum=a:linenum 
     let b:lastGoodLine=0 
     let b:lastGoodBlock=b:inBlock 
     let b:lastLevel=level + b:inBlock 
     return level + b:inBlock 
    endif 

    " not calculate from the mid of text 
    if ((b:lastLineNum+1) != a:linenum) 
     let level  = indent(a:linenum) /&shiftwidth 
     let lastGoodNum = a:linenum-1 
     while (lastGoodNum>1 && getline(lastGoodNum) =~? '\v^\s*$') 
      let lastGoodNum -= 1 
     endwhile 
     if (foldlevel(lastGoodNum)==-1) 
      let b:inBlock=b:lastGoodBlock 
     else 
      let lastlevel = indent(lastGoodNum) /&shiftwidth 
      let lastlinetext = getline(lastGoodNum) 
      let lastlinelevel = foldlevel(lastGoodNum) 
      if lastlinetext =~ b:startFoldingMark 
       let b:inBlock = lastlinelevel - lastlevel + 1 
      elseif lastlinetext =~ b:endFoldingMark 
       let b:inBlock = lastlinelevel - lastlevel - 1 
      else 
       let b:inBlock = lastlinelevel - lastlevel 
      endif 
     endif 
    endif 

    "blank lines have undefined fold level 
    if getline(a:linenum) =~? '\v^\s*$' 
     let b:lastLineNum=a:linenum 
     let b:lastLevel=-1 
     return -1 
    endif 

    "if next line is a start of new marker block, inBlock ++ 
    if linetext =~ b:startFoldingMark 
     let b:lastLineNum=a:linenum 
     if (b:lastLevel != -1) 
      let b:lastGoodLine=a:linenum 
      let b:lastGoodBlock=b:inBlock 
     endif 
     let b:lastLevel=level + b:inBlock - 1 
     return level + b:inBlock - 1 
    "if next line is an end of new marker block, inBlock - 
    elseif linetext =~ b:endFoldingMark 
     let b:inBlock = b:inBlock - 1 
     let b:lastLineNum=a:linenum 
     let b:lastGoodLine=a:linenum 
     let b:lastGoodBlock=b:inBlock 
     let b:lastLevel=level + b:inBlock + 1 
     return level + b:inBlock + 1 
    endif 

    let b:lastLineNum=a:linenum 
    if (b:lastLevel != -1) 
     let b:lastGoodLine=a:linenum 
     let b:lastGoodBlock=b:inBlock 
    endif 
    let b:lastLevel=level + b:inBlock 
    return level+b:inBlock 
endfunction 

ahora, puedo mantener todas las características cuando se utiliza el método de plegado guión, y puedo fo ld cada bloque de marcador # < =, # =>, también, las relaciones de plegado de sangría de las líneas todavía se mantienen en cada bloque.

En esta función, evito usar el nivel "a1", "s1" y "=", lo que causará iteración para esta función y puede ser lento para archivos grandes. Sin embargo, cuando se actualiza líneas, el cálculo del nivel del pliegue puede ser incorrecta (porque vim no puede actualizar todos los niveles pliegue desde el principio, y por lo tanto tienen un valor inBlock incorrecta)

puede utilizar ZX para actualizar los niveles de plegado manualmente .

ver más en https://github.com/Fmajor/configs

Cuestiones relacionadas