LV02-vimscript-09-插件.md

本文主要是vimscript一些基础知识和操作的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。

点击查看使用工具及版本
Windows windows11
Ubuntu Ubuntu16.04的64位版本
VMware® Workstation 16 Pro 16.2.3 build-19376536
点击查看本文参考资料
点击查看相关文件下载
--- ---

一、插件

插件,我们应该并不陌生,软件插件会给我们带来更好的使用体验。vim中也有很多的插件,有很多会提高我们的工作效率。

当没有插件管理器时,我们必须手动下载tarball包形式的插件,并将它们解压到 ~/.vim 目录中。在少量插件的时候可以。但当安装很多的插件时,这就会变得一团糟,尤其是更新的时候,简直无法想象。所有插件文件分散在单个目录中,我们根本无法找到哪个文件属于哪个插件。此外,我们当然也无法找到应该删除哪个文件来卸载不想要的插件。

这时 vim 插件管理器就为我们带来了极大的便利。插件管理器将安装插件的文件保存在单独的目录中,因此管理所有插件变得非常容易。

二、插件管理器

vim中有一些插件管理器,我们可以通过插件管理器来安装和管理插件,我一般常用的有两种,一个是vim-plug,另一个是Vundle

1. vim-plug

1.1 简介

vim-plug 是一个自由、开源、速度非常快的、极简的 vim 插件管理器。我自己用的也是这一个,那它有什么特点呢?

  • 可以并行地安装或更新插件。
  • 可以回滚更新。
  • 创建浅层克隆shallow clone最小化磁盘空间使用和下载时间。
  • 支持按需加载插件以加快启动时间。
  • 支持分支/标签/提交、post-update 钩子、支持外部管理的插件等。

不过要注意的是,这个插件源码仓库是在GitHub上的,很有可能不能访问,此时科学上网一下就可以了。

  • vim-plug仓库地址
1
2
https://github.com/junegunn/vim-plug  # GitHub 仓库
https://gitee.com/ijliu/vim-plug # Gitee 仓库

1.2 安装vim-plug

  • 通过curl安装
1
2
curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
  • 直接安装
1
mkdir -p ~/.vim/autoload/

然后可以通过下载源码的方式将压缩包下载下来,将其中的plug.vim放入刚才创建的文件夹即可。

image-20220313205431162

1.3 安装插件

  • 创建插件安装目录
1
2
cd ~/.vim
mkdir plugged # 注意与下边的文件中的 plug#begin 后边的文件目录要一致
  • 修改~/.vimrc文件

将要安装的插件仓库名称写入到~/.vimrc中,按以下格式即可:

1
2
3
4
5
6
7
" ~/.vim/plugged 为插件安装目录
call plug#begin('~/.vim/plugged') " 开始,这句话必须有
" airline 状态栏插件
Plug 'vim-airline/vim-airline'
" snazzy 配色插件
Plug 'connorholyday/vim-snazzy'
call plug#end() " 结束,这句话必须有
  • 安装插件

在任意vim窗口中,进入命令模式,然后执行以下命令:

1
:PlugInstall

然后,vim就会开始安装插件,不过就是这些似乎经常安装失败,最好就是科学上网,这样会好点。

这样,我们写在~/.vimrc中的插件就会被安装了,安装的目录为/home/hk/.vim/plugged,每个插件都会有一个单独的目录:

image-20220314151731479

1.4常用命令

