詳解如何使用Python編寫(xiě)vim插件
前言
vim是個(gè)偉大的編輯器,不僅在于她特立獨(dú)行的編輯方式,還在于她強(qiáng)大的擴(kuò)展能力。然而,vim自身用于寫(xiě)插件的語(yǔ)言vimL功能有很大的局限性,實(shí)現(xiàn)功能復(fù)雜的插件往往力不從心,而且運(yùn)行效率也不高。幸好,vim早就想到了這一點(diǎn),她提供了很多外部語(yǔ)言接口,比如Python,ruby,lua,Perl等,可以很方便的編寫(xiě)vim插件。本文主要介紹如何使用Python編寫(xiě)vim插件。
準(zhǔn)備工作
1. 編譯vim,使vim支持Python
在編譯之前,configure的時(shí)候加上--enable-pythoninterp和--enable-python3interp選項(xiàng),使之分別支持Python2和Python3
編譯好之后,可以通過(guò)vim --version | grep +python來(lái)查看是否已經(jīng)支持Python,結(jié)果中應(yīng)該包含+python和 +python3,當(dāng)然也可以編譯成只支持Python2或Python3。
現(xiàn)在好多平臺(tái)都有直接編譯好的版本,已經(jīng)包含Python支持,直接下載就可以了:
- Windows:可以在這里下載。
- Mac OS:可以直接brew install vim來(lái)安裝。
- Linux:也有快捷的安裝方式,就不贅言了。
2. 如何讓Python能正常工作
雖然vim已經(jīng)支持Python,但是可能:echo has("python")或:echo has("python3")的結(jié)果仍是0,說(shuō)明Python還不能正常工作。
此時(shí)需要檢查:
- 系統(tǒng)上是否裝了Python?
- Python是32位還是64位跟vim是否匹配?
- Python的版本跟編譯時(shí)的版本是否一致(編譯時(shí)的版本可以使用:version查看)
- 通過(guò)pythondll和pythonthreedll來(lái)分別指定Python2和Python3所使用的動(dòng)態(tài)庫(kù)。
例如,可以在vimrc里添加
set pythondll=/Users/yggdroot/.python2.7.6/lib/libpython2.7.so
經(jīng)此4步,99%能讓Python工作起來(lái),剩下的1%就看人品了。
補(bǔ)充一點(diǎn):
對(duì)于neovim,執(zhí)行
pip2 install --user --upgrade neovim pip3 install --user --upgrade neovim
就可以添加Python2和Python3的支持,具體參見(jiàn):h provider-python。
從hello world開(kāi)始
在命令行窗口執(zhí)行:pyx print("hello world!"),輸出“hello world!”,說(shuō)明Python工作正常,此時(shí)我們已經(jīng)可以使用Python來(lái)作為vim的EX命令了。
操作vim像vimL一樣容易
怎么用Python來(lái)訪問(wèn)vim的信息以及操作vim呢?很簡(jiǎn)單,vim的Python接口提供了一個(gè)叫vim的模塊(module)。vim模塊是Python和vim溝通的橋梁,通過(guò)它,Python可以訪問(wèn)vim的一切信息以及操作vim,就像使用vimL一樣。所以寫(xiě)腳本,首先要import vim。
vim模塊
vim模塊提供了兩個(gè)非常有用的函數(shù)接口:
vim.command(str)
執(zhí)行vim中的命令str(ex-mode),返回值為None,例如:
:py vim.command("%s/\s\+$//g") :py vim.command("set shiftwidth=4") :py vim.command("normal! dd")
vim.eval(str)
求vim表達(dá)式str的值,(什么是vim表達(dá)式,參見(jiàn):h expr),返回結(jié)果類型為:
- string: 如果vim表達(dá)式的值的類型是string或number
- list:如果vim表達(dá)式的值的類型是一個(gè)vim list(:h list)
- dictionary:如果vim表達(dá)式的值的類型是一個(gè)vim dictionary(:h dict)
例如:
:py sw = vim.eval("&shiftwidth") :py print vim.eval("expand('%:p')") :py print vim.eval("@a")
vim模塊還提供了一些有用的對(duì)象:
- Tabpage對(duì)象(:h python-tabpage) 一個(gè)Tabpage對(duì)象對(duì)應(yīng)vim的一個(gè)Tabpage。
- Window對(duì)象(:h python-window) 一個(gè)Window對(duì)象對(duì)應(yīng)vim的一個(gè)Window。
- Buffer對(duì)象(:h python-buffer) 一個(gè)Buffer對(duì)象對(duì)應(yīng)vim的一個(gè)buffer,Buffer對(duì)象提供了一些屬性和方法,可以很方便操作buffer。
例如 (假定b是當(dāng)前的buffer) :
:py print b.name # write the buffer file name :py b[0] = "hello!!!" # replace the top line :py b[:] = None # delete the whole buffer :py del b[:] # delete the whole buffer :py b[0:0] = [ "a line" ] # add a line at the top :py del b[2] # delete a line (the third) :py b.append("bottom") # add a line at the bottom :py n = len(b) # number of lines :py (row,col) = b.mark('a') # named mark :py r = b.range(1,5) # a sub-range of the buffer :py b.vars["foo"] = "bar" # assign b:foo variable :py b.options["ff"] = "dos" # set fileformat :py del b.options["ar"] # same as :set autoread<
vim.current對(duì)象(:h python-current)
vim.current對(duì)象提供了一些屬性,可以方便的訪問(wèn)“當(dāng)前”的vim對(duì)象
屬性 | 含義 | 類型 |
---|---|---|
vim.current.line | The current line (RW) | String |
vim.current.buffer | The current buffer (RW) | Buffer |
vim.current.window | The current window (RW) | Window |
vim.current.tabpage | The current tab page (RW) | TabPage |
vim.current.range | The current line range (RO) | Range |
python訪問(wèn)vim中的變量
訪問(wèn)vim中的變量,可以通過(guò)前面介紹的vim.eval(str)來(lái)訪問(wèn),例如:
:py print vim.eval("v:version")
但是, 還有更pythonic的方法:
預(yù)定義vim變量(v:var)
可以通過(guò)vim.vvars來(lái)訪問(wèn)預(yù)定義vim變量,vim.vvars是個(gè)類似Dictionary的對(duì)象。例如,訪問(wèn)v:version:
:py print vim.vvars["version"]
全局變量(g:var)
可以通過(guò)vim.vars來(lái)訪問(wèn)全局變量,vim.vars也是個(gè)類似Dictionary的對(duì)象。例如,改變?nèi)肿兞縢:global_var的值:
:py vim.vars["global_var"] = 123
tabpage變量(t:var)
例如:
:py vim.current.tabpage.vars["var"] = "Tabpage"
window變量(w:var)
例如:
:py vim.current.window.vars["var"] = "Window"
buffer變量(b:var)
例如:
:py vim.current.buffer.vars["var"] = "Buffer"
python訪問(wèn)vim中的選項(xiàng)(options)
訪問(wèn)vim中的選項(xiàng),可以通過(guò)前面介紹的vim.command(str)和vim.eval(str)來(lái)訪問(wèn),例如:
:py vim.command("set shiftwidth=4") :py print vim.eval("&shiftwidth")
當(dāng)然, 還有更pythonic的方法:
全局選項(xiàng)設(shè)置(:h python-options)
例如:
:py vim.options["autochdir"] = True
注意:如果是window-local或者buffer-local選項(xiàng),此種方法會(huì)報(bào)KeyError異常。對(duì)于window-local和buffer-local選項(xiàng),請(qǐng)往下看。
window-local選項(xiàng)設(shè)置
例如:
:py vim.current.window.options["number"] = True
buffer-local選項(xiàng)設(shè)置
例如:
:py vim.current.buffer.options["shiftwidth"] = 4
兩種方式寫(xiě)vim插件
內(nèi)嵌式
py[thon] << {endmarker} {script} {endmarker}
{script}中的內(nèi)容為Python代碼,{endmarker}是一個(gè)標(biāo)記符號(hào),可以是任何字符串,不過(guò){endmarker}前面不能有任何的空白字符,也就是要頂格寫(xiě)。
例如,寫(xiě)一個(gè)函數(shù),打印出當(dāng)前buffer所有的行(Demo.vim):
function! Demo() py << EOF import vim for line in vim.current.buffer: print line EOF endfunction call Demo()
運(yùn)行:source %查看結(jié)果。
獨(dú)立式
把Python代碼寫(xiě)到*.py中,vimL只用來(lái)定義全局變量、map、command等,LeaderF就是采用這種方式。個(gè)人更喜歡這種方式,可以把全部精力集中在寫(xiě)Python代碼上。
異步
多線程
可以通過(guò)Python的threading模塊來(lái)實(shí)現(xiàn)多線程。但是,線程里面只能實(shí)現(xiàn)與vim無(wú)關(guān)的邏輯,任何試圖在線程里面操作vim的行為都可能(也許用“肯定會(huì)”更合適)導(dǎo)致vim崩潰,甚至包括只讀一個(gè)vim選項(xiàng)。雖然如此,也比vimL好多了,畢竟聊勝于無(wú)。
subprocess
可以通過(guò)Python的subprocess模塊來(lái)調(diào)用外部命令。
例如:
:py import subprocess :py print subprocess.Popen("ls -l", shell=True, stdout=subprocess.PIPE).stdout.read()
也就是說(shuō),從支持Python起,vim就已經(jīng)支持異步了(雖然直到vim7.4才基本沒(méi)有bug),Neovim所增加的異步功能,對(duì)用Python寫(xiě)插件的小伙伴來(lái)說(shuō),沒(méi)有任何吸引力。好多Neovim粉竟以引入異步(job)而引以為傲,它什么時(shí)候能引入真正的多線程支持我才會(huì)服它。
案例
著名的補(bǔ)全插件YCM和模糊查找神器LeaderF都是使用Python編寫(xiě)的。
缺陷
由于GIL的原因,Python線程無(wú)法并行處理;而vim又不支持Python的進(jìn)程(https://github.com/vim/vim/issues/906),計(jì)算密集型任務(wù)想利用多核來(lái)提高性能已不可能。
奇技淫巧
把buffer中所有單詞首字母變?yōu)榇髮?xiě)字母
:%pydo return line.title()
把buffer中所有的行鏡像顯示
例如,把
vim is very useful 123 456 789 abc def ghi who am I
變?yōu)?/p>
lufesu yrev si miv 987 654 321 ihg fed cba I ma ohw
可以執(zhí)行此命令::%pydo return line[::-1]
總結(jié)
以上只是簡(jiǎn)單的介紹,更詳細(xì)的資料可以參考:h python。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Python爬蟲(chóng)基礎(chǔ)之爬蟲(chóng)的分類知識(shí)總結(jié)
來(lái)給大家講python爬蟲(chóng)的基礎(chǔ)啦,首先我們從爬蟲(chóng)的分類開(kāi)始講起,下文有非常詳細(xì)的知識(shí)總結(jié),對(duì)正在學(xué)習(xí)python的小伙伴們很有幫助,需要的朋友可以參考下2021-05-05Python常用類型轉(zhuǎn)換實(shí)現(xiàn)代碼實(shí)例
這篇文章主要介紹了Python常用類型轉(zhuǎn)換實(shí)現(xiàn)代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07python的去重以及數(shù)據(jù)合并的用法說(shuō)明
這篇文章主要介紹了python的去重以及數(shù)據(jù)合并的用法說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02QT5 Designer 打不開(kāi)的問(wèn)題及解決方法
這篇文章主要介紹了QT5 Designer 打不開(kāi)的問(wèn)題及解決方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08python+selenium自動(dòng)化實(shí)戰(zhàn)攜帶cookies模擬登陸微博
這篇文章主要介紹了python+selenium自動(dòng)化實(shí)戰(zhàn)攜帶cookies模擬登陸微博,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01簡(jiǎn)單介紹一下pyinstaller打包以及安全性的實(shí)現(xiàn)
這篇文章主要介紹了簡(jiǎn)單介紹一下pyinstaller打包以及安全性的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06python端口掃描系統(tǒng)實(shí)現(xiàn)方法
這篇文章主要介紹了python端口掃描系統(tǒng)實(shí)現(xiàn)方法,可實(shí)現(xiàn)簡(jiǎn)單的外網(wǎng)IP掃描及寫(xiě)入MySQL數(shù)據(jù)庫(kù)等功能,需要的朋友可以參考下2014-11-11Python中np.percentile和df.quantile分位數(shù)詳解
分位數(shù)(Quantile)亦稱分位點(diǎn)是指將一個(gè)隨機(jī)變量的概率分布范圍分為幾個(gè)等份的數(shù)值點(diǎn),下面這篇文章主要給大家介紹了關(guān)于Python中np.percentile和df.quantile分位數(shù)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05基于Pydantic封裝的通用模型在API請(qǐng)求驗(yàn)證中的應(yīng)用詳解
這篇文章主要介紹了基于Pydantic封裝的通用模型在API請(qǐng)求驗(yàn)證中的應(yīng)用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2023-05-05