Найти тему
Vim

VimScript 33 [ оператор grep часть 1]

Оглавление

| ч32. Базовые регулярные выражения | Содержание | ч34. оператор grep часть 2|

В этой и следующей статьях мы рассмотрим процесс создания довольно сложных вещей в Vimscript. Рассмотрим новые темы и те что изучали раньше увидим как их можно применить на практике.

Grep

Если вы никогда не использовали [ :grep ], вам следует сейчас потратить пару минут на чтение [ :help :grep ] и [ :help :make ]. Прочитайте так же [ :help quickfix-window ] , это список быстрых исправлений она много что позволяет делать, начиная с того что вы можете задать список мест в различных файлах где необходимо внести изменения, до если компилятор выдаёт ошибку то quickfix направит вас на точное местоположение где эта ошибка возникла. Кстати это отлично работает и с питоном и с Makefile и с CMake, очень прикольная штука, рекомендую.

Итак: [ :grep ... ] запустит внешнюю grep-программу с приведенными аргументами, проанализирует результат и заполнит список исправлений, чтобы вы могли перейти к результатам внутри Vim.

Например [ :grep ] упростит вызов, добавив "оператор grep", который вы можете использовать с любыми действиями в Vim при поиске текста .

Использование

И как же будет использоваться эта функциональность? Давайте прикинем план действий.

  • Мы собираемся создать "оператор grep" и привязать его к <leader>g.
  • Он будет действовать как любой другой оператор Vim, например как работает w или i{. т.е он должен стать частью Vim .
  • Он выполнит поиск и откроет окно quickfix для отображения результатов.
  • Он не будет переходить к первому совпадению, потому что это может вызвать раздражение, если первый результат не соответствует нашим ожиданиям.

Несколько примеров того, как мы можем в конечном итоге использовать его:

  • [ <leader>giw ]: Grep для слова под курсором.
  • [ <leader>giW ]: Grep для СЛОВА под курсором.
  • [ <leader>gi' ]: Grep для содержимого строки, заключенной в одинарные кавычки, в которой вы находитесь в данный момент.
  • [ viwe<leader>g ]: Визуально выделите слово, расширьте выделение до конца слова после него, затем выполните grep для выделенного текста.

Можно найти, много других способов которые повторяют эту функциональность. И вы можете подумать что для этого нужно много кодить. Но в реальности все что нам надо, так это реализовать функциональность "Оператор" , а с остальным справиться Vim

Предварительный набросок

Как обычно при написании сложного кода, мы вначале упрощаем нашу задачу, решаем ее, берем за основу и продолжаем совершенствовать.

Итак задача минимум. Необходимо "Создать сопоставление для поиска слова под курсором" и сопоставить его с [ <leader> g ]

Выполните эту команду:

:nnoremap <leader>g :grep -R something .<cr>

Надеюсь вы уже прочитали [ :help grep ] и у вас не осталось вопросов. Сопоставления мы определяли уже много раз тут все должно быть ясно. Далее мы рекурсивно ищем во всех файлах в текущем и ниже каталогах совпадение со словом something

Давайте уточним наше сопоставление. И сделаем поиск не слова something а поиск слова под курсором.

:nnoremap <leader>g :grep -R <cword> .<cr>

[ <cword> ] это специальный фрагмент текста который указывает Vim что перед запуском команды следует заменить его на слово которое находится под курсором. (смотри :help <cword>)

Вы можете использовать <cWORD>для получения СЛОВА вместо слова. Разница между словом и СЛОВОМ это учет специальных символов. Выполните эту команду:

:nnoremap <leader>g :grep -R <cWORD> .<cr>

Теперь давайте испытаем его в работе, запустите его поставив курсор над чем то вроде foo-bar. Vim нормально отработает этот пример.

Но есть проблема с нашим поиском, и это специальные символы оболочки Vim. Давайте сломаем наш поиск и попробуем поискать что то вроде [ foo;ls ]. Фактически мы выполнили в консоли команду ls! А ведь тут могла быть и более опасная команда чем ls.

Чтобы исправить это, мы добавим одинарные кавычки, это скажет Vim обрабатывать содержимое их буквально.

:nnoremap <leader>g :grep -R '<cWORD>' .<cr>

Теперь работа нашего сопоставления стала более надежной.

Экранирование аргументов командной оболочки

Есть еще одна проблема с поиском. Попробуйте наше сопоставление с [ that's ]. Это не сработает, потому что там одинарная кавычка внутри слова и она мешает команде grep! Мы опять все сломали.

Обойти это можно использовав функцию Vim [ shellescape ( ) ].

Прочтите :help escape() и :help shellescape() посмотрите как это работает. Поскольку shellescape() работает со строками, нам придется их динамически создать с помощью [ execute ]. Итак, чтобы преобразовать [ :grep ] отображение в [ :execute "..." ]форму, выполните следующую команду:

:nnoremap <leader>g :execute "grep -R '<cWORD>' ."<cr>

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

:nnoremap <leader>g :execute "grep -R " . shellescape("<cWORD>") . " ."<cr>

Если что то не работает, проверьте правильность расстановки пробелов.

Итак тестируем с [ foo;ls ] и это работает. Теперь попробуйте использовать слово [ that's ]. И это все еще не работает! Что произошло?

Проблема в том, что Vim выполнил вызов shellescape() до того, как он расширил специальную строку <cWORD> Итак, Vim просто экранировал строку "<cWORD>"(которая ничего не сделала, кроме добавления к ней одинарных кавычек), а затем объединил ее со строками нашей grep команды.

Вы можете убедиться в этом, выполнив следующую команду:

:echom shellescape("<cWORD>")

Vim выведет [ '<cWORD>' ]. Обратите внимание, что эти кавычки на самом деле являются частью строки. Vim подготовил его для использования в качестве аргумента командной оболочки.

Чтобы исправить это, мы будем использовать функцию expand() для принудительного расширения <cWORD>в фактическую строку, прежде чем она будет передана shellescape.

Давайте разберем все по шагам. Наведите курсор на слово с кавычкой, например that's, и выполните следующую команду:

:echom expand("<cWORD>")

Vim выводит [ that's ], потому что [ expand("<cWORD>")] возвращает текущее слово под курсором в виде строки Vim. Теперь давайте добавим shellescape обратно:

:echom shellescape(expand("<cWORD>"))

На этот раз вывод Vim будет такой [ 'that'\''s'] . Если это выглядит немного забавно, вы, вероятно , не имели удовольствия обернуть свой мозг вокруг shell-цитирования во всей его безумной красе. Пока не беспокойтесь об этом. Просто поверьте, что Vim взял строку expand и правильно ее экранировал.

Теперь, когда мы знаем, как получить полностью экранированную версию слова под курсором, пришло время вставить его в наше отображение! Здесь и далее выполните следующую команду в одну строчку:

:nnoremap <leader>g :exe "grep -R " . shellescape(expand("<cWORD>")) . " ."<cr>

Теперь все работает как надо. Теперь поиск слова идет даже если встречаются странные символы

Можно нас поздравить, наша маленькая команда преобразилось во что то близкое к нашей цели.

Очистка

Есть еще пара мелочей, о которых нужно позаботиться, прежде чем наше сопоставление будет завершено. Во-первых, мы сказали, что не хотим автоматически переходить к первому результату, и для этого мы можем использовать [ grep! ] вместо [ grep ]. Выполните эту команду:

:nnoremap <leader>g :execute "grep! -R " . shellescape(expand("<cWORD>")) . " ."<cr>

Попробуйте еще раз, и, похоже, ничего не произошло. Vim заполнил окно quickfix результатами, но мы это окно еще не открывали. Выполните следующую команду:

:nnoremap <leader>g :execute "grep! -R " . shellescape(expand("<cWORD>")) . " ."<cr>:copen<cr>

Попробуйте это сопоставление, и вы увидите, что Vim автоматически открывает окно quickfix с результатами поиска. Все, что мы сделали, это привязали [ :copen<cr>] к концу нашего сопоставления. Теперь мы можем перемещаться по документам с найденным нашем словом.

Мы закончили, так что мы можем смело восхищаться нашей работой!

Упражнения

Добавьте только что созданное сопоставление в свой ~/.vimrc файл.

Прочитайте :help :grep, если вы не читали его раньше.

Прочитайте :help cword.

Прочитайте :help cnext и :help cprevious. Попробуйте их после использования нашего нового сопоставления grep.

Настройте сопоставления для :cnext и:cprevious, чтобы упростить быстрый просмотр совпадений.

Прочитайте :help expand.

Прочитайте :help copen.

Добавьте удобную высоту для окна quickfix создайте нужное сопоставление к :copen

Прочитайте :help silent.

| ч32. Базовые регулярные выражения | Содержание | ч34. оператор grep часть 2|