Skip to content

Instantly share code, notes, and snippets.

@wonderful-panda
Created December 13, 2011 15:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wonderful-panda/1472644 to your computer and use it in GitHub Desktop.
Save wonderful-panda/1472644 to your computer and use it in GitHub Desktop.
VimのコマンドラインでBazaarコマンドの補完をしてみる
let g:BZR_EXECUTABLE='bzr'
if exists('s:commands')
unlet s:commands
endif
let s:cmd_options = {}
" コマンド名のリストを返す
function! s:GetCommands()
if !exists('s:commands')
" `bzr help commands` の出力からコマンドの一覧を生成する
let s:commands = []
let l:output = system(g:BZR_EXECUTABLE . ' help commands')
for l:line in split(l:output, '\n')
let l:matches = matchlist(l:line, '\v^([a-z0-9_-]+)\s')
if !empty(l:matches)
call add(s:commands, l:matches[1])
endif
endfor
endif
return copy(s:commands)
endfunction
" 指定されたコマンドのオプションのリストを返す
function! s:GetCommandOptions(cmd_name)
if has_key(s:cmd_options, a:cmd_name)
return copy(s:cmd_options[a:cmd_name])
endif
" `bzr cmd_name --help` の出力からオプションの一覧を生成する
let l:cmd_options = []
let l:output = system(g:BZR_EXECUTABLE . ' ' . a:cmd_name . ' --help')
let l:patterns = ['\v^\s*(-[a-zA-Z])( [a-zA-Z-]+|)(\s|,|$)',
\ '\v^\s*(--[a-zA-Z-]+)(\s|,|$)',
\ '\v^\s*(--[a-zA-Z-]+\=)[a-zA-Z-_]+(\s|,|$)']
for l:line in split(l:output, '\n')
if !(l:line =~ '\v^\s+-')
continue
endif
while 1
for l:pattern in l:patterns
let l:matches = matchlist(l:line, l:pattern)
if !empty(l:matches)
break
endif
endfor
if empty(l:matches)
break
endif
call add(l:cmd_options, l:matches[1])
let l:line = l:line[strlen(l:matches[0]):]
endwhile
endfor
call sort(l:cmd_options)
let s:cmd_options[a:cmd_name] = l:cmd_options
return copy(l:cmd_options)
endfunction
" 指定されたパスを含むBazaarブランチの、.bzrディレクトリのパスを返す
function! s:GetBzrDir(dirpath)
let l:path = substitute(a:dirpath, '\\', '/', 'g')
if l:path[-1:-1] == '/'
let l:path = l:path[0:-2]
endif
while 1
if isdirectory(l:path.'/.bzr')
return l:path.'/.bzr'
endif
let l:pos = strridx(l:path, '/')
if l:pos > 0
let l:path = l:path[:l:pos - 1]
else
return ""
endif
endwhile
endfunction
" 指定されたパスを含むBazaarブランチのルートのパスを返す
function! s:GetRoot(dirpath)
let l:bzrdir = s:GetBzrDir(a:dirpath)
if l:bzrdir == ""
return ""
else
return l:bzrdir[:-5]
endif
endfunction
" 指定されたColocatedワークスペースの中にあるColocatedブランチのリストを返す
function! s:GetColoBranches(rootdir)
let l:output = []
let l:dirs = glob(a:rootdir.'/.bzr/branches/**/.bzr')
if empty(l:dirs)
return l:output
endif
for l:subdir in split(l:dirs, '\n')
let l:name = substitute(l:subdir, '\\', '/', 'g')[strlen(a:rootdir.'/.bzr/branches/'):-6]
if !empty(l:name)
call add(l:output, l:name)
endif
endfor
return l:output
endfunction
function! s:GetRecentRevisions(rootdir)
" not impremented.
endfunction
" コマンドラインを補完するためのFunction
function! s:Complete(arg_lead, cmdline, cursor_pos)
let l:cmd = split(a:cmdline)
let l:len_cmd = len(l:cmd)
if l:len_cmd <= 1 || (l:len_cmd == 2 && l:cmd[1] == a:arg_lead)
" コマンド名を補完する
return filter(s:GetCommands(), printf("v:val =~ '^%s'", a:arg_lead))
elseif a:arg_lead[:4] == 'colo:'
" coloブランチ名を補完する
let l:root = s:GetRoot(getcwd())
if !empty(l:root)
return filter(map(s:GetColoBranches(l:root), "'colo:'.v:val"),
\ printf("v:val[:%d] == '%s'", strlen(a:arg_lead) - 1, a:arg_lead))
endif
elseif a:arg_lead =~ '\v^\-\-[a-zA-Z-]*$'
" オプションを補完する
return filter(s:GetCommandOptions(l:cmd[1]), printf("v:val =~ '^%s'", a:arg_lead))
else
" ディレクトリ、ファイルを補完する
if a:arg_lead =~ '^--[A-Za-z-]+\=$'
return map(split(glob('*'), '\n'), "a:arg_lead . v:val")
elseif !empty(a:arg_lead)
return split(glob(a:arg_lead . '*'), '\n')
else
return s:GetCommandOptions(l:cmd[1]) + split(glob(a:arg_lead . '*'), '\n')
endif
endif
return []
endfunction
command! -complete=customlist,s:Complete -nargs=* Bzr call s:RunShellCommand(g:BZR_EXECUTABLE.' '.<q-args>)
command! -complete=customlist,s:Complete -nargs=* BzrAsync call vimproc#system_gui(g:BZR_EXECUTABLE.' '.<q-args>)
function! s:RunShellCommand(cmdline)
botright new
setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap
call setline(1,a:cmdline)
call setline(2,substitute(a:cmdline,'.','=','g'))
execute 'silent $read !'.escape(a:cmdline,'()%#')
setlocal nomodifiable
1
if search('\m\C^--- .*\n+++ .*\n@@','n')
setlocal filetype=diff
endif
if a:cmdline =~ '\m\C^git '
2match Statement /\v\C<commit \x{7,}>/
elseif a:cmdline =~ '\m\C^bzr log'
2match Statement /\v-{50,}/
endif
endfunction
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment