Execute命令

execute命令,把字符串当作vimscript命令来执行.

基本用法

:exe[cute] {expr1} .. 把{expr1}当作一个Ex命令来执行,并返回结果。多个参数,用空格分隔。

多个命令可以用| 连起来
:execute '!ls' | echom "theend" 

在execute后面的字符串中可以使用\<esc>这样的方式来使用\e,看上去跟明显
\e	escape <Esc>
\f	formfeed <FF>
\n	newline <NL>
\r	return <CR>
\t	tab <Tab>

当文件名中有特殊字符的时候,要小心了。
:execute "e ".fnameescape(filename) " fnameescape()函数用在vim的命令中
:execute "!ls " . shellescape(filename, 1) " shellescape()函数用在shell命令中

当要执行多行的命令时,用|来 执行得了,|要放在引号之内
:execute 'while i < 5 | echo i | let i = i + 1 | endwhile'

注释,|"之后的是注释
execute "echo 'foo'" | " this is a comment

Normal命令

normal 命令简单地接受一串键值并当作是在normal模式下输入的

:normal ggdd  "删除第一行
:normal G "一般情况下,这个会把光标移到最后一行。
"但是如果用户设置映射呢?比如nnoremap G dd ,这个时候,就会变成删除了。。。。惊不惊喜?
:normal! G "这样就能确保光标移到最后,即便用户设置了G的映射,映射也不会生效。

所以,在写vim脚本的时候,应该总是用normal!,因为你不确定用户在他的.vimrc文件中做了哪些映射

:normal! /foo<cr> "这样不会起作用 ,这种情况,需要结合execute来进行

:execute "normal! /foo\<cr>" " 这样就可以起到查找foo的作用了

:execute "normal! mqA;\<esc>`q" "在行尾添加一个;然后光标回到原来的位置

转义字符

"string"		string constant		*expr-quote*

Note that double quotes are used.

A string constant accepts these special characters:
\...	three-digit octal number (e.g., "\316")
\..	two-digit octal number (must be followed by non-digit)
\.	one-digit octal number (must be followed by non-digit)
\x..	byte specified with two hex numbers (e.g., "\x1f")
\x.	byte specified with one hex number (must be followed by non-hex char)
\X..	same as \x..
\X.	same as \x.
\u....	character specified with up to 4 hex numbers, stored according to the
	current value of 'encoding' (e.g., "\u02a4")
\U....	same as \u but allows up to 8 hex numbers.
\b	backspace <BS>
\e	escape <Esc>
\f	formfeed <FF>
\n	newline <NL>
\r	return <CR>
\t	tab <Tab>
\\	backslash
\"	double quote
\<xxx>	Special key named "xxx".  e.g. "\<C-W>" for CTRL-W.  This is for use
	in mappings, the 0x80 byte is escaped.
	To use the double quote character it must be escaped: "<M-\">".
	Don't use <Char-xxxx> to get a utf-8 character, use \uxxxx as
	mentioned above.

Note that "\xff" is stored as the byte 255, which may be invalid in some
encodings.  Use "\u00ff" to store character 255 according to the current value
of 'encoding'.

Note that "\000" and "\x00" force the end of the string.

既然把vimscript是一个脚本语言,那就会有脚本语言的一些共性,比如变量的定义,变量的类型,变量的作用域,分支循环结构,函数等等。

变量

变量的定义

  • 一般的变量定义

    • 变量名规范: 字母、数字、下划线,并且不能以数字开头

      :let foo = “bar” :let num = 32 :echo foo num “ 显示foo和num :unlet foo “ 销毁一个变量 以上好像看出vimscript是动态类型,其实,你们想错了。(党国的高官,怎么会有钱?)

  • 配置选项也是变量

      比如,我要看配置选项textwidth的值
      :echo &textwidth "需要在前面加上& ,这就告诉vim,你在引用这个选项;如果这个选项不存在,就会报错
      :set textwidth=80
      :echo textwidth "直接输出,也会报错
          E121: Undefined variable: textwidth
          E15: Invalid expression: textwidth
      :echo &textwidth "输出 80
    
      :set nowrap
      :echo &wrap " 0
      :set wrap
      :echo &wrap " 1
      在vimscript中0为false,非0值整数为true 
    
      可以用let来设置选项的值,并且let比set更灵活	
      :let &textwidth = &textwidth + 10
      :echo &textwidth " 输出 90
      :set &textwidth = &textwidth + 10 "set 只能给设置一个常量值
          E518: Unknown option: &textwidth = 
    
      本地选项,将某个选项作为变量来来设置它的本地值,而不是全局值,
      本地变量的前缀:  <code>l:</code>
      :let &l:number = 0 "只对当前buffer生效,当前buffer,行号消失
    
  • 寄存器变量

      :let @a="hello!"
      :echo @a "输出 hello!
      :echo @" "输出无名寄存器的值
      :echo @/ "输出,搜索寄存器的值
    
  • b:变量前缀(只在当前buffer生效的变量)

      :let b:hello = "world"
      :echo b:hello " 输出world
      切换到另一个buffer
      :echo b:hello 
          E121: Undefined variable: b:hello
          E15: Invalid expression: b:hello
    
  • help internal-variables

