Щоб відповісти на ваше запитання: прототип 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.