| ч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|