dive-into-vim
Published: 2022-03-03 07:37:32

## 前言

vim依靠海量的插件库可以打造成一款神器的编辑器，但是网络上的教程都是几乎一模一样的，教我们怎么安装插件管理器，然后怎么安装插件，千篇一律，很少涉及到更本质的东西，本文会从几个重要的目录入手，把Vim的插件管理与加载详细的说明。



在使用 Vundle 或者是 vim-plug 等插件管理工具的时候，当我们安装完之后，我们通过用户目录之下的 .vimrc 配置文件下载相应的插件，然后再用户目录之下的 .vim 文件夹之下就有了相应的插件所对应的文件夹，每一个文件夹下面或者是子文件夹之下都存在一个 xxxx.vim 的文件，它是什么呢？

另一个问题就是，Vim仅从 ~/.vimrc 文件中读取其所有设置和脚本吗？

先来回答两个问题：

（1）xxxx.vim 文件的本质就是脚本，因此在启动 vim 的时候会加载这些脚本文件，正式这些脚本的存在，才让我们可以自定义 vim；

（2）~/ .vimrc 文件只是我们习惯性地用户配置方式，其实 vim 的配置还来自于很多其他的地方。




## vim启动时到底加载了哪些脚本 xxx.vim

前面说了，Vim的结构非常整洁，.vimrc只是多个配置文件中的其中一个而已。其实，你可以让Vim告诉你究竟加载了哪些脚本。

用 vim 打开一个文件，然后运行如下命令:

```shell
# 查看vim加载时加载了那些插件（执行了哪些脚本）
:scriptnames 

  1: /usr/share/vim/vimrc
  2: /usr/share/vim/vim81/debian.vim
  3: /usr/share/vim/vim81/syntax/syntax.vim
  4: /usr/share/vim/vim81/syntax/synload.vim
  5: /usr/share/vim/vim81/syntax/syncolor.vim
  6: /usr/share/vim/vim81/filetype.vim
  7: ~/.vim/ftdetect/nginx.vim
  8: ~/.vimrc
  9: /usr/share/vim/vim81/colors/space-vim-dark.vim
 10: /usr/share/vim/vim81/plugin/getscriptPlugin.vim
 11: /usr/share/vim/vim81/plugin/gzip.vim
 12: /usr/share/vim/vim81/plugin/logiPat.vim
 13: /usr/share/vim/vim81/plugin/manpager.vim
 14: /usr/share/vim/vim81/plugin/matchparen.vim
 15: /usr/share/vim/vim81/plugin/netrwPlugin.vim
 16: /usr/share/vim/vim81/plugin/rrhelper.vim
 17: /usr/share/vim/vim81/plugin/spellfile.vim
 18: /usr/share/vim/vim81/plugin/tarPlugin.vim
 19: /usr/share/vim/vim81/plugin/tohtml.vim
 20: /usr/share/vim/vim81/plugin/vimballPlugin.vim
 21: /usr/share/vim/vim81/plugin/zipPlugin.vim
 22: /usr/share/vim/vim81/scripts.vim
 23: /usr/share/vim/vim81/syntax/vim.vim
 24: /usr/share/vim/vim81/syntax/python.vim
 25: ~/.vim/plugged/vim-airline/plugin/airline.vim
 26: ~/.vim/plugged/vim-airline/autoload/airline/init.vim
 27: ~/.vim/plugged/vim-airline/autoload/airline/parts.vim
 28: ~/.vim/plugged/vim-airline/autoload/airline/util.vim
 29: ~/.vim/plugged/vim-easy-align/plugin/easy_align.vim
```






清单比你预期的要长吗？我们发现加载了很多来自不同地方（即不同文件夹之下）的脚本xxx.vim文件（因为我这里安装了一些插件，有的可能没有这么多，这个数目是不一定的）。而且我们发现，不仅仅加载了我们自己安装的那些来自于.vim文件夹下面的插件，还有很多其他地方的插件，这是哪里来的呢？后面会说到。

这其实也就是vim在启动的时候会加载脚本，脚本越多就越耗时间。如果你安装了大量插件的话，那么编辑器需要做大量工作。

#### 查看 vim 启动时间

```shell
vim --startuptime start.log test1.py
```

打开这个 test1.py 文件的同时，生成一个 start.log 的日志文件：

