×

vi 命令手册

vi/vim 命令大全

vim 命令手册

Vim 关于Vim 安装Vim 用法Vim 配置vim 配置.vimrc方案vim 配置.vimrc方案1vim 配置.vimrc方案2Vim 文件合并Vim 技巧和建议Vim 插件Vim 参阅

Vimscript 编程参考

Vimscript 前言Vimscript 鸣谢Vimscript 预备知识Vimscript 打印信息Vimscript 设置选项Vimscript 基本映射Vimscript 模式映射Vimscript 精确映射Vimscript LeadersVimscript 编辑你的Vimrc文件Vimscript AbbreviationsVimscript 更多的MappingsVimscript 锻炼你的手指本地缓冲区的设置和映射Vimscript 自动命令Vimscript 本地缓冲区缩写Vimscript 自动命令组Operator-Pending 映射Operator-Pending 更多映射Vimscript 状态条Vimscript 负责任的编码Vimscript 变量Vimscript 变量作用域Vimscript 条件语句Vimscript 比较Vimscript 函数Vimscript 函数参数Vimscript 数字Vimscript 字符串Vimscript 字符串函数Vimscript Execute命令Vimscript Normal命令Vimscript 执行normal!Vimscript 基本的正则表达式Grep 运算符Operator 第1部分Grep 运算符Operator 第2部分Grep 运算符Operator 第3部分Vimscript 列表Vimscript 循环Vimscript 字典Vimscript 切换Vimscript 函数式编程Vimscript 路径Vimscript 创建一个完整的插件Vimscript 基本插件配置方式用Pathogen配置插件Vimscript 检测文件类型Vimscript 基本语法高亮Vimscript 高级语法高亮Vimscript 基本折叠Vimscript 高级折叠Vimscript 段移动原理Vimscript Potion段移动Vimscript 外部命令Vimscript 自动加载Vimscript 文档Vimscript 发布Vimscript 还剩下什么?

Vimscript 自动加载


我们已经为我们的Potion插件写了大量的功能,覆盖了本书所要讲的内容。 在结束之前,我们将讲到一些非常重要的方法,可以给我们的插件锦上添花。

第一项是使用自动加载让我们的插件更有效率。

如何自动加载

目前,当用户加载我们的插件时(比如打开了一个Potion文件),所有的功能都会被加载。 我们的插件还很小,所以这大概不是什么大问题,但对于较大的插件,加载全部代码将会导致可被察觉的卡顿。

Vim使用称为"自动加载(autoload)"来解决这个问题。自动加载让你直到需要时才加载某一部分代码。 会有一些性能上的损失,但如果用户不总是需要你的插件的每一行代码,自动加载将带来速度上的飞跃。

示范一下它是怎么工作的。看看下面的命令:

:call somefile#Hello()

当你执行这个命令,Vim的行为与平常的函数调用有些许不同。

如果这个函数已经加载了,Vim简单地像平常一样调用它。

否则Vim将在你的~/.vim(或~/.vim/bundles/对应的插件/autoload)下查找一个叫做autoload/somefile.vim的文件。

如果文件存在,Vim将加载/source文件。接着Vim就会像平常一样调用它。

在这个文件内,函数应该这样定义:

function somefile#Hello()
    " ...
endfunction

你可以在函数名中使用多个#来表示子目录。举个例子:

:call myplugin#somefile#Hello()

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

function myplugin#somefile#Hello()
    " ...
endfunction

实验一下

为了更好地理解自动加载,让我们实验一下。 创建一个~/.vim/autoload/example.vim文件并加入下面的内容:

echom "Loading..."

function! example#Hello()
    echom "Hello, world!"
endfunction

echom "Done loading."

保存文件并执行:call example#Hello()。Vim将输出下面内容:

Loading...
Done loading.
Hello, world!

这个小演示证明了几件事:

  1. Vim的确是在半途加载了example.vim文件。当我们打开Vim的时候它并不存在,所以不可能是在启动时加载的。
  2. 当Vim找到它需要自动加载的文件后,它在调用对应函数之前就加载了整个文件。

先不要关闭Vim,修改函数的定义成这样:

echom "Loading..."

function! example#Hello()
    echom "Hello AGAIN, world!"
endfunction

echom "Done loading."

保存文件并不要关闭Vim,执行:call example#Hello()。Vim将简单地输出:

Hello, world!

Vim已经有了example#Hello的一个定义,所以它不再需要重新加载文件,这意味着:

  1. 函数以外的代码将不再执行。
  2. 它不会反映函数本身的变化。

现在执行:call example#BadFunction()。你将再一次看到加载信息,伴随着一个函数不存在的错误。 但现在尝试再次执行:call example#Hello()。这次你将看到更新后的信息!

