2012-01-24 11 views
21

He estado buscando un nuevo operador en Vim que tome un parámetro adicional.Definición de un nuevo operador de Vim con un parámetro

Por ejemplo, sabemos que ciw "cortará palabra dentro" y le pondrá en el modo de inserción, lo que busco es tener una acción personalizada para reemplazar c (por ejemplo s) que se lleva a movimientos como iw pero requiere un parámetro extra

Un ejemplo trivial sería:

Given a line in a text file 

y ejecutar en modo normal (dado el cursor en la primera columna) siw* que rodearía la primera palabra con * así:

*Given* a line in a text file 

Lo sé, esto es lo que hace el complemento surround.vim más excelente. Pero solo estoy dando un ejemplo aquí, y estoy buscando una respuesta sobre cómo obtener las asignaciones para que el trabajo anterior funcione.

He intentado jugar con onoremap y opfunc pero parece que no puedo hacer que jueguen como yo quiero.

Esto es una combinación de movimientos más mapeos pendientes del operador.

+1

Pregunta interesante :) – Rook

+1

Porque eso es lo que hace Surround, ¿miraste el código de Surround? – romainl

+0

Eso es más o menos lo que Surround hace, excepto que agrega los movimientos después de las acciones de Vim como 'y',' d' y 'c'.Una vez más, tenga en cuenta que estoy dando un ejemplo, sin decir que quiero volver a escribir Surround. Y sí, he visto la fuente de Surround. – alfredodeza

Respuesta

12

Aquí hay una implementación de ejemplo del comando descrito en la pregunta, con fines ilustrativos.

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 

Para obtener la entrada del usuario, se utiliza la función InputChar(), suponiendo que el argumento necesario es un carácter único.

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

Si es necesario aceptar un argumento de cadena, llame input() en lugar de InputChar().

7

El título de la pregunta puede causar malentendidos. Lo que quiere hacer es definir un nuevo operador como y, d y c, ni los movimientos ni los objetos de texto, ¿no es así? :help :map-operator describe cómo definir un nuevo operador. Para tomar un parámetro como el complemento surround, use getchar() en su 'operatorfunc'.

Aunque :help :map-operator describe los conceptos básicos, es un poco problemático tratar con argumentos pasados ​​a 'operatorfunc'. Puede usar vim-operator-user para simplificar el manejo de argumentos. Con este plugin, operador de sonido envolvente como se puede escribir de la siguiente manera:

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) 

Si realmente quiere definir sus propios objetos de texto, por favor considere vim-textobj-user.

+0

¿Alguien le importaría dar un ejemplo concreto de cómo funciona esto? He intentado todo. Por ejemplo, ¿qué comando hace qué? ¡Gracias! –

Cuestiones relacionadas