0 引言
理解vim的啟動過程對於增強使用vim的信心非常重要,本文所有的資訊均來自vim自身提供的參考手冊和作者實際操作實踐。VIM REFERENCE MANUAL的Starting Vim這節詳細描述了vim的啟動過程。vim完整的啟動過程非常複雜,因為要相容不同的平台,不同的運行模式。本文只考慮Windows, Mac OS X, Linux平台上最常見的啟動流程。
1 vim啟動初始化流程
(1)設定內部變數shell和term
vim根據環境變數$SHELL和$TERM設定這兩個內部變數(option).
(2)處理命令列參數
命令列參數包括選項和要開啟的檔案名稱,vim為每一個檔案開闢記憶體空間。
(3)載入系統層級和使用者層級的設定檔
(a) 根據編譯時間指定的路徑,載入系統層級vimrc設定檔
(b) 根據編譯時間指定的路徑或預設路徑,載入使用者層級的vimrc設定檔
(4)載入外掛程式檔案
根據runtimepath內部變數的值載入。所有runtimepath中的所有目錄下名為plugin的子目錄們下面所有以.vim結尾的檔案都會被載入執行。
(5)設定shellpipe和shellredir內部變數
(6)如果命令列參數有-n,則設定updatecount內部變數
(7)如果命令列參數有-b,則設定二進位相關的多個內部變數
(8)執行GUI部分的初始化
(9)如果viminfo不為空白,則讀取指定的viminfo檔案,恢複上次的編輯環境
(10)如果命令列參數有-q,則讀取quickfix檔案
(11)開啟顯示所有的視窗
(12)執行使用者指定的啟動時命令
可以看出,vim的啟動初始化流程非常複雜。本文我們只關心設定檔的載入部分,這也是與大多數vim使用者直接相關的部分。從上面的流程看出:
vim載入系統級設定檔是根據編譯時間指定的路徑載入的;
使用者級設定檔則可以在編譯時間指定,也可以不指定,如果不指定,則使用預設值。預設值對於不同的平台是不同的。
對於unix平台:$HOME/.vimrc對於Windows平台:$HOME/_vimrc,如果不存在,則使用$VIM/_vimrc 外掛程式檔案是根據runtimepath來確定路徑的。仔細分析就會發現,其實這裡面還有很多不確定的東西: 編譯時間指定的系統級設定檔路徑可以是絕對路徑,也可能含有$VIM環境變數。使用者層級設定檔路徑中含有環境變數$HOME。runtimepath的預設值如下:對於Unix平台: $HOME/.vim, $VIM/vimfiles, $VIMRUNTIME, $VIM/vimfiles/after,$HOME/.vim/after;對於Window平台:$HOME/vimfiles,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after, $HOME/vimfiles/after. 可見除了編譯時間通過絕對路徑指定的系統級設定檔vimrc之外的所有其他情況下的設定檔路徑都嚴重依賴於環境變數的設定。問題是使用者如果在運行vim之前沒有設定這些環境變數,vim該如何是好呢?2 設定檔路徑的確定2.1 編譯時間指定的路徑
在編譯vim源碼的時候,需要指定各種設定檔的路徑。如果終端使用者不是當初執行編譯的人如何知道這些資訊呢?編譯後的二進位vim可執行檔,自身包含了當初編譯的時候指定的配置資訊。我們可以通過執行vim --version來查看,如下是三個執行個體,一個是CentOS6.4下內建vim的編譯時間資訊,另一個是Mac OS X 10.1系統內建vim的編譯時間資訊,第三個是Windows8.1平台安裝的vim官方7.4二進位版本。
【CentOS內建vim的編譯時間配置資訊】
[root@localhost test]# vim --versionVIM - Vi IMproved 7.2 (2008 Aug 9, compiled Apr 5 2012 10:12:47)Included patches: 1-411Modified by <bugzilla@redhat.com>Compiled by <bugzilla@redhat.com>Huge version without GUI. Features included (+) or not (-):+arabic +autocmd -balloon_eval -browse ++builtin_terms +byte_offset +cindent-clientserver -clipboard +cmdline_compl +cmdline_hist +cmdline_info +comments+cryptv +cscope +cursorshape +dialog_con +diff +digraphs -dnd -ebcdic+emacs_tags +eval +ex_extra +extra_search +farsi +file_in_path +find_in_path+float +folding -footer +fork() +gettext -hangul_input +iconv +insert_expand+jumplist +keymap +langmap +libcall +linebreak +lispindent +listcmds +localmap+menu +mksession +modify_fname +mouse -mouseshape +mouse_dec +mouse_gpm-mouse_jsbterm +mouse_netterm -mouse_sysmouse +mouse_xterm +multi_byte+multi_lang -mzscheme -netbeans_intg -osfiletype +path_extra +perl +postscript+printer +profile +python +quickfix +reltime +rightleft -ruby +scrollbind+signs +smartindent -sniff +startuptime +statusline -sun_workshop +syntax+tag_binary +tag_old_static -tag_any_white -tcl +terminfo +termresponse+textobjects +title -toolbar +user_commands +vertsplit +virtualedit +visual+visualextra +viminfo +vreplace +wildignore +wildmenu +windows +writebackup-X11 -xfontset -xim -xsmp -xterm_clipboard -xterm_save system vimrc file: "/etc/vimrc" user vimrc file: "$HOME/.vimrc" user exrc file: "$HOME/.exrc" fall-back for $VIM: "/usr/share/vim"Compilation: gcc -c -I. -Iproto -DHAVE_CONFIG_H -O2 -g -pipe -Wall -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i686 -mtune=atom -fasynchronous-unwind-tables -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=1 -D_REENTRANT -D_GNU_SOURCE -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/lib/perl5/CORE -I/usr/include/python2.6 -pthreadLinking: gcc -Wl,-E -Wl,-rpath,/usr/lib/perl5/CORE -L/usr/local/lib -o vim -lselinux -lncurses -lacl -lgpm -Wl,-E -Wl,-rpath,/usr/lib/perl5/CORE -fstack-protector -L/usr/local/lib -L/usr/lib/perl5/CORE -lperl -lresolv -lutil -lc -L/usr/lib/python2.6/config -lpython2.6 -lutil -lm -Xlinker -export-dynamic[root@localhost test]#
【Mac OS X內建vim的編譯時間配置資訊】
smstongtekiMac-mini:~ smstong$ vim --versionVIM - Vi IMproved 7.3 (2010 Aug 15, compiled Aug 24 2013 18:58:47)Compiled by root@apple.comNormal version without GUI. Features included (+) or not (-):-arabic +autocmd -balloon_eval -browse +builtin_terms +byte_offset +cindent-clientserver -clipboard +cmdline_compl +cmdline_hist +cmdline_info +comments-conceal +cryptv +cscope +cursorbind +cursorshape +dialog_con +diff +digraphs-dnd -ebcdic -emacs_tags +eval +ex_extra +extra_search -farsi +file_in_path+find_in_path +float +folding -footer +fork() -gettext -hangul_input +iconv+insert_expand +jumplist -keymap -langmap +libcall +linebreak +lispindent+listcmds +localmap -lua +menu +mksession +modify_fname +mouse -mouseshape-mouse_dec -mouse_gpm -mouse_jsbterm -mouse_netterm -mouse_sysmouse+mouse_xterm +multi_byte +multi_lang -mzscheme +netbeans_intg -osfiletype+path_extra -perl +persistent_undo +postscript +printer -profile +python/dyn-python3 +quickfix +reltime -rightleft +ruby/dyn +scrollbind +signs+smartindent -sniff +startuptime +statusline -sun_workshop +syntax +tag_binary+tag_old_static -tag_any_white -tcl +terminfo +termresponse +textobjects +title -toolbar +user_commands +vertsplit +virtualedit +visual +visualextra +viminfo+vreplace +wildignore +wildmenu +windows +writebackup -X11 -xfontset -xim -xsmp -xterm_clipboard -xterm_save system vimrc file: "$VIM/vimrc" user vimrc file: "$HOME/.vimrc" user exrc file: "$HOME/.exrc" fall-back for $VIM: "/usr/share/vim"Compilation: gcc -c -I. -D_FORTIFY_SOURCE=0 -Iproto -DHAVE_CONFIG_H -arch i386 -arch x86_64 -g -Os -pipeLinking: gcc -arch i386 -arch x86_64 -o vim -lncursessmstongtekiMac-mini:~ smstong$
【Windows8.1 安裝的vim官方二進位vim7.4編譯配置資訊】
VIM - Vi IMproved 7.4 (2013 Aug 10, compiled Aug 10 2013 14:33:40)MS-Windows 32 位控制台版本編譯者 mool@tororo大型版本 無圖形介面。 可使用(+)與不可使用(-)的功能:+arabic +ex_extra -mouseshape +tag_binary+autocmd +extra_search +multi_byte +tag_old_static-balloon_eval +farsi +multi_lang -tag_any_white-browse +file_in_path -mzscheme -tcl++builtin_terms +find_in_path -netbeans_intg -tgetent+byte_offset +float +path_extra -termresponse+cindent +folding -perl +textobjects+clientserver -footer +persistent_undo +title+clipboard +gettext/dyn -postscript -toolbar+cmdline_compl -hangul_input +printer +user_commands+cmdline_hist +iconv/dyn -profile +vertsplit+cmdline_info +insert_expand -python +virtualedit+comments +jumplist -python3 +visual+conceal +keymap +quickfix +visualextra+cryptv +langmap +reltime +viminfo+cscope +libcall +rightleft +vreplace+cursorbind +linebreak -ruby +wildignore+cursorshape +lispindent +scrollbind +wildmenu+dialog_con +listcmds +signs +windows+diff +localmap +smartindent +writebackup+digraphs -lua -sniff -xfontset-dnd +menu +startuptime -xim-ebcdic +mksession +statusline -xterm_save+emacs_tags +modify_fname -sun_workshop -xpm_w32+eval +mouse +syntax 系統 vimrc 檔案: "$VIM\vimrc" 使用者 vimrc 檔案: "$HOME\_vimrc" 第二使用者 vimrc 檔案: "$HOME\vimfiles\vimrc" 第三使用者 vimrc 檔案: "$VIM\_vimrc" 使用者 exrc 檔案: "$HOME\_exrc" 第二使用者 exrc 檔案: "$VIM\_exrc"編譯方式: cl -c /W3 /nologo -I. -Iproto -DHAVE_PATHDEF -DWIN32 -DFEAT_CSCOPE -DWINVER=0x0400 -D_WIN32_WINNT=0x0400 /Fo.\ObjCi386/ /Ox /GL -DNDEBUG /Zl /MT -DDYNAMIC_ICONV -DDYNAMIC_GETTEXT -DFEAT_BIG /Fd.\ObjCi386/ /Zi連結方式: link /RELEASE /nologo /subsystem:console /LTCG:STATUS oldnames.lib kernel32.lib advapi32.lib shell32.lib gdi32.lib comdlg32.lib ole32.lib uuid.lib /machine:i386 /nodefaultlib libcmt.lib user32.lib /PDB:vim.pdb -debug
可以看出,不同版本的vim,其編譯時間指定的設定檔路徑並不相同。除了CentOS平台的vim使用絕對路徑指定/etc/vimrc為其系統設定檔以外,其他的平台及設定檔均依賴於環境變數$VIM和$HOME。2.2 環境變數的確定步驟
先來看$VIM,大部分使用者在使用vim前並沒有手動去設定這個環境變數,而vim仍然正確的找到了設定檔,這是如何做到的呢?vim內部按照如下順序尋找或者定義$VIM,一旦有一個步驟成功,那麼後面的步驟就會忽略掉。
(1)如果作業系統平台定義了$VIM環境變數,則直接使用;
(2)如果helpfile變數的值不包含其他的環境變數,則使用這個變數值來確定。實際上helpfile的預設值是$VIMRUNTIME/doc/help.txt,也就是說包含一個環境變數,所以預設情況下不能通過helpfile來確定。
(3)對於Windows平台,vim使用自身的可執行檔所在的位置來確定。我們前面Windows平台的例子中,vim就是在這一步確定的$VIM,其值為:VIM=C:\Program Files (x86)\Vim。
對於*inx平台,使用編譯時間指定的安裝路徑來確定(也就是前面vim --version結果中顯示的"fall-back for $VIM" 。前面Mac OS X和CentOS平台的vim都是在這一步確定的$VIM,其值均為VIM=/usr/share/vim。
再來看$VIMRUNTIME。這個環境變數一般不需要使用者去設定,而是讓vim自身去猜測。下面是猜測步驟:
(1)如果使用者定義了$VIMRUNTIME環境變數,直接使用;
(2)如果$VIM/vim{版本號碼}這個路徑存在,那麼使用它作為$VIMRUNTIME的值;
(3)如果$VIM/runtime存在,使用它作為$VIMRUNTIME的值;
(4)使用$VIM的值作為$VIMRUNTIME的值,這是vi時期的相容模式;
(5)如果helpfile內部變數不包含環境變數,則使用helpfile來推導$VIMRUNTIME。
對於我們前面的三個平台,都是在第(2)步驟確定了$VIMRUNTIME的值。
最後來看$HOME,這個對於unix類環境來說,一般都會設定的,無需多說。
3 在實踐中使用設定檔通過前面的分析,我們弄清楚了vim設定檔及外掛程式檔案的載入時機與載入路徑。接下來就可以根據這些知識來定製屬於我們自己的配置了。3.1 添加或修改設定檔設定檔的主要作用是修改vim的預設行為以滿足個人化需求,也就是修改vim內部變數的預設值。vim分為系統級設定檔和使用者級設定檔。vim的手冊推薦使用者自訂的配置放入使用者自訂檔案中。我們以CentOS平台下的vim為例。使用者級設定檔路徑為:$HOME/.vimrc。在這個檔案裡增加如下代碼:
set nu set tabstop=4
set autoindent
這樣我們以當前賬戶運行vim的時候,就會總是顯示行號,tab鍵相當於4個空格的寬度,自動縮排。3.2 添加外掛程式檔案外掛程式檔案的主要作用是增強vim的功能,也就是創造新的功能而不是修改已有的功能。從前面的分析,我們知道外掛程式檔案可以存在很多重路徑下。我們以/usr/share/vim/vim72/plugin目錄下為例。在這個目錄下隨便建立一個文字檔test.vim。內容如下:
nmap <F10> ggODate:<Esc>:read !date<CR>kJ$
這樣,啟動vim後,就可以通過F10快速鍵直接在首行輸入當前的日期資訊。
其實vim設定檔和外掛程式檔案所支援的文法完全一樣,只是人為的按照功能作用分開儲存了,兩者都支援vim的專用指令碼語言VimScript,關於vimscript的使用超出了本文的範疇,作者本人也尚未掌握,以後學習的時候再做記錄。