Изменение имен переменных в Vim - PullRequest
87 голосов
/ 28 февраля 2009

Я пытаюсь прочитать много кода C / Perl через Vim, который содержит много однобуквенных имен переменных.

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

Есть ли какая-нибудь команда в Vim, которая могла бы позволить мне быстро сделать это?

Я не думаю, что регулярные выражения будут работать, потому что:

  1. одно и то же имя одной буквы может иметь разные цели в разных областях видимости

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

Какие-нибудь известные решения?

Ответы [ 7 ]

180 голосов
/ 28 февраля 2009

Ниже описано, как переименовать переменную, определенную в текущей области действия {}.

Переместите курсор на использование переменной. Нажмите gd. Что значит - переместить курсор на определение. Теперь нажмите [{ - это приведет вас к началу прицела. Нажмите V - включит выбор визуальной линии. Нажмите % - перейдете к противоположному }, таким образом, выберете всю область. Нажмите :s/ - запуск команды замены. <C-R>/ - вставит шаблон, который соответствует имени переменной (имя, которое вы использовали до нажатия gd). /newname/gc<CR> - инициирует поиск и заменяет подтверждение при каждом совпадении.

Теперь вам нужно записать макрос или, что еще лучше, сопоставить ключ.

Вот окончательные сопоставления:

" For local replace
nnoremap gr gd[{V%::s/<C-R>///gc<left><left><left>

" For global replace
nnoremap gR gD:%s/<C-R>///gc<left><left><left>

Поместите это в .vimrc или просто выполните. После этого нажатие gr на локальной переменной приведет вас к команде :s, в которой вы просто должны ввести new_variable_name и нажать Enter .

9 голосов
/ 28 февраля 2009

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

  1. Ограничить сферу изменения пометок использования.
  2. При вводе регулярного выражения заключите в скобки имя с помощью \ <и>. Это приведет к тому, что оно будет соответствовать целому слову, что уменьшит количество типов неправильных переименований.
  3. Не выполняйте многострочную замену, чтобы уменьшить вероятность плохой замены
  4. Внимательно просмотрите код diff, если это что-то кроме небольшого изменения.

Мое окончательное изменение выглядит примерно так

:'a,'bs/\<foo\>/bar

Я бы хотел ошибиться из-за того, что не существует инструмента рефакторинга для VIM, но я его не видел.

8 голосов
/ 14 ноября 2013

Поместите это в свой .vimrc

" Function to rename the variable under the cursor
function! Rnvar()
  let word_to_replace = expand("<cword>")
  let replacement = input("new name: ")
  execute '%s/\(\W\)' . word_to_replace . '\(\W\)/\1' . replacement . '\2/gc'
endfunction

Позвоните по номеру :call Rnvar()

expand("<cword>") получает слово под курсором. Строка поиска использует % для области видимости файла, а шаблоны \(\W\) ищут несимвольные символы на границе слова для замены и сохраняют их в переменных \1 и \2, чтобы получить вставляется в шаблон замены.

7 голосов
/ 16 апреля 2018

Я знаю, что это старый вопрос, и путь @ mykola-golubyev, очевидно, является лучшим ответом для конкретного случая в OP-вопросе (который, я полагаю, проходит через запутанный код, в котором вы, вероятно, будете иметь несколько блоки с одинаковыми именами var); но с таким названием вопроса многие люди, приходящие сюда из поисков Google, вероятно, ищут менее специфичные для конкретной ситуации способы переименования переменных в VIM - и они могут быть более краткими

Я удивлен, что никто не предложил такой способ:

* :s// NEWNAME /gc

* совпадает с gn - он ищет следующее вхождение слова под курсором И становится последним найденным шаблоном, поэтому, когда вы пропускаете шаблон поиска в команде замены, VIM предполагает, что это шаблон для поиска.

Для небольшого количества var-копий, еще более быстрого:

* cw NEWNAME <esc>, затем повторите n. для других случаев

Поиск вхождений, cw - команда для изменение слова , n - переход к следующему вхождению для последнего поиска и . повторение последней команды (то есть изменение слова на NEWNAME )

(Кредиты для меня, зная все это, перейдите на @ doomedbunnies на Reddit )

Еще один крутой трюк: ( кредиты @ nobe4 )

* cgn NEWNAME <esc>, затем повторите . для других случаев

cgn - это «изменить то, что является результатом (найти следующее вхождение)». Теперь, когда это последняя команда, вам не нужно n, чтобы перейти к следующему вхождению, поэтому снова нужно меньше ударов и, что более важно, не нужно чередовать n и .. Но, очевидно, у этого есть недостаток, заключающийся в отсутствии способа пропустить событие.

Вот некоторые преимущества:

  • нет сопоставления, нет .vimrc (или init.vim), так что вы можете использовать его в любой копии VIM, с которой вы сталкиваетесь (например, быстрое задание на каком-нибудь VPS или компьютере вашего друга, где настройка VIM на вашем пути не позволит 'быстрый')
  • Использование * или gn для выбора слов очень быстро - всего одно нажатие клавиши (ну, скажем, 1,5)
  • с использованием * или gn гарантирует, что вы не получите совпадений внутри других слов, как :%s/<C-R>//gc. Ударяет ввод :%s/\<OLDNAME\>/NEWNAME/gc от руки: лично я склонен забывать использовать вещи \<, чтобы ограничить совпадения только целыми словами.
  • Не использование области действия приведет только к нескольким дополнительным штрихам n, чтобы пропустить нежелательные совпадения - возможно, даже меньше, чем дополнительные штрихи, необходимые для ограничения области. При нормальных обстоятельствах ваши переменные, скорее всего, в какой-то степени все-таки локализуются в определенном блоке кода.
2 голосов
/ 28 февраля 2009

Вы можете использовать модификатор 'c' в глобальном поиске и замене, который будет запрашивать подтверждение для каждой замены. Это заняло бы больше времени, но могло бы работать для файла кода, не имеющего большого размера:

%s/\$var/\$foo/gc

C означает подтверждение.

0 голосов
/ 01 марта 2009

Если это в нескольких файлах, вы можете взглянуть на sed. Используйте find, чтобы получить ваши файлы и xargs плюс sed для замены. Скажем, вы хотите заменить a на a_better_name во всех файлах, соответствующих * .c, вы можете сделать

найти. имя "* .c" | xargs sed -i -e 's / a / a_better_name / g'

Имейте в виду, что это заменит ВСЕ вхождения a, поэтому вам может потребоваться более надежное регулярное выражение.

0 голосов
/ 28 февраля 2009

В c вы можете добиться некоторого прогресса, используя cscope. Он пытается понять синтаксис, поэтому у него будет шанс узнать, когда буква была переменной.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...