vimscript设置与按键
配置文件~/.vimrc
-
打开配置文件:
:o $MYVIMRC
-
生效修改:
:source $MYVIMRC
vimrc脚本
在「任意」系统中,在Vim中执行:echo $MYVIMRC
命令显示配置文件的位置。
命令source
让Vim读取指定的文件,并将其当做Vimscript执行。
-
<leader>ev
打开配置文件。 -
使用
<leader>sv
重读配置使修改生效。
注释
"
开头注释一行。
打印信息
-
:messages
命令:查看历史信息。 -
:echo
命令:输出信息,任务结束后丢弃,:messages
命令看不到。 -
:echom
命令:输出信息,在:messages
查看的历史信息中。
:echo "Hello, world!" :echom "Hello again, world!" :messages
Vim环境选项(Options)
查询选项设置
可以通过选项来控制vim的行为,通过选项的名称<name>
加上后缀?
构成<name>?
的形式,
可以查询指定选项的值。
以是否显示行号的选项number
为例:
:set number? # 如果当前有显示行号,结果为:number # 如果当前不显示行号,结果为:nonumber
布尔类型的选项
布尔类型选项只有「开启」与「关闭」两种状态。
通过在名称<name>
加上前缀no
组成no<name>
的形式表示关闭选项。
以是否显示行号的选项number
为例:
:set number :set nonumber
也可以加上后缀!
组成<name>!
的形式在开启与关闭两种状态之间切换。
还是以是否显示行号的选项number
为例:
set number!
键值类型的选项
键值类型的选项不只有开与关两种状态,它需要一个值。
以行号宽度的numberwidth
为例:
:set numberwidth=4
一次性设置多个值
:set number numberwidth=6
按键映射(Mapping)
格式:
(n|v|i)?(u)?map (key) (value)
-
(n|v|i)
:指定环境。 -
(u)
:删除映射。 -
key
:按键。 -
value
:映射的操作。
映射的场景:
-
map
:在所有模式下映射 -
nmap
:只在「普通模式」下映射 -
vmap
:只在「Visual模式」下映射 -
imap
:只在「插入模式」下映射
取消映射的场景:
-
unmap
:在所有模式下删除映射 -
nunmap
:只在「普通模式」下删除映射 -
vunmap
:只在「Visual模式」下删除映射 -
iunmap
:只在「插入模式」下删除映射
普通字符
在普通模式下使用map
命令定义按键映射。
普通模式下映射-
到x
:
:map - x
普通模式下映射-
到dd
:
:map - dd
映射多个按键
Vim还可以映射多个按键:
:map -d dd
特殊字符
用 <keyname>
的格式映射特殊字符
空格键选中光标所在的单词:
:map <space> viw
Ctrl + d
删除当前行:
:map <c-d> dd
映射无法使用注释
映射命令无视注释,把整个内容作为映射的结果:
:map <space> viw " Select word
指定模式下映射
nmap
指定normal模式下映射删除一行:
:nmap \ dd
vmap
指定visual模式下映射,把选中的内容转为大写:
:vmap \ U
imap
指定insert模式下映射。转为normal模式,删除一行,再回到insert模式:
:imap <c-d> <esc>ddi
删除映射
:nunmap - :nunmap \ :vunmap - :vunmap \ :iunmap - :iunmap \
嵌套与递归
映射会嵌套,不小心还会造成递归,成为死循环:
:nmap dd O<esc>jddk
*map
系列命令的一个缺点就是存在递归的危险。另外一个是如果你安装一个插件,
插件映射了同一个按键为不同的行为,两者冲突,有一个映射就无效了。
非递归映射
每一个*map
系列的命令都有个对应的*noremap
命令,包括:
noremap
/nnoremap
、vnoremap
和inoremap
。这些命令将不递归解释映射的内容。
(n|v|i)?noremap (key) (value)
-
(n|v|i)
:指定环境。 -
key
:按键。 -
value
:映射的操作。
「任何时候」都应该使用非递归映射,当安装一个新的插件时,
可能你不会使用或记住每一个其创建的映射。即使你记住了,
你还得 回看下你的~/.vimrc
文件以确保你自定义的映射与插件创建的没有冲突。
映射为空
把按键映射为<nop>
无操作(no operation),即禁用该按键。
例如禁用Esc键:
:inoremap <esc> <nop>
前缀(Leaders)
通过映射按键有一个问题就是,用来映射的按键就用不到了,例如:
:nnoremap <space> dd
这样就不能再用空格了。
全局前缀
另一个定义快捷操作的方法是使用前缀(Leaders):
:let mapleader = "-"
这样就定义了-
作为一个前缀,以后用这个前缀可以用来定义映射:
:nnoremap <leader>d dd
这样以后要用定义的前缀符号-
加上d
组成的-d
就能触发dd
。
使用前缀的优点:
- 首先,你某天可能会想要更换你的「leader」。在一个地方定义它使得更方便更换它。
-
第二,其他人看你的
~/.vimrc
文件时,一旦看到<leader>
就能够立即知道你的用意。 如果他们 喜欢你的~/.vimrc
配置, 即使他们使用不同的leader也可以简单的复制你的映射配置。 -
最后,许多Vim插件都会创建以
<leader>
开头的映射。如果你已经设置了leader, 你会更容易上手使用那些插件。
本地前缀
本地前缀(Local leader)于那些只对某类文件(如Python文件、HTML文件) 而设置的映射。
平时使用时反斜线用得少,所以一般用它来用为本地前缀:
:let maplocalleader = "\\"
因为\
在Vimscript中是转义字符,所以要用\\
。
在映射中使用<localleader>
代表本地映射的前缀。
缩写(Abbreviations)
自动纠错
定义在映射模式下的缩写替换:
:iabbrev adn and
以后在insert模式下输入:
One adn two.
会自动纠正为:
One and two.
缩写替换
还可以定义常用的短语,比如邮件地址与版权信息:
:iabbrev @@ steve@stevelosh.com :iabbrev ccopy Copyright 2013 Steve Losh, all rights reserved.
关键字
在缩写以后输入一个「非关键字字符」(non-keyword character)后, 才会触发替换操作。
查看哪些关键字,要选中一个单词,然后用以下命令查看是不是关键字:
:set iskeyword?
输出的结果是关键字的合法格式,类似于:
iskeyword=@,48-57,_,128-167,224-235,-
这个格式很复杂,但本质上 "keyword characters"包含一下几种:
-
下划线字符
_
- 所有字母字符,包括大小写。
- ASCII值在48到57之间的字符(数字0-9)。
- ASCII值在128到167之间的字符(一些特殊ASCII字符)。
- ASCII值在224到235之间的字符(一些特殊ASCII字符)。
简单地说只要记住输入非字母、数字、下划线的字符就会引发abbreviations替换。 如果你想阅读这个选项格式的完整描述,你可以运行命令
:help isfname
缩写与映射的区别
abbreviations和mappings很像,但是他们的定位不同。例子:
运行命令:
:inoremap ssig -- <cr>Steve Losh<cr>steve@stevelosh.com
这个 mapping 用于快速插入你的签名。进入insert模式并输入ssig
试试看。
看起来一切正常,但是还有个问题。进入insert模式并输入如下文字:
Larry Lessig wrote the book "Remix".
注意到Vim将Larry名字中的ssig也替换了!mappings不管被映射字符串的前后字符是什么-- 它只在文本中查找指定的字符串并替换他们。
运行下面的命令删除上面的mappings并用一个abbreviation替换它:
:iunmap ssig :iabbrev ssig -- <cr>Steve Losh<cr>steve@stevelosh.com
再次试试这个abbreviation。
这次Vim会注意ssig的前后字符,只会在需要的时候替换它。
常用的例子
例子:修改vimrc的快捷键
绑定一个快速打开.vimrc
的快捷键。垂直分屏窗口打开.vimrc
:
:nnoremap <leader>ev :vsplit $MYVIMRC<cr>
绑定一个重新加载.vimrc
的快捷键:
:nnoremap <leader>sv :source $MYVIMRC<cr>
用符号包围单词
用双引号包围单词:
:nnoremap <leader>" viw<esc>a"<esc>hbi"<esc>lel
分析:
-
viw
: 高亮选中单词 -
<esc>
: 退出visual模式,此时光标会在单词的最后一个字符上 -
a
: 移动光标至当前位置之 后 并进入insert模式 -
"
: 插入一个"
-
<esc>
: 返回到normal模式 -
h
: 左移一个字符 -
b
: 移动光标至单词头部 -
i
: 移动光标至当前位置之前,并进入insert
模式 -
"
: 插入一个"
-
<esc>
: 返回到normal模式 -
l
: 右移一个字符,光标置于单词的头部 -
e
: 移动光标至单词尾部 -
l
: 右移一个字符,置光标位置在第一个添加的引号上
生效范围
按键映射范围
按键映射全局生效:
:nnoremap <leader>d dd
只按键映射在当前缓冲区生效:
:nnoremap <buffer> <leader>d dd
Vim找不到一个跟它匹配的映射,它将会被解析了两个命令:
-
<leader>
(这个什么都不会干) -
x
(通常会删除一个字符)。
localleader
如果我们需要设定一个只会用于特定缓冲区的映射,一般会使用<localleader>
,
而不是<leader>
。
在编写一个会被其他人用到的插件的时候,这点显得尤其重要。
使用<localleader>
来设置本地映射会防止你的插件覆盖别人用
<leader>
设置的全局映射,因为他们可能已经对他们做设置的全局映射非常之习惯了。
setlocal
的生效范围
set
全局生效,setlocal
对当前缓冲区有效:
:setlocal wrap :setlocal nowrap :setlocal number :setlocal nonumber
不是所有的选项都可以使用setlocal
进行设置。
如果你想知道某个特定的选项是否可以设置为本地选项,
执行:help
查看它的帮助文档。
覆盖
缓冲区的映射有更高的优先级:
:nnoremap <buffer> Q x :nnoremap Q dd
生效的是第一行配置,优先级更高。
自动命令(autocmd)
例:Vim默认在第一次保存前不会在硬盘上创建文件。 现在设置自动在新建文件时自动保存到硬盘。
:autocmd BufNewFile * :write
自动命令的结构
让我们来深入分析下我们刚才创建的自动命令:
:autocmd BufNewFile * :write ^ ^ ^ | | | | | 要执行的命令 | | | 用于事件过滤的「模式(pattern)」 | 要监听的「事件」
这个命令的第一部分是我们想监听的事件的类型。Vim提供了很多可以监听的事件。 这些事件包括:
- 开始编辑一个当前并不存在的文件。
- 读取一个文件,不管这个文件是否存在。
- 改变一个缓冲区的filetype设置。
- 在某段时间内不按下键盘上面的某个按键。
- 进入插入模式。
- 退出插入模式。
-
等等…… 浏览
:help autocmd-events
查看自动命令可以绑定的所有事件。
这个自动命令的下一部分是一个「模式」, 这个模式可以进一步限定你要执行的命令的执行范围。
新开一个Vim实例,执行下面的命令:
:autocmd BufNewFile *.txt :write
这个跟之前的那个自动命令基本一样,不过这个自动命令只对后缀为.txt
的文件有效,
也就是说当你新建的文件为txt文件的时候,
Vim会在文件创建的时候自动执行write命令将文件保存到硬盘上。
例子:保存HTML文件前先格式化一下
:autocmd BufWritePre *.html :normal gg=G
-
BufWritePre
这个事件会在保存任何字符到文件之前触发。 -
*.html
模式只在扩展名为.html
文件时触发。
多个事件触发
触发可以绑定多个事件,多个事件在分隔时用逗号分隔。
读与写HTML文件时都会触发:
:autocmd BufWritePre,BufRead *.html :normal gg=G
多个事件的配套
在Vim脚本编程中有一个不成文的规定,你应该同时使用BufRead
和BufNewFile
(译注:这里不是BufWritePre
)这两个事件来运行命令,这
样当你打开某个类型的文件,不论这个文件是否存在命令都会执行。执行下面的命令:
:autocmd BufNewFile,BufRead *.html setlocal nowrap
上面的命令会使得无论你在什么时候编辑HTML文件自动换行都会被关闭。
FileType事件
最有用的事件是FileType事件。这个事件会在Vim设置一个缓冲区的filetype的时候触发。
让我们针对不同文件类型设置一些有用的映射。
比如对于不同语言的源代码,定制不同的注释快捷键。运行命令:
:autocmd FileType javascript nnoremap <buffer> <localleader>c I//<esc> :autocmd FileType python nnoremap <buffer> <localleader>c I#<esc>
-
后缀为
.js
文件,<localleader>c
,光标所在的那一行会被注释掉。 -
后缀为
.py
文件,<localleader>c
,光标所在的那一行会被注释掉。