Vim - могу ли я передать несколько аргументов в пользовательскую команду без написания функции

Я написал следующую пользовательскую команду в моем файле.vimrc:

command! -nargs=+ Sub :%s/<args>/g

Это позволяет мне заменить одно слово на другое и выполняется так:

:Sub <word>/<new word>

Я бы предпочел писать команды с несколькими аргументами, например так:

:Sub <word> <new word>

Могу ли я переписать команду, чтобы принять несколько аргументов?

В идеале я хотел бы что-то вроде этого:

command! -nargs=+ Sub :%s/<arg1>/<arg2>/g

Заранее спасибо.

1 ответ

Решение

Сделайте разбор самостоятельно

Если вы используете :help <q-args>, вы получите строку в кавычках, что вы можете split() на две части разделенные пространством:

command! -nargs=+ Sub execute '%substitute/' . split(<q-args>, ' ')[0] . '/' . split(<q-args>, ' ')[1] . '/g'

Мы можем избежать синтаксического анализа дважды с помощью метапрограммирования (call()) а также printf():

command! -nargs=+ Sub execute call('printf', ['%%substitute/%s/%s/g'] + split(<q-args>, ' '))

Это работает, но обработка ошибок все еще не хороша (если вы передадите только один аргумент, он будет жаловаться E766: Insufficient arguments for printf()). Вы получите больше контроля, извлекая код в :function,

Vim может разобрать аргументы

Отдельный :function также позволяет Vim выполнять разбор аргументов за вас через :help <f-args>,

command! -nargs=+ Sub call Sub(<f-args>)
function! Sub( ... )
    execute printf('%%substitute/%s/%s/g', a:1, a:2)
endfunction

С помощью функции вы можете легко проверить правильность количества аргументов:

function! Sub( ... )
    if a:0 != 2
        echo "Need two arguments"
        return
    endif
    ...

Недостатком функции является то, что ошибки (например, шаблон не совпадает, буфер не модифицируется) приводят к многострочному, недружественному сообщению об ошибке. try...catch должно быть использовано для получения красивого однострочного сообщения об ошибке.

Бонус: где взять его оттуда

  • Как ты прячешь :s Команда (и используемые разделители) от пользователя, я думаю, не должно требоваться, чтобы разделители были экранированы. использование escape(a:1, '/') вместо a:1 / a:2,
  • С :help :command-range Вы по-прежнему можете использовать команду по умолчанию для всего буфера, но также разрешить пропуск других диапазонов.

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

Другие вопросы по тегам