变量前缀 名称 说明
b: buffer-variable Local to the current buffer.
w: window-variable Local to the current window.
t: tabpage-variable Local to the current tab page.
g: global-variable Global.
l: local-variable Local to a function.
s: script-variable Local to a |:source|’ed Vim script.
a: function-argument Function argument (only inside a function).
v: vim-variable Global, predefined by Vim.

分支结构

条件语句

  • 多行命令,写成一行。用管道符(|)来隔开命令

      :echom "foo" | echom "bar"
      :if 1 | :echom "one" | :else | :echom "not one" | :endif " 输出 one
      :if 0 | echom "one" | else | echom "not one" | endif " 输出not one
    
  • if的用法

    • 必要情况下(数学计算、条件表达式),vim强制转换变量和字面量的类型。10+”20foo” 最后等于10+20 = 30
    • 以数字开头的字符串会转化为数字,否则会转化为0

        :echo 0+"12.64ab" "输出12
        :echo 0+"-12.34ab" "输出-12
      
    • if判断时,非零整数为true,0为false

        let a = 3
        if a == 1
            echom "one"
        elseif  a == 2
            echom "two"
        else
            echom "not one or two"
        endif
        "最后输出 not one or two
      
        if "string"  "等价于 if 0
            echom "zero"
        endif
      
        if "12Ab" ==# "12ab"
            echom "yeshi"
        else
            echom "no"  " 输出 no, 说明 ==# 没有进行强制转化
        endif
      
比较运算符 说明
> 大于,如 10 >1
< 小于,如 1 < 10
== 相等,如 10 == 11 ,”foo” == “bar”,会受用户设置noignorecase/ignorecase影响
==? 字符串比较,大小写不敏感(无论vim对大小写的设置是否敏感),”foo” ==? “FOO” is true
==# 字符串比较,大小写敏感(无论vim对大小写的设置是否敏感),”foo” ==# “FOO” is false
># 大于, 区分大小写的比较
<# 小于, 区分大小写的比较
>? 大于, 不区分大小写的比较
<? 小于, 不区分大小写的比较

所以最好使用==#来比较字符串,统一自己的规范

循环

for循环

  • help for

      let c = 0
      for i in [1,2,3,4]
          let c += i
      endfor
      echom c
    
      for [lnum, col] in [[1, 3], [2, 5], [3, 8]]
         echo getline(lnum)[col]
      endfor
    

while循环

  • help while

      let c = 1
      let total = 0 
      while c <= 4
          let total += c
          let c += 1
      ednwhile 函数 ====
    

没有作用域限制的vimscript函数,必须以一个大写字母开头

function Hello()
	echom "helloworld"
endfunction
call Hello()

function SayHi(name)
	if a:name ==# "Mark"
		return "Hi,Mark"
	endif
endfunction
echom SayHi() " 函数如果没有返回,默认是return 0

"可变参数
function Multiargs(...)
	echom a:0 "参数数量,可变参数的数量
	echom a:1 "第一个参数
	echom a:2 "第二个参数
endfunction
"可变参数和普通参数一起使用
function Multiargs2(foo,...)
	echom a:0 
	echom a:foo
	echom a:1
	echom a:2
	for s in a:000 "a:000,所有的可变参数
		echom ' '.s
	endfor
endfunction
call Multiargs2("hh","jak","luc")
输出:
2
hh
jak
luc
 jak
 luc
可见a:0,只是代表可变参数的数量

"函数参数是只读的,不能在函数内部改变
function Assign(foo)
	let a:foo = "Nope"  
