Vim 插件管理器 - dein.vim

前言

vim-plug 是一个非常优秀的 Vim 插件管理器,但是随着安装的插件越来越多,逐渐发现即使使用 vim-plug,首次启动速度仍然很慢。

究其原因,虽然 vim-plug 本身提供了优秀的延迟加载机制,但是可用于延迟加载的选项相对较少,另一方面,vim-plug 对插件的延迟加载与配置无法进行统一,很多时候,我们想对插件进行延迟加载,但是插件配置项如果调用了插件功能,则加载的时候就会报错(因为插件此时还未加载)...

针对上述问题,dein.vim 都给出了更优秀的解决方案。

vim-plug 是一款非常优秀的插件管理器,具备优秀的插件管理性能,同时操作及其简单,且具备优秀的 UI 显示,通常情况下,建议使用 vim-plug
但是如果当使用 vim-plug 后,启动速度仍然很慢,那就可以考虑下 dein.vim

dein 本身只提供函数接口进行操作,没有提供命令与 UI 显示,对于用户相对不友好。
不过 Github 上面已经有人对其进行了再一次封装:

可以结合以上两个插件,简化 dein 使用。

优点

  • 启动快
  • 支持异步安装
  • 支持本地插件
  • 支持多种 VCS(包括 git)
  • 支持缓存
  • 支持merge特性,有效减少runtimepath层级
    ...

安装

  • 对于 Unix/Linux/Mac:
curl https://raw.githubusercontent.com/Shougo/dein.vim/master/bin/installer.sh > installer.sh
# 安装路径我们选择:~/.vim/dein
sh ./installer.sh ~/.vim/dein
  • 对于 Windows:
Invoke-WebRequest https://raw.githubusercontent.com/Shougo/dein.vim/master/bin/installer.ps1 -OutFile installer.ps1
# Allow to run third-party script
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
# 安装路径我们选择:~/.vim/dein
./installer.ps1 ~/.vim/dein

dein 基本使用

  • 最简配置:基本结构如下:
if &compatible
    set nocompatible
endif

let s:dein_path = '~/.vim/dein'

" Add the dein installation directory into runtimepath
let &runtimepath = &runtimepath.','.s:dein_path.'/repos/github.com/Shougo/dein.vim'

if dein#load_state(s:dein_path)
  call dein#begin(s:dein_path)

  call dein#add(s:dein_path.'/repos/github.com/Shougo/dein.vim')

  " install third-party plugins
  " call dein#add('tpope/vim-surround')

  call dein#end()
  call dein#save_state()
endif

