To answer your question: the prototype of call()
in the manual is call({func}, {arglist} [, {dict}])
; the {arglist}
argument needs to be literally a List object, not a list of arguments. That is, you have to write it like this:
let @x = call(a:functionToExecute, [GetSelectedText()])
This assumes a:functionToExecute
is either a Funcref (see :help Funcref
), or the name of a function (i.e. a string, such as 'Type1ProcessString'
).
Now, that's a powerful feature that gives Vim a sort of LISP-like quality, but you'd probably seldom use it as above. If a:functionToExecute
is a string, the name of a function, then you can do this:
function! Wrapper(functionToExecute)
" ...
let s:processing = function(a:functionToExecute)
let @x = s:processing(GetSelectedText())
" ...
endfunction
and you'd call the wrapper with the name of the function:
call Wrapper('Type1ProcessString')
If on the other hand a:functionToExecute
is a Funcref, you can call it directly:
function! Wrapper(functionToExecute)
" ...
let @x = a:functionToExecute(GetSelectedText())
" ...
endfunction
but you need to call the wrapper like this:
call Wrapper(function('Type1ProcessString'))
You can check for existence of functions with exists('*name')
. This makes possible the following little trick:
let s:width = function(exists('*strwidth') ? 'strwidth' : 'strlen')
i.e. a function that uses the built-in strwidth()
if Vim is new enough to have it, and falls back to strlen()
otherwise (I'm not arguing that such a fallback makes sense; I'm just saying it can be done). :)
With dictionary functions (see :help Dictionary-function
) you can define something resembling 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
Then you'd instantiate objects like this:
let little_object = g:MyClass.New({'foo': 'bar'})
And call its methods:
call little_object.setFoo('baz')
echomsg little_object.getFoo()
call little_object.process()
You can also have class attributes and methods:
let g:MyClass.__meaning_of_life = 42
function g:MyClass.GetMeaningOfLife()
return get(g:MyClass, '__meaning_of_life')
endfunction
(notice no need for dict
here).
Subclassing is something like this:
let g:MySubclass = copy(g:MyClass)
call extend(g:MySubclass, subclass_attributes)
The subtle point here is the use of copy()
instead of deepcopy()
. The reason for this is to be able to access the attributes of the parent class by reference. This can be achieved, but it's highly fragile and getting it right is far from trivial. Another potential problem is that this kind of subclass conflates is-a
with has-a
. For this reasons class attributes are usually not really worth the pain.
Ok, this should be enough to give you some food for thought.
Back to your initial code snippet, there are two details with it that could be improved:
- You don't need
normal gvd
to remove the old selection, normal "xp
will replace it even if you don't kill it first
- Use
call setreg('x', [lines], type)
instead of let @x = [lines]
. This explicitly sets the type of the register x
. Otherwise you're relying on x
already having the correct type (i.e. characterwise, linewise, or blockwise).