自动命令

自动命令,是在指定事件发生时自动执行的命令。利用自动命令可以将重复的手工操作自动化,以提高编辑效率并减少人为操作的差错。

定义自动命令

自动命令的格式:

:autocmd [group] events pattern [nested] command
  • group 组名(可选项),用于分组管理多条自动命令
  • events 事件参数,用于指明触发命令的一个或多个事件
  • pattern 限定针对符合匹配模式的文件执行命令
  • nested 嵌套标记是可选项,用于允许嵌套自动命令
  • command 指明需要执行的命令、函数或脚本

events 参数

Vim 内置了近 80 个事件,可以使用以下命令查看各个事件的详细说明:

:help autocommand-events

以下为较常用的事件:

类别 事件 触发条件
读取 BufNewFile 编辑一个新文件时
BufReadPre 读入新缓冲区之前
BufRead, BufReadPost 读入新缓冲区之后
BufReadCmd 开始编辑新缓冲区之前读取
FileReadPre 使用 :read 命令读入文件之前
FileReadPost 使用 :read 命令读入文件之后
StdinReadPre 由标准输入设备读入缓冲区之前
StdinReadPost 由标准输入设备读入缓冲区之后
写入 BufWrite,BufWritePre 将整个缓冲区写入文件时
BufWritePost 将整个缓冲区写入文件之后
BufWriteCmd 将整个缓冲区写入文件之前
缓冲区 BufAdd, BufCreate 将缓冲区加入缓冲区列表之后
BufDelete 从缓冲区列表中移除缓冲区之前
BufEnter 进入缓冲区之后
BufLeave 离开缓冲区之前
BufWinEnter 在窗口中显示缓冲区之后
BufWinLeave 从窗口中关闭缓冲区之前
BufNew 创建缓冲区之后
BufUnload 卸载缓冲区之前
选项 FileType 设置 filetype 选项之后
Syntax 设置 syntax 选项之后
EncodingChanged encoding 选项改变之后
OptionSet 设置任何选项之后

启动

退出

VimEnter Vim 启动并载入初始化文件之后
GUIEnter 启动 GUI 之后
VimLeavePre 改写 viminfo 文件之前,退出 Vim 之前
VimLeave 改写 viminfo 文件之后,退出 Vim 之前
其它 FileChangedShell 当文件的最后修改时间等属性发生改变时
InsertEnter 进入插入模式时
InsertLeave 离开插入模式时
FocusGained Vim成为当前窗口时
FocusLost Vim不再是当前窗口时
WinEnter 进入窗口时
WinLeave 离开窗口时
CursorMoved 在常规模式下移动光标时
CursorMovedI 在插入模式下移动光标时
CursorHold 当超过 updatetime 时间用户没有输入时
vimResized 窗口尺寸变化之后

当打开文件并输入文本,最后保存并退出。那么这将触发一系列事件:

操作 事件
启动 Vim 并创建默认窗口 BufWinEnter
创建默认缓冲区 BufEnter
:edit example.txt VimEnter
创建新缓冲区 BufNew
将新缓冲区加入到缓冲区列表中 BufAdd
退出默认缓冲区 BufLeave
退出默认窗口 BufWinLeave
将默认缓冲区从缓冲区列表中移除 BufUnload
删除默认缓冲区 BufDelete
将 demo.txt 读入新缓冲区 BufReadCmd
激活新缓冲区 BufEnter
激活新窗口 BufWinEnter
进入插入模式 InsertEnter
输入文本 CursorMovedI
退出插入模式 InsertLeave
将文件内容保存到磁盘 BufWriteCmd
退出新窗口 BufWinLeave
将新缓冲区从缓冲区列表中移除 BufUnload
准备退出 Vim VimLeavePre
退出 Vim VimLeave

参考: 事件驱动的脚本和自动化

pattern 参数

使用以下命令查看匹配模式的详细说明:

:help autocmd-patterns

匹配模式用来指定应用自动命令的文件。在匹配模式中,可以使用以下特殊字符:

  • * 匹配任意字符串
  • ? 匹配单个字符
  • \? 匹配英文问号字符
  • . 匹配英文句号字符
  • , 分割多个 pattern
  • \, 匹配英文逗号字符

可以使用逗号来分割多个模式,以匹配多种类型的文件。例如以下命令,对于 .c.h 文件设置 textwidth 选项:

:autocmd BufRead,BufNewFile *.c,*.h set tw=0

nested 参数

默认情况下,自动命令并不会嵌套执行。例如在自动命令中执行 :e:w 命令,不会再次触发 BufRead 和 BufWrite 事件。而使用 nested 参数,则可以激活嵌套的事件。

:autocmd FileChangedShell *.c nested e!

查看自动命令

使用以下命令,可以查看所有自动命令:

