Определение нового оператора 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
, но не могу заставить их играть так, как я хочу.
Таким образом, это комбинация движений плюс операторные ожидающие отображения.
Ответы
Ответ 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