Как мне повторить функцию vimscript, которая содержит встроенную функцию `input`? - PullRequest
2 голосов
/ 02 ноября 2019

Текущее поведение

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

Интерфейс пользователя

  1. Он запрашивает у пользователя текстовый объект, в котором нужно выполнить команду обычного режима
  2. Он запрашивает регулярное выражение, описывающее строки для выполнения команды
  3. Он просит команду выполнить
  4. Он запускает команду

Код

function! s:lines(...) abort
  return [line("'["), line("']")]
endfunction

function! s:gObject(...) abort
  if !a:0
    let &operatorfunc = matchstr(expand('<sfile>'), '[^. ]*$')
    return 'g@'
  else
    let [lnum1, lnum2] = <SID>lines(a:0, a:1) 
    let search = input("Run (Leave empty for last search): g/\\v")
    let prompt = lnum1 . "," . lnum2 . "g/\\v" . search . "/". "norm "
    let cmd = input("Run: " . a:prompt)
    exec a:prompt . cmd
  endif
endfunction

Желаемый результат

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

Я могу сделать это, записав макрос перед запуском функции, затемвоспроизведение макроса будет производить именно то поведение, которое я хочу. Я хочу этого точного результата, но без накладных расходов пользователя на объявление макроса.

Что я пробовал

  1. Установив vim-repeat и нажав .. Это перезапускает выделение текста, но не вводит команды (отсюда и вопрос).
  2. Запись макроса последовательности и ее воспроизведение. Это приводит к плохому UX.

Заранее спасибо за вашу помощь.

1 Ответ

0 голосов
/ 04 ноября 2019

Использование repeat.vim - правильный подход;он позволяет вам настраивать то, что повторяется, а также предлагает функцию повторения для случаев, не охватываемых встроенной командой .. (И мой плагин visualrepeat расширяет это до повторов в визуальном режиме.)

Если я вас правильно понял, вы хотите пропустить пользовательский запрос и просто повторно использовать предыдущий ответ при повторении. Для этого вам нужно зарегистрировать другое <Plug> отображение с repeat#set(), чем то, которое используется для запуска вашего плагина. Обычно я бы выглядел следующим образом:

function! s:Impl()
    let l:search = input(...)
    " action here, using l:search
    call repeat#set("\<Plug>PeculiarMapping")
endfunction
nnoremap <silent> <Plug>PeculiarMapping :<C-u>call <SID>Impl()<CR>
if ! hasmapto('<Plug>PeculiarMapping', 'n')
    nmap <Leader>p <Plug>PeculiarMapping
endif

Чтобы повторно использовать запрашиваемый l:search при повторении, параметризовать s:Impl() с флагом, а затем либо сохранить ввод в локальной переменной сценария,или вспомнить это. Добавьте вариант <Plug> -mapping для repeat, который устанавливает флаг isRepeat:

let s:search = ''
function! s:Impl( isRepeat )
    if ! a:isRepeat
        let s:search = input(...)
    endif
    " action here, using s:search
    call repeat#set("\<Plug>PeculiarRepeat")    " Different repeat mapping
endfunction
nnoremap <silent> <Plug>PeculiarRepeat :<C-u>call <SID>Impl(1)<CR>
nnoremap <silent> <Plug>PeculiarMapping :<C-u>call <SID>Impl(0)<CR>
if ! hasmapto('<Plug>PeculiarMapping', 'n')
    nmap <Leader>p <Plug>PeculiarMapping
endif

Дополнительные комментарии

Я стараюсь избегать использования input(), поскольку это делает команду по своей сутиинтерактивный, поэтому он не может быть повторно использован для сценариев или даже легко вызван другим отображением. Если вам просто нужно сначала получить какой-либо параметр (ы) от пользователя, прежде чем выполнять работу, я предпочитаю пользовательский :command, который принимает аргумент (ы). Для одного параметра это просто и не требует синтаксического анализа. Для нескольких параметров я стараюсь придерживаться соглашений существующих команд Ex (самые сложные, :substitute занимает {pattern}, {replacement}, [flags] и даже [count]);различные флаги :command предлагают множество вариантов, и вы можете дополнительно помочь пользователю с помощью пользовательской функции завершения.

С помощью специальной команды это можно повторить с помощью @: или истории команд, ипользователь может решить, использовать ли аргументы повторно (полностью / частично). Если вы думаете, что ввод команды занимает слишком много времени, дополнительное отображение может войти в режим командной строки, поместить команду туда, возможно, даже добавить сценарий (например, разделители /// в :substitute) и расположить курсор, так чтопользователь просто должен заполнить параметры и нажать <Enter>.

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