endfunction
call Assign() 会报错,如下:
E46: Cannot change read-only variable "a:foo"

"function! 如果出现重复函数名,感叹号不会报错。
When a function by this name already exists and [!] is
not used an error message is given. 
function! Assign()
	return ["suceess",1]
endfunction

let [msg,code] = Assign() "返回一个数组

数据类型

布尔

  • 0为false, 其他整数为true

数字

  • 整数(Number,32位带符号整数(如果编译的时候+num64,就支持64位))

      echom 100
      echom 0xff 0X1f  " 0x或0X前缀的来指定16进制
      echom 010 017 "0前缀,是八进制,8,15
      echom 019 "因为它不是一个八进制,所以输出19
      echom 0b1010 "0b前缀,是二进制 ,输出十进制10
      "尽量避免使用八进制
    
  • 浮点(Float)

      [-+]{N}.{M}
      [-+]{N}.{M}[eE][-+]{exp}
      N,M都是正整数,exp代表10的多少次方,exp也是一个正整数
    
      echo 12.0 "12.0
      echo 5.45e+3 " 5450.0
      echo 5.3453e9 " 5.3453e9
      if 5.345e2 > 500  " this is true
          echom "biger"
      endif
    
  • 强制转换

      echo 3/2 "1
      echo 3.0/2 "1.5 Number和Float混用时,会把Number转换为Float
      echo 1/3.0 "0.33333,默认是6位小数的精度
      echo printf('%.15e',11/7.0)  "1.571428571428571e+00
      echo printf('%.15e',atan(1)) "7.853981633974483e-01
    

字符串