filetype plugin indent on
syntax enable
  • 插件安装:插件基本安装方法如下:

    1. dein#begin()dein#end()之间使用dein#add({plugin})声明要安装的插件:
    call dein#begin(s:dein_path)
    
    " install third-party plugins
    call dein#add('tpope/vim-surround')
    
    call dein#end()
    
    1. 重新打开 Vim 或者手动重新加载配置:so %后,使用如下命令安装插件:
    :call dein#install()
    

    :由于 dein 没有 UI 显示下载进度,需等待一段时间,等下载完成后,底部提示栏会有显示通知。
    也可以直接到<dein_path>/repos/查看插件是否已安装完成。

    1. 关闭 Vim,再重新打开,就可以使用已安装的插件功能了。
  • 插件卸载:dein.vim 并未直接提供插件卸载功能,因此其插件卸载相对麻烦,步骤如下:

    1. 取消插件添加配置:将要卸载的插件进行注释:
    call dein#begin(s:dein_path)
    
    " uninstall vim-surround
    " call dein#add('tpope/vim-surround')
    
    call dein#end()
    
    1. 清除缓存:关闭再重新打开 Vim,执行:call dein#recache_runtimepath()
      :由于 dein 采用了merge功能,其会将所有插件的plugin/目录下的内容都缓存到同一个目录(具体为<dein_path>/.cache/init.vim/.dein/plugin)中,因此虽然我们上一步配置文件取消了添加插件,但由于缓存未删除,导致本次启动仍然会加载相应插件,故还需手动进行缓存清除操作。

    2. 关闭再重新打开 Vim,就可以发现插件功能已禁止(可选)

    3. 删除插件:以上操作只是停用了插件,插件仍然存在于本地电脑,如果想进行删除,还需调用如下命令:

    :call map(dein#check_clean(), "delete(v:val, 'rf')")
    

    此时就可以看到 dein 目录下的repo下的相应插件被删除了,缓存文件夹.cache下的.dein/plugin相关的插件缓存也被删除了。

  • 失能插件:不删除插件,只是不进行加载,步骤如下:

    1. 将配置文件中的dein#add改为dein#disable,如下所示:
    call dein#begin(s:dein_path)
    
    call dein#add('tpope/vim-surround')
    " disable 添加到 add 后面
    call dein#disable('vim-surround')
    
    call dein#end()
    
    1. 关闭 Vim,再重新打开,执行:call dein#recache_runtimepath()

    2. 关闭 Vim,再重新打开,就可以看到插件功能禁止了。

:以上任何操作如果失败,一律进行如下操作,确保不受 dein 缓存机制影响:

  1. 重新打开 Vim,执行:call dein#clear_state(),清除状态文件,强制 dein 重新加载配置。
  2. 退出后重新打开 Vim,执行:call dein#recache_runtimepath(),清除旧缓存
  3. 退出 Vim,再重新打开,执行剩余操作

一些有用操作/设置

在对 dein 进行详细介绍前,先了解下其提供的一些比较有用的操作/设置,方便理解与使用。

  • 手动安装插件:依次输入以下命令:
" 开始块,安装路径可以自由更改
:call dein#begin('~/.cache/dein') 
" 添加插件安装声明
:call dein#add('~/.vim/plugB')
" 配置块结束,安装自动开始
:call dein#end()
  • 手动加载插件:dein#source([{plugins}])
:call dein#source('vim-surround')

dein#source会直接加载插件,无论插件是否配置了懒加载。

  • 检测插件是否已安装:dein#check_install({plugins})

    • 返回0:表示插件已安装,可以正常使用
    • 返回-1:表示是无效插件
    • 返回其他:表示插件未安装
    :call dein#check_install('vim-surround')
    
  • 检测插件是否已加载:dein#is_sourced({plugin-name})

    • 返回0:表示插件未加载
    • 返回其他:表示插件存在且已加载
    :call dein#is_sourced('vim-surround')
    

    :由于 dein 存在懒加载,因此存在插件已安装(dein#check_install)但未加载(dein#is_sourced)的情形。

  • 检测插件是否被禁用:dein#tap({plugin-name})

    • 返回0:表示插件不存在,或者被禁用
    • 返回其他:表示插件存在,且可以使用(懒加载插件在未加载前也是属于可以使用状态)
    :call dein#tap('vim-surround')
    
  • 插件懒加载

call dein#add('junegunn/fzf', {
    \'lzay': 1,                                               " 非0 表示启用懒加载
    \ 'if': s:has_exec('fzf'),                                " 条件满足时才加载(判断类型`String`/`Number`)
    \ 'on_if': 'winnr("$") > 1',                              " 条件满足时才加载(判断类型`String`)
    \ 'on_cmd': 'FZF',                                        " 存在 FZF 命令时才加载
    \ 'on_func': 'fzf#run',                                   " 调用了函数 fzf#run 时才进行加载
    \ 'on_event': ['VimEnter', 'BufRead']                     " 事件发生时才加载
    \ 'on_ft': 'python'                                       " 文件类型匹配时才加载
    \ 'on_map': { 'n' : ['<C-n>', '<C-p>'], 'x' : '<C-n>'}} " 匹配特定模式下的按键映射时才加载
    \ 'on_path': '.editorconfig',                             " 路径匹配时才加载
    \ 'on_source':  ['vim-surround']                          " 插件 vim-surround 加载时才加载
    \ })

:懒加载时lazy可忽略,dein 会自动根据其他选项自动判断是否启用懒加载。

  • 检测未使用的插件目录(可以清除):dein#check_clean()

  • 获取插件配置:dein#get([{plugin-name}])

:echo dein#get('vim-surround')

函数

