Быстрый поиск, ограниченный функцией C ++

13

Я работаю над довольно большим проектом C ++. Один из самых неприятных аспектов его организации - очень большие функции, помещенные в смехотворно большие файлы.

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

(У меня установлены ctags и я использую Tagbar ... что может быть полезно для этого)

jkerian
источник

Ответы:

9

Вот как бы я это сделал. Добавьте это к вашему.vimrc

vnoremap if [[O][

Объяснение: vnoremap означает отображение левой стороны ifна правую, [[mO][когда вы находитесь в визуальном режиме. ifозначает в функции , хотя вы можете переименовать это, если хотите. [[переходит к началу функции. Oпереместится на другой конец вашего визуально выделенного текста, а затем ][переместится в конец функции.

Итак, если вы хотите выполнить поиск в функции, теперь вы входите в визуальный режим с помощью vи выбираете всю функцию с помощью if. Теперь выйдите из визуального режима с помощью кнопки <esc>и выполните поиск с помощью /\%V. \%Vограничивает ваш поиск ранее выбранным текстом. Если вы не хотите нажимать, <esc>/\%Vвы можете добавить это к своему .vimrc:

vnoremap / <esc>/\%V

Тогда ваша последовательность нажатий клавиш будет выглядеть так:

vif/foo<enter>

и это найдет все вхождения foo в текущей функции.


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

int foo() {
    bar()
}

тогда эта немного более сложная версия будет работать:

vnoremap if ][ma%O'a

Это только ожидает, что закрывающая скобка будет иметь 0 отступов. Если открывающая скобка имеет отступы, она все равно работает, хотя и занимает отметку. Если вы регулярно используете знак «а», вы можете переместить это, например,

vnoremap if ][mb%O'b
vnoremap if ][mc%O'c
...
Джеймс
источник
Увы, это не очень хорошо работает с функциями C ++. В отличие от функций C, они, вероятно, имеют отступ (это имеет место с встроенными функциями-членами, определенными в их определении класса, и с отступом функций по умолчанию в пространствах имен). Однако ваша идея может быть построена благодаря диапазону определения функций, который можно получить с помощью ctags. Я делаю это в функции lh#dev#find_function_boundariesот lh-dev
Люк Эрмитт
3
Хороший подход. Если вы можете надежно найти верхнюю строку функции, то вы можете перейти к, {а затем использовать %для достижения нижней строки. Не уверен, как вы можете найти запуск функции в C ++, но это хорошо работает для Javascript:vnoremap if <Esc>?^\s*function<CR>v/{<CR>%o
joeytwiddle
1
Относительно вашего последнего редактирования. CTRL-]переходит к тегу под курсором. Не до начала текущей функции. Это не поможет
Люк Эрмита
По поводу нового редактирования. Это не так просто. Сложность в том, чтобы vim знал текущую функцию. Если бы у него была информация, ему бы не понадобилась помощь ctags. Единственный способ получить информацию (из ctags) - это проанализировать команды перехода к объявлению, созданные ctags. Если бы эти команды были :linenumber, vim мог бы делать то, что я делаю в своем плагине. Но нет никакой гарантии, и эти команды могут вместо этого быть поисковыми /pattern- Vim не может проверить все шаблоны, чтобы узнать, какой из них соответствует текущей функции. Я не знаю ни одного действия vim для перехода к началу текущей функция
Люк Эрмита
6

Решение DJ McMayhem вдохновило меня на написание собственного, который использует ctags и matchit для правильного анализа границ функций.

Сложная часть уже была сделана lh-dev и lh-tags в течение нескольких лет:

  • текущий файл анализируется через ctags с правильными параметрами
  • мы ищем все определения функций в базе данных тегов, которая ограничена тегами, полученными для текущего файла
  • благодаря БД у нас есть номера стартовой строки для всех функций (ну templateи inlineчасть может пропустить ctags)
  • с помощью простого итеративного поиска (бинарный поиск мог быть выполнен, но файлы должны быть «короткими»), начало текущей функции найдено
  • И благодаря плагину matchit, его последняя строка также найдена - я вижу, что универсальные ctags предлагают endполе, которое можно использовать с C, C ++, Python и Vim, которое также можно использовать для поиска конца функции.

Обратите внимание, что любые части этого алгоритма могут быть переопределены в зависимости от типа файла. то есть обнаружение границ функций python может искать defи анализировать отступы, мы можем просто искать functionв javascript и т. д. Другими словами, текущая версия также работает с Java, Vim и некоторыми другими языками (у меня еще есть работа делать для Python)

Итак, я определил теперь два новых отображения: отображение визуального режима и отображение режима, ожидающего оператора:

onoremap <silent> if :<c-u>call lh#dev#_select_current_function()<cr>
xnoremap <silent> if :<c-u>call lh#dev#_select_current_function()<cr><esc>gv

Которые полагаются на:

function! lh#dev#_select_current_function() abort
  let fn = lh#dev#find_function_boundaries(line('.'))
  exe fn.lines[0]
  normal! v
  exe fn.lines[1]
endfunction

Я избавлю вас от нескольких сотен строк кода lh#dev#find_function_boundaries()

И благодаря картографии DJ McMayhem

" Note that my vim settings requires two backslashes here instead of one
vnoremap / <esc>/\\%V

мы можем сделать vif/patternпоиск patternв текущей функции.

Мы также можем удалять функции dif, восстанавливать их yifи т. Д.

Вот как это выглядит при применении к реалистичной функции C ++ (т.е. без отступа 0):Скринкаст: выберите функцию C ++

Люк Эрмитт
источник
4

Поиск начала и конца функции может быть затруднен, особенно в языке без functionключевого слова ... и многих противоречивых стилей отступа.

Если ваша функция заканчивается закрывающей фигурной скобкой в ​​отдельной строке (как в 10 из 13 перечисленных здесь стилей ), вы можете визуально выбрать ее примерно так:

xnoremap if /^\s*}<CR><Esc>V%

Отсюда поиск fooв вашей функции - это только вопрос:

:'<,'>g/foo/#

Собрав все это вместе, мы можем получить довольно хорошее отображение:

xnoremap if /^\s*}<CR><Esc>V%
nmap <key> vif:g//#<Left><Left>

поиск в функции

Тем не менее, отображение визуального режима, вероятно, будет легко одурачено a whileили a, ifтак что оно, вероятно, выиграет от небольшой полировки. Кроме того, сохранение визуального выбора может быть не очень хорошей идеей ...

romainl
источник
Это просто выбирает следующий блок, который он может найти. Она не работает на всех , как только вы добавляете if, for, whileи т.д.
Джеймс
3

Несовершенное решение использует складки . Сложите все:

set foldmethod=syntax
set foldlevel=0
set foldminlines=0

Скажите Vim не открывать сложенные области для результатов поиска:

set foldopen-=search

А затем откройте сгиб рассматриваемой функции ( zO).

Теперь все попадания для искомого текста в сложенной области приведут к тому, что Vim прыгнет на линию сгиба один раз, а затем перейдет к следующему попаданию.

Например, в случае ниже:

введите описание изображения здесь

Сложенная функция имеет много применений size, но nне поможет мне использовать каждую sizeфункцию в этой функции.

Мур
источник
3

Другой путь:

  • используйте ctags и т. д., чтобы найти целевую функцию, иди туда
  • переместить курсор вперед внутри тела функции
  • используйте оператор поиска Osyo Manga (зависит от vim-operator-user ), чтобы искать только внутри текущего блока. Например:

    " configure the plugin (once, vimrc):
     map g/ <Plug>(operator-search)
    
    " 1. use ctags etc. to jump to the beginning of the target function;
    " 2. move cursor inside the function definition, then:
    g/i{
    

... теперь вы можете вставить свой поисковый запрос в соответствующее приглашение; нажмите, nчтобы увидеть, как результаты поиска ограничены текущим предоставленным движением / текстовым объектом. Поскольку это оператор Vim (т. Е. Компонуемый), если у вас есть хороший текстовый объект-функция, вам даже не нужно перемещаться внутри тела определения перед поиском, а напрямую использовать что-то подобное g/ifили подобное.

VanLaser
источник