目前为止你应该清晰地了解到Vim会怎么处理一个自动加载类型的函数调用吧:

  1. 它首先是否已经存在同名的函数了。如果是,就调用它。
  2. 否则,查找名字对应的文件,并source它。
  3. 然后试图调用那个函数。如果成功,太棒了。如果失败,就输出一个错误。

如果你还是没有完成弄懂,回到前面重新过一遍演示,注意观察每条规则生效的地方。

自动加载什么

自动加载不是没有缺陷的。 设置了自动加载后,会有一些(小的)运行开销,更别说你不得不在你的代码里容忍丑陋的函数名了。

正因为如此,如果你不是写一个用户会在_每次_打开Vim对话时都用到的插件,最好尽量把功能代码都挪到autoload文件中去。 这将减少你的插件在用户启动Vim时的影响,尤其是在人们安装了越来越多的插件的今天。

所以有什么是可以安全地自动加载?那些不由你的用户直接调用的部分。 映射和自定义命令不能自动加载(因为它们需要由用户调用),但别的许多东西都可以。

让我们看看Potion插件里有什么可以自动加载的。

在Potion插件里添加自动加载

我们将从编译和执行功能开始下手。 在前一章的最后,我们的ftplugin/potion/running.vim文件大概是这样:

if !exists("g:potion_command")
    let g:potion_command = "/Users/sjl/src/potion/potion"
endif

function! PotionCompileAndRunFile()
    silent !clear
    execute "!" . g:potion_command . " " . bufname("%")
endfunction

function! PotionShowBytecode()
    " Get the bytecode.
    let bytecode = system(g:potion_command . " -c -V " . bufname("%"))

    " Open a new split and set it up.
    vsplit __Potion_Bytecode__
    normal! ggdG
    setlocal filetype=potionbytecode
    setlocal buftype=nofile

    " Insert the bytecode.
    call append(0, split(bytecode, '\v\n'))
endfunction

nnoremap <buffer> <localleader>r :call PotionCompileAndRunFile()<cr>
nnoremap <buffer> <localleader>b :call PotionShowBytecode()<cr>

这个文件仅仅当Potion文件加载时才会调用,所以它通常不会影响Vim的启动时间。 但可能会有一些用户就是不想要这些功能,所以如果我们可以自动加载某些部分, 每次打开Potion文件时可以省下他们以毫秒记的时间。

是的,这种情况下我们不会节省多少。 但你可以想象到可能有那么一个插件包括了数千行可以通过自动加载来减少每次的加载时间的代码。

让我们开始吧。在你的插件repo中创建一个autoload/potion/running.vim文件。 然后移动两个函数进去,并修改它们的名字,让它们看上去像:

echom "Autoloading..."

function! potion#running#PotionCompileAndRunFile()
    silent !clear
    execute "!" . g:potion_command . " " . bufname("%")
endfunction

function! potion#running#PotionShowBytecode()
    " Get the bytecode.
    let bytecode = system(g:potion_command . " -c -V " . bufname("%"))

    " Open a new split and set it up.
    vsplit __Potion_Bytecode__
    normal! ggdG
    setlocal filetype=potionbytecode
    setlocal buftype=nofile

    " Insert the bytecode.
    call append(0, split(bytecode, '\v\n'))
endfunction

注意potion#running部分的函数名怎么匹配它们所在的路径。 现在修改ftplugin/potion/running.vim文件成这样:

if !exists("g:potion_command")
    let g:potion_command = "/Users/sjl/src/potion/potion"
endif

nnoremap <buffer> <localleader>r
            \ :call potion#running#PotionCompileAndRunFile()<cr>

nnoremap <buffer> <localleader>b
            \ :call potion#running#PotionShowBytecode()<cr>

保存文件,关闭Vim,然后打开你的factorial.pn文件。尝试这些映射,确保它们依然正常工作。

确保你仅仅在第一次执行其中一个映射的时候才看到诊断信息Autoloading...(你可能需要使用:message来看到)。 一旦认为自动加载正常工作,你可以移除那些信息。

正如你看到的,我们保留nnoremap映射部分不变。 我们不能自动加载它们,不然用户就没办法引发自动加载了!

你将在Vim插件中普遍看到:大多数的功能将位于自动加载函数中,仅有nnoremapcommand命令每次都被Vim加载。 每次你写一个有用的Vim插件时,不要忘了这一点。

练习

阅读:help autoload

稍微测试一下并弄懂自动加载变量是怎么一回事。

假设你想要强制加载一个Vim已经加载的自动加载文件,并不会惊扰到用户。 你会怎么做?你可能想要阅读:help silent!(译注:此处应该是:help :silent)。不过在现实生活中请不要那么做。


分类导航

关注微信下载离线手册

bootwiki移动版 bootwiki
(群号:472910771)