Определение нового оператора Vim с параметром - PullRequest
22 голосов
/ 25 января 2012

Я искал для отображения нового оператора в Vim, который принимает дополнительный параметр.

Например, мы знаем, что ciw «обрежет внутреннее слово» и переведет вас в режим вставки. Мне нужно пользовательское действие для замены c (например, s), которое требует такие движения, как iw, но требуют дополнительного параметра.

Тривиальным примером будет:

Given a line in a text file

И выполнить в обычном режиме (с указанием курсора на первом столбце) siw*, который окружит первое слово *, например:

*Given* a line in a text file

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

Я пытался играть с onoremap и opfunc, но не могу заставить их играть так, как я хочу.

Итак, это комбинация движений и сопоставления, ожидающие оператора.

Ответы [ 3 ]

12 голосов
/ 25 января 2012

Вот пример реализации команды, описанной в вопросе, в иллюстративных целях.

nnoremap <silent> s :set opfunc=Surround<cr>g@
vnoremap <silent> s :<c-u>call Surround(visualmode(), 1)<cr>
function! Surround(vt, ...)
    let s = InputChar()
    if s =~ "\<esc>" || s =~ "\<c-c>"
        return
    endif
    let [sl, sc] = getpos(a:0 ? "'<" : "'[")[1:2]
    let [el, ec] = getpos(a:0 ? "'>" : "']")[1:2]
    if a:vt == 'line' || a:vt == 'V'
        call append(el, s)
        call append(sl-1, s)
    elseif a:vt == 'block' || a:vt == "\<c-v>"
        exe sl.','.el 's/\%'.sc.'c\|\%'.ec.'c.\zs/\=s/g|norm!``'
    else
        exe el 's/\%'.ec.'c.\zs/\=s/|norm!``'
        exe sl 's/\%'.sc.'c/\=s/|norm!``'
    endif
endfunction

Для получения пользовательского ввода используется функция InputChar(), при условии, что Обязательный аргумент - один символ.

function! InputChar()
    let c = getchar()
    return type(c) == type(0) ? nr2char(c) : c
endfunction

Если необходимо принять строковый аргумент, вызовите input() вместо InputChar().

7 голосов
/ 31 января 2012

Название вопроса может вызвать недопонимание.Что вы хотите сделать, это определить новый оператор, такой как y, d и c, ни движения, ни текстовые объекты, не так ли?:help :map-operator описывает, как определить новый оператор.Чтобы взять такой параметр, как плагин объемного звучания, используйте getchar() в вашем 'operatorfunc'.

Хотя :help :map-operator описывает основы, работать с аргументами, передаваемыми 'operatorfunc', довольно сложно.Вы можете использовать vim-operator-user , чтобы упростить обработку аргументов.С помощью этого плагина оператор окружающего типа может быть записан следующим образом:

function! OperatorSurround(motion_wise)
  let _c = getchar()
  let c = type(_c) == type(0) ? nr2char(_c) : _c
  if c ==# "\<Esc>" || c == "\<C-c>"
    return
  endif

  let bp = getpos("'[")
  let ep = getpos("']")
  if a:motion_wise ==# 'char'
    call setpos('.', ep)
    execute "normal! \"=c\<Return>p"
    call setpos('.', bp)
    execute "normal! \"=c\<Return>P"
  elseif a:motion_wise ==# 'line'
    let indent = matchstr(getline('.'), '^\s*')
    call append(ep[1], indent . c)
    call append(bp[1] - 1, indent . c)
  elseif a:motion_wise ==# 'block'
    execute bp[1].','.ep[1].'substitute/\%'.ep[2].'c.\zs/\=c/'
    execute bp[1].','.ep[1].'substitute/\%'.bp[2].'c\zs/\=c/'
    call setpos('.', bp)
  else
  endif
endfunction
call operator#user#define('surround', 'OperatorSurround')
map s  <Plug>(operator-surround)

Если вы действительно хотите определить свои собственные текстовые объекты, рассмотрите vim-textobj-user .

1 голос
/ 25 января 2012

Рассмотрим один из плагинов для написания пользовательских текстовых объектов.Например: https://github.com/kana/vim-textobj-user

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