Чтобы ответить на ваш вопрос: прототип call()
в руководстве есть call({func}, {arglist} [, {dict}])
; {arglist}
аргумент должен быть буквально объект списка, а не список аргументов. То есть вы должны написать это так:
let @x = call(a:functionToExecute, [GetSelectedText()])
Предполагается, что a:functionToExecute
это либо Funcref (см. :help Funcref
), Либо имя функции (например, строка, например 'Type1ProcessString'
).
Теперь это мощная функция, которая дает Vim своего рода LISP-подобное качество, но вы, вероятно, редко будете использовать его, как указано выше. Если a:functionToExecute
это строка, имя функции, то вы можете сделать это:
function! Wrapper(functionToExecute)
" ...
let s:processing = function(a:functionToExecute)
let @x = s:processing(GetSelectedText())
" ...
endfunction
и вы вызываете упаковщик с именем функции:
call Wrapper('Type1ProcessString')
Если, с другой стороны a:functionToExecute
, это Funcref, вы можете вызвать его напрямую:
function! Wrapper(functionToExecute)
" ...
let @x = a:functionToExecute(GetSelectedText())
" ...
endfunction
но вам нужно вызвать оболочку следующим образом:
call Wrapper(function('Type1ProcessString'))
Вы можете проверить наличие функций с помощью exists('*name')
. Это делает возможным следующий маленький трюк:
let s:width = function(exists('*strwidth') ? 'strwidth' : 'strlen')
то есть функция, которая использует встроенную функцию, strwidth()
если Vim достаточно новая, чтобы иметь ее, и прибегает к strlen()
обратному (я не утверждаю, что такой запасной вариант имеет смысл; я просто говорю, что это возможно). :)
С помощью функций словаря (см. :help Dictionary-function
) Вы можете определить нечто похожее на классы:
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
Тогда вы будете создавать экземпляры таких объектов:
let little_object = g:MyClass.New({'foo': 'bar'})
И назовите его методами:
call little_object.setFoo('baz')
echomsg little_object.getFoo()
call little_object.process()
Вы также можете иметь атрибуты класса и методы:
let g:MyClass.__meaning_of_life = 42
function g:MyClass.GetMeaningOfLife()
return get(g:MyClass, '__meaning_of_life')
endfunction
(обратите внимание, нет необходимости dict
здесь).
Редактировать: Подклассы это что-то вроде этого:
let g:MySubclass = copy(g:MyClass)
call extend(g:MySubclass, subclass_attributes)
Тонким моментом здесь является использование copy()
вместо deepcopy()
. Причиной этого является возможность доступа к атрибутам родительского класса по ссылке. Этого можно достичь, но он очень хрупкий, и правильно понять это далеко не тривиально. Другая потенциальная проблема заключается в том, что этот вид подкласса связан is-a
с has-a
. По этой причине атрибуты класса обычно не стоят такой боли.
Хорошо, этого должно быть достаточно, чтобы дать вам пищу для размышлений.
Возвращаясь к вашему фрагменту кода, есть две деталей с ней, что можно было бы улучшить:
- Вам не нужно ,
normal gvd
чтобы удалить старый выбор, normal "xp
заменит его , даже если вы не убить его первым
- использовать
call setreg('x', [lines], type)
вместо let @x = [lines]
. Это явно устанавливает тип регистра x
. В противном случае вы полагаетесь на x
уже имеющих правильный тип (т.е. посимвольный, построчной или покадрово).
dict
ключевое слово. Это относится к вашим "методам класса". См:h numbered-function
.