获取所选文本的函数:只需拉出最后一个选择并返回它。
包装函数:调用一个处理函数,获取其结果并用该结果替换旧选择。
现在,我的包装函数如下所示:
function! Wrapper()
" Get the string to insert
let @x = Type1ProcessString(GetSelectedText())
" remove the old selection
normal gvd
" insert the new string
normal "xp
endfunction
我必须创建第二个包装器,将第3行替换为
let @x = Type2ProcessString(GetSelectedText())
我想给包装器函数一个参数,该参数包含要执行的Process函数并使用第3行中的一般调用。到目前为止,我尝试使用
call
的不同方式,例如,例如:在委托主题上并没有真正帮助。
总结一下,这是我的问题:
我怎样才能仅为所有对象创建一个包装函数?正在处理吗?
有什么东西可以用作delega在vimscript中?
如果不存在代表,那么做我想要的事情的“好”方法是什么?
#1 楼
回答您的问题:手册中call()
的原型为call({func}, {arglist} [, {dict}])
; {arglist}
参数实际上是一个List对象,而不是参数列表。也就是说,您必须这样编写: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')
即如果Vim足够新,则使用内置
strwidth()
的函数,否则将使用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
。#2 楼
将命令构建为字符串,然后使用:exe
运行该命令。有关更多详细信息,请参见:help execute
。在这种情况下,使用
execute
进行函数调用并将结果存储在寄存器中,该命令的不同元素必须与.
运算符串联在一起常规字符串。第3行应变为:execute "let @x = " . a:functionToExecute . "(GetSelectedText())"
评论
直接在字典中创建函数(即“编号函数”)时,不需要dict关键字。这适用于您的“类方法”。参见:h numbered-function。
– Karl YngveLervåg
15年7月11日在19:33
@KarlYngveLervåg从技术上讲,它适用于类和对象方法(即,对于任何MyClass函数都不需要dict)。但是我发现这很令人困惑,因此我倾向于显式地添加字典。
–lcd047
15年7月11日在20:46
我懂了。因此,您为对象方法而不是类方法添加了dict,以帮助阐明您的意图?
– Karl YngveLervåg
15年7月12日在11:08
@ lcd047非常感谢这个惊人的答案!我将不得不对其进行处理,但这正是我所寻找的!
–statox♦
15年7月12日在12:02
@KarlYngveLervåg这里有一个微妙之处,self的含义对于类方法和对象方法是不同的-在前一种情况下,它是类本身,而在后一种情况下,是当前对象的实例。因此,我总是将类本身称为g:MyClass,从不使用self,而我大多将dict看作是可以使用self的提示(即,具有dict的函数始终作用于对象实例) 。再说一次,我不太使用类方法,当我这样做时,我也倾向于在各处忽略字典。是的,自洽是我的中间名。 ;)
–lcd047
15年7月12日在16:25