以下是 dein.vim 内置的函数简介:

  • dein#add({repo}[, {options}]):初始化/添加插件。

    • {repo}:表示插件 URI 或者插件本地路径。

    • {options}:对插件进行额外选项配置,具体选项请参考下文:选项(OPTIONS)

    dein#add必须在dein#begin()块中使用。

  • dein#begin({base-path}, [{vimrcs}]):初始化 dein.vim,开启插件配置块。

    • {base-path}:表示插件下载安装路径

    • {vimrcs}:额外配置选项或者 TOML 配置文件。默认值为$MYVIMRC

    :不能在has('vim_starting')块中调用dein#begin()
    dein#begin()会自动设置:filetype off

  • dein#build([{plugins}]):编译插件{plugins}

    :当使用类似dein#add('autozimu/LanguageClient-neovim', {'build': 'bash install.sh'})配置插件时,指定了build选项,则可通过调用:call dein#build()对插件进行重新编译安装,即执行bash install.sh

  • dein#call_hook({hook-name}):调用钩子函数{hook-name}

    :如果{hook-name}设置为source,那么 dein 就会触发已加载的插件的hook_source钩子函数。

  • dein#check_install({plugins}):查看插件是否已安装。

    • 对于已安装的插件{plugins},该函数返回0
    • 对于未安装的插件{plugins},该函数返回 非0 数值。
    • 对于无效插件,该函数返回 -1。
    • 如果{plugins}忽略不写,则对所有插件进行检测。
    " 已安装,则返回 0
    :echo dein#check_install('vim-surround')
    
  • dein#check_lazy_plugins():检测无意义的懒加载插件。

    插件如果没有plugin/目录,那么对这类插件进行懒加载是没有意义的。

  • dein#check_update([{plugins}]):异步检测插件是否可更新。

  • dein#check_clean():返回未使用的插件。可以结合其他命令手动进行删除。

  • dein#clear_state():手动清除状态文件。

    :状态文件的路径为:<dein_path>/state_vim.vim

  • dein#config({plugin-name}, {options})/dein#config({options}):修改插件配置选项。

    如果忽略{plugin-name},那么配置选项作用于全局变量g:dein#name指定的值。
    如果{plugin-name}是列表,那么一套相同的配置项就可以作用于多个插件。
    如果{plugin-name}已经加载,或者是无效状态,那么忽略该配置选项{options}

    call dein#add('Shougo/deoplete.nvim')
    call dein#config('deoplete.nvim', {
        \ 'lazy' : 1, 'on_i' : 1,
        \ })
    

    dein#config()必须在dein#begin()dein#end()块中调用。

  • dein#direct_install({repo}[, {options}]):下载插件,并直接进行加载(source),即不会加载配置块(dein#begin()/dein#end())选项。

    " 直接加载插件 deoplete.vim
    call dein#direct_install('Shougo/deoplete.nvim')
    

    dein#direct_install直接下载的插件配置文件存放于dein#get_direct_plugins_path(),我们可以手动加载更改该文件配置。

  • dein#disable({plugins}):失能/禁止加载插件。

    dein#disable()函数必须在相关插件加载之前进行使用。因为 Vim 默认机制在加载插件后,无法直接失能/禁止。

    call dein#add('skywind3000/asyncrun.vim')
    call dein#disable('asyncrun.vim')
    
  • dein#each({command}[, {plugins}]):为每个插件{plugins}执行{command}命令。

  • dein#end()dein 配置块结束位置。

    :如果使能了g:dein#auto_recache,那么dein#end()会自动执行dein#recache_runtimepath(),重新加载缓存。
    :在dein#end()执行后,runtimepath会被更改。

  • dein#get([{plugin-name}]):获取插件{plugin-name}配置选项。

    :echo dein#get('asyncrun.vim')
    

    :如果未指定{plugin-name},则返回所有插件信息。

  • dein#get_direct_plugins_path():获取直接下载安装插件脚本路径。

  • dein#get_log():获取插件安装日志信息。

  • dein#get_progress():获取当前更新进程信息。

  • dein#get_updates_log():打印插件更新日志。

  • dein#install([{plugins}]):异步安装插件。

    • {plugins}:指定插件名称。如果该参数未设置,则默认安装所有插件。
  • dein#is_sourced({plugin-name}):查询插件加载状态。返回任意非 0 值表示插件存在且已加载(source)。

    :更多相关信息,可参考::h dein#source():h dein#tap()

  • dein#load_dict({dict}, [{options}]):从字典{dict}中加载插件配置选项。

    • {dict}key为插件 URI,valuedein-options构成的字典。比如:
    call dein#load_dict({
        \ 'Shougo/denite.nvim': {},
        \ 'Shougo/deoplete.nvim': {'name': 'deoplete'}
        \ })
    
  • dein#load_rollback({rollbackfile}[, {plugins}]):以{rollbackfile}文件回滚插件。

    :这是一个危险命令。

  • dein#load_state({base-path}):从缓存脚本文件中加载 dein 状态信息。

    • {base-path}:为插件下载存放路径。
      如果该函数返回 1,则表示缓存脚本过期,或者无效,或者不存在。
    if dein#load_state(path)
        call dein#begin(path)
        " My plugins here:
        " ...
        call dein#end()
        call dein#save_state()
    endif
    

    dein 的状态缓存脚本存放路径为:dein#util#_get_runtime_path() . '/state_' . fnamemodify(v:progname, ':r') . '.vim',也即:<dein_path>/.cache/init.vim/.dein/state_nvim.vim:实践中发现,状态文件存储路径为:<dein_path>/state_nvim.vim
    dein#load_state()函数必须在dein#begin()前进行调用,因为它会清除 dein 的所有配置。
    dein#load_state()会完全覆盖runtimepath,因此在动态更改runtimepath后,千万不要调用该函数,否则前面的设置就无效了。
    :当 dein 的状态信息已被加载时,会自动跳过该块内容。

  • dein#load_toml({filename}, [{options}]):从{filename}文件中以 TOML 格式加载插件配置。

  • dein#local({directory}, [{options}, [{names}]]):添加{directory}的子目录到runtimepath

    {names}:为子目录的名称。如果指定了{names},那么 dein 就只会加载这些子目录(子目录可使用通配符匹配)。

    " Load plugin from "~/.vim/bundle".
    call dein#local("~/.vim/bundle")
    " Load plugin1 and plugin2 from "~/.vim/bundle".
    call dein#local("~/.vim/bundle", {},
    \ ['plugin1', 'plugin2', 'vim-*', '*.vim'])
    
  • dein#update([{plugins}]):安装/更新插件。

    dein#update()在 Vim 8.0+ 和 Neovim 中,会以异步方式执行。

  • dein#plugins2toml({plugins}):获取插件{plugins} TOML 格式的配置信息。

  • dein#reinstall({plugins}):重新安装插件。

  • dein#remote_plugins():加载尚未加载的远程插件remote-plugin,并执行命令:UpdateRemotePlugins

    dein#remote_plugins()只在 Neovim 中可用。

  • dein#rollback({date}[, {plugins}]):回滚到最接近{date}指定日期的插件版本。

    • {data}:如果设置为"",则回滚到插件最新版本。

    dein#rollback()是一个危险命令。

  • dein#recache_runtimepath():重新加载 deinruntimepath缓存目录,并执行:helptags。该命令会在安装完成后自动调用。

    dein 中使用了一种称为merge特性的功能,简单来讲,就是 dein 会自动将所有插件plugin/目录都融合merge到一个缓存目录中,目的就是为了减少runtimepath的层级,通常的插件管理器都是将插件的路径添加到runtimepath中,这样runtimepath就会变得很大,插件搜索与加载就会变慢,而 dein 采用merge特性,将所有插件都融合到一个目录中,以后无论安装多少插件,都只需在该目录下进行查找即可,提升了插件加载效率。

  • dein#save_rollback({rollbackfile}[, {plugins}]):保存插件回滚信息到文件{rollbackfile}中。

  • dein#save_state():保存 dein 状态到缓存脚本中。

    dein#save_state()必须在dein#end()后面被调用。
    dein#save_state()会完整保存当前runtimepath,因此在调用后不能再动态更改runtimepath

  • dein#set_hook({plugins}, {hook-name}, {hook}):为插件设置钩子函数{hook},钩子函数名称为{hook-name}

    • {plugins}:如果未指定,则表示为所有插件设置钩子函数。

    dein#set_hook()可以在dein#begin()/dein#end()块后调用。
    dein#set_hook()如果设置在dein#load_state()/dein#save_state()块中的时候,如果钩子函数是函数类型Funcref,那么就不起作用。

    call dein#add('Shougo/neosnippet.vim', {'lazy': 1})
    
    function! Foo() abort
    endfunction
    
    " Does not work for dein#load_state()/dein#save_state() block
    call dein#set_hook('neosnippet.vim', 'hook_source', function('Foo'))
    
    " Does work for dein#load_state()/dein#save_state() block
    call dein#set_hook('neosnippet.vim', 'hook_source', 'echomsg "foo"')
    
  • dein#source([{plugins}]):加载(:source)插件。

    • {plugins}:如果未指定,则会加载所有插件。
  • dein#tap({plugin-name}):如果插件存在且没有被禁止,则返回非 0 数值。

    dein#tap()会初始化全局变量g:dein#name:dein#plugin

