Vim 是一个功能强大的文本编辑器,适用于编程和文档编辑。Vimscript 是 Vim 的脚本语言,可以帮助用户实现更高效的工作流。本文将详细介绍 Vimscript 的基本用法,包括常用命令、数据类型、函数、按键映射等,帮助您更好地掌握 Vimscript。
一、基本命令
在 Vim 中输入 :help <CMD>
可以查看该命令详细的帮助信息,比如 :help echo
、:help python
。
打印信息
打印信息可以使用 :echo "hi, axiaoxin."
,也可以使用 :echom "hi, Mr.axiaoxin"
,运行时都会输出后面的字符串。他们的区别在于 :echom
会在运行后将其打印的信息保存在 messages
的列表中,而 :echo
则不会。运行 :messages
可以查看 Vim 所有历史输出的信息,用 echom
可以更方便地进行调试信息的输出。
二、Vimscript 基本数据类型及强制类型转换
1. 数字
数字包括整型、浮点型,基本的数字运算和 Python 都差不多:
:echom 100
:echom 0xff "16进制
:echom 010 "8进制
:echom 019 "不合法8进制,自动被视为十进制
2. 字符串
字符串不能使用 +
连接,+
只用于数字。当用 +
连接字符串时,会强制将字符串转为开头的数字再相加。正确的连接符号为 .
:
:echom "Hello, " + "world" " return 0
:echom "3 mice" + "2 cats" " return 5
:echom "3 mice" + "cats 2" " return 3
:echom 10 + "10.1" " return 10
:echom 10 + 10.1 " return 20.1
:echom "Hello, " . "world" " return hello, world
当整数和字符串用 .
连接时,会将整数转换成字符串,但不能将浮点数和字符串连接,会报错。
当字符串用单引号包住时,里面的特殊字符只会显示为原来的样子:
:echo "foo\nbar" "显示为两行
:echom "foo\nbar" "显示为foo^@bar,^@表示换行字符
:echom '\n\\' "显示为\n\\,失去本身的意义
:echom 'That''s enough.' "显示为That's enough. 单引号需要用'来转义,用\是错误语法
字符串也可以像 Python 一样切片::echo "abcd"[0:2]
用下标取字符串中的字符不能使用负数下标,:echo "abcd"[-1]
返回为空,但可以使用负数进行切片::echo "abcd"[-2:]
3. 列表
列表下标从 0 开始,比如 :echo [0, [1, 2]][1]
输出 [1, 2]
,:echo [0, [1, 2]][-2]
输出倒数第二个元素 0
,同样支持 Python 风格的切片操作。列表可以相加::echo ['a', 'b'] + ['c']
返回 ['a', 'b', 'c']
。
列表函数
add(list, item)
len(list)
get(list, index, default) " 获取给定index的item,index超过range返回default
index(list, item) " 返回-1表示不存在该item
join(list[, joiner])
reverse(list)
sort(list)
function! Sorted(l)
let new_list = deepcopy(a:l)
call sort(new_list)
return new_list
endfunction
4. 字典
取值:
:echo {'a': 1, 100: 'foo',}['a']
:echo {'a': 1, 100: 'foo',}[100]
:echo {'a': 1, 100: 'foo',}.a
:echo {'a': 1, 100: 'foo',}.100
删除有两种方式,一种是 :let a = remove(dict, key)
,另一种是 unlet dict.key
,区别在于第一种方式有返回值(即被删除 key 的 value),第二种没有,如果删除一个不存在的 key 会报错:
:let foo = {'a': 1, 'b': 2}
:let test = remove(foo, 'a')
:unlet foo.b
:echo foo
:echo test
赋值:
:let foo.x = 11
字典方法:
get(dict, key, default)
has_key(dict, key) " 返回0/1
items(dict) " 返回list
:echo items({'a': 100, 'b': 200})
返回 [['a', 100], ['b', 200]]
三、Vimscript 变量
变量赋值
:let foo = "bar"
:echo foo
使用 let
关键字,等号左右可以有空格也可以没有,直接使用变量名。
使用变量 scope 指定为当前 buff 的 local 变量:
:let b:foo = "bar"
:echo b:foo
g:
代表 global。
选项变量
:set textwidth=80
:echo &textwidth
使用 set
关键字,当变量为设置选项时,等号左右不能有空格,而且 echo
时必须加 &
。也可以使用 let
赋值,但是前面要加 &
::let &textwidth = 100
。
Local 选项变量
在同一窗口 split 多个窗口,在不同的窗口设置自己的 local 变量:
:let &l:number = 1
注册变量:
:let @h = 'hi axiaoxin' " 现在按 "hp 将 h 中保存的值粘贴到当前位置
选中文字按 y 复制后,执行 :echo @"
便可以打印出按 y 复制的值。
:echo @/
可以查看查找过的文字,如果没有查找过则返回 noh,noh 就是在你查找高亮后取消高亮的命令 :noh
。
四、Vimscript 控制结构
if 语句
1 代表 True,0 代表 False,非空字符串如果不是数字开头被强制转换为 0(False),数字字符串或数字开头的字符串为 True:
:if 1
: echom "ONE" "display
:endif
:if 10 > 1
: echom "foo" "display
:elseif 100 == 10
: echom "bar"
:else
: echom "ooxx"
:endif
:if "9024"
: echom "WHAT?!" "display
:endif
:if "something"
: echom "INDEED" "no display
:endif
当比较字符串的时候不要使用 ==
来判断相等,因为有 :set ignorecase
和 :set noignorecase
来修改是否区分大小写。如果 :if "foo" == "FOO"
前被添加了 :set ignorecase
,该判断依旧为 True。
正确的方式应该总是使用 ==?
和 ==#
来判断,无论是否使用 set ignorecase or noignorecase,?
总是不区分大小写,而 #
总是区分大小写,<
>
同样适用:
:if "foo" ==# "FOO"
: echom "no, it couldn't be"
:elseif "foo" ==# "foo"
: echom "this must be the one"
:endif
五、Vimscript 布尔设置开关
所有布尔设置都是通过 :set <name>
来开启,通过 :set no<name>
来关闭。
也可以用 toggle
来设置自动开或关,:set <name>!
。
检查某个布尔设置的开关情况可以使用 :set <name>?
,比如查看是否显示行号用 :set number?
,如果是显示行号则显示 number
,不显示行号显示为 nonumber
。
特别笔记下 :set shiftround
命令,其作用是在你按 >
或 <
或者是在插入模式下按 C-T
或 C-D
时的缩进取整对齐。比如我设置了 :set shiftwidth=4
,然后有如下缩进不规则的文本:
asdasd
asd
先 :set noshiftround
,然后光标移动到行首,按 >>
将其缩进一次,输出为:
asdasd
asd
然后再按一次 >>
,输出为:
asdasd
asd
最后再按一次 <<
将其反向缩进,输出为:
asdasd
asd
可以看出,没有使用 shiftround
,缩进时文本会不规则,而使用 shiftround
后的缩进更加整齐。
六、Vimscript 函数定义与调用
1. 定义函数
使用 function
定义函数,endfunction
结束函数,函数参数用 a:
作为前缀:
function! MyFunction(arg1, arg2)
return a:arg1 + a:arg2
endfunction
调用函数时使用 call
:
:let result = call('MyFunction', [5, 10])
:echo result " 15
2. 匿名函数
可以使用 function
直接定义匿名函数,但无法通过 call
直接调用,只能使用 :execute
:
:execute 'call function("add", [5, 10])'
3. lambda 表达式
Vim 8.0 之后支持 lambda 表达式,使用 {}
定义:
:let add = {a, b -> a + b}
:echo add(5, 10) " 15
七、Vimscript 按键映射
在 Vim 中,可以使用 nnoremap
、inoremap
、vnoremap
等命令进行按键映射。
1. 普通模式映射
使用 nnoremap
进行普通模式的映射:
:nnoremap <F5> :echo "Hello, World!"<CR>
2. 插入模式映射
使用 inoremap
进行插入模式的映射:
:inoremap jk <Esc>
3. 可视模式映射
使用 vnoremap
进行可视模式的映射:
:vnoremap <C-c> "+y
八、总结与建议
Vimscript 是 Vim 的强大脚本语言,掌握其基本用法可以极大提升您的 Vim 使用效率。可以从常用的命令、数据类型、函数、按键映射等方面入手,逐步熟悉并灵活应用这些知识。
建议多实践,尝试编写一些简单的 Vim 插件或配置,逐渐深入了解 Vimscript 的魅力。同时,定期查阅 Vim 的帮助文档,学习更多的内置函数和命令,保持对 Vim 的探索与热爱。