2010-04-21 9 views

risposta

28

Questa è una domanda intrigante.

Penso che @sixtyfootersdude abbia l'idea giusta - lascia che l'evidenziazione della sintassi di Vim ti dica cos'è un commento e cosa no, quindi cerca le corrispondenze all'interno dei non-commenti.

Cominciamo con una funzione che imita Vim di built-in search() di routine, ma fornisce anche un "saltare" il parametro di lasciar ignorare alcuni incontri:

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 

Ecco un paio di funzioni che costruire su SearchWithSkip() per implementare le ricerche di sintassi sensibili:

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 

Qui sono comandi che rendono le sintassi sensibili funzioni di ricerca più facile da usare:

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

E 'stata una lunga strada da percorrere, ma ora siamo in grado di fare cose come questa:

:SearchInside String hello 

che cerca hello, ma solo all'interno del testo che Vim considera una stringa.

E (! Finalmente) Questo cerca double ovunque tranne commenti:

:SearchOutside Comment double 

Per ripetere una ricerca, utilizzare la macro @: per eseguire lo stesso comando più volte, come premendo n per ripetere una ricerca.

(Grazie per questa domanda, tra l'altro. Ora che ho costruito queste routine, mi aspetto di utilizzare loro un sacco.)

+0

Grazie per la tua * ottima * risposta. Mi aspetto di usarli molto :-) –

+7

Questo è fantastico! C'è un piccolo problema, però. Se la stringa di ricerca si trova nel file, ma solo in luoghi che vengono saltati, si ottiene un ciclo infinito. Puoi sistemarlo mettendo una guardia in posizione. Sopra il ciclo: 'let l: guard = []'. Quindi nel ciclo: 'if l: guard == [] | let l: guard = getpos ('.') | elseif l: guard == getpos ('.') | pausa | endif'. –

+2

Questo è davvero fantastico. Nota che puoi escludere più SynNames con 'SearchOutside Comment \\\\ | String double', yes hai bisogno di quattro backslash per uscire dalla pipe. – Drasill

0

Ecco come vorrei procedere:

  1. Cancella Commenti Tutto C/C++ (utilizzando il sostituire comando %s)
  2. Procedere alla ricerca utilizzando ricerca normale comando /
  3. Set a mark nella posizione che utilizza m a (per impostare il segno "a")
  4. annullare l'eliminazione dei commenti utilizzando u
  5. Vai al marchio "a" utilizzando `` a`
  6. eliminazione Alla fine il marchio utilizzando delm a (sarebbe sovrascritto nel caso in cui non elimina, in modo che nessun grosso affare)

Naturalmente è possibile farlo in un'unica grande operazione/funzione. Non ho padronanza degli script di Vim abbastanza da dare un esempio di ciò.

Ammetto che la mia soluzione è un po '"pigra" (e probabilmente lo puoi fare modo meglio) ma questo è tutto quello che ho trovato.

Spero che aiuti.

+0

Spero che ci sia un modo più adatto, ma meglio che niente .. :-) –

+0

Piuttosto pericoloso se me lo chiedi. –

+1

@Ken Bloom: una vita senza pericolo deve essere piuttosto noiosa no ?! ;) – ereOn

6

Questo modello cerca una stringa che non sia preceduta dalle due convenzioni di commento C++. Ho anche escluso "*" come il primo carattere non di spazio bianco, poiché si tratta di una convenzione comune per i commenti su più righe.

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

Solo il primo e il quarto foo sono abbinati.

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

Mettere \ v all'inizio del modello elimina un gruppo di backslash:

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

È possibile associare un tasto di scelta rapida a questo modello mettendo questo nel vostro .vimrc

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

Intelligente, bello e semplice. – ereOn

+0

Funziona anche con 'hlsearch' –

+0

non funziona con alcuni commenti/* */commenti senza una stella all'inizio della riga. –

1

Non so se questo è utile ma whe n digiti :syn ha tutta la formattazione usata nel tuo tipo di file. Forse puoi riferirti in qualche modo. Potresti dire qualcosa come:

map n betterN 

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