变量

  • g:dein#auto_recache:是否自动调用dein#recache_runtimepath()更新缓存。

    • 1:开启自动更新缓存。
    • 0:则关闭自动更新缓存(默认值)

    :该选项会重新加载$MYVIMRC

  • g:dein#cache_directory:设置缓存目录。

    其默认缓存目录为:dein#begin()指定的路径。

  • g:dein#download_command:默认下载命令。

    其默认值为:curl --silent --location --output
    或者为:wget -q -O
    或者使用 PowerShell。

  • g:dein#enable_name_conversion:使能命名转换。

    • 1:如果值为1,且配置时未指定插件名,则使用dein-options-normalized_name作为插件名称。
    • 0:禁止命名转换(默认值)。
    " 使能命名转换
    let g:dein#enable_name_conversion = 1
    
    if dein#load_state(s:dein_path)
      call dein#begin(s:dein_path)
    
      " 将 asyncrun.vim 名称设置为 asyncrun
      call dein#add('skywind3000/asyncrun.vim',{'normalized_name' :'asyncrun'})
    
      call dein#end()
      call dein#save_state()
    endif
    

    上述代码将插件名为asyncrun.vim修改为asyncrun,现在使用asyncrun可以成功访问插件,使用asyncrun.vim访问会失效。

  • g:dein#enable_notification:开启通知功能。

    • 1:表示开启通知功能。
    • 0:表示失能通知功能(默认值)。

    :该选项涉及外部命令调用,因此在不同的平台上,需要有相应的命令存在,具体为:

  • g:dein#install_max_processes:设置 dein 最大进程数。

    其默认值为 8,即最大开启进程数为 8。

    :如果该值小于等于 1,则表示关闭多进程。

  • g:dein#install_process_timeout:插件安装/更新超时时间,单位为秒。

    其默认值为:120(即超时时间为 120 秒)

  • g:dein#install_progress_type:安装进度条输出样式。

    其值有如下几个选项:

    • 'none':不进行输出
    • 'echo'echo区中显示(默认值)
    • 'tabline'tabline中显示
    • title:标题栏中显示(该选项只在 Neovim 中生效)

    :如果需要在状态栏statusline中进行展示,需要结合dein#get_progress()函数。

  • g:dein#install_message_type:安装消息输出类型。

    其值有如下两个选项:

    • 'none':不输出安装信息
    • 'echo'echo区域显示安装信息
  • g:dein#install_log_filename:安装日志文件。

    该值默认为"",表示失能日志记录。

  • g:dein#name:当前插件名称。

    g:dein#name只能在dein#tap()块中使用。
    g:dein#name已被标记为废弃状态deprecated

  • g:dein#notification_icon:设置通知图标路径。

    该值默认为""

  • g:dein#notification_time:通知显示时长,单位为秒。

    该选项默认值为:2,表示默认显示时间为 2 秒。

    :该选项只支持 Linux 和 Windows 平台。

  • g:dein#plugin:当前插件。

    g:dein#plugin可用在dein#tap()dein-hooks块中。

  • g:dein#types#git#clone_depthgit clone默认历史深度(default history depth)。

    其默认值为 0。
    如果该值设置为 1,则 dein 会采用浅拷贝功能。
    更多信息,请参考:dein-options-type__depth

  • g:dein#types#git#command_pathgit命令路径。

    其默认值为:git

  • g:dein#types#git#default_protocolgit默认使用协议。

    其有两种类型可选:httpsssh
    其默认值为:https

  • g:dein#types#git#pull_commandgit pull命令。

    其默认值为:"pull --ff --ff-only"