```shell
times in msec
 clock   self+sourced   self:  sourced script
 clock   elapsed:              other lines

000.014  000.014: --- VIM STARTING ---
000.415  000.401: Allocated generic buffers
000.717  000.302: locale set
000.734  000.017: window checked
001.838  001.104: inits 1
002.059  000.221: parsing arguments
002.063  000.004: expanding arguments
002.094  000.031: shell init
002.794  000.700: Termcap init
002.844  000.050: inits 2
003.193  000.349: init highlight
006.708  002.160  002.160: sourcing /usr/local/share/vim/vim82/syntax/syncolor.vim
007.073  002.654  000.494: sourcing /usr/local/share/vim/vim82/syntax/synload.vim
021.470  014.263  014.263: sourcing /usr/local/share/vim/vim82/filetype.vim
021.561  017.365  000.448: sourcing /usr/local/share/vim/vim82/syntax/syntax.vim
021.671  000.022  000.022: sourcing /usr/local/share/vim/vim82/filetype.vim
022.298  000.327  000.327: sourcing /usr/local/share/vim/vim82/syntax/syncolor.vim
023.018  000.311  000.311: sourcing /usr/local/share/vim/vim82/syntax/syncolor.vim
023.498  000.315  000.315: sourcing /usr/local/share/vim/vim82/syntax/syncolor.vim
024.292  002.567  001.614: sourcing /root/.vim/colors/molokai.vim
027.588  003.206  003.206: sourcing /root/.vim/autoload/plug.vim
031.007  001.300  001.300: sourcing /usr/local/share/vim/vim82/ftoff.vim
044.017  000.408  000.408: sourcing /root/.vim/plugged/vim-go/ftdetect/gofiletype.vim
044.226  011.661  011.253: sourcing /usr/local/share/vim/vim82/filetype.vim
044.435  000.064  000.064: sourcing /usr/local/share/vim/vim82/ftplugin.vim
044.607  000.054  000.054: sourcing /usr/local/share/vim/vim82/indent.vim
044.775  041.278  005.039: sourcing $HOME/.vimrc
044.785  000.314: sourcing vimrc file(s)
045.472  000.173  000.173: sourcing /root/.vim/plugged/vim-airline/autoload/airline/init.vim
046.018  000.142  000.142: sourcing /root/.vim/plugged/vim-airline/autoload/airline/parts.vim
047.723  000.339  000.339: sourcing /root/.vim/plugged/vim-airline/autoload/airline/util.vim
047.793  002.877  002.223: sourcing /root/.vim/plugged/vim-airline/plugin/airline.vim
048.251  000.357  000.357: sourcing /root/.vim/plugged/vim-easy-align/plugin/easy_align.vim
048.429  000.084  000.084: sourcing /root/.vim/plugged/neodark.vim/plugin/neodark.vim
049.881  001.103  001.103: sourcing /root/.vim/plugged/vim-go/autoload/go/config.vim
051.495  000.824  000.824: sourcing /root/.vim/plugged/vim-go/autoload/go/util.vim
...
...
中间省略
...
...
084.259  000.044  000.044: sourcing /root/.vim/plugged/vim-airline/autoload/airline/extensions/keymap.vim
091.665  000.092  000.092: sourcing /root/.vim/plugged/vim-airline/autoload/airline/themes.vim
092.103  000.665  000.573: sourcing /root/.vim/plugged/vim-airline/autoload/airline/themes/dark.vim
120.187  000.269  000.269: sourcing /root/.vim/plugged/vim-airline/autoload/airline/builder.vim
120.828  000.132  000.132: sourcing /root/.vim/plugged/vim-airline/autoload/airline/extensions/default.vim
190.934  110.326: opening buffers
190.988  000.054: BufEnter autocommands
191.000  000.012: editing files in windows
191.559  000.559: VimEnter autocommands
191.561  000.002: before starting main loop
194.803  003.242: first screen update
194.806  000.003: --- VIM STARTED ---
```

可以看到，用 vim 打开这个 test1.py 文件，花费了 194.806 毫秒。



#### 干净的启动vim(不带任何插件的启动)

```shell
#  --clean  'nocompatible', Vim defaults, no plugins, no viminfo，
#  即仅仅使用默认的vim设置，不加载插件，也不启用其它的vimrc的配置等。
#  vim8.0版本可以使用--clean参数，vim7.4版本似乎没有这么参数，所以还是更新一下vim到新版本
vim --clean --startuptime start3.log test1.py
```

打开 start3.log，发现总共耗时 022.682 毫秒。

```shell
...
省略前面的
...
022.208  000.032: VimEnter autocommands
022.209  000.001: before starting main loop
022.680  000.471: first screen update
022.682  000.002: --- VIM STARTED ---
```





