Швидкий пошук, обмежений функцією C ++


13

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

Мені часто хочеться шукати будь-який примірник певної глобальної змінної або виклику функції, обмежений поточною функцією. Чи існує досить проста формула для цього?

(У мене встановлені каталоги та використовую Tagbar ... що може бути корисним для цього)

Відповіді:


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 відступів. Якщо на вступній дузі є відступи, вона все ще спрацьовує, хоча і не має позначки. Якщо ви регулярно використовуєте позначку "a", ви можете перемістити це, наприклад

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. Якби ці команди були :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

ми можемо зробити a vif/patternдля пошуку patternв поточній функції.

Ми також можемо видалити функції за допомогою dif, витягнути їх yifтощо.

Ось як це виглядає при застосуванні до реалістичної функції C ++ (тобто не 0 з відступом):Screencast: Виберіть функцію 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>

пошук у функції

При цьому, візуальне відображення в режимі вірогідно буде легко обдуритися whileабо ifтак, тому, ймовірно, виграє трохи полірування. Крім того, збереження візуального вибору може бути не дуже хорошою ідеєю ...


Це просто вибирає наступний блок, який він може знайти. Вона не працює на всіх , як тільки ви додаєте if, for, whileі т.д.
Джеймс

3

Недосконале рішення - використання складок . Складіть все:

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

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

set foldopen-=search

А потім відкрийте складку на функції, про яку йдеться ( zO).

Тепер усі звернення до тексту, що шукається, у складеному регіоні призведуть до того, що Вім один раз перейде на лінію згину, а потім перейде до наступного звернення.

Наприклад, у нижченаведеному випадку:

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

Складена функція має багато звичок 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чи подібне.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.