用双引号或者单引号包围的字符。双引号会转义\n,\,"等特殊字符,而单引号不会(除了’‘转义为’之外)。

  • 连接(concatenation)用点号. 和php一样

      echom "hello "."world" "helloworld"
      echom 12."foo" "12foo
      echom 12."123" "12123
      echom 12.1. "foo" "121foo
      echom 12.1."foo" "121foo
      浮点数连接字符串,报错:
      echom 12.1 ."foo" "E806: using Float as a String E15: Invalid expression: 12.1 ."foo"
      echom 12.1 . "foo" "E806: using Float as a String E15: Invalid expression: 12.1 ."foo"
    
  • 特殊字符(双引号才能转义)

      help expr-quote
      echom "foo \"bar\""   "输出 foo "bar"
      echom "a\nb" "输出 a^@b
      echo "a\nb" "输出两行,a 和 b
    
  • 字符串字面量(除了’‘会转义为’,其他的原样输出)

      help literal-string
      echom '\n\\' "输出\n\\
      echo '12''23' "输出12'34
      echo '12''''23' "输出12''34
    
  • 字符串函数

      字符串字节数量
      echom strlen("foo") "3	
      echom strlen("我的1") "7
      echom len("foo") "3
    
      字符串字符个数
      echom strchars("hello") "5
      echom strchars("我的1") "3
    
      字符串截取
      strcharpart({src}, {start} [, {len}])
      echo strcharpart("我的123",0,2) "我的
      echo strcharpart("我的123",-1,2) "我,start为负,就是从0开始,截取start+len个字符
      echo strcharpart("我的123",-1,3) "我的
      echo strcharpart("我的123",-1,4) "我的1
    
      echo "abcdef"[1:3] " bcd
      echo "abcdef"[1:1] " b
      echo "abcdef"[1:] " bcdef
      echo "我的123"[3,6] "的1
    
    	
      分割,默认通过空格分割
      split({expr} [, {pattern} [, {keepempty}]])			*split()*
    
      echo split("one two three") " ["one","two","three"] 不能用echom输出一个list
      echo split("one,two,three,",") " ["one","two","three"] 不能用echom输出一个list,最后一个,不会有用
    
      连接,默认通过空格连接
      echo join(["hello","world"]) "  hello world
      echo join(["hello","world"],",") " hello,world
      echo join(["hello","world"],"") " helloworld
    
      大小写转换
      echom tolower("FOo")
      echom toupper("hello")
    	
      字符串查找
      stridx({haystack}, {needle} [, {start}])
      :echo stridx("An Example", "Example")	     3
      :echo stridx("Starting point", "Start")    0
      :echo stridx("Starting point", "start")   -1
    
      string()强制转化为字符串
    

列表

help List		
列表是有序的,元素的集合, 每一个item可以是任何type	
echo ['foo',34,12.2]	
echo ['foo',[3,'bar']]

索引,从0开始
echo [1,23,[1,34]][0] " 1
echo [1,23,[1,34]][2][1] " 34
echo [1,23,[1,34]][-1] "[1,34]

切割,和python相似,但不同
echo [1,3,4,5][0:2] "[1,3,4]
echo [1,3,4,5][0:20000] "[1,3,4,5] 超过列表索引也是安全的。
echo [1,3,5,6][-2:-1] " [5,6]
echo [1,2,3,5][:1] "[1,2]
echo [1,2,3,5][2:] "[3,5]
字符串也可以切割

连接+
echo ['a','b'] + ['c']  " ['a','b','c']

函数列表
1.add
let foo = ['a']
call add(foo,'b') " 往foo后面加上'b'
echo foo " ['a','b']

2.len
echo len(foo) " 2

3.get,返回指定索引的值
echo get(foo,0,'default') " a
echo get(foo,10,'default') " default

4.index
echo index(foo,'b') "1
echo index(foo,'cet') " -1  不存在返回-1

5.join

6.reverse ,转置
echo reverse(['a','b']) "['b','a']

7.List unpack
let [var1, var2; rest] = mylist "等同于下面三个表达式
let var1 = mylist[0]
let var2 = mylist[1]
let rest = mylist[2:]

8.复制和深度复制
let aa = [1,2,4]
let bb = aa "aa 和bb 指向同一个列表,改变其中一个,也对相应改变另一个

let aa = [[1,'a'],3,4]
let bb = copy(aa) " 浅复制,改变已经有的元素(该元素也是一个列表),aa和bb都会变化,但是,往aa中追加元素,不会影响
let aa[0][1] = 'aaa' " 浅复制,所以 bb[0][1] == 'aaa'

如果要做到完全独立,就用deepcopy()
let cc = deepcopy(aa) " 这样,cc和aa就是完全独立的变量,不会相会影响了。

9.列表相等
echo [1,3] == [1,3] " 1 ,true 
echo [3,1] == [1,3] " 0 ,false
echo 2 == "2" " 1,true 
echo [2] == ["2"] " 0, false

let a = [1,3]
let b = [1,3]
echo a is b " 0

字典

类似python中的dict,ruby中的hash, javascript中的object
字典用花括号创建,索引是字符串(即便定义的时候是数字,也会被转化为字符串)

:echo {'a':1,'100':'foo',} " 字典最后可以留下一个逗号,js的愚蠢之处,在这里被修复了

let dic = {'a':1,'100':'foo',}
echo dic['a'] " 1

当键是字母数字下划线组成时,字典也支持"点"查找
echo dic.a
echo dic.100

赋值和添加,移除项
let dic.a = 222
let dic.c = 'new val'

let a = remove(dic,'a') " 此方法移除a后,会返回a对应的值
unlet dic.a "直接移除a,不会返回

字典函数
echo get(dic,'a','default') " 1 和list一样
echo get(dic,'dd','not') " not

echo has_key(dic, "a") " 1

echo items(dic) " [['a',1],['100','foo']]
echo  keys(dic) "['a','100']
echo values(dic) "[1,'foo']

遍历Dictionary
for key in keys(dic)
	echo key.":'.dic[key]
endfor

for v in values(dic)
	echo "value:".v
endfor

for [k,v] in items(dic)
	echo k.':'.v
endfor

合并数组
call extend(adic, bdic) "把bdic的值,加到a中,如果有重复的key,a的会被b覆盖(默认)

过滤元素
call filter(dict, 'v:val =~ "x"') " 把value匹配"x"的元素都剔除掉。

函数(Funcref)

特殊(Special)

v:false
v:true
v:none
v:null

任务(Job)

job_start()

通道(channel)

ch_open()

对大部分命令和选项,vim支持他们的缩写。但是建议在vimrc或者自己编写的插件中使用全称,这样才会有更好的可读性。

启动vim不加载.vimrc

vim -u NONE -N    -N 就是和vi不兼容
-u <vimrc>		Use <vimrc> instead of any .vimrc
-N			Not fully Vi compatible: 'nocompatible' ### 注释 

"  这就是注释,双引号之后的就是注释内容
但是下面的注释会失效。。
:map <space> viw " 按下空格键高亮选中一个单词	

所以vim的注释,最好不要行末添加

!切换布尔选项

:set number!   或:set nu!

?查看配置的值

:set fileencoding? 返回fileencoding=utf-8
:set number? 返回 number 或 nonumber

键盘映射

  • normal模式下的简单映射

      :map - dd   按下 - 就相当于dd,会删除一行
      也可以用<keyname>来告诉vim一个特殊的按键
      :map <space> viw  按下空格,vim将高亮选中一个单词
    	
      :unmap - 取消-的映射
      :unmap <space>
    
  • nmap 在normal模式下的映射

      :nmap - ddp
      取消映射
      :nunmap -
    
  • vmap 在visual模式下的映射

      visual模式下,按下\,会把小写字母变大写
      :vmap \ U 
      取消映射
      :vunmap \
    
  • imap 在insert模式下的映射

      在insert模式下,ctrl+d 会删除一行
      :imap <c-d> <esc>ddi   
      取消映射
      :iunmap <c-d>
    
  • 映射可能会出现递归调用

      :nmap - dd
      :namp \ -
      在normal模式下,按下\,vim会解释为-,而 -会继续被解析为 dd,最后就是删除了一行
    
  • 非递归映射*noremap

      :nmap x dd
      :nnoremap \ x
      当按下\ 就是x,删除一个字符,vim不会把x再解析为dd
    
      ** 应该在所有的情况下使用 noremap **
      " insert mode下jj --> <esc>
      inoremap jj <esc>
      noremap/nnoremap , vnoremap, inoremap
      取消非递归映射(和取消递归映射的方法一样)
      :unnmap  \
    
      :map x <nop> 就会让按键x失效
    
      :nnoremap <buffer> Q x 只在当前缓冲区生效
    

Leaders(导航键?)

vim默认的leader是\

:let mapleader = "-"  把leader键设置为-
在配置文件的其他地方,就用<leader>,而不是"-"

local leader 这个leader只用于那些对某类文件(python,html)而设置的映射

:let maplocalleader = "\\"  把loacalleader设置为\,以为\\会转意为\
如果要设定一个只会用户特定缓冲区的映射,一般会使用 <localleader>,而不是<leader>
使用<leader>和<localleader>按键就像设置了一种命名空间,
用<localleader>来设置本地映射,会防止你的插件覆盖别人的全局映射

打开vimrc文件
nnoremap <leader>ev :vsplit $MYVIMRC<cr>
重新加载vimrc文件
nnoremap <leader>sv :source $MYVIMRC<cr>

Abbreviations

在一个abbrevivation后输入一个 non-keyword character后,vim会替换那个abbrevivation not-keyword character指的是那些不在iskeyword选项中的字符(iskeyword=@,48-57,_,192-255)

  • insert模式下的abbrevivations

      :iabbrev adn and
      :iabbrev ture true
    
  • replace模式下的abbrevivations

  • command模式下的abbrevivations

自动命令

:autocmd BufNewFile * :write  "该命令会在打开一个文件后,自动自动保存
         ^          ^ ^
         |          | |
         |          | 要执行的命令
         |          | 
         |          用于事件过滤的"模式pattern" 
         |           
         要监听的事件          

:autocmd BufNewFile *.php :write  只会保存php文件
:autocmd BufWritePre *.html :normal gg=G  在保存html文档之前,先格式化
多个事件用逗号分隔
:autocmd BufNewFile,BufRead *.html setlocal nowarp
vim脚本编程中,一般会同时使用BufRead和BufNewFile
  • FileType 事件

    针对不同的文件,设置一些有用的映射,比如注释 可以设置localleader为,, :let maplocalleader=”,,” :autocmd FileType erlang nnoremap c I%% 然后打开一个erlang文件,normal模式下,按下,,c 就可以注释一行

  • 本地缓冲区缩写

    :iabbrev --- test 对当前缓冲区生效,会覆盖如下的全局设置 :iabbrev --- tes2 会话的所有缓冲区都生效,但是优先级没有定义的缩写高

    :autocmd FileType php :iabbrev iff if () {}kkA :sleep 10m 睡眠10ms

自动命令组Grouping Autocommands

:aug[roup] {name}  group name 大小写敏感
	...
:augroup end/END

:augroup testgroup
:autocmd BufWrite * : echom "foo"
:autocmd BufWrite * : echom "bar"
:augroup END

定义两个名称相同的命令组,一般情况下,后面定义的不会覆盖前面的,除非把autocmd!放在组里
:augroup testgroup
:autocmd!
:autocmd BufWrite * : echom "test"
:augroup END

更多详情: :help autocmd-groups

Operator-Pending映射

:help omap-info 	

Operator-pending mappings can be used to define a movement command that can be
used with any operator.  Simple example: ":omap { w" makes "y{" work like "yw"
and "d{" like "dw".

:onoremap { :<c-u>normal! 0f{vi{<cr>   "在包含{}的一行,执行d{、c{、y{  就可以删除/改变/复制{}之间的内容
:onoremap ( :<c-u>normal! 0f(vi(<cr>  "在包含()的一行,执行d(、c(、y(  就可以删除/改变/复制()之间的内容 

The CTRL-U (<C-U>) is used to remove the range that Vim may insert. 


:onoremap ih :<c-u>execute "normal! ?^==\\+$\r:nohlsearch\rkvg_"<cr>

normal! 可以执行一些命令,但是遇到特殊字符就不行了,比如<cr>
execute 把后面的字符串当作命令来执行。特殊字符需要转义,如\r代表回车 \\代表\

g_: 移动到当前行的最后一个非空字符。$会选中最后一个换行符

状态条statusline

statusline可以展示一些当前buffer内文件的信息,比如文件名称%f,完整路径%F, %m如果缓冲区内容修改表示为[+] 默认情况下,statusline是隐藏的。显示: :set laststatus=2,隐藏 :set laststatus=0

定制项目 参数意义
%f 文件名称
%F 文件完整路径,我觉得这个完整路径有助于回答,我在哪里?
%m 如果缓冲区内容发生改变表示为[+],有助于你提醒自己,你在做什么?
%n 缓冲区号,
%y 文件类型,不过我觉得如果输出了文件名,这个有点多余
%v 虚列号
%l 行号
%L 总行数
%= 之后的状态都是右对齐,在这个之前是左对齐
%{expr} 表达式的结果,可以用这个定制很多特性的状态

我的statusline设置

set statusline=buf%n\ %m
set statusline+=\ %l,%v/%L
set statusline+=\ %{&fileencoding?&fileencoding:&encoding} "文件编码
set statusline+=\ [%{&fileformat}] "文件类型
set statusline+=\ %{(exists(\"bomb\")\ &&\ &bomb)?\"Bom\":\"\"} "如果有bomb头,就会显示Bom
set statusline+=%{StatuslineGit()} "显示git分支名称,需要定义如下两个函数
set statusline+=\ %F

function! GitBranch()
  return system("git rev-parse --abbrev-ref HEAD 2>/dev/null | tr -d '\n'")
endfunction

function! StatuslineGit()
  let l:branchname = GitBranch()
  return strlen(l:branchname) > 0?'  '.l:branchname.' ':''
endfunction


\<space> 是空格
最后的效果如下:
buf1  223,5/365 utf-8 [unix]   master  ~/Documents/github.io/_posts/2019-01-23-vimscript-note-1.md

autocmd 所有的事件

  • :help autocmd-events
Name			triggered by ~

	Reading
|BufNewFile|		starting to edit a file that doesn't exist
|BufReadPre|		starting to edit a new buffer, before reading the file
|BufRead|		starting to edit a new buffer, after reading the file
|BufReadPost|		starting to edit a new buffer, after reading the file
|BufReadCmd|		before starting to edit a new buffer |Cmd-event|

|FileReadPre|		before reading a file with a ":read" command
|FileReadPost|		after reading a file with a ":read" command
|FileReadCmd|		before reading a file with a ":read" command |Cmd-event|

|FilterReadPre|		before reading a file from a filter command
|FilterReadPost|	after reading a file from a filter command

|StdinReadPre|		before reading from stdin into the buffer
|StdinReadPost|		After reading from the stdin into the buffer

	Writing
|BufWrite|		starting to write the whole buffer to a file
|BufWritePre|		starting to write the whole buffer to a file
|BufWritePost|		after writing the whole buffer to a file
|BufWriteCmd|		before writing the whole buffer to a file |Cmd-event|

|FileWritePre|		starting to write part of a buffer to a file
|FileWritePost|		after writing part of a buffer to a file
|FileWriteCmd|		before writing part of a buffer to a file |Cmd-event|

|FileAppendPre|		starting to append to a file
|FileAppendPost|	after appending to a file
|FileAppendCmd|		before appending to a file |Cmd-event|

|FilterWritePre|	starting to write a file for a filter command or diff
|FilterWritePost|	after writing a file for a filter command or diff

	Buffers
|BufAdd|		just after adding a buffer to the buffer list
|BufCreate|		just after adding a buffer to the buffer list
|BufDelete|		before deleting a buffer from the buffer list
|BufWipeout|		before completely deleting a buffer

|BufFilePre|		before changing the name of the current buffer
|BufFilePost|		after changing the name of the current buffer

|BufEnter|		after entering a buffer
|BufLeave|		before leaving to another buffer
|BufWinEnter|		after a buffer is displayed in a window
|BufWinLeave|		before a buffer is removed from a window

|BufUnload|		before unloading a buffer
|BufHidden|		just after a buffer has become hidden
|BufNew|		just after creating a new buffer

|SwapExists|		detected an existing swap file

	Options
|FileType|		when the 'filetype' option has been set
|Syntax|		when the 'syntax' option has been set
|EncodingChanged|	after the 'encoding' option has been changed
|TermChanged|		after the value of 'term' has changed
|OptionSet|		after setting any option

	Startup and exit
|VimEnter|		after doing all the startup stuff
|GUIEnter|		after starting the GUI successfully
|GUIFailed|		after starting the GUI failed
|TermResponse|		after the terminal response to |t_RV| is received

|QuitPre|		when using `:quit`, before deciding whether to quit
|VimLeavePre|		before exiting Vim, before writing the viminfo file
|VimLeave|		before exiting Vim, after writing the viminfo file

	Various
|FileChangedShell|	Vim notices that a file changed since editing started
|FileChangedShellPost|	After handling a file changed since editing started
|FileChangedRO|		before making the first change to a read-only file

|ShellCmdPost|		after executing a shell command
|ShellFilterPost|	after filtering with a shell command

|CmdUndefined|		a user command is used but it isn't defined
|FuncUndefined|		a user function is used but it isn't defined
|SpellFileMissing|	a spell file is used but it can't be found
|SourcePre|		before sourcing a Vim script
|SourceCmd|		before sourcing a Vim script |Cmd-event|

|VimResized|		after the Vim window size changed
|FocusGained|		Vim got input focus
|FocusLost|		Vim lost input focus
|CursorHold|		the user doesn't press a key for a while
|CursorHoldI|		the user doesn't press a key for a while in Insert mode
|CursorMoved|		the cursor was moved in Normal mode
|CursorMovedI|		the cursor was moved in Insert mode

|WinNew|		after creating a new window
|TabNew|		after creating a new tab page
|TabClosed|		after closing a tab page
|WinEnter|		after entering another window
|WinLeave|		before leaving a window
|TabEnter|		after entering another tab page
|TabLeave|		before leaving a tab page
|CmdwinEnter|		after entering the command-line window
|CmdwinLeave|		before leaving the command-line window

|InsertEnter|		starting Insert mode
|InsertChange|		when typing <Insert> while in Insert or Replace mode
|InsertLeave|		when leaving Insert mode
|InsertCharPre|		when a character was typed in Insert mode, before
			inserting it

|TextChanged|		after a change was made to the text in Normal mode
|TextChangedI|		after a change was made to the text in Insert mode
|TextYankPost|		after text is yanked or deleted

|ColorScheme|		after loading a color scheme

|RemoteReply|		a reply from a server Vim was received

|QuickFixCmdPre|	before a quickfix command is run
|QuickFixCmdPost|	after a quickfix command is run

|SessionLoadPost|	after loading a session file

|MenuPopup|		just before showing the popup menu
|CompleteDone|		after Insert mode completion is done

|User|			to be used in combination with ":doautocmd"


graph TB subgraph devops test(("fa:fa-users Test")) dev(("fa:fa-user Dev")) ops(("Ops")) branch("branch") dev -->|创建分支| branch branch -->|jenkins| jenkins["jenkins"] end tes1t["fa:fa-camera-retro:5x Camera"] jenkins["fa:fa-futbol:fa-5x Iggool"] classDef green fill:#9f6,stroke:#333,stroke-width:2px; classDef orange fill:#f96,stroke:#333,stroke-width:4px; class sq,e green class di orange