## vim运行时加载的搜索路径

为了确定启动时或加载缓冲区时会运行哪些脚本，Vim会遍历 'runtimepath'。该设置是一组以逗号分隔的目录列表，各个目录的结构都是一致的。

Vim会检查每个目录的结构，找到需要运行的脚本，并按照目录在列表中的顺序一一处理。



#### 遍历搜索路径runtimepath

启动一个vim之后，执行

```
:set runtimepath
```

得到结果：

```shell
  runtimepath=~/.vim,
  ~/.vim/plugged/vim-airline,
  ~/.vim/plugged/vim-easy-align,
  ~/.vim/plugged/neodark.vim,
  ~/.vim/plugged/vim-monokai,
  ~/.vim/plugged/vim-colors-github,
  ~/.vim/plugged/vim-one,
  ~/.vim/plugged/vim-go,
  ~/.vim/plugged/vim-godef,
  ~/.vim/plugged/nerdtree,
  ~/.vim/plugged/vim-nerdtree-tabs,
  ~/.vim/plugged/nerdtree-git-plugin,
  /usr/local/share/vim/vimfiles,
  /usr/local/share/vim/vim82,
  /usr/local/share/vim/vimfiles/after,
  ~/.vim/after
```

#### runtimepath包含的目录简介

- **~/.vim**         

  - 主目录，保存个人偏好的文件。

- **/usr/local/share/vim/vimfiles**

  - 系统范围的 vim 目录，保存由系统管理员决定的文件。

- **/usr/local/share/vim/vim81**

  - 即 $VIMRUNTIME，保存与 vim 一起分发的文件。

- **/usr/local/share/vim/vimfiles/after**

  - 系统范围Vim目录中的“after”目录。系统管理员可以利用该目录来覆盖默认设置，或添加新的设置。

- **~/.vim/after**

  - 主目录中的“after”目录。可以利用该目录用个人偏好覆盖默认设置或系统设置，或添加新的设置。

这些目录会按照顺序处理，所以要说“after”目录有什么特别的话，那就是它位于列表末尾。实际上“after”并没有什么特别之处。

在处理每个目录时，Vim都会查找具有特定名称的子文件夹。如果想了解更多这方面的信息。请参阅 **:help runtimepath**

- **plugin/**
  - 编辑任何类型的文件都会自动加载的Vim脚本文件，称为“全局插件”。
- **autoload/**
  - （不要与“插件”相混淆。）自动加载中的脚本包含仅在其他脚本请求时加载的函数。

- **ftdetect/**
  - 用于检测文件类型的脚本。可以根据文件扩展名、位置或内部文件内容决定文件类型。

- **ftplugin/**
  - 编辑已知类型的文件时执行的脚本。

- **compiler/**
  - 定义如何运行各种编译器或格式化工具，以及如何解析其输出。可以在多个 ftplugins 之间共享。且不会自动执行，必须通过 :compiler 调用。

- **pack/**
- Vim 8 原生软件包的目录，它采用了“Pathogen”格式的包管理。原生的包管理系统不需要任何第三方代码。







##  自定义安装第三方插件



vim的插件的本质是脚本，在Vim中，**插件只是脚本**，必须放在runtimepath中的正确位置才能执行。







### vim插件管理工具

- **[Vundle](https://github.com/VundleVim/Vundle.vim)**

- **[vim-plug](https://github.com/junegunn/vim-plug)**

- Vim 8 packages

  



## vim8 native package manager



最稳定的管理插件的方法是使用Vim8的内置的 native package manager功能，该功能不需要第三方代码。



首先在用户目录之下的.vim文件夹之下创建一个pack目录，然后在pack目录中创建两个子目录opt和start。

注意这里，这里的自定义名称是我们要对插件进行的一个分类，比如自动补全的、导航的、调试的等等，方便管理，当然我就统统放在一个目录之下也行，只是不方便管理。

```
mkdir -p ~/.vim/pack/{自定义名称}/{opt,start}
```



注意**占位符自定义名称**。这个名称完全取决于你。我们用它对包进行分类。大多数人会把所有的插件都扔进一个无意义的类别中，这样完全没问题。你可以选择自己喜欢的名称，在本文中我选择使用 foobar。理论上，你也可以创建多个类别，比如~/.vim/pack/navigation， ~/.vim/pack/linting等，当然我也可以都放在foobar 这个目录之下。



**Vim不会检测类别之间的重复，**如果存在重复，则会加载两次。