选项(OPTIONS)

以下是 dein 提供的选项列表简介:dein-options

  • augroup:插件对于VimEnterGUIEnter事件的自动命令组名称。

    类型String

  • build:指定编译脚本。

    类型String

    build指定的命令最终由system()函数执行。
    build会在插件根目录执行命令,如果想使用cd命令,必须结合使用sh -c命令:

    " 在 vimproc.vim 目录下执行 make
    call dein#add('Shougo/vimproc.vim', {'build': 'make'})
    
    " 在 command-t 目录下执行:sh -c "cd ruby/command-t && ruby extconf.rb && make"
    call dein#add('wincent/command-t', {
        \ 'build':'sh -c "cd ruby/command-t && ruby extconf.rb && make"'
        \ })
    
  • depends:指定插件依赖的其他插件。

    类型StringList

    call dein#add('tpope/vim-surround', {
        \'on_map': {'n' : ['cs', 'ds', 'ys'], 'x' : 'S'}, 
        \'depends' : 'vim-repeat'
        \})
    

    depends列表指定的依赖 不会 自动进行安装。
    :对于非懒加载插件,depends指定的依赖插件加载顺序无法确保有序。

  • frozen:如果设置为1,则表示禁止该插件自动更新。

    类型Number

  • ftplugin:这个应该是指定插件类型路径(不是很确定)。

    类型Dictionary,其中:

    • key_时,在加载完所有ftplugin后,会执行该操作。
    • key{filetype}时,就只会加载ftplugin目录中的{filetype}插件。
  • if:添加条件判断。

    类型NumberString,其中:

    • 如果其值为0,则 dein 不会注册该插件,相当于禁止加载插件。
    • 如果其值为String类型,dein 会执行字符串指令。
    • 如果未设置if指令,dein 默认会使能/启用该插件。
  • lazy:设置插件懒加载。

    类型Number,其中:

    • 如果设置为 非0 值,表示启用懒加载(此时 dein 不会把插件路径添加到runtimepath)。
    • 如果未设置lazy选项,dein 会根据插件当前条件自动进行判断是否启用懒加载。

    :对于没有plugin/目录的插件,不要设置懒加载,因为这是没有意义的。可以通过dein#check_lazy_plugins()找到无意义的懒加载插件。

  • merged:启用merged特性。

    类型Number,其中:

    • 如果设置为0,则表示禁止merged特性,这样当前插件的plugin/目录就不会被融合进缓存目录中,这对于插件文件存在冲突的情形下是一个很好的解决方案。
  • name:指定插件名称。

    类型String

    :如果未指定name选项,则 dein 会默认将插件名称设置为插件仓库尾部名称,即:skywind3000/asyncrun.vim的名称为asyncrun.vim
    :插件名称必须全局唯一,如果存在两个或以上相同的插件名称,则后面的会覆盖前面,此时使用name选项自己指定名称就可以很好地解决这个冲突。

  • normalized_name:设置插件标准名称。

    类型String

    :如果未指定normalized_name选项,则默认使用插件名称主体部分作为其标准化名称,如下所示:

    name            : normalized name
    
    denite.nvim       denite
    dein.vim          dein
    vim-quickrun      quickrun
    
  • on_cmd:如果执行了指定的命令,dein 就会加载该插件dein#source()

    类型StringList

    call dein#add('tpope/vim-fugitive', {'on_cmd' : 'Gstatus'})
    

    上述代码中,当我们在 Vim 中执行Gstatus时,dein 就会加载vim-fugitive插件。

  • on_event:当指定的事件发生时,dein 就会加载该插件dein#source()

    类型StringList

    call dein#add('RomainEndelin/vim-projectionist', {
        \    'on_event': ['VimEnter', 'BufRead'],
        \    'on_if': 'findfile(".projections.json", a:event == "VimEnter" ? ";" : ".;") != ""'
        \ })
    
  • on_func:当指定的函数被调用时,dein 就会加载该插件dein#source()

    类型String

    call dein#add('junegunn/fzf', {
        \ 'if': s:has_exec('fzf'),
        \ 'on_cmd': 'FZF',      " 存在 FZF 命令时才加载
        \ 'on_func': 'fzf#run', " 调用了函数 fzf#run 时才进行加载
        \ })
    
  • on_ft:打开指定的文件类型时,才加载插件。

    类型StringList

    call dein#add('bps/vim-textobj-python', { 'on_ft' : 'python' }) 
    call dein#add('tmhedberg/matchit', { 'on_ft' : 'html' })
    
  • on_if:当满足条件时,dein 就会加载该插件dein#source()

    类型String

    on_if选项的默认会在事件BufReadBufNewFileVimEnterFileType发生时进行判断。
    如果存在dein-options-on_event事件,则在dein-options-on_event事件中进行判断,比如:

    call dein#add('blueyed/vim-diminactive',
    \ {'on_event': 'WinEnter', 'on_if': 'winnr("$") > 1'})
    

    上述代码中,on_if会在事件WinEnter发生时进行判断。

  • on_map:当指定模式下,发生指定的按键映射时,加载该插件。

    类型DictionaryListString,其中:

    • 当值为Dictionary类型时,key为模式{mode}指定,其余条目为按键映射:{mapping}[{mapping1},{mapping2},...],比如:
    call dein#add('terryma/vim-multiple-cursors', { 'on_map' : { 'n' : ['<C-n>', '<C-p>'], 'x' : '<C-n>'}})
    
    • 当值为List类型时,则其条目设置格式为:{mapping}[{mode}, {mapping1}, [{mapping2}, ...]],比如:
    call dein#add('dhruvasagar/vim-table-mode', {'on_map'    : '<LocalLeader>t' })
    call dein#add('terryma/vim-multiple-cursors', { 'on_map' : ['<C-n>', '<C-p>']})
    

    :当未指定模式{mode}时,则默认为nx
    on_map选项支持<Plug>按键映射,如果映射只指定了<Plug>,那么实质上映射的是<Plug>(normalized_name,比如:

    " It is same as "'mappings': '<Plug>(anzu'
    call dein#add('osyo-manga/vim-anzu', {'on_map': '<Plug>'})
    
  • on_path:当编辑指定路径的文件时,加载相应插件dein#source()

    类型StringList,其中:

    • 如果值为.*,则表示编辑任何文件时,都加载插件。
    • 其他情况,则只有缓冲区名称匹配on_path指定的字符串时,才进行加载。
    call dein#add('editorconfig/editorconfig-vim', {
        \ 'if': has('pythonx'),
        \ 'on_event': 'InsertEnter',
        \ 'on_path': '.editorconfig',
    \ })
    

    on_path选项对于文件夹浏览类型的插件很有用。

  • on_source:指定插件依赖关系,表示在指定的插件加载后,会加载当前插件。

    类型StringList

    :插件必须设置了懒加载选项。

    " ~/.vim/plugA/plugin/a.vim
    echom 'a.vim loaded!!'
    command! -nargs=0 CmdA :echom 'this is command a'
    echom 'a.vim done!!'
    
    " ~/.vim/plugB/plugin/b.vim
    echom 'b.vim loaded!!'
    command! -nargs=0 CmdB :echom 'this is command b'
    echom 'b.vim done!!'
    
    " ~/.config/nvim/init.vim
    call dein#add('~/.vim/plugA', {
          \ 'on_source': ['plugB'],
          \ 'on_cmd': ['CmdA'],
          \ 'lazy': 1})
    
    call dein#add('~/.vim/plugB', {
          \ 'on_cmd': ['CmdB'],
          \ 'lazy':1 })
    

    上述代码中,当触发加载plugB后,会加载plugA

    官方文档写的是:

    on_source   (List) or (String)
    Load the plugin before the listed plugins are loaded.
    Note: The plugins must be lazy loaded plugins.
    

    on_source指定的插件加载之前,先加载当前插件。
    对应我们上面的例子,应该是当加载plugB之前,先加载plugA
    但是我本地运行显示的结果是:

    • 执行:CmdB,触发加载PlugB,然后再触发加载plugA
    • 执行:CmdA,只触发加载plugAplugB不会被加载。
      因此,我认为官方文档此处存在错误描述。

    :可通过:scriptnames查看已加载的插件(有序)

  • path:指定插件下载路径。

    类型String

  • rev:指定插件版本/标签号。

    类型String,其中:

    • *:如果选项typegit,则表示使用最新的released标签版本
    • 支持通配符选择,比如:0.*
    • 如果typeraw,那么rev必须是一个哈希值。
    call dein#add('Shougo/deol.nvim', { 'rev': 'a1b5108fd5' })
    
  • rtp:将指定目录添加到runtimepath

    类型String

    :当一个仓库中的子目录包含 Vim 插件时,可以通过设置rtp选项将该目录添加到runtimepath中,从而使能插件:

    " 选择仓库 rstacruz/sparkup 的 vim 目录作为插件添加
    call dein#add('rstacruz/sparkup', {'rtp': 'vim'})
    

    :如果rtp为空字符串"",那么 dein 不会将其路径添加到runtimepath

  • script_type:指定脚本类型。

    类型String

    :对于没有按照 Vim 官方文档规定的目录组织结构的插件,可以通过script_type手动设置脚本类型,比如"indent""plugin""ftplugin"...

    call dein#add(
    \ 'https://raw.githubusercontent.com/Shougo/'
    \ . 'shougo-s-github/master/vim/colors/candy.vim',
    \ {'script_type' : 'colors'})
    
    call dein#add(
    \ 'https://github.com/bronzehedwick/impactjs-colorscheme',
    \ {'script_type' : 'colors'})
    
  • timeout:安装/更新插件的超时时间(单位:秒)。

    类型Number

    :如果忽略该选项,那么超时时间由g:dein#install_process_timeout控制。

  • trusted:以管理员权限(sudo)加载插件。

    类型Number,其中:

    • 如果设置为 非0 值,dein 就会使用管理员权限加载插件。
    • 如果未设置,dein 不会进行加载。

    :dein.vim 默认在sudo会话下,不会对插件进行加载,这是为了增加安全性,否则插件在sudo模式下可以进行任何操作。
    但是如果一定需要在sudo会话下加载插件,则为插件添加trusted选项即可。比如,coc.nvim如果没有加载的话,会一直弹出烦人的错误信息(晕),那么最好为其添加trusted选项,避免在sudo会话时一直弹窗:

