vim: Продолжить макрос после ошибки в submacro?


14

Я нахожусь в процессе украшения некоторого исходного кода, используя vim. {1}

Я создал пару макросов vim, которые выполняют отдельные шаги: удаление конечного пространства, удаление пустых строк после {, удаление пустых строк до {, и тому подобное.

Теперь я хочу создать макрос, который последовательно выполняет все отдельные макросы. Однако, как только первый рекурсивный макрос завершает свою работу (поскольку он больше не может найти совпадений -> ошибка соответствия), мой макрос-оболочка также завершается.

Есть ли способ заставить макрос vim продолжить после того, как submacro сгенерировал ошибку?

{1} Я знаю об автоматических переформаторах. Я мог бы даже использовать их в моей текущей проблеме. Я просто упомянул источник переформатирования для примера. Не размещайте никаких ответов об этом источнике красоты или что. Вопрос не в переформатировании кода как таковом , а в макросах vim.

Пример:

  • Макрос 1 - обрезка замыкающего пробела - qw/\s\+$d$@wq
  • Макрос 2 - удаление пустых строк перед} - qe/\n\n *}dd@eq
  • Wrapper Macro - retabbing, Макрос 1, Макрос 2 - qr:retab@w@eq

Когда я @rзапускаю обертку - она будет перезагружена, затем выполнит Макро 1, пока не будет найдено больше конечных пробелов, а затем завершится ( без выполнения Макро 2).

Разъяснение:

Что я ищу, так это как вызвать submacro, чтобы, когда этот submacro завершается, вызывающий макрос продолжается?

Ответы:


12

Я предлагаю вам использовать, :tryчтобы «поглотить» ошибку субмакро.

Вот глупый пример:

:let @a='f|dt|@a'
:let @q=':try|exe "norm! @a"|endtry^Mj0@q'
@q

Ваш макрос-обертка будет выглядеть примерно так:

let @r=':retab^M:try|exe "norm! @w"|endtry|try|exe "norm! @e"|endtry^M'

В то время как garyjohn предусмотрен обходной путь для не имеющей ошибки в submacro, это единственный ответ , который на самом деле обрабатывать такую ошибку. Я должен извиниться, хотя; Я не проверил ваш ответ вовремя, чтобы вы могли получить (теперь
истекшее

25

Если неудачная команда является заменой, которая не находит свой шаблон, например,

:%s/foo/bar/

когда fooв буфере не существует, вы можете добавить eфлаг, чтобы игнорировать эту ошибку, например,

:%s/foo/bar/e

Видеть

:help :s_flags

Вы можете сказать Vim игнорировать ошибки некоторых команд: ex, предшествуя им с помощью :silent!. Видеть

:help :silent


Изменить после добавления примера к вопросу

Макрос 1 и Макрос 2 оба рекурсивны, и ни один из них не имеет какого-либо явного механизма завершения рекурсии. Я предполагаю, что запускается один из внутренних тестов Vim на неограниченную рекурсию, который выдает ошибку. Если макрос 1 генерирует такую ​​ошибку, то эта ошибка сразу же прекратит выполнение макроса Wrapper @w.

Я бы предложил ограничить число выполнений ваших макросов, переписав их как: ex команды и ограничив диапазон строк, в которых они выполняются. Например:

qw:%s/\s\+$//^Mq
qe:%s/\n\n *}/\r}/^Mq

где ^Mозначает ввод вашей клавиши ввода или возврата. Я не проверял их вместе в вашем макросе Wrapper, но думаю, вы сможете исправить любые ошибки, которые я мог допустить.


В моем случае это не замена, а простая находка (т.е. /foo). Хотя :silent!рекурсивный субмакро и не прерывал макрос-обертку, он действительно не завершался, теперь субмакро-файл вообще не завершается ... и я подозреваю, что повторное его выполнение каким-либо образом завершится снова, и макрос-обертка тоже снова завершится. Похоже, я застрял. : - \
DevSolar

Трудно сказать, что может быть не так, не видя используемые вами макросы или простой пример, демонстрирующий ту же проблему.
garyjohn

Добавил пример.
DevSolar

2

Для меня сработала комбинация ответов @Peter Rincker и @garyjohn. Отдельно я продолжал получать странные проблемы.

nnoremap <leader>rt :silent! %s/\s\+$//e<CR>
let @r='\rt'
let @t=':try|silent! exe "norm! @r"|endtry|w^M'

Я думаю, что silent!в и <leader>rt, и символы канала между endtryи wбыли ключами - просто разрыв строки после endtryнеудачного завершения . Они tryработали, когда я просто вводил их, но при запуске в качестве макроса ошибка о поисковом тексте не была найдена.


1

Я обычно создаю макросы на лету, когда мне нужно выполнить повторяющуюся задачу среди множества файлов. В моем случае в VIM установлено NERDtree ( http://www.vim.org/scripts/script.php?script_id=1658 ), которое создает vsplitокно, а слева у меня есть список всех файлов в текущий каталог. В одном примере мне нужно найти первый экземпляр строки MY_TESTв файле, а затем удалить, если он есть, префикс, помеченный как CUSTOM_PREFIX-из этой строки, сохранить файл, а затем перейти к следующему.

Вот как у меня работает этот макрос на 2000 файлов в текущем каталоге. Я мог бы написать скрипт bash для этого, но в моем случае это быстрее в VIM. Эти +клавиши означает нажат сеанс одновременной

# Start recording a macro sequence to register 'A'

q,a

# Search silently for the string "MY_TEST"; DO NOT report an error
# if the string could not be found.
:silent! /MY_TEST


# Replace, on just the current line, the string "CUSTOM_PREFIX-", with
# nothing (ie: delete it), and suppress any warning messages if the
# string could not be found on the current line.
:s/CUSTOM_PREFIX-//e


# Now issue some UI commands. CTRL-W then and arrow key lets you hope
# between tabs/splits/windows within vim.

CTRL+ W,

# Scroll down to the next file in the list in NERDtree



# Open the next file

ENTER

# End the macro

q

# Run the macro a thousand times in VIM

1000 @,a

Надеюсь это поможет!

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.