Pour répondre à votre question: le prototype de call()
dans le manuel est call({func}, {arglist} [, {dict}])
; l' {arglist}
argument doit être littéralement un objet List, pas une liste d'arguments. Autrement dit, vous devez l'écrire comme ceci:
let @x = call(a:functionToExecute, [GetSelectedText()])
Cela suppose a:functionToExecute
soit un Funcref (voir :help Funcref
), soit le nom d'une fonction (c'est-à-dire une chaîne, par exemple 'Type1ProcessString'
).
Maintenant, c'est une fonctionnalité puissante qui donne à Vim une sorte de qualité semblable à LISP, mais vous l'utiliseriez probablement rarement comme ci-dessus. Si a:functionToExecute
est une chaîne, le nom d'une fonction, vous pouvez le faire:
function! Wrapper(functionToExecute)
" ...
let s:processing = function(a:functionToExecute)
let @x = s:processing(GetSelectedText())
" ...
endfunction
et vous appelleriez le wrapper avec le nom de la fonction:
call Wrapper('Type1ProcessString')
Si d'autre part a:functionToExecute
est un Funcref, vous pouvez l'appeler directement:
function! Wrapper(functionToExecute)
" ...
let @x = a:functionToExecute(GetSelectedText())
" ...
endfunction
mais vous devez appeler le wrapper comme ceci:
call Wrapper(function('Type1ProcessString'))
Vous pouvez vérifier l'existence de fonctions avec exists('*name')
. Cela rend possible la petite astuce suivante:
let s:width = function(exists('*strwidth') ? 'strwidth' : 'strlen')
c'est-à-dire une fonction qui utilise la fonction intégrée strwidth()
si Vim est suffisamment nouvelle pour l'avoir, et revient à strlen()
autre chose (je ne dis pas qu'une telle solution de repli est logique; je dis simplement que cela peut être fait). :)
Avec les fonctions de dictionnaire (voir :help Dictionary-function
), vous pouvez définir quelque chose qui ressemble à des classes:
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
Ensuite, vous instanciez des objets comme celui-ci:
let little_object = g:MyClass.New({'foo': 'bar'})
Et appelez ses méthodes:
call little_object.setFoo('baz')
echomsg little_object.getFoo()
call little_object.process()
Vous pouvez également avoir des attributs et des méthodes de classe:
let g:MyClass.__meaning_of_life = 42
function g:MyClass.GetMeaningOfLife()
return get(g:MyClass, '__meaning_of_life')
endfunction
(remarquez pas besoin dict
ici).
Edit: Le sous-classement est quelque chose comme ceci:
let g:MySubclass = copy(g:MyClass)
call extend(g:MySubclass, subclass_attributes)
Le point subtil ici est l'utilisation de copy()
au lieu de deepcopy()
. La raison en est de pouvoir accéder aux attributs de la classe parente par référence. Cela peut être réalisé, mais c'est très fragile et le faire est loin d'être trivial. Un autre problème potentiel est que ce type de sous-classe se confond is-a
avec has-a
. Pour cette raison, les attributs de classe ne valent généralement pas vraiment la peine.
D'accord, cela devrait suffire à vous donner matière à réflexion.
Retour à votre extrait de code initial, il y a deux détails qui pourraient être améliorés:
- vous n'avez pas besoin
normal gvd
de supprimer l'ancienne sélection, la normal "xp
remplacera même si vous ne la tuez pas en premier
- utiliser
call setreg('x', [lines], type)
au lieu de let @x = [lines]
. Cela définit explicitement le type du registre x
. Sinon, vous comptez x
déjà sur le bon type (c.-à-d. Par caractère, par ligne ou par bloc).
dict
mot - clé. Cela s'applique à vos "méthodes de classe". Tu vois:h numbered-function
.