call dein#add('neoclide/coc.nvim', {'merged':0, 'rev': 'release', 'trusted': 1})

sudo模式启动后,dein.vim 的状态会变更,导致下一次非sudo会话时,普通插件无法触发加载,此时手动调用call dein#clear_state(),然后重启 Vim 即可。

  • type:指定仓库类型。

    类型String,其值有如下几个可选:

    • none:无仓库
    • raw:原始插件文本(必须指定script_type
    • git:Git 仓库

    :如果忽略该选项,dein 会自动根据{repository}类型设置该选项

  • type__depthgit clone下载历史深度。

    类型Number,其中:

    • 如果忽略该选项,则使用g:dein#types#git#clone_depth
    • 如果该值大于0,则使用浅拷贝,这会加快下载速度。

    :浅拷贝在克隆某些仓库时可能存在问题,具体请参考:

    • https://github.com/Shougo/neobundle.vim/issues/81
    • https://github.com/Homebrew/homebrew/issues/12024

    :建议不使用浅拷贝机制,反正时间不会增加多少。

钩子函数(HOOKS)

dein 提供了一些钩子函数,对于插件的初始化操作很有用。

:函数类型的钩子函数( Function hooks)不会被缓存,必须手动初始化。
:对于非懒加载插件,钩子函数的加载顺序无法保证有序。
:钩子函数的字符串表达式以命令行模式(Ex commands)进行执行。
:钩子函数中涉及多个操作时,使用换行符进行分割。

以下是 dein 提供的钩子函数简介:

  • hook_add:当解析完dein#add()行后,触发该钩子函数。

    类型StringFunction

    cal dein#add("~/.vim/plugA", {
        \'hook_add': "echom 'hook_add invoked!!'"
        \})
    

    上述代码为本地插件plugA设置了一个hook_add钩子,当 dein 解析到call dein#add("~/.vim/plugA")语句后,会先调用钩子函数hoot_add,然后再加载插件plugA

    当钩子函数涉及多个操作时,使用换行符进行分割,如下所示:

    call dein#add('kana/vim-niceblock', {
        \ 'hook_add': join(['xmap I  <Plug>(niceblock-I)',
                            'xmap A  <Plug>(niceblock-A)'], "\n")
        \ })
    call dein#add('godlygeek/csapprox', {
        \ 'hook_add': "
        \ let g:CSApprox_konsole = 1\n
        \ let g:CSApprox_attr_map =
        \     { 'bold' : 'bold', 'italic' : '', 'sp' : '' }\n
        \ "})
    

    :不能在钩子函数hook_add中调用插件内定义的函数,因此此时插件还未加载。

  • hook_done_update:当所有插件都更新完毕后,触发该钩子函数。

    类型StringFunction

  • hook_post_source:当插件加载(:source)完成后,触发该钩子函数。

    类型StringFunction

    cal dein#add("~/.vim/plugA", {
        \'lazy': 1,
        \'on_cmd': ['CmdA'],
        \'hook_post_source': "echom 'hook_post_source invoked!!'"
        \})
    

    :本人实验过后,发现hook_post_source只在懒加载插件上才会被回调,如果要想让插件每次加载(无论是懒加载还是直接加载)时,都能触发hook_post_source,则可以VimEnter事件手动触发:

    autocmd VimEnter * call dein#call_hook('post_source')
    
  • hook_post_update:当插件更新完成后,触发该钩子函数。

    类型StringFunction

  • hook_source:在加载(:source)插件前,触发该钩子函数。

    类型StringFunction

    hoot_sourcehook_post_source一致,只能作用于栏加载插件,如果要想让插件每次加载(无论是懒加载还是直接加载)时,都能触发hook_source,则必须手动进行触发:

    call dein#begin()
    ...
    call dein#end()
    call dein#call_hook('source')
    

    hook_source不能跟hoo_post_source一样,结合VimEnter使用,因为插件直接加载发生在VimEnter事件之前,如果hook_sourceVimEnter结合,实际上是等到插件加载完成后,才会触发hook_source,此时该钩子的作用就与hook_post_source一样了。

参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335