VimScript 五分钟入门(翻译) - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
skywind3000
V2EX    Vim

VimScript 五分钟入门(翻译)

  •  4
     
  •   skywind3000 2018-05-27 13:20:46 +08:00 5168 次点击
    这是一个创建于 2763 天前的主题,其中的信息可能已经有所发展或是发生改变。

    译注:折腾 Vim 当然要能看懂和改写相关脚本,而中文资料匮乏,缺一个提纲挈领的教程。本文翻译自 Andrew Scala 的 《Five Minute Vimscript》,立足于让你用最短的时间掌握 VimScript 的基础和要点,你可以把它看成一份语言速查表。

    Vim 有着丰富的内建文档系统,使用 code>:h <关键词> 就可以阅读,如果你想在方便的尝试各种 vimscript,你可以通过 NORMAL 模式下使用 gQ 命令进入 VimScript 的交互式环境调试命令。

    注意:下面的例子中会包含一些形如 <符号> 的符号,意味着正式使用时应该被完全替换成真实的东西,包括左右两边的尖括号。而单独的 <> 在 VimScript 中被用作比较符号。

    变量

    • let 命令用来对变量进行初始化或者赋值。
    • unlet 命令用来删除一个变量。
    • unlet! 命令同样可以用来删除变量,但是会忽略诸如变量不存在的错误提示。

    默认情况下,如果一个变量在函数体以外初始化的,那么它的作用域是全局变量;而如果它是在函数体以内初始化的,那它的作用于是局部变量。同时你可以通过变量名称前加冒号前缀明确的指明变量的作用域:

    g:var - 全局 a:var - 函数参数 l:var - 函数局部变量 b:var - buffer 局部变量 w:var - window 局部变量 t:var - tab 局部变量 s:var - 当前脚本内可见的局部变量 v:var - Vim 预定义的内部变量 

    你可以通过 $name 的模式读取或者改写环境变量,同时可以用 &option 的方式来读写 vim 内部的设置值。

    数据类型

    Number:32 位有符号整数

    -123 0x10 0177 

    Float: 浮点数,需要编译 Vim 的时候,有 +float 特性支持

    123.456 1.15e-6 -1.1e3 

    String: NULL 结尾的 8 位无符号字符串

    "ab\txx\"--" 'x-z''a,c' 

    Funcref: 函数引用,函数引用类型的变量名必须以大写字母开头

    :let Myfunc = function("strlen") :echo Myfunc('foobar') " Call strlen on 'foobar'. 6 

    List: 有序列表

    :let mylist = [1, 2, ['a', 'b']] :echo mylist[0] 1 :echo mylist[2][0] a :echo mylist[-2] 2 :echo mylist[999] E684: list index out of range: 999 :echo get(mylist, 999, "THERE IS NO 1000th ELEMENT") THERE IS NO 1000th ELEMENT 

    Dictionary: 无序的 Key/Value 容器

    :let mydict = {'blue': "#0000ff", 'foo': {999: "baz"}} :echo mydict["blue"] #0000ff :echo mydict.foo {999: "baz"} :echo mydict.foo.999 baz :let mydict.blue = "BLUE" :echo mydict.blue BLUE 

    没有布尔类型,整数 0 被当作假,其他被当作真。字符串在比较真假前会被转换成整数,大部分字符串都会被转化为 0,除非以非零开头的字符串才会转化成非零。

    VimScript 的变量属于动态弱类型。

    :echo 1 . "foo" 1foo :echo 1 + "1" 2 :function! TrueFalse(arg) : return a:arg? "true" : "false" :endfunction :echo TrueFalse("foobar") false :echo TrueFalse("1000") true :echo TrueFalse("x1000") false :echo TrueFalse("1000x") true :echo TrueFalse("0") false 

    字符串比较

    • <string> == <string>: 字符串相等
    • <string> != <string>: 字符串不等
    • <string> =~ <pattern>: 匹配 pattern
    • <string> !~ <pattern>: 不匹配 pattern
    • <operator>#: 匹配大小写
    • <operator>?: 不匹配大小写

    注意:设置选项 ignorecase 会影响 == 和 != 的默认比较结果,可以在比较符号添加 ? 或者 # 来明确指定大小写是否忽略。

    <string> . <string>: 字符串链接

    :function! TrueFalse(arg) : return a:arg? "true" : "false" :endfunction :echo TrueFalse("X start" =~ 'X$') false :echo TrueFalse("end X" =~ 'X$') true :echo TrueFalse("end x" =~# 'X$') false 

    If, For, While, and Try/Catch

    if <expression> ... elseif <expression> ... else ... endif for <var> in <list> continue break endfor 
    for [var1, var2] in [[1, 2], [3, 4]] " on 1st loop, var1 = 1 and var2 = 2 " on 2nd loop, var1 = 3 and var2 = 4 endfor 
    while <expression> endwhile 
    try ... catch <pattern (optional)> " HIGHLY recommended to catch specific error. finally ... endtry 

    函数

    使用 function 关键字定义一个函数,使用 function! 覆盖一个函数的定义,函数和变量一样也有作用范围的约束。需要注意函数名必须以大写字母开头。

    function! <Name>(arg1, arg2, etc) <function body> endfunction 

    delfunction <function> 删除一个函数

    call <function> 调用一个函数,函数调用前的 call 语句是必须的,除非在一个表达式里。

    例如:强制创建一个全局函数(使用感叹号),参数使用 ... 这种不定长的参数形式时,a:1 表示 ... 部分的第一个参数,a:2 表示第二个,如此类推,a:0 用来表示 ... 部分一共有多少个参数。

    function! g:Foobar(arg1, arg2, ...) let first_argument = a:arg1 let index = 1 let variable_arg_1 = a:{index} " same as a:1 return variable_arg_1 endfunction 

    有一种特殊的调用函数的方式,可以指明该函数作用的文本区域是从当前缓冲区的第几行到第几行,按照 1,3call Foobar() 的格式调用一个函数的话,该函数会在当前文件的第一行到第三行每一行执行一遍,再这个例子中,该函数总共被执行了三次。

    如果你在函数声明的参数列表后添加一个 range 关键字,那函数就只会被调用一次,这时两个名为 a:firstlinea:lastline 的特殊变量可以用在该函数内部使用。

    例如:强制创建一个名为 RangeSize 的函数,用来显示被调用时候的文本范围:

    function! b:RangeSize() range echo a:lastline - a:firstline endfunction 

    面向对象

    Vim 没有原生的类的支持,但是你可以用字典模拟基本的类。为了定义一个类的方法,可以在函数声明时使用 dict 关键字来将内部字典暴露为 self 关键字:

    let MyClass = {foo: "Foo"} function MyClass.printFoo() dict echo self.foo endfunction 

    类的实现更类似于 singleton,为了在 VimScript 中创建类的实例,我们对字典使用 copy() 方法进行拷贝:

    :let myinstance = copy(MyClass) :call myinstance.printFoo() Foo :let myinstance.foo = "Bar" :call myinstance.printFoo() Bar 

    接下来做什么?

    现在既然你已经知道了大致原理,下面给你推荐一些好的资源

    教程:

    其他:

    感谢

    希望你觉得本文对你有用,感谢阅读。

    第 1 条附言    2018-05-27 16:18:44 +08:00
    修正,面向对象部分,对象实例化中的 copy() 应该为 deepcopy()
    4 条回复    2018-05-28 08:31:37 +08:00
    glues
        1
    glues  
       2018-05-27 13:30:17 +08:00
    nG29DOMuRYTWfcSr
        2
    nG29DOMuRYTWfcSr  
       2018-05-27 13:54:16 +08:00
    Vim 脚本中的变量类型,其实时可以用函数获取的,自带的函数 type() 可以返回 0 - 7 八种类型,分别表示 Number, String, Funcref, List, Dictionary, Float, Boolean, Null.

    新的 Vim 中时存在 Boolean 这种类型的,他们是 v:true 和 v:false
    nG29DOMuRYTWfcSr
        3
    nG29DOMuRYTWfcSr  
       2018-05-27 14:02:16 +08:00
    let MyClass = {foo: "Foo"}

    这里应该改为 let MyClass = { "foo" : "Foo" }

    function MyClass.printFoo() dict
    echo self.foo
    endfunction

    我们来比较这段:
    :let myinstance = copy(MyClass)
    这里应该用 deepcopy()

    我们来看这个示例

    let MyClass = {"foo" : {"bar" : "Foo"}}
    function MyClass.printFoo() dict
    echo self.foo.bar
    endfunction

    :let myinstance = copy(MyClass)
    :let yourinstance = copy(MyClass)
    :call myinstance.printFoo()
    :let myinstance.foo.bar = "Bar"
    :call myinstance.printFoo()
    :call yourinstance.printFoo()


    你会发现,后面两个都是打印 Bar
    faywong8888
        4
    faywong8888  
       2018-05-28 08:31:37 +08:00 via Android
    很赞,感谢楼主科普。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2227 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 16:01 PVG 00:01 LAX 08:01 JFK 11:01
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86