Para responder a su pregunta: el prototipo de call()
en el manual es call({func}, {arglist} [, {dict}])
; el {arglist}
argumento debe ser literalmente un objeto List, no una lista de argumentos. Es decir, tienes que escribirlo así:
let @x = call(a:functionToExecute, [GetSelectedText()])
Esto supone que a:functionToExecute
es un Funcref (ver :help Funcref
), o el nombre de una función (es decir, una cadena, como 'Type1ProcessString'
).
Ahora, esa es una característica poderosa que le da a Vim una especie de calidad similar a LISP, pero probablemente rara vez la usará como se indicó anteriormente. Si a:functionToExecute
es una cadena, el nombre de una función, puede hacer esto:
function! Wrapper(functionToExecute)
" ...
let s:processing = function(a:functionToExecute)
let @x = s:processing(GetSelectedText())
" ...
endfunction
y llamarías al contenedor con el nombre de la función:
call Wrapper('Type1ProcessString')
Si por otro lado a:functionToExecute
es un Funcref, puede llamarlo directamente:
function! Wrapper(functionToExecute)
" ...
let @x = a:functionToExecute(GetSelectedText())
" ...
endfunction
pero necesitas llamar al contenedor así:
call Wrapper(function('Type1ProcessString'))
Puede verificar la existencia de funciones con exists('*name')
. Esto hace posible el siguiente pequeño truco:
let s:width = function(exists('*strwidth') ? 'strwidth' : 'strlen')
es decir, una función que usa el incorporado strwidth()
si Vim es lo suficientemente nuevo como para tenerlo, y recurre a lo strlen()
contrario (no estoy argumentando que tal retroceso tenga sentido; solo digo que se puede hacer). :)
Con las funciones de diccionario (ver :help Dictionary-function
) puede definir algo parecido a las clases:
let g:MyClass = {}
function! g:MyClass.New(...)
let newObj = copy(self)
if a:0 && type(a:1) == type({})
let newObj._attributes = deepcopy(a:1)
endif
if exists('*MyClassProcess')
let newObj._process = function('MyClassProcess')
else
let newObj._process = function('s:_process_default')
endif
return newObj
endfunction
function! g:MyClass.getFoo() dict
return get(get(self, '_attributes', {}), 'foo')
endfunction
function! g:MyClass.setFoo(val) dict
if !has_key(self, '_attributes')
let self._attributes = {}
endif
let self._attributes['foo'] = a:val
endfunction
function! g:MyClass.process() dict
call self._process()
endfunction
function! s:_process_default()
echomsg 'nothing to see here, define MyClassProcess() to make me interesting'
endfunction
Entonces crearías instancias de objetos como este:
let little_object = g:MyClass.New({'foo': 'bar'})
Y llame a sus métodos:
call little_object.setFoo('baz')
echomsg little_object.getFoo()
call little_object.process()
También puede tener atributos y métodos de clase:
let g:MyClass.__meaning_of_life = 42
function g:MyClass.GetMeaningOfLife()
return get(g:MyClass, '__meaning_of_life')
endfunction
(Aviso no es necesario dict
aquí).
Editar: Subclasificar es algo como esto:
let g:MySubclass = copy(g:MyClass)
call extend(g:MySubclass, subclass_attributes)
El punto sutil aquí es el uso de en copy()
lugar de deepcopy()
. La razón de esto es poder acceder a los atributos de la clase padre por referencia. Esto se puede lograr, pero es muy frágil y hacerlo bien está lejos de ser trivial. Otro problema potencial es que este tipo de subclase se combina is-a
con has-a
. Por esta razón, los atributos de clase generalmente no valen la pena.
Ok, esto debería ser suficiente para pensar un poco.
Volviendo a su fragmento de código inicial, hay dos detalles que podrían mejorarse:
- no necesita
normal gvd
eliminar la selección anterior, la normal "xp
reemplazará incluso si no la mata primero
- usar en
call setreg('x', [lines], type)
lugar de let @x = [lines]
. Esto establece explícitamente el tipo de registro x
. De lo contrario, dependerá de que x
ya tenga el tipo correcto (es decir, en forma de caracteres, en línea o en bloque).
dict
palabra clave. Esto se aplica a sus "métodos de clase". Ver:h numbered-function
.dict
de ninguna de lasMyClass
funciones). Pero me parece confuso, así que tiendo a agregardict
explícitamente.dict
métodos de objeto, pero no métodos de clase, para ayudar a aclarar su intención?self
es diferente para los métodos de clase y para los métodos de objeto: es la clase misma en el primer caso y la instancia del objeto actual en el segundo. Por esta razón, siempre me refiero a la clase en sí misma comog:MyClass
, nunca usandoself
, y en su mayoría veo eldict
recordatorio de que está bien usarself
(es decir, una función quedict
siempre actúa en una instancia de objeto). Por otra parte, no uso mucho los métodos de clase, y cuando lo hago, también tiendo a omitir endict
todas partes. Sí, la autoconsistencia es mi segundo nombre. ;)Cree el comando en una cadena y úselo
:exe
para ejecutarlo. Ver:help execute
para más detalles.En este caso,
execute
se utiliza para hacer la llamada a la función y poner el resultado en el registro, los diferentes elementos del comando deben concatenarse con el.
operador como una cadena regular. La línea 3 debería convertirse en:fuente