作为一个Vimer用了这么久vim,其实Vimscript一直是一知半解,从刚开始接触的时候复制别人的配置,到现在的各种需求已经无法满足。看着自己1000+行的vimrc,看来是很有简化和优化的必要,这篇文章是学习Vimscript的一些笔记。
本文写作使用的vim版本:8.1.177,+gui,文中的测试都是在此之上进行的
使用技巧
这里是对使用技巧的补充,不涉及脚本。纯粹是在学脚本的过程中顺便学习到的(有点惭愧,:-\)
- CTRL-T 插入模式缩进当前行
- CTRL-D 插入模式反缩进当前行
- CTRL-W 插入模式删除前一个单词
- CTRL-U 插入模式删除行
- CTRL-A 增加数字
- 插入模式下重复上一次插入模式插入的所有内容
- CRTL-X 减少数字(目前设置为0开头八进制 0x开头十六进制)
- 插入模式下CTRL-G+u设置undo点,下一次普通模式的undo会从这里截止(准确地说是在插入的文本打上undo节点,这和脚本结合非常强大)
非脚本特性
实用命令
- :execute 将字符串里的内容当作命令执行,同时对其中的特殊字符进行转义,比如\r,\\。后面需要<cr>
- :normal 将命令当作普通模式的键入而操作,只是键入,不会解释<cr>之类的特殊字符,要这样做需要在外部使用execute输入特殊字符
- :normal! 忽略用户定义的映射
- 总是使用normal!
- execute “normal! xxxx"是很好的组合
消息
- :echo 打印消息,空格分割表达式 “\n”换行
- 不会扩展,比如%,需要使用expand
- 可以使用外部echo,%会被扩展但是会暂时退出vim
- :echom 打印消息,添加至消息历史,但是不打印特殊字符
- :messages 查看消息历史 大部分情况下可以记录100条(history可以设置记录条数)
- :echo errmsg 可以打印错误信息
选项
格式
- set <bool>
- set no<bool>
- set <bool>! 切换开关
- set <bool>? 查看当前值
- set <name> = <value>
- setlocal 设置选项为针对缓冲区,但并非所有时候都有效
一些选项
showmatch
插入配对符号时短暂跳转到对应符号 matchtime 设置十分之一秒数wrap
设置长行是否回旋shiftwidth
自动缩进空白数statusline
状态条显示的格式 注意空格需要转义hlsearch
高亮搜索结果incsearch
实时搜索
映射
- 普通的映射可以依次被解析,也许是优点,不过更多是缺点,只需要考虑递归的映射就可以了
- noremap 系列不会进行递归
- 尽量使用非递归的映射 或者说得直白:只用noremap
- 在lfs前加入<buffer>创建本地映射。本地映射会覆盖全局映射
- onoremap 是对移动操作符的映射,只有在操作符之后接上这些映射才会生效
- 结合本地映射、exe、normal、regex、自动命令可以相当强大
Leader
- :let mapleader=
- :let maplocalleader=
缩写
iabbrev
插入模式下输入非字母数字下划线引发自动替换- 和inoremap的不同是缩写只会对独立的单词有效
- 类似,加入<buffer>创建本地缩写
正则表达式
vim默认的正则表达式需要对正则的特殊符号转义,要使用通常意义下的正则方式,可以输入\v,则之后的模式按照一般正则的规则进行。
要使用vim的默认模式,但避免双重反斜杠的话,可以用下面所说的单引号字面量,但是就不能转义回车一类的不可输入字符。
解决办法是用.操作符连接,使用双引号输入不可输入字符
自动命令
- :autocmd <事件> <模式> <命令>
- 可以创建绑定多个事件的自动命令
BufRead
BufNewFile
应该一起使用,这样无论是新建还是读取都有效BufWritePre
写入数据前的操作FileType
设置文件类型的事件
- 和缩写结合,可以创建高效的Snippets
自动命令组
- :augroup <name>
- :augroup END
- 可以给自动命令分组,之后主动调用或者删除的时候可以按组进行
- 有一个作用是防止重复定义相同的自动命令(重复载入配置时),只需要在组内加入autocmd!
autocmd!
删除当前组的所有自动命令,不在组内则是默认的全局
脚本语言
管道符|
用于分割不同命令。命令被认为是独立而顺序执行
字面量
数字
- 整数 可以使用十六进制、八进制。但如果八进制写法有误,隐式转化十进制
- 浮点数 可以用科学计数法
- 强制类型转换:从整数到浮点数。
- 除法: 除非整数相除舍弃余数,否则是浮点数除法
字符串
- 字符串连接符是.而不是+(+只对数有效。对字符串用+会强制转换为整数,它甚至不能转换为浮点数)
- .操作符如果对非字符串使用也会强制转换,但一样只对整数有效
- TIP:显示调用函数转换类型,不要进行强制转换。
- 可以在字符串里转义,但是只对echo有效。echom会输出特殊字符
- 用单引号定义的字符串不需要转义,除非是用两个单引号表示单引号。类似于py的r字面量。
变量
- 变量用关键字
let
设置 - 选项可以作为变量使用,可以理解为对选项值“引用”
- 格式为
&
选项名
- 格式为
- 选项也可以通过引用+let设置,和set的不同是可以通过脚本的特性在运行时计算选项值,而不是set所设置的固定值
- 如:
1
let &textwidth=&textwidth +10
- 如:
- 寄存器的值也可以被作为变量。
- 格式为@x
- 寄存器:
- _ 寄存器 类似于/dev/null,文档称为黑洞寄存器
- 无名寄存器"是默认的寄存器,不管有没有指定目标,最近的操作都会被存在这个寄存器里
- /寄存器存储了搜索模式
- 英文字母代表的寄存器可以通过大写和小写访问,大写是追加,小写是覆盖。只有主动指定才使用这些
- -寄存器是行内删除时存储删除内容的寄存器
- 0寄存器是最近抽出的文本,除非特别指定
- 1~9寄存器是最近删除或修改,且不存储在行内寄存器的文本。随着修改,寄存器的值依次复制到后一个寄存器。直到9寄存器后被丢弃
- . 寄存器只读, 有最近插入的文本。类似于插入模式ctrl-a的效果
- % 寄存器只读。有当前文件名
- : 寄存器只读。保存上一次执行的命令行,但映射除外。可以用@:重复。
- + * ~和gui剪贴板相关;
- = 表达式寄存器。当使用@=时会交互输入表达式并执行
- @x 执行寄存器的内容
- qx 将按键输入存入寄存器
变量作用域
字符: | 代表作用域 |
---|---|
b: | 局部于当前缓冲区。 |
w: | 局部于当前窗口。 |
t: | 局部于当前标签页。 |
g: | 全局。 |
l: | 局部于函数。 |
s: | 局部于:source的 Vim 脚本。 |
a: | 函数参数 (只限于函数内使用)。 |
v: | Vim 预定义的全局变量。 |
分支语句
- if的判断值是通过整数来判断,其他类型的变量会被强制转换
|
|
- 比如字符串,如不能转换为数字,则为0(false)
- elseif
- else
比较运算
- 字符串的==比较运算符 大小写是否敏感是由ignorecase的设置决定的
- 使用==# 无论如何大小写敏感
- 或者==? 无论如何大小写不敏感
- Tip: 一直使用==#或者==?
函数
- function关键字定义函数
- 函数的首字母必须大写(不一定是必须的,不过是大多数人的标准)
- 调用函数:
- 使用call,函数返回值会被丢弃
- 将函数用在任意一个表达式中,取决于返回值。如果函数没有返回值,返回0
- 本人测试:可以使用下划线,不能用重音符号和点,不能用unicode
- return关键字返回值
- 函数体内使用参数需要a:作用域符(见上)
- 参数无法在函数体内被赋值,但可以被拷贝。除非传入的是列表或字典,则可以对其元素进行操作
可变参数
|
|
可变参数用…指定,这样,0将被设置为额外可变参数的数量,从1开始是传入的额外可变参数。000是所有可变参数的列表
内置函数
部分的:
函数 | 作用 | 参数 |
---|---|---|
strlen | 字符串长度 | string |
split | 切割字符串 | string,分隔符 |
join | 连接字符串 | string的列表,分隔符 |
tolower/toupper | 转换大小写 | string |
add | 列表尾部增添元素 | 元素 |
len | 列表长度 | 列表 |
get | 可以设定默认值的列表元素访问 | 列表,索引值,默认值 |
index | 列表中元素第一次出现处 | 列表,键值 |
join | 将列表元素以字符串形式拼接 | 列表,分隔符 |
reverse | 就地反转列表 | 列表 |
全部函数使用:h functions 查看
关于实战,将在后续单独post中讲述。接下来我会对我又臭又长的vimrc进行一次修改:)