Is there any way to search a string in a C/C++ source file while skipping commented lines?
Use ctrl-V to do a block selection and then hit I followed by //[ESC] . Then you just shift-V , select the range, and type // (or whatever you bind it to).
One can search forward in vim/vi by pressing / and then typing your search pattern/word. To search backward in vi/vim by pressing ? and then typing your search pattern/word. Once word found in vim, you can press the n key to go directly to the next occurrence of the word in backwards.
To find a character string, type / followed by the string you want to search for, and then press Return. vi positions the cursor at the next occurrence of the string. For example, to find the string “meta,” type /meta followed by Return. Type n to go to the next occurrence of the string.
This is an intriguing question.
I think @sixtyfootersdude has the right idea -- let Vim's syntax highlighting tell you what's a comment and what's not, and then search for matches within the non-comments.
Let's start with a function that mimics Vim's built-in search()
routine, but also provides a "skip" parameter to let it ignore some matches:
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
Here are a couple of functions that build on SearchWithSkip()
to implement syntax-sensitive searches:
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
Here are commands that make the syntax-sensitive search functions easier to use:
command! -nargs=+ -complete=command SearchOutside call SearchOutside(<f-args>) command! -nargs=+ -complete=command SearchInside call SearchInside(<f-args>)
That was a long way to go, but now we can do stuff like this:
:SearchInside String hello
That searches for hello
, but only within text that Vim considers a string.
And (finally!) this searches for double
everywhere except comments:
:SearchOutside Comment double
To repeat a search, use the @:
macro to execute the same command repeatedly, like pressing n
to repeat a search.
(Thanks for asking this question, by the way. Now that I've built these routines, I expect to use them a lot.)
This pattern searches for a string that is not preceded by the two C++ commenting conventions. I've also excluded '*' as the first non-whitespace character, as that's a common convention for multi-line comments.
/\(\(\/\*\|\/\/\|^\s*\*[^/]\).*\)\@<!foo
Only the first and fourth foo are matched.
foo /* foo * baz foo */ foo // bar baz foo
Putting \v at the beginning of the pattern eliminates a bunch of backslashes:
/\v((\/\*|\/\/|^\s*\*[^/]).*)@<!foo
You can bind a hotkey to this pattern by putting this in your .vimrc
"ctrl+s to search uncommented code noremap <c-s> <c-o>/\v((\/\*\|\/\/\|^\s*\*[^/]).*)@<!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With