Подтвердить что ты не робот

Определение нового оператора Vim с параметром

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

Например, мы знаем, что ciw будет "обрезать внутреннее слово" и переместит вас в режим вставки. Я ищу, чтобы выполнить замену c (например s), которое принимает таких как iw, но требует дополнительного параметра.

Тривиальный пример:

Given a line in a text file

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

*Given* a line in a text file

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

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

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

4b9b3361

Ответ 1

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

nnoremap <silent> s :set opfunc=Surround<cr>[email protected]
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().

Ответ 2

Название вопроса может вызвать недоразумение. Что вы хотите сделать, так это определить новый оператор, такой как 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.

Ответ 3

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