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:functionToExecutees 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:functionToExecutees 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:functionToExecutees 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 dictaquí).
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-acon 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 gvdeliminar la selección anterior, la normal "xpreemplazará 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 xya tenga el tipo correcto (es decir, en forma de caracteres, en línea o en bloque).
dictpalabra clave. Esto se aplica a sus "métodos de clase". Ver:h numbered-function.dictde ninguna de lasMyClassfunciones). Pero me parece confuso, así que tiendo a agregardictexplícitamente.dictmétodos de objeto, pero no métodos de clase, para ayudar a aclarar su intención?selfes 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 eldictrecordatorio de que está bien usarself(es decir, una función quedictsiempre 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 endicttodas partes. Sí, la autoconsistencia es mi segundo nombre. ;)Cree el comando en una cadena y úselo
:exepara ejecutarlo. Ver:help executepara más detalles.En este caso,
executese 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