:autocmd

--- Autocommands ---
filetypedetect  BufEnter
    *.xpm     if getline(1) =~ "XPM2" |   setf xpm2 | else |   setf xpm | endif
    *.xpm2    setf xpm2
BufEnter
    *         if (winnr("$") == 1 && exists("b:NERDTree") && b:NERDTree.isTabTre
e()) | q | endif
NERDTree  BufEnter
    NERD_tree_*
              stopinsert
NERDTreeHijackNetrw  BufEnter
    *         call nerdtree#checkForBrowse(expand('<amatch>'))
Vimball  BufEnter
    *.vba     setlocal bt=nofile fmr=[[[,]]] fdm=marker|if &ff != 'unix'|setloca
l ma ff=unix noma|endif|if line('$') > 1|call vimball#ShowMesg(0,"Source this fi
le to extract it! (:so %)")|endif
    *.vba.gz  setlocal bt=nofile fmr=[[[,]]] fdm=marker|if &ff != 'unix'|setloca
l ma ff=unix noma|endif|if line('$') > 1|call vimball#ShowMesg(0,"Source this fi
le to extract it! (:so %)")|endif
    *.vba.bz2 setlocal bt=nofile fmr=[[[,]]] fdm=marker|if &ff != 'unix'|setloca
l ma ff=unix noma|endif|if line('$') > 1|call vimball#ShowMesg(0,"Source this fi
le to extract it! (:so %)")|endif

自动命令的列表将非常的长,其中既包括了在 vimrc 配置文件中定义的自动命令,也包括了各种插件定义的自动命令。

如果在命令中指定了 group,那么将会列出所有与指定 group 相匹配的自动命令;同理,也可以在命令中指定 event 和 pattern,以查看相匹配的自动命令:

:autocmd filetypedetect * *.html

--- Autocommands ---
filetypedetect  BufNewFile
    *.html    call dist#ft#FThtml()
filetypedetect  BufRead
    *.html    call dist#ft#FThtml()

删除自动命令

使用以下命令,可以删除所有自动命令:

:autocmd!

提示

此操作将删除所有自动命令,包括插件所定义的自动命令,请谨慎操作。

在命令中指定组、事件和匹配模式,可以删除特定的自动命令:

:autocmd! Unfocussed FocusLost *.txt

在命令中使用 * 来指代所有事件或文件。例如以下命令,将删除 Unfocussed 组中所有针对 txt 文件的自动命令:

:autocmd! Unfocussed * *.txt

在命令中忽略文件匹配模式,所有针对指定事件的命令都将被删除。例如以下命令,将删除 Unfocussed 组在所有针对 FocusLost 事件的自动命令:

:autocmd! Unfocussed FocusLost

自动命令组

可以使用以下命令,获得自动命令组的帮助信息:

:help :augroup

通过 :augroup 命令,可以将多个相关联的自动命令分组管理,以便于按组来查看或删除自动命令。例如以下命令,将 C 语言开发的相关自动命令,组织在 cprogram 组内:

:augroup cprograms
:    autocmd!
:    autocmd FileReadPost *.c :set cindent
:    autocmd FileReadPost *.cpp :set cindent
:augroup END

如果针对同样的文件和同样的事件定义了多条自动命令,那么当满足触发条件时将分别执行多条自动命令。因此,建议在自动命令组的开头增加 :autocmd! 命令,确保不会重复的执行自动命令。

自动命令选项

通过 eventignore 选项,可以忽略指定的事件,而不触发自动命令。例如使用以下命令,将忽略进入窗口和离开窗口的事件:

:set eventignore=WinEnter,WinLeave

如果希望忽略所有事件,那么可以使用以下设置:

:set eventignore=all

使用实例

  1. 自动切换中英文输入法, ! 为 shell 命令。
GUIEnter * :silent !ibus engine xkb:us::eng
InsertLeave * :silent !ibus engine xkb:us::eng
InsertEnter * :silent !ibus engine libpinyin
VimLeave * :silent !ibus engine libpinyin
  1. 调用自定义函数。
:function DateInsert()
:    $read !date
:endfunction

" 调用函数
FileWritePre * :callDateInsert()
  1. 离开 Vim 编辑器时,自动保存文件:
:autocmd FocusLost * :wa
  1. 根据文件类型执行自动命令
"删除 php 文件行尾的空格
autocmd BufEnter *.php :%s/[ \t\r]\+$//e

"根据文件类型载入插件
autocmd Filetype html,xml,xsl source $VIM/vimfile/plugin/closetag.vim

"根据文件类型设置键盘映射
autocmd bufenter *.tex map <F1> :!latex %<CR>

"根据文件类型设置不同的选项
autocmd FileType ruby setlocal ts=2 sts=2 sw=2 expandtab