使用参数定义新的Vim运算符

alf*_*eza 22 vim

我一直在寻找在Vim中映射一个带有额外参数的新运算符.

例如,我们知道ciw将"切入内部单词"并将使您进入插入模式,我正在寻找的是一个自定义动作来替换c(例如s)iw需要额外参数的动作.

一个简单的例子是:

Given a line in a text file
Run Code Online (Sandbox Code Playgroud)

并执行正常模式(给定光标在第一列)siw*,这将围绕第一个单词,*如下所示:

*Given* a line in a text file
Run Code Online (Sandbox Code Playgroud)

我知道,这是最优秀的surround.vim插件.但我只是在这里给出一个例子,并寻找一个关于如何获得映射以便上述工作的答案.

我试着用打onoremapopfunc,但似乎无法让他们打我想要的方式.

所以这是运动和运算符挂起映射的组合.

ib.*_*ib. 13

这里是用于说明目的的问题中描述的命令的示例实现.

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
Run Code Online (Sandbox Code Playgroud)

为了获得用户输入,使用该函数InputChar(),假设所需参数是单个字符.

function! InputChar()
    let c = getchar()
    return type(c) == type(0) ? nr2char(c) : c
endfunction
Run Code Online (Sandbox Code Playgroud)

如果有必要接受字符串参数,请调用input()而不是 InputChar().


Kan*_*uno 7

问题的标题可能会引起误解.你想要做的是定义一个新的运营商一样y,dc,既不运动也不文本对象,不是吗? :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)
Run Code Online (Sandbox Code Playgroud)

如果您确实想要定义自己的文本对象,请考虑使用vim-textobj-user.