Я работаю над довольно большим проектом C ++. Один из самых неприятных аспектов его организации - очень большие функции, помещенные в смехотворно большие файлы.
Я часто хочу искать любой экземпляр определенной глобальной переменной или вызова функции, ограниченный текущей функцией. Есть ли достаточно простая формула для достижения этой цели?
(У меня установлены ctags и я использую Tagbar ... что может быть полезно для этого)
Вот как бы я это сделал. Добавьте это к вашему.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 отступов. Если открывающая скобка имеет отступы, она все равно работает, хотя и занимает отметку. Если вы регулярно используете знак «а», вы можете переместить это, например,
Увы, это не очень хорошо работает с функциями 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
Поиск начала и конца функции может быть затруднен, особенно в языке без 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так что оно, вероятно, выиграет от небольшой полировки. Кроме того, сохранение визуального выбора может быть не очень хорошей идеей ...
set foldmethod=syntax
set foldlevel=0
set foldminlines=0
Скажите Vim не открывать сложенные области для результатов поиска:
set foldopen-=search
А затем откройте сгиб рассматриваемой функции ( zO).
Теперь все попадания для искомого текста в сложенной области приведут к тому, что Vim прыгнет на линию сгиба один раз, а затем перейдет к следующему попаданию.
Например, в случае ниже:
Сложенная функция имеет много применений size, но nне поможет мне использовать каждую sizeфункцию в этой функции.
" 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или подобное.
lh#dev#find_function_boundaries
от lh-dev{
а затем использовать%
для достижения нижней строки. Не уверен, как вы можете найти запуск функции в C ++, но это хорошо работает для Javascript:vnoremap if <Esc>?^\s*function<CR>v/{<CR>%o
CTRL-]
переходит к тегу под курсором. Не до начала текущей функции. Это не поможет:linenumber
, vim мог бы делать то, что я делаю в своем плагине. Но нет никакой гарантии, и эти команды могут вместо этого быть поисковыми/pattern
- Vim не может проверить все шаблоны, чтобы узнать, какой из них соответствует текущей функции. Я не знаю ни одного действия vim для перехода к началу текущей функцияРешение DJ McMayhem вдохновило меня на написание собственного, который использует ctags и matchit для правильного анализа границ функций.
Сложная часть уже была сделана lh-dev и lh-tags в течение нескольких лет:
template
иinline
часть может пропустить ctags)end
поле, которое можно использовать с C, C ++, Python и Vim, которое также можно использовать для поиска конца функции.Обратите внимание, что любые части этого алгоритма могут быть переопределены в зависимости от типа файла. то есть обнаружение границ функций python может искать
def
и анализировать отступы, мы можем просто искатьfunction
в javascript и т. д. Другими словами, текущая версия также работает с Java, Vim и некоторыми другими языками (у меня еще есть работа делать для Python)Итак, я определил теперь два новых отображения: отображение визуального режима и отображение режима, ожидающего оператора:
Которые полагаются на:
Я избавлю вас от нескольких сотен строк кода
lh#dev#find_function_boundaries()
И благодаря картографии DJ McMayhem
мы можем сделать
vif/pattern
поискpattern
в текущей функции.Мы также можем удалять функции
dif
, восстанавливать ихyif
и т. Д.Вот как это выглядит при применении к реалистичной функции C ++ (т.е. без отступа 0):
источник
Поиск начала и конца функции может быть затруднен, особенно в языке без
function
ключевого слова ... и многих противоречивых стилей отступа.Если ваша функция заканчивается закрывающей фигурной скобкой в отдельной строке (как в 10 из 13 перечисленных здесь стилей ), вы можете визуально выбрать ее примерно так:
Отсюда поиск
foo
в вашей функции - это только вопрос:Собрав все это вместе, мы можем получить довольно хорошее отображение:
Тем не менее, отображение визуального режима, вероятно, будет легко одурачено a
while
или a,if
так что оно, вероятно, выиграет от небольшой полировки. Кроме того, сохранение визуального выбора может быть не очень хорошей идеей ...источник
if
,for
,while
и т.д.Несовершенное решение использует складки . Сложите все:
Скажите Vim не открывать сложенные области для результатов поиска:
А затем откройте сгиб рассматриваемой функции (
zO
).Теперь все попадания для искомого текста в сложенной области приведут к тому, что Vim прыгнет на линию сгиба один раз, а затем перейдет к следующему попаданию.
Например, в случае ниже:
Сложенная функция имеет много применений
size
, ноn
не поможет мне использовать каждуюsize
функцию в этой функции.источник
Другой путь:
используйте оператор поиска Osyo Manga (зависит от vim-operator-user ), чтобы искать только внутри текущего блока. Например:
... теперь вы можете вставить свой поисковый запрос в соответствующее приглашение; нажмите,
n
чтобы увидеть, как результаты поиска ограничены текущим предоставленным движением / текстовым объектом. Поскольку это оператор Vim (т. Е. Компонуемый), если у вас есть хороший текстовый объект-функция, вам даже не нужно перемещаться внутри тела определения перед поиском, а напрямую использовать что-то подобноеg/if
или подобное.источник