Подтвердить что ты не робот

Поиск Vim в строках кода C/С++

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

4b9b3361

Ответ 1

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

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

Начнем с функции, которая имитирует встроенную подпрограмму search() Vim, но также предоставляет параметр "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, чтобы повторить поиск.

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

Ответ 2

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

/\(\(\/\*\|\/\/\|^\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*\*[^/]).*)@<!

Ответ 3

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

map n betterN

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

Ответ 4

Вот как я буду продолжать:

  • Удалить все комментарии C/С++ (с помощью команды replace %s)
  • Перейдите к поиску с помощью обычной команды поиска /
  • Установите отметку в позиции с помощью m a (чтобы установить отметку "a" )
  • Отмените удаление комментариев с помощью u
  • Перейти к значению "a" с помощью `` a`
  • В конце концов удаление метки с помощью delm a (она будет перезаписана в случае, если вы ее не удалите, так что неважно)

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

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

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