2010-04-21 23 views

Respuesta

28

Esta es una pregunta intrigante.

Creo que @sixtyfootersdude tiene la idea correcta: deje que el resaltado de sintaxis de Vim le indique qué es un comentario y qué no, y luego busque coincidencias dentro de los no comentarios.

Vamos a empezar con una función que imita Vim incorporado en search() rutina, sino que también proporciona un "salto" de parámetros para dejarlo pasar por alto algunos partidos

function! SearchWithSkip(pattern, flags, stopline, timeout, skip) 
" 
" Returns true if a match is found for {pattern}, but ignores matches 
" where {skip} evaluates to false. This allows you to do nifty things 
" like, say, only matching outside comments, only on odd-numbered lines, 
" or whatever else you like. 
" 
" Mimics the built-in search() function, but adds a {skip} expression 
" like that available in searchpair() and searchpairpos(). 
" (See the Vim help on search() for details of the other parameters.) 
" 
    " Note the current position, so that if there are no unskipped 
    " matches, the cursor can be restored to this location. 
    " 
    let l:matchpos = getpos('.') 

    " Loop as long as {pattern} continues to be found. 
    " 
    while search(a:pattern, a:flags, a:stopline, a:timeout) > 0 

     " If {skip} is true, ignore this match and continue searching. 
     " 
     if eval(a:skip) 
      continue 
     endif 

     " If we get here, {pattern} was found and {skip} is false, 
     " so this is a match we don't want to ignore. Update the 
     " match position and stop searching. 
     " 
     let l:matchpos = getpos('.') 
     break 

    endwhile 

    " Jump to the position of the unskipped match, or to the original 
    " position if there wasn't one. 
    " 
    call setpos('.', l:matchpos) 

endfunction 

Aquí hay un par de funciones que se basan en SearchWithSkip() para implementar búsquedas de sintaxis sensible:

function! SearchOutside(synName, pattern) 
" 
" Searches for the specified pattern, but skips matches that 
" exist within the specified syntax region. 
" 
    call SearchWithSkip(a:pattern, '', '', '', 
     \ 'synIDattr(synID(line("."), col("."), 0), "name") =~? "' . a:synName . '"') 

endfunction 


function! SearchInside(synName, pattern) 
" 
" Searches for the specified pattern, but skips matches that don't 
" exist within the specified syntax region. 
" 
    call SearchWithSkip(a:pattern, '', '', '', 
     \ 'synIDattr(synID(line("."), col("."), 0), "name") !~? "' . a:synName . '"') 

endfunction 

aquí tiene ordenes que hacen las sintaxis sensible a las funciones de búsqueda más fácil de usar:

command! -nargs=+ -complete=command SearchOutside call SearchOutside(<f-args>) 
command! -nargs=+ -complete=command SearchInside call SearchInside(<f-args>) 

Eso fue un largo camino por recorrer, pero ahora podemos hacer cosas como esta:

:SearchInside String hello 

que las búsquedas de hello, pero sólo dentro de Vim texto que considera una cadena.

Y (¡por fin!), Esto busca en todas partes excepto double comentarios:

:SearchOutside Comment double 

Para repetir una búsqueda, utilice la macro @: para ejecutar el mismo comando en varias ocasiones, como presionar n a repetir una búsqueda.

(Gracias por hacer esta pregunta, por cierto. Ahora que he construido estas rutinas, espero que les utilizar una gran cantidad.)

+0

Gracias por su * gran * respuesta. Espero usarlos también :-) –

+7

¡Esto es genial! Sin embargo, hay un pequeño problema. Si su cadena de búsqueda se encuentra en el archivo, pero solo en lugares que se saltan, obtiene un ciclo infinito. Puedes arreglarlo poniendo un guardia en su lugar. Sobre el ciclo: 'let l: guard = []'. Luego en el ciclo: 'if l: guard == [] | let l: guard = getpos ('.') | elseif l: guard == getpos ('.') | romper | endif'. –

+2

Esto es realmente genial. Tenga en cuenta que puede excluir múltiples SynNames con 'SearchOutside Comment \\\\ | String double', sí necesita cuatro barras invertidas para escapar de la tubería. – Drasill

0

Aquí es cómo iba a proceder:

  1. Borrar Todo C/C++ (utilizando el reemplazar comando %s)
  2. proceder a la búsqueda usando búsqueda normal comando /
  3. Conjunto una marca en la posición usando m a (para establecer la marca "a")
  4. deshacer la eliminación de los comentarios usando u
  5. Saltar a la marca "A" con `` a `
  6. borrar Finalmente la marca usando delm a (sería sobrescrita en el caso de que no se elimina, por lo que no gran cosa)

Por supuesto que puede hacer eso en una gran operación/función. No domino el guion de Vim lo suficiente como para dar un ejemplo de eso.

Admito que mi solución es un poco "floja" (y probablemente puedas hacerlo manera mejor) pero eso es todo lo que encontré.

Espero que ayude.

+0

espero que haya una manera más adecuada, pero es mejor que nada .. . :-) –

+0

Bastante peligroso si me preguntas. –

+1

@Ken Bloom: una vida sin peligro debe ser bastante aburrida, ¿no? ;) – ereOn

6

Este patrón busca una cadena que no esté precedida por las dos convenciones de comentario de C++. También he excluido '*' como el primer personaje que no es de espacio en blanco, ya que es una convención común para comentarios de varias líneas.

/\(\(\/\*\|\/\/\|^\s*\*[^/]\).*\)\@<!foo 

Solo coinciden el primer y el cuarto foo.

foo 
/* foo 
* baz foo 
*/ foo 
// bar baz foo 

Poner \ v en el principio del patrón elimina un montón de barras invertidas:

/\v((\/\*|\/\/|^\s*\*[^/]).*)@<!foo 

Puede enlazar una tecla de acceso directo a este patrón, poniendo esto en su .vimrc

"ctrl+s to search uncommented code 
noremap <c-s> <c-o>/\v((\/\*\|\/\/\|^\s*\*[^/]).*)@<! 
+0

Inteligente, agradable y simple. – ereOn

+0

Incluso funciona con 'hlsearch' –

+0

que no funciona con algunos comentarios/* */comentario sin una estrella al principio de la línea. –

1

No estoy seguro de si esto es útil pero whe n escribe :syn tiene todo el formato que se usa en su tipo de archivo. Tal vez puedas referirte a eso de alguna manera. Podría decir algo como:

map n betterN 

function betterN{ 
    n keystroke 
    while currentLine matches comment class 
    do another n keystroke 
}