Vim search in C/C++ code lines

前端 未结 4 892
再見小時候
再見小時候 2020-12-24 03:27

Is there any way to search a string in a C/C++ source file while skipping commented lines?

相关标签:
4条回答
  • 2020-12-24 04:02

    Not sure if this is helpful but when you type :syn it has all the formatting that is used in your file type. Maybe you can refer to that somehow. You could say something like:

    map n betterN
    
    function betterN{
      n keystroke
      while currentLine matches comment class
        do another n keystroke
    }
    
    0 讨论(0)
  • 2020-12-24 04:03

    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.)

    0 讨论(0)
  • 2020-12-24 04:04

    Here is how I would proceed:

    1. Delete all C/C++ comments (using the replace command %s)
    2. Proceed to the search using regular search command /
    3. Set a mark at the position using m a (to set the mark "a")
    4. Undo the deletion of the comments using u
    5. Jump to the mark "a" using ``a`
    6. Eventually deleting the mark using delm a (it would be overwritten in the case you don't delete it, so no big deal)

    Of course you can do that in one big operation/function. I do not master Vim scripting good enough to give an example of that though.

    I admit my solution is a bit "lazy" (and you can probably do it way better) but that's all I came to.

    Hope it helps.

    0 讨论(0)
  • 2020-12-24 04:09

    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*\*[^/]).*)@<!
    
    0 讨论(0)
提交回复
热议问题