PlugInstall [name ...] [#threads]Install plugins
PlugUpdate [name ...] [#threads]Install or update plugins
PlugClean[!]Remove unlisted plugins (bang version will clean without prompt)
PlugUpgradeUpgrade vim-plug itself
PlugStatusCheck the status of plugins
PlugDiffExamine changes from the previous update and the pending changes
PlugSnapshot[!] [output path]Generate script for restoring the current snapshot of the plugins

2. Vundle

2.1 简介

Vundle vim bundle 的简称,Vundle 为每一个安装的插件创建一个独立的目录树,并在相应的插件目录中存储附加的配置文件。因此,相互之间没有混淆的文件。简言之,Vundle 允许我们安装新的插件、配置已有的插件、更新插件配置、搜索安装的插件和清理不使用的插件。

  • Vundle仓库地址
1
2
https://github.com/VundleVim/Vundle.vim " GitHub 仓库
https://gitee.com/jason_lkm/Vundle.vim " Gitee 仓库

2.2 安装Vundle

  • 安装git
1
sudo apt-get install git
  • clone仓库
1
git clone https://github.com/VundleVim/Vundle.vim.git ~/.vim/bundle/Vundle.vim
1
git clone https://gitee.com/jason_lkm/Vundle.vim.git ~/.vim/bundle/Vundle.vim

2.3 安装插件

  • 修改~/.vimrc文件

将要安装的插件仓库名称写入到~/.vimrc中,按以下格式即可:

点击查看格式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
set nocompatible              " 去除VI一致性,必须
filetype off " 必须

" 设置包括vundle和初始化相关的runtime path
set rtp+=~/.vim/bundle/Vundle.vim
call vundle#begin()
" 另一种选择, 指定一个vundle安装插件的路径
"call vundle#begin('~/some/path/here')

" 让vundle管理插件版本,必须
Plugin 'VundleVim/Vundle.vim'

" 以下范例用来支持不同格式的插件安装.
" 请将安装插件的命令放在vundle#begin和vundle#end之间.
" Github上的插件
" 格式为 Plugin '用户名/插件仓库名'
Plugin 'tpope/vim-fugitive'
" 来自 http://vim-scripts.org/vim/scripts.html 的插件
" Plugin '插件名称' 实际上是 Plugin 'vim-scripts/插件仓库名' 只是此处的用户名可以省略
Plugin 'L9'
" 由Git支持但不再github上的插件仓库 Plugin 'git clone 后面的地址'
Plugin 'git://git.wincent.com/command-t.git'
" 本地的Git仓库(例如自己的插件) Plugin 'file:///+本地插件仓库绝对路径'
Plugin 'file:///home/gmarik/path/to/plugin'
" 插件在仓库的子目录中.
" 正确指定路径用以设置runtimepath. 以下范例插件在sparkup/vim目录下
Plugin 'rstacruz/sparkup', {'rtp': 'vim/'}
" 安装L9,如果已经安装过这个插件,可利用以下格式避免命名冲突
Plugin 'ascenator/L9', {'name': 'newL9'}

" 你的所有插件需要在下面这行之前
call vundle#end() " 必须
filetype plugin indent on " 必须 加载vim自带和插件相应的语法和文件类型相关脚本
" 忽视插件改变缩进,可以使用以下替代:
"filetype plugin on
"
" 简要帮助文档
" :PluginList - 列出所有已配置的插件
" :PluginInstall - 安装插件,追加 `!` 用以更新或使用 :PluginUpdate
" :PluginSearch foo - 搜索 foo ; 追加 `!` 清除本地缓存
" :PluginClean - 清除未使用插件,需要确认; 追加 `!` 自动批准移除未使用插件
"
" 查阅 :h vundle 获取更多细节和wiki以及FAQ
" 将你自己对非插件片段放在这行之后
  • 安装插件

在任意vim窗口中,进入命令模式,然后执行以下命令:

1
:PlugInstall

或者直接在终端执行以下命令也可以:

1
vim +PluginInstall +qall

2.4 常用命令

😓我用vim-plug来管理插件,所以这个插件的相关命令没有试过吗,这里就暂时先不写了。

三、以前的插件配置

上边我们了解了插件管理器,那么没有插件管理器的时候是怎样的呢?这对我们了解插件的结构有很大的帮助。vim支持把插件分割成多个文件,我们可以在~/.vim下创建许多不同种类的文件夹来放置不同的内容。接下来我们就来了解一下一些重要文件夹作用。

1. ~/.vim/colors/

vim将会查找~/.vim/colors/mycolors.vim并执行它。 这个文件应该包括生成插件配色方案所需的一切vimscript命令。

2. ~/.vim/plugin/

~/.vim/plugin/下的文件将在每次vim启动的时候执行。 这里的文件包括那些无论何时,在启动vim之后就想加载的代码。

3.  ~/.vim/ftdetect/

~/.vim/ftdetect/下的文件在每次启动vim的时候也会执行。ftdetectfiletype detection的缩写。 这里的文件仅仅负责启动检测和设置文件的filetype类型的自动命令。 这意味着它们一般不会超过一两行。

4. ~/.vim/ftplugin/

~/.vim/ftplugin/下的文件则各不相同。一切皆取决于它的名字。当vim把一个缓冲区的filetype设置成某个值时, 它会去查找~/.vim/ftplugin/下对应的文件。 比如:如果我们执行set filetype=derpvim将查找~/.vim/ftplugin/derp.vim。 一旦文件存在,vim将执行它。

vim也支持在~/.vim/ftplugin/下放置文件夹。 再以我们刚才的例子为例:set filetype=derp将告诉vim去执行~/.vim/ftplugin/derp/下的全部*.vim文件。 这使得我们可以按代码逻辑分割在ftplugin下的文件。

因为每次在一个缓冲区中执行filetype时都会执行这些文件,所以它们只能设置buffer-local选项。 如果在它们中设置了全局选项,所有打开的缓冲区的设置都会遭到覆盖!

5. ~/.vim/indent/

~/.vim/indent/下的文件类似于ftplugin下的文件。加载时也是只加载名字对应的文件。

indent文件应该设置跟对应文件类型相关的缩进,而且这些设置应该是buffer-local的。我们当然可以把这些代码也一并放入ftplugin文件, 但最好把它们独立出来,让其他vim用户理解插件开发者的意图。这只是一种惯例,不过还是尽量体贴用户并遵从它。

6. ~/.vim/compiler/

~/.vim/compiler下的文件非常类似于indent文件。它们应该设置同类型名的当前缓冲区下的编译器相关选项。

7. ~/.vim/after/

~/.vim/after文件夹有点神奇。这个文件夹下的文件会在每次vim启动的时候加载, 不过是在~/.vim/plugin/下的文件加载了之后。

这允许我们覆盖vim的默认设置。实际上我们将很少需要这么做,所以不用理它, 除非我们有vim设置了选项x,但又想要不同的设置的主意。

8. ~/.vim/autoload/

~/.vim/autoload文件夹就更加神奇了。事实上它的作用没有听起来那么复杂。简单地说:autoload是一种延迟插件代码到需要时才加载的方法,后边会有详细介绍。

9. ~/.vim/doc/

~/.vim/doc/文件夹提供了一个我们可以放置的插件的文档的地方。 vim对文档的要求是多多益善(看看我们执行过的所有:help命令就知道),所以为我们的插件写文档是非常重要的。

四、自动加载

还记得刚才说的autoload目录吧,这个目录下的文件很有用,接下来就让我们来了解一下吧。

虽然我还没有开发过vim的插件,但是我很乐意了解一下这个自动加载的功能,这样也许我可以更加容易的看懂插件,从而修改自己不喜欢的地方。自动加载有什么用?简单来说就是可以让我们的插件效率更高。

想象一下,当我们打开vim的时候,某个插件有很多的功能,可是那个功能我们很少用到,但是它一开始的时候就直接进行了加载,这不仅会很浪费时间吗,也会很浪费内存。我自己觉得就跟Windows系统下的开机自启动一样,有些软件我们基本不用,但是如果设置了开启启动,它就会拖慢我们的开机速度,在后台的时候也会占用内存,为什么不能不让它开启自启,我想用的时候在打开不好吗?自动加载大概就是这个意思吧。

vim中自动加载让我们直到需要时才加载某一部分代码。 这会有一些性能上的损失,但如果我们不总是需要那个插件的每一行代码,自动加载将带来速度上的飞跃。

接下来就让我们一起来探索一下它是如何工作的。

1. 如何定义函数?

在命令模式下尝试执行:

1
:call plugfile#Hello()

执行这个命令的时候,当然我们只是尝试,这个函数还没有定义,一定会报错的,这里只是一个示例。

在这里vim的行为与平常的函数调用有些许不同,如果这个函数已经加载了,vim简单地像平常一样调用它。但是若是函数并未加载,那么vim将在~/.vim(或~/.vim/plugged/plug_name/autoload)下查找一个叫做autoload/plugfile.vim的文件。如果文件存在,vim将加载这个文件,接着vim就会像平常一样调用它。

这里有一条关于文件位置的说明

【说明】这里只是因为我的插件安装在~/.vim/plugged下,所以是这个目录,要是使用其他插件管理器的话可能在其他目录中,这里只是提供一个实例,比如我的airline插件:

image-20220314152900563

在这个文件中,函数的定义应该是这样的格式:

1
2
3
function plugfile#Hello()
" ...
endfunction
点击查看对 # 的说明

这里函数名中的#表示子目录,我们可以使用多个#来表示目录层级关系,例如

1
:call myplugin#plugfile#Hello()

那么,vim将会在autoload/myplugin/plugfile.vim查找自动加载文件。 里面的函数需要使用自动加载的绝对路径进行定义:

1
2
3
function myplugin#plugfile#Hello()
" ...
endfunction

2. 开始实践

  • 创建文件

让我们创建~/.vim/autoload/test.vim文件:

1
vim ~/.vim/autoload/test.vim

在文件中添加以下内容:

1
2
3
4
5
6
7
echo "Loading..."

function! test#Hello()
echo "Hello, world!"
endfunction

echo "Done loading."

然后通过:wq命令保存文件并退出。

  • 保存并载入文件

当我们没有通过source命令载入~/.vim/autoload/test.vim脚本文件的时候,这个脚本文件是不会生效的,随便打开一个vim窗口,在命令模式中执行:

1
:source ~/.vim/autoload/test.vim

source %命令表示载入该脚本,此时输出结果如下:

1
2
Loading...
Done loading.

有两行输出结果,这说明这个脚本已经通过source命令被载入并生效了。

  • 调用函数载入文件

首先关闭刚才的vim窗口,使刚才生效的脚本文件失效。然后重新打开一个vim窗口(任意一个即可),在命令模式中执行:

1
:call test#Hello() 

输出结果如下:

1
2
3
Loading...
Done loading.
Hello, world!

这说明了什么?当我们打开一个vim窗口的时候,~/.vim/autoload/test.vim脚本文件并没有打印出以下内容:

1
2
Loading...
Done loading.

这就说明脚本文件并没有生效,并没有被载入。而当我们执行了刚才的函数调用命令后,vim在调用函数之前加载了整个文件,所以加上调用函数的输出,一共有三行的输出。同时也证明了,刚才的脚本文件在调用函数的时候才被加载。

  • 修改文件会发生什么?

首先我们开测试脚本文件:

1
vim ~/.vim/autoload/test.vim

然后在命令模式中执行:

1
:call test#Hello() 

这样,就会通过自动加载而载入整个文件,输出结果如下:

1
2
3
Loading...
Done loading.
Hello, world!

接下来,我们不要关闭vim,直接修改函数内容为:

1
2
3
4
5
6
7
echo "Loading..."

function! test#Hello()
echo "Hello, world! again!"
endfunction

echo "Done loading."

然后在命令模式中执行:

1
2
:w " 保存文件
:call test#Hello()

会发现输出结果如下:

1
Hello, world!

仅仅只有一行输出,还是脚本文件修改前的输出情况。这是为什么呢?我的文件明明修改并保存了呀。vim已经有了test#Hello的一个定义,所以它不再需要重新加载文件,这意味着:

(1)函数以外的代码将不再执行。

(2)它不会反映函数本身的变化。