Vimscript 自動加載

2018-02-24 16:03 更新

我們已經(jīng)為我們的Potion插件寫了大量的功能,覆蓋了本書所要講的內(nèi)容。 在結(jié)束之前,我們將講到一些非常重要的方法,可以給我們的插件錦上添花。

第一項是使用自動加載讓我們的插件更有效率。

如何自動加載

目前,當用戶加載我們的插件時(比如打開了一個Potion文件),所有的功能都會被加載。 我們的插件還很小,所以這大概不是什么大問題,但對于較大的插件,加載全部代碼將會導致可被察覺的卡頓。

Vim使用稱為"自動加載(autoload)"來解決這個問題。自動加載讓你直到需要時才加載某一部分代碼。 會有一些性能上的損失,但如果用戶不總是需要你的插件的每一行代碼,自動加載將帶來速度上的飛躍。

示范一下它是怎么工作的??纯聪旅娴拿睿?/p>

:call somefile#Hello()

當你執(zhí)行這個命令,Vim的行為與平常的函數(shù)調(diào)用有些許不同。

如果這個函數(shù)已經(jīng)加載了,Vim簡單地像平常一樣調(diào)用它。

否則Vim將在你的~/.vim(或~/.vim/bundles/對應的插件/autoload)下查找一個叫做autoload/somefile.vim的文件。

如果文件存在,Vim將加載/source文件。接著Vim就會像平常一樣調(diào)用它。

在這個文件內(nèi),函數(shù)應該這樣定義:

function somefile#Hello()
    " ...
endfunction

你可以在函數(shù)名中使用多個#來表示子目錄。舉個例子:

:call myplugin#somefile#Hello()

這將在autoload/myplugin/somefile.vim查找自動加載文件。 里面的函數(shù)需要使用自動加載的絕對路徑進行定義:

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

實驗一下

為了更好地理解自動加載,讓我們實驗一下。 創(chuàng)建一個~/.vim/autoload/example.vim文件并加入下面的內(nèi)容:

echom "Loading..."

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

echom "Done loading."

保存文件并執(zhí)行:call example#Hello()。Vim將輸出下面內(nèi)容:

Loading...
Done loading.
Hello, world!

這個小演示證明了幾件事:

  1. Vim的確是在半途加載了example.vim文件。當我們打開Vim的時候它并不存在,所以不可能是在啟動時加載的。
  2. 當Vim找到它需要自動加載的文件后,它在調(diào)用對應函數(shù)之前就加載了整個文件。

先不要關(guān)閉Vim,修改函數(shù)的定義成這樣:

echom "Loading..."

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

echom "Done loading."

保存文件并不要關(guān)閉Vim,執(zhí)行:call example#Hello()。Vim將簡單地輸出:

Hello, world!

Vim已經(jīng)有了example#Hello的一個定義,所以它不再需要重新加載文件,這意味著:

  1. 函數(shù)以外的代碼將不再執(zhí)行。
  2. 它不會反映函數(shù)本身的變化。

現(xiàn)在執(zhí)行:call example#BadFunction()。你將再一次看到加載信息,伴隨著一個函數(shù)不存在的錯誤。 但現(xiàn)在嘗試再次執(zhí)行:call example#Hello()。這次你將看到更新后的信息!

目前為止你應該清晰地了解到Vim會怎么處理一個自動加載類型的函數(shù)調(diào)用吧:

  1. 它首先是否已經(jīng)存在同名的函數(shù)了。如果是,就調(diào)用它。
  2. 否則,查找名字對應的文件,并source它。
  3. 然后試圖調(diào)用那個函數(shù)。如果成功,太棒了。如果失敗,就輸出一個錯誤。

如果你還是沒有完成弄懂,回到前面重新過一遍演示,注意觀察每條規(guī)則生效的地方。

自動加載什么

自動加載不是沒有缺陷的。 設(shè)置了自動加載后,會有一些(小的)運行開銷,更別說你不得不在你的代碼里容忍丑陋的函數(shù)名了。

正因為如此,如果你不是寫一個用戶會在_每次_打開Vim對話時都用到的插件,最好盡量把功能代碼都挪到autoload文件中去。 這將減少你的插件在用戶啟動Vim時的影響,尤其是在人們安裝了越來越多的插件的今天。

所以有什么是可以安全地自動加載?那些不由你的用戶直接調(diào)用的部分。 映射和自定義命令不能自動加載(因為它們需要由用戶調(diào)用),但別的許多東西都可以。

讓我們看看Potion插件里有什么可以自動加載的。

在Potion插件里添加自動加載

我們將從編譯和執(zhí)行功能開始下手。 在前一章的最后,我們的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文件加載時才會調(diào)用,所以它通常不會影響Vim的啟動時間。 但可能會有一些用戶就是不想要這些功能,所以如果我們可以自動加載某些部分, 每次打開Potion文件時可以省下他們以毫秒記的時間。

是的,這種情況下我們不會節(jié)省多少。 但你可以想象到可能有那么一個插件包括了數(shù)千行可以通過自動加載來減少每次的加載時間的代碼。

讓我們開始吧。在你的插件repo中創(chuàng)建一個autoload/potion/running.vim文件。 然后移動兩個函數(shù)進去,并修改它們的名字,讓它們看上去像:

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部分的函數(shù)名怎么匹配它們所在的路徑。 現(xiàn)在修改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>

保存文件,關(guān)閉Vim,然后打開你的factorial.pn文件。嘗試這些映射,確保它們依然正常工作。

確保你僅僅在第一次執(zhí)行其中一個映射的時候才看到診斷信息Autoloading...(你可能需要使用:message來看到)。 一旦認為自動加載正常工作,你可以移除那些信息。

正如你看到的,我們保留nnoremap映射部分不變。 我們不能自動加載它們,不然用戶就沒辦法引發(fā)自動加載了!

你將在Vim插件中普遍看到:大多數(shù)的功能將位于自動加載函數(shù)中,僅有nnoremapcommand命令每次都被Vim加載。 每次你寫一個有用的Vim插件時,不要忘了這一點。

練習

閱讀:help autoload

稍微測試一下并弄懂自動加載變量是怎么一回事。

假設(shè)你想要強制加載一個Vim已經(jīng)加載的自動加載文件,并不會驚擾到用戶。 你會怎么做?你可能想要閱讀:help silent!(譯注:此處應該是:help :silent)。不過在現(xiàn)實生活中請不要那么做。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號