Vim自定義命令的參數自動補全

| Comments

UltraBlog.vim起初的幾個版本采用增加命令個數的方式減少每個命令的參數個數,目的是降低命令格式記憶的難度。從2.3.0版本起,開始采用Vim自定義命令的一些高級特性,精簡命令個數,雖然參數個數增加了,但由于實現了參數補全,反而更加直觀。

Vim對自定義命令提供了多種補全參數的方式,詳見:h command-complete。其中,最常用的當屬custom

1
command! -nargs=? -complete=custom,StatusCmpl UBSend exec('py ub_send_item(<f-args>)')

以上代碼定義了一個自定義命令UBSend,它可以獲得一個或零個參數(-nargs=?),如果指定參數,則補全方式采用custom,該方式調用一個名為StatusCmpl的函數并以其返回值作為補全的值域:

1
2
3
function! StatusCmpl(ArgLead, CmdLine, CursorPos)
  return "draft\npublish\nprivate\npending\n"
endfunction

從以上代碼可以看出,該函數需要接受三個參數,返回值應該是一個用換行符“\n”分割的字符串,在執行補全時,Vim自動使用正則表達式匹配備選項。對于只有一個參數的情況,這種實現方式簡單高效。

對于參數較多的情況,customlist補全方式最為適用:

1
command! -nargs=* -complete=customlist,UBNewCmpl UBNew exec('py ub_new_item(<f-args>)')

以上代碼定義了命令UBNewcustomlist補全方式調用函數UBNewCmpl獲取補全的值域:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function! UBNewCmpl(ArgLead, CmdLine, CursorPos)
    let lst = split(a:CmdLine)
    if len(a:ArgLead)>0
        let lst = lst[0:-2]
    endif

    let results = []
    " For the first argument, complete the object type
    if len(lst)==1
        let objects = ['post','page','tmpl']
        for obj in objects
            if stridx(obj,a:ArgLead)==0
                call add(results,obj)
            endif
        endfor
    " For the second argument, complete the syntax for :UBNew post or :UBNew
    " page
    elseif len(lst)==2 && count(['post', 'page'], lst[1])==1
        let syntaxes = ['markdown','html','rst','textile','latex']
        for synx in syntaxes
            if stridx(synx,a:ArgLead)==0
                call add(results,synx)
            endif
        endfor
    endif
    return results
endfunction

這時侯,前面提到的三個參數就派上用場了。ArgLead是進行補全時,已輸入的參數部分,例如輸入:UBNew p,然後按Tab鍵,則ArgLead的值就是“p”;CmdLine是已經輸入的命令的全部,按上例,這個參數的值就是“UBNew p”;CursorPost是當前光標距離命令行開頭的字符數。利用這三個參數,就可以判斷正在補全命令的第幾個參數,進而利用ArgLead篩選該參數的值域。

custom調用的函數不同,customlist調用的函數的返回值應該是一個list類型的值。

Posted via UltraBlog.vim.

Comments