Vimscript 切換

2018-02-24 16:03 更新

在開(kāi)頭前幾章我們?cè)v過(guò)怎么在Vim里設(shè)置選項(xiàng)。 對(duì)于布爾選項(xiàng),我們可以使用set someoption!來(lái)"切換"選項(xiàng)。 如果我們能給這個(gè)命令創(chuàng)建一個(gè)映射,那就再好不過(guò)了。

執(zhí)行下面的命令:

:nnoremap <leader>N :setlocal number!<cr>

在normal模式中按下<leader>N看看。Vim將會(huì)在開(kāi)啟和關(guān)閉行號(hào)顯示之間切換。 像這樣的"切換"映射是十分方便的,因此我們就不需要兩個(gè)獨(dú)立的鍵來(lái)開(kāi)/關(guān)。

不幸的是,這只對(duì)布爾選項(xiàng)起作用。如果我們想要切換一個(gè)非布爾選項(xiàng),還需要做更多的工作。

切換選項(xiàng)

從創(chuàng)建一個(gè)可以切換選項(xiàng)的函數(shù),以及調(diào)用該函數(shù)的映射開(kāi)始吧。 把下面的代碼加入到你的~/.vimrc(或一個(gè)~/.vim/plugin/中的獨(dú)立文件,如果你想要的話):

nnoremap <leader>f :call FoldColumnToggle()<cr>

function! FoldColumnToggle()
    echom &foldcolumn
endfunction

保存并source文件,然后按下<leader>f試試看。Vim顯示當(dāng)前foldcolumn選項(xiàng)的值。 如果你不熟悉這個(gè)選項(xiàng),閱讀:help foldcolumn再繼續(xù)。

讓我們添加真正的切換功能。修改代碼成這樣:

nnoremap <leader>f :call FoldColumnToggle()<cr>

function! FoldColumnToggle()
    if &foldcolumn
        setlocal foldcolumn=0
    else
        setlocal foldcolumn=4
    endif
endfunction

保存并source文件,然后試試看。每次你按下它Vim將顯示或隱藏折疊狀態(tài)條(fold column)。

if語(yǔ)句判斷&foldcolumn是否為真(記住Vim把0看作假而其他數(shù)字為真)。 如果是,把它設(shè)成0(隱藏它)。否則就設(shè)置它為4。就是這么簡(jiǎn)單。

你可以使用一個(gè)簡(jiǎn)單的函數(shù)像這樣來(lái)切換任何以0代表關(guān),以其他數(shù)字代表開(kāi)的選項(xiàng)。

切換其他東西

我們的夢(mèng)想不應(yīng)止于切換選項(xiàng)。還有一個(gè)我們想切換的東西是quickfix窗口。 依然以之前的骨架代碼作為起點(diǎn)。加入下面的代碼到你的文件:

nnoremap <leader>q :call QuickfixToggle()<cr>

function! QuickfixToggle()
    return
endfunction

這個(gè)映射暫時(shí)什么都不干。讓我們把它轉(zhuǎn)變成其他稍微有點(diǎn)用的東西(不過(guò)還沒(méi)有徹底完成)。 把代碼改成這樣:

nnoremap <leader>q :call QuickfixToggle()<cr>

function! QuickfixToggle()
    copen
endfunction

保存并source文件。如果現(xiàn)在你試一下這個(gè)映射,你就會(huì)看到一個(gè)空蕩蕩的quickfix窗口。

為了達(dá)到實(shí)現(xiàn)切換功能的目的,我們將選擇一個(gè)既快捷又骯臟的手段:全局變量。 把代碼改成這樣:

nnoremap <leader>q :call QuickfixToggle()<cr>

function! QuickfixToggle()
    if g:quickfix_is_open
        cclose
        let g:quickfix_is_open = 0
    else
        copen
        let g:quickfix_is_open = 1
    endif
endfunction

我們干的事情十分簡(jiǎn)單 —— 每次調(diào)用函數(shù)時(shí),我們用一個(gè)全局變量來(lái)儲(chǔ)存quickfix窗口的開(kāi)關(guān)狀態(tài)。

