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
.dict
pour l' une desMyClass
fonctions). Mais je trouve cela déroutant, j'ai donc tendance à ajouterdict
explicitement.dict
des méthodes d'objet, mais pas des méthodes de classe, afin de clarifier votre intention?self
est différente pour les méthodes de classe et pour les méthodes d'objet - c'est la classe elle-même dans le premier cas, et l'instance de l'objet actuel dans le second. Pour cette raison, je me réfère toujours à la classe elle-même commeg:MyClass
, ne l'utilisant jamaisself
, et je vois principalement ledict
comme un rappel qu'il est correct d'utiliserself
(c'est-à-dire une fonction qui adict
toujours agi sur une instance d'objet). Encore une fois, je n'utilise pas beaucoup les méthodes de classe, et quand je le fais, j'ai également tendance à omettredict
partout. Oui, l'auto-cohérence est mon deuxième prénom. ;)Générez la commande dans une chaîne et utilisez-la
:exe
pour l'exécuter. Voir:help execute
pour plus de détails.Dans ce cas,
execute
permet d'appeler la fonction et de mettre le résultat dans le registre, les différents éléments de la commande doivent être concaténés avec l'.
opérateur sous forme de chaîne régulière. La ligne 3 devrait alors devenir:la source