Vim:Как обрабатывать переводы строк при хранении нескольких команд в регистрах?
-
02-10-2019 - |
Вопрос
У меня есть файл, в котором я храню фрагменты команд vim.Когда мне нужен фрагмент кода, я дергаю его, а затем выполняю с помощью @"
.Фрагменты хранятся в виде скрипта, по одной строке на команду, вот так:
:s/foo/bar/g
:echo "hello"
:s/1/2/g
Редактировать:Я удалил команды обычного режима из примера, поскольку они не были частью проблемы.
Теперь эта процедура больше не работает:при выполнении фрагмента он просто останавливается на первой строке, как будто ожидает перевода строки.
Есть ли где-нибудь вариант, влияющий на то, как @
выполняется?Я почти уверен, что некоторое время назад это работало...
Замена новой строки символом ^M работает, но усложняет обработку файла.
Дополнительная информация:
Вот еще один симптом:когда я выдергиваю фрагмент, если я выполняю его с помощью @"
это заканчивается на первой строке, как я только что объяснил.Но если я выполню это с помощью :@
это работает.Но файл справки, похоже, не подразумевает никакой разницы в том, как эти две команды обрабатывают содержимое регистра...
Решение 2
Я наконец нашел виновник. Как-то у меня было отображение команды на <C-J>
в моем файле .vimrc. При чтении с по умолчанию cpoptions
, это превратилось в картирование на <NL>
.
Как я узнал: я заметил, что при запуске Vim с -u ~/.vimrc
, это действительно будет выполнять снужные фрагменты. Я сгенерировал файл сеанса с помощью этой командой опции и сравнил их. Таким образом, я узнал, что другой набор cpoptions
где используется для чтения одного и того же файла .vimrc, так что в одном случае отображение было действительно на <C-J>
, в другой он был преобразован в отображение на <NL>
!
Если у кого-то есть похожая проблема, я предлагаю внимательно посмотреть на текущие установленные командные сопоставления, с :cmap
.
Другие советы
Я не думаю, что проблема в том, что ^M
против. ^J
.Макросы Vim будут обрабатывать любой из них как допустимый символ конца строки для записанных макросов.Я думаю, проблема в дополнительных символах новой строки.
В вашем примере есть по крайней мере один ложный перевод строки после 2j
, и если вы не будете особенно осторожны при копировании фрагмента, вероятно, после него появится еще один 10k
также хорошо.Эти дополнительные новые строки подобны нажатию <Enter>
в обычном режиме - они перемещают курсор вниз на одну строку.
Вот как, я думаю, вы хотите, чтобы фрагмент выглядел следующим образом:
:s/foo/bar/g
2j:s/1/2/g
10k
(Даже это немного вводит в заблуждение - вам все равно придется быть осторожным, чтобы не копировать новую строку после 10k
.)
Почему эти дополнительные новые строки имеют такое большое значение?Ну, во-первых, они заставляют вас находиться по крайней мере на одну строку дальше от того места, где вы ожидаете быть, что отбрасывает все, что вы хотите сделать в определенной строке (например, выполнить :s//
команда).
Однако что еще более важно - и это то, что, я думаю, происходит в вашем примере - Vim останавливает воспроизведение макроса, если макрос пытается использовать <Enter>
в последней строке буфера.(Я предполагаю, что Vim считает это ошибкой, и любая ошибка приводит к остановке запуска макроса.)
Вот пример.Предположим, у вас есть этот фрагмент, сохраненный в регистре x:
4j
:echo "Done"
(Обратите внимание на перевод строки после 4j
.)
Кроме того, предположим, что у вас есть следующие пять строк (и только эти пять строк) в буфере:
line 1
line 2
line 3
line 4
line 5
Если вы сейчас нажмете @x
вкл . line 1
, тот самый :echo "Done"
никогда не выполняется.Vim перемещает курсор вниз на 4 строки, чтобы line 5
, затем пытается переместиться вниз еще на одну строку из-за дополнительного перевода строки, но не может.Макрос прекращает выполнение в этот момент, перед тем как :echo
команда получает шанс на запуск.
Однако это сработает, если вы измените регистр x на этот:
4j:echo "Done"
Итак, чтобы вернуться к вашему исходному примеру, я готов поспорить, что происходит то, что дополнительная новая строка после 2j
пытается переместить ваш курсор туда, куда он не может попасть, и это приводит к остановке макроса.Нижняя строка экрана содержит последнюю выполненную команду (:s/foo/bar/g
), из-за чего создается впечатление, что Vim ждет, когда вы нажмете Return.
Наконец, я бы настоятельно рекомендовал использовать другой метод для хранения и выполнения последовательностей команд Vim.Техника, которую вы используете, приемлема для простых случаев, но она хрупкая и плохо масштабируется.Vim имеет полноценный скриптовый язык, который включает функции и пользовательские команды, и его можно использовать для выполнения всего того, что вы делаете сейчас, но гораздо более надежным способом.Скриптинг в Vim - это большая тема, но я бы начал с этого:
:help script
Обязательно прочтите о :normal
команда, которая позволяет вам выполнять команды обычного режима (например 2j
и 10k
) внутри скриптов.
Удачи вам!