保存并source文件,接著執(zhí)行映射試試看。Vim將抱怨變量尚未定義!那么我們先把變量初始化吧。

nnoremap <leader>q :call QuickfixToggle()<cr>

let g:quickfix_is_open = 0

function! QuickfixToggle()
    if g:quickfix_is_open
        cclose
        let g:quickfix_is_open = 0
    else
        copen
        let g:quickfix_is_open = 1
    endif
endfunction

保存并source文件,接著試一下映射。成功了!

改進(jìn)

我們的切換函數(shù)可以工作,但還留有一些問(wèn)題。

第一個(gè)問(wèn)題是,假設(shè)用戶用:copen:cclose手動(dòng)開(kāi)關(guān)窗口,我們的全局變量將不會(huì)刷新。 實(shí)際上這不會(huì)是個(gè)大問(wèn)題,因?yàn)榇蠖鄶?shù)情況下用戶會(huì)用這個(gè)映射開(kāi)關(guān)窗口,萬(wàn)一沒(méi)有打開(kāi),他們也會(huì)再按一次。

這又是關(guān)于寫(xiě)Vimscript代碼的重要經(jīng)驗(yàn):如果你試圖處理每一個(gè)邊際條件,你將陷在里面,而且不會(huì)有任何進(jìn)展。

在大多數(shù)情況下,先推出可工作(而且即使不能工作也不會(huì)造成破壞)的代碼然后回過(guò)頭改善, 要比耗費(fèi)許多小時(shí)苛求完美好得多。除外你正在開(kāi)發(fā)一個(gè)很可能有很多人用到的插件。 在這種情況下它才值得耗費(fèi)時(shí)日來(lái)達(dá)到無(wú)懈可擊的程度,讓用戶滿意并減少bug報(bào)告。

重新加載窗口/緩沖區(qū)

我們的函數(shù)的另外一個(gè)問(wèn)題是,當(dāng)用戶已經(jīng)打開(kāi)了quickfix窗口,并執(zhí)行這個(gè)映射時(shí), Vim關(guān)閉了窗口,接著把他們彈到上一個(gè)分割中,而不是送他們回之前的地方。 如果你僅僅想快速查看一下quickfix窗口然后繼續(xù)工作,發(fā)生這種事是讓人惱怒的。

為了解決這個(gè)問(wèn)題,我們將引入一種寫(xiě)Vim插件時(shí)非常有用的慣用法。把你的代碼改成這樣:

nnoremap <leader>q :call QuickfixToggle()<cr>

let g:quickfix_is_open = 0

function! QuickfixToggle()
    if g:quickfix_is_open
        cclose
        let g:quickfix_is_open = 0
        execute g:quickfix_return_to_window . "wincmd w"
    else
        let g:quickfix_return_to_window = winnr()
        copen
        let g:quickfix_is_open = 1
    endif
endfunction

我們?cè)谟成渲屑尤肓诵碌膬尚?。其中一?在else分支)設(shè)置了另一個(gè)全局變量,來(lái)保存執(zhí)行:copen時(shí)的當(dāng)前窗口序號(hào)。

另一行(在if分支)執(zhí)行以那個(gè)序號(hào)作前綴的wincmd w,來(lái)告訴Vim跳轉(zhuǎn)到對(duì)應(yīng)窗口。

我們的解決方法又一次不是無(wú)懈可擊的,用戶可能在兩次執(zhí)行映射之間打開(kāi)或關(guān)閉新的分割。 即使這樣,它還是適合于大多數(shù)場(chǎng)合,所以目前這已經(jīng)夠好的了。

在大多數(shù)程序中,這種手工保存全局狀態(tài)的伎倆會(huì)遭到譴責(zé),但對(duì)于一個(gè)非常短小的Vimscript函數(shù)而言, 它既快捷又骯臟,卻能不辱使命,完成重任。

練習(xí)

閱讀:help foldcolumn.

閱讀:help winnr()

閱讀:help ctrl-w_w.

閱讀:help wincmd.

在需要的地方加上s:<SID>來(lái)把函數(shù)限定在獨(dú)自的命名空間中。

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

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)