Vim поиск в строках кода C / C ++ - PullRequest
23 голосов
/ 21 апреля 2010

Есть ли способ поиска строки в исходном файле C / C ++, пропуская закомментированные строки?

Ответы [ 4 ]

29 голосов
/ 23 апреля 2010

Это интригующий вопрос.

Я думаю, что @sixtyfootersdude имеет правильную идею - пусть подсветка синтаксиса Vim скажет вам, что такое комментарий, а что нет, а затем поиск совпадений в не-комментариях.

Давайте начнем с функции, которая имитирует встроенную подпрограмму Vim search(), но также предоставляет параметр «skip», позволяющий игнорировать некоторые совпадения:

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

Вот парафункции, основанные на SearchWithSkip() для реализации поиска, чувствительного к синтаксису:

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

Вот команды, облегчающие использование функций поиска, чувствительных к синтаксису:

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

Это былодолгий путь, но теперь мы можем сделать что-то вроде этого:

:SearchInside String hello

Это ищет hello, но только внутри текста, который Vim считает строкой.

И (наконец!) это ищет double везде, кроме комментариев:

:SearchOutside Comment double

Чтобы повторить поиск, используйте макрос @: для повторного выполнения одной и той же команды, например, нажмите n, чтобы повторить поиск.

(СпасибоКстати, для того, чтобы задать этот вопрос.Теперь, когда я создал эти подпрограммы, я ожидаю, что они будут часто использоваться.)

6 голосов
/ 21 апреля 2010

Этот шаблон ищет строку, которой не предшествуют два соглашения о комментировании C ++. Я также исключил «*» в качестве первого непробельного символа, так как это общее соглашение для многострочных комментариев.

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

Только первый и четвертый foo совпадают.

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

Помещение \ v в начало шаблона устраняет кучу обратных косых черт:

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

Вы можете привязать горячую клавишу к этому шаблону, поместив это в свой .vimrc

"ctrl+s to search uncommented code
noremap <c-s> <c-o>/\v((\/\*\|\/\/\|^\s*\*[^/]).*)@<!
1 голос
/ 22 апреля 2010

Не уверен, что это полезно, но когда вы набираете :syn, он имеет все форматирование, используемое в вашем типе файла.Может быть, вы можете обратиться к этому как-нибудь.Вы могли бы сказать что-то вроде:

map n betterN

function betterN{
  n keystroke
  while currentLine matches comment class
    do another n keystroke
}
0 голосов
/ 21 апреля 2010

Вот как бы я поступил:

  1. Удалить все комментарии C / C ++ (используя команду replace %s)
  2. Перейти к поиску, используя обычный поиск команда /
  3. Установите метку в позиции, используя m a (для установки метки "a")
  4. Отменить удаление комментариев, используя u
  5. Перейти к отметке «a» с помощью `` a`
  6. В конечном итоге удаление метки с помощью delm a (она будет перезаписана, если вы ее не удалите, поэтому ничего страшного)

Конечно, вы можете сделать это за одну большую операцию / функцию. Я не достаточно хорошо владею сценариями Vim, чтобы привести пример этого.

Я признаю, что мое решение немного "ленивое" (и вы, вероятно, можете сделать это способ лучше), но это все, к чему я пришел.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...