Vim脚本基础

viml语言基础

viml是为Vim编辑器编写扩展而创建的一门脚本语言.

变量

有效变量名

由ASCII字符, 数字, 或下划线组成,但是变量名不能够一数字开始

变量类型

  1. b: 在单一Vim缓冲区里被辨识的变量
  2. w: 在单一Vim窗口里被辨识的变量
  3. t: 在单一Vim标签里被辨识的变量
  4. g: 全局变量
  5. l: 在函数内被辨识的变量(局部变量)
  6. s: 在Vim脚本里面被辨识的变量
  7. a: 函数的参数
  8. v: Vim变量 – 由Vim控制(全局变量)

注意: 如果不以前缀定义Vim变量的作用域,当变量定义在函数外时,默认为全局变量(g:), 定义在函数内时,默认是局部变量(l:).

变量赋值

1
let g:var = "value"

删除变量

1
2
3
unlet g:var
" 如果不确定某个变量是否存在
unlet! g:var

当一个脚本结束时,他使用的局部变量(s:var)并不会自动删除,下一次脚本被执行时,仍然有效, 例:

1
2
3
4
5
if !exists("s:call_count")
let s:call_count = 0
endif
let s:call_count += 1
echo "called: " . s:call_count . "times"

字符串常量和变量

使用字符串常量为字符串变量赋值

1
2
3
4
5
6
7
8
9
let name = "peter"
let name1 = 'peter'
let name2 = "\"peter\""
let name3 = '"peter"'

echo name
echo name1
echo name2
echo name3

控制语句

条件语句

1
2
3
4
5
6
7
8
9
10
11
12
13
if &term == 'xterm'
" Do for item
elseif &term == 'vt100'
" Do for it
else
" Do for other
endif

if v:version > 700
echo "你的版本符合使用此插件的条件"
else
echo "你的版本过旧, 需要升级!"
endif
  • 对数值和字符串可以进行逻辑操作,俩个字符串的算术差被用来进行比较;
  • 字符串与数值进行比较时,字符串会被转换成一个数值,当字符串看起来不是一个数值时,会被转换为0;
1
2
3
4
5
6
7
if 0 == 'one'
echo '成立'
endif

if 0 < '3trhee'
echo '成立'
endif
  • 对于字符串匹配有俩种模式:
  • a =~ b 匹配
  • a !~ b 不匹配
  • 左边的a被当作一个字符串, b被当作一个匹配模式, 就如string里面的find操作一样
  • 字符串比较与匹配中的大小写问题
  • # 表示大小写敏感
  • ‘?’ 表示忽略大小写
  • 更多的字符串操作请:h expr4
  • 更多的字符串匹配请:h pattern-searches
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if str =~ " "
echo "判断str里面是否包含字符串"
endif

if str !~ '\.$'
echo "str 是否以句号结尾!"
endif

if str =~# 'a'
echo "字符串中是否包含字母a"
endif

if str =~? 'a'
echo "字符串中是否包含字符 a 或 A"
endif

注意: 在匹配模式下多使用单引号, 因为正则表达式中有很多反斜杠, 而反斜杠双引号中必须写俩次才有效.

循环语句

  • continue 跳出本次循环
  • break 跳出循环(所有循环)
1
2
3
4
5
6
7
8
9
10
11
" while 语句
let i = 1
while i < 5
echo 'count is ' . i
let i += 1
endwhile

" for .. in 语句
for i in range(1, 4)
echo 'count is ' . i
endfor

表达式

表达式语法

详细的表达式语法请:h expression-syntax

执行表达式

  • :execute执行一个表达式, 但是只能执行冒号命令,例如根据时间改变配色的示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    let color_scheme = 'desert'
    if strftime('%H') < 12
    let color_scheme = 'molokai'
    elseif strftime('%H') < 18
    let color_scheme = 'winter'
    else
    let color_scheme = 'solarzied'
    endif
    execute 'colorscheme ' . color_scheme
  • normal 执行普通模式命令,但只能按表面意义解释,不能是表达式,比如将上面的代码中的execute改成normal,就没效果

  • 常用形式: :normal gg=G

  • 为了使normal 命令也可以带表达式, 可以将execute连起来使用,如::execute 'normal '. normal_command
  • 必须确保:normal的参数是一个完整的命令,否则,Vim碰到参数的结尾就会终止运行, 如: 在当前行插入new text: :execute "normal Inew text \<ESC>" 注意: 使用了特殊字符\<ESC, 避免在在脚本中输入真正的

    字符.
  • 不想执行表达式, 指向获取结果, 可以使用eval()函数, 作为表达式计算的结果.

1
2
3
4
let optname = 'path'
let optval = eval('&'.optname)

execute 'let optval = &'.optname

函数

定义函数

  • 函数名必须以大写开头
  • 形式如下:
1
2
3
4
5
6
7
8
9
10
11
function funcname(var1, var2, var3)
"body
endfunction

function Min(num1, num2)
if a:num1 > a:num2
return a:num2
else
return a:num1
endif
endfunction
  • 如果重定义一个已经存在的函数, 可以在function后面加!, 如: function! Min(num1, num2, num3)
  • 定义函数的时候习惯性的加个!是个好习惯

调用函数

  • 通过call调用函数:
1
2
3
let line = getline('.')
let repl = substitute(line, '\a', "*", 'g')
call setline('.', repl)
  • 上面的代码相当于命令行: :substitute/\a/*/g

带范围的函数

  • call命令可以带一个行表示的范围, 这可以分为俩种情况:
  • range 关键字, 调用这样的函数时,会自动传给a:firstline和a:lastline来个参数,例如:
1
2
3
4
5
6
7
8
9
function CountWords() range
let lnum = a:firstline
let n = 0
while lnum <= a:lastline
let n += len(split(getline(lnum)))
let lnum += 1
endwhile
echo 'Fount ' . n . ' words!'
endfunction

可以通过:10, 30call CountWords()调用上面的函数

  • 不带有range 关键字, Vim将把光标移动到范围内的每一行,然后调用该函数,如:
1
2
3
function Number()
echo 'Line '. line('.') . ' has ' . getline('.')
endfunction

可以通过:10, 15call Number()调用上面的函数

可变参数的函数

  • Vim允许你定义参数个数可变的函数, a:0代表参数个数, a:000代表可选参数的list, a:1, a:2 代表可选参数,如下:
1
2
3
4
5
6
7
8
9
10
function Show(start, ...)
echol Title
echo 'start is ' . a:start
echol none
let index = 1
while index <= a:0
echo 'Arg ' . index . ' is ' . a:{index}
let index += 1
endwhile
endfunction

函数清单

  • 通过:function可以列出用户所有自定义函数及其参数
  • 通过:function 函数名查看函数定义

删除函数

:delfunction 函数名-> :delfunction Show

函数引用

  • 类似与c语言中的函数指针, Vim可以使用function(函数名)将函数转换为引用,如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
let result = 0
function! Right()
return 'Right!'
endfunction
function! Error()
return 'Error!'
endfunction

if result == 1
let Afunc = function('Right')
else
let Afunc = function('Error')
endif
:echo call(Afunc, [])
  • 保存函数引用的变量必须以大写开头, 不然和内建函数的名字会引起混淆, call的第一个参数是引用, 第二个是函数参数的列表
  • 和字典组合使用函数引用时最常用