W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
在本章和下一章中,我們將使用Vimscript來實(shí)現(xiàn)一個(gè)相當(dāng)復(fù)雜的程序。我們將探討一些聞所未聞的東西, 也將在實(shí)戰(zhàn)中把之前學(xué)過的東西聯(lián)系起來。
在本實(shí)例研究中,遇到不熟悉的內(nèi)容,你得用:help
弄懂它。如果你只是走馬觀花,就將所獲無多。
如果你未曾用過:grep
,現(xiàn)在你應(yīng)該花費(fèi)一分鐘讀讀:help :grep
和:help :make
。 如果之前沒用過quickfix window,閱讀:help quickfix-window
。
簡(jiǎn)明扼要地說::grep ...
將用你給的參數(shù)來運(yùn)行一個(gè)外部的grep程序,解析結(jié)果,填充quickfix列表, 這樣你就能在Vim里面跳轉(zhuǎn)到對(duì)應(yīng)結(jié)果。
我們將會(huì)添加一個(gè)"grep運(yùn)算符"到任意Vim的內(nèi)置(或自定義!)的動(dòng)作中,來選擇想要搜索的文本, 讓:grep
更容易使用。
在寫下每一個(gè)有意義的Vimscript程序的第一步,你需要思索一個(gè)問題:“它會(huì)被用戶怎么使用呢?”。 嘗試構(gòu)思出一種優(yōu)雅,簡(jiǎn)易,符合直覺的調(diào)用方法。
這次我會(huì)替你把這活干了:
<leader>g
。w
和i{
)中。一些你將怎么使用它的用例:
<leader>giw
: Grep光標(biāo)下的詞(word)。<leader>giW
: Grep光標(biāo)下的詞的大寫形式(WORD)。<leader>gi'
: Grep當(dāng)前所在的單引號(hào)括住的詞。viwe<leader>g
: 可視狀態(tài)下選中一個(gè)詞并拓展選擇范圍到下一詞,然后Grep。有很多,_很多_其他的方法可以用它??瓷先ニ孟裥枰獙懞芏?,很多代碼, 但事實(shí)上我們只需要實(shí)現(xiàn)"運(yùn)算符"功能然后Vim就會(huì)完成剩下的工作。
在埋頭寫下巨量(trickey bits)的Vimscript之前,有一個(gè)也許會(huì)幫上忙的方法是簡(jiǎn)化你的目標(biāo)并實(shí)現(xiàn)它, 來推測(cè)你最終解決方案可能的"外形"。
讓我們簡(jiǎn)化我們的目標(biāo)為"創(chuàng)造一個(gè)映射來搜索光標(biāo)下的詞"。這有用而且應(yīng)該更簡(jiǎn)單,所以我們能更快得到可運(yùn)行的成果。 目前我們將映射它到<leader>g
。
我們從一個(gè)映射骨架開始并逐漸填補(bǔ)它。執(zhí)行這個(gè)命令:
:nnoremap <leader>g :grep -R something .<cr>
如果你閱讀過:help grep
,你就能輕易理解這個(gè)命令。我們之前也看過許多映射,這里沒有什么是新的。
顯然我們還沒做什么,所以讓我們一步步打磨這個(gè)映射直到它符合我們的要求。
首先我們需要搜索光標(biāo)下的詞,而不是something
。執(zhí)行下面的命令:
:nnoremap <leader>g :grep -R <cword> .<cr>
現(xiàn)在試一下。<cword>
是一個(gè)Vim的command-line模式的特殊變量, Vim會(huì)在執(zhí)行命令之前把它替換為"光標(biāo)下面的那個(gè)詞"。
你可以使用<cWORD>
來得到大寫形式(WORD)。執(zhí)行這個(gè)命令:
:nnoremap <leader>g :grep -R <cWORD> .<cr>
現(xiàn)在試試把光標(biāo)放在諸如foo-bar
的詞上面。Vim將grepfoo-bar
而不是其中的一部分。
我們的搜索部分還有一個(gè)問題:如果這里面有什么特殊的shell字符,Vim會(huì)毫不猶豫地傳遞給外部的grep命令。 這樣會(huì)導(dǎo)致程序崩潰(或更糟:鑄成某些大錯(cuò))。
讓我們看看如何使它掛掉。輸入foo;ls
并把光標(biāo)放上去執(zhí)行映射。grep命令失敗了, 而Vim將執(zhí)行ls
命令!這肯定糟透了,如果詞里包括比ls
更危險(xiǎn)的命令呢?
為了解決這個(gè)問題,我們將調(diào)用參數(shù)用引號(hào)括起來。執(zhí)行這個(gè)命令:
:nnoremap <leader>g :grep -R '<cWORD>' .<cr>
大多數(shù)shell把單引號(hào)括起來的內(nèi)容當(dāng)作(大體上)字面量,所以我們的映射現(xiàn)在更加健壯了。
搜索部分還有一個(gè)問題。在that's
上嘗試這個(gè)映射。它不會(huì)工作,因?yàn)樵~里的單引號(hào)與grep命令的單引號(hào)發(fā)生了沖突!
為了解決問題,我們可以使用Vim的shellescape
函數(shù)。 閱讀:help escape()
和:help shellescape()
來看它是怎樣工作的(真的很簡(jiǎn)單)。
因?yàn)?code>shellescape()要求Vim字符串,我們需要用execute
動(dòng)態(tài)創(chuàng)建命令。 首先執(zhí)行下面命令來轉(zhuǎn)換:grep
映射到:execute "..."
形式:
:nnoremap <leader>g :execute "grep -R '<cWORD>' ."<cr>
試一下并確信它可以工作。如果不行,找出拼寫錯(cuò)誤并改正。 然后執(zhí)行下面的使用了shellescape
的命令。
:nnoremap <leader>g :execute "grep -R " . shellescape("<cWORD>") . " ."<cr>
在一般的詞比如foo
上執(zhí)行這個(gè)命令試試。它可以工作。再到一個(gè)帶單引號(hào)的詞,比如that's
,上試試看。 它還是不行!為什么會(huì)這樣?
問題在于Vim在拓展命令行中的特殊變量,比如<cWORD>
,的之前,就已經(jīng)執(zhí)行了shellescape()
。 所以Vim shell-escaped了字面量字符串"<cWORD>"
(什么都不做,除了給它添上一對(duì)單引號(hào))并連接到我們的grep
命令上。
通過執(zhí)行下面的命令,你可以親眼目睹這一切。
:echom shellescape("<cWORD>")
Vim將輸出'<cWORD>'
。注意引號(hào)也是輸出字符串的一部分。Vim把它作為shell命令參數(shù)保護(hù)了起來。
為解決這個(gè)問題,我們將使用expand()
函數(shù)來強(qiáng)制拓展<cWORD>
為對(duì)應(yīng)字符串, 搶在它被傳遞給shellescape
之前。
讓我們單獨(dú)看看這一部分是怎么工作的。把你的光標(biāo)移到帶單引號(hào)的詞(比如that's
)上去, 并執(zhí)行下面命令:
:echom expand("<cWORD>")
Vim輸出that's
,因?yàn)?code>expand("<cWORD>")以Vim字符串的形式返回當(dāng)前光標(biāo)下的詞。 是時(shí)候加入shellescape
的部分了:
:echom shellescape(expand("<cWORD>"))
這次Vim輸出'that'\''s'
。 如果覺得這看上去真可笑,你大概沒有感受過看透了各種shell轉(zhuǎn)義的瘋狂形式后的淡定吧。 目前,不用為此而糾結(jié)。就相信Vim接受了expand
的輸出并正確地轉(zhuǎn)義了它。
目前我們已經(jīng)得到了光標(biāo)下的詞的徹底轉(zhuǎn)義版本。是時(shí)候連接它到我們的映射了! 執(zhí)行下面的命令:
:nnoremap <leader>g :exe "grep -R " . shellescape(expand("<cWORD>")) . " ."<cr>
試一下。這個(gè)映射不再有問題,即使我們用它搜索帶古怪符號(hào)的詞。
"從簡(jiǎn)單的Vimscript開始并一點(diǎn)點(diǎn)轉(zhuǎn)變它直到達(dá)成你的目標(biāo)"這樣的工作方式將會(huì)被你一再取用。
在完成映射之前,還要處理一些小問題。首先,我們說過我們不想自動(dòng)跳到第一個(gè)結(jié)果, 所以要用grep!
替換掉grep
。執(zhí)行下面的命令:
:nnoremap <leader>g :execute "grep! -R " . shellescape(expand("<cWORD>")) . " ."<cr>
再一次試試,發(fā)現(xiàn)什么都沒發(fā)生。Vim用結(jié)果填充了quickfix窗口,我們卻無法打開。 執(zhí)行下面的命令:
:nnoremap <leader>g :execute "grep! -R " . shellescape(expand("<cWORD>")) . " ."<cr>:copen<cr>
現(xiàn)在試試這個(gè)映射,你將看到Vim自動(dòng)打開了包含搜索結(jié)果的quickfix窗口。 我們所做的僅僅是在映射的結(jié)尾續(xù)上:copen<cr>
。
最后一點(diǎn),在搜索的時(shí)候,我們要移除Vim所有的grep輸出。執(zhí)行下面的命令:
:nnoremap <leader>g :silent execute "grep! -R " . shellescape(expand("<cWORD>")) . " ."<cr>:copen<cr>
我們完成了,試一試并犒勞一下自己吧!silent
命令僅僅是在運(yùn)行一個(gè)命令的同時(shí)隱藏它的正常輸出。
把我們剛剛做出來的映射加入到你的~/.vimrc
文件。
如果你未曾讀過:help :grep
,去讀它。
閱讀:help cword
。
閱讀:help cnext
和help cprevious
。修改你的grep映射,試一下它們。
設(shè)置:cnext
和:cprevious
的映射,讓在匹配內(nèi)容間的移動(dòng)更加方便。
閱讀:help expand
。
閱讀:help copen
。
在我們創(chuàng)建的映射中加入height參數(shù)到:copen
命令中,看看quickfix窗口能不能以指定的高度打開。
閱讀:help silent
。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: