1
0
mirror of https://github.com/amix/vimrc synced 2025-06-16 01:25:00 +08:00

Updated plugins

This commit is contained in:
amix
2016-12-27 11:46:49 -03:00
parent 04abc6907c
commit a6de243fca
67 changed files with 2836 additions and 1097 deletions

View File

@ -1,47 +1,63 @@
" guru.vim -- Vim integration for the Go guru.
func! s:RunGuru(mode, format, selected, needs_scope) range abort
" guru_cmd returns a dict that contains the command to execute guru. option
" is dict with following options:
" mode : guru mode, such as 'implements'
" format : output format, either 'plain' or 'json'
" needs_scope : if 1, adds the current package to the scope
" selected : if 1, means it's a range of selection, otherwise it picks up the
" offset under the cursor
" example output:
" {'cmd' : ['guru', '-json', 'implements', 'demo/demo.go:#66']}
function! s:guru_cmd(args) range abort
let mode = a:args.mode
let format = a:args.format
let needs_scope = a:args.needs_scope
let selected = a:args.selected
let result = {}
let dirname = expand('%:p:h')
let pkg = go#package#ImportPath(dirname)
" this is important, check it!
if pkg == -1 && needs_scope
return {'err': "current directory is not inside of a valid GOPATH"}
endif
"return with a warning if the binary doesn't exist
let bin_path = go#path#CheckBinPath("guru")
if empty(bin_path)
return {'err': "bin path not found"}
endif
let dirname = expand('%:p:h')
let pkg = go#package#ImportPath(dirname)
" this is important, check it!
if pkg == -1 && a:needs_scope
return {'err': "current directory is not inside of a valid GOPATH"}
endif
" start constructing the 'command' variable
let command = bin_path
" start constructing the command
let cmd = [bin_path]
let filename = fnamemodify(expand("%"), ':p:gs?\\?/?')
let in = ""
let stdin_content = ""
if &modified
let sep = go#util#LineEnding()
let content = join(getline(1, '$'), sep )
let in = filename . "\n" . strlen(content) . "\n" . content
let command .= " -modified"
let result.stdin_content = filename . "\n" . strlen(content) . "\n" . content
call add(cmd, "-modified")
endif
" enable outputting in json format
if a:format == "json"
let command .= " -json"
if format == "json"
call add(cmd, "-json")
endif
" check for any tags
if exists('g:go_guru_tags')
let tags = get(g:, 'go_guru_tags')
let command .= printf(" -tags %s", tags)
call extend(cmd, ["-tags", tags])
let result.tags = tags
endif
" some modes require scope to be defined (such as callers). For these we
" choose a sensible setting, which is using the current file's package
let scopes = []
if a:needs_scope
if needs_scope
let scopes = [pkg]
endif
@ -66,274 +82,421 @@ func! s:RunGuru(mode, format, selected, needs_scope) range abort
let scopes = go#util#StripTrailingSlash(scopes)
" create shell-safe entries of the list
let scopes = go#util#Shelllist(scopes)
if !go#util#has_job() | let scopes = go#util#Shelllist(scopes) | endif
" guru expect a comma-separated list of patterns, construct it
let l:scope = join(scopes, ",")
let command .= printf(" -scope %s", l:scope)
let result.scope = l:scope
call extend(cmd, ["-scope", l:scope])
endif
let pos = printf("#%s", go#util#OffsetCursor())
if a:selected != -1
if selected != -1
" means we have a range, get it
let pos1 = go#util#Offset(line("'<"), col("'<"))
let pos2 = go#util#Offset(line("'>"), col("'>"))
let pos = printf("#%s,#%s", pos1, pos2)
endif
" this is our final command
let filename .= ':'.pos
let command .= printf(' %s %s', a:mode, shellescape(filename))
call extend(cmd, [mode, filename])
let result.cmd = cmd
return result
endfunction
" sync_guru runs guru in sync mode with the given arguments
function! s:sync_guru(args) abort
let result = s:guru_cmd(a:args)
if has_key(result, 'err')
call go#util#EchoError(result.err)
return -1
endif
if !has_key(a:args, 'disable_progress')
if a:args.needs_scope
call go#util#EchoProgress("analysing with scope ". result.scope . " ...")
elseif a:args.mode !=# 'what'
" the query might take time, let us give some feedback
call go#util#EchoProgress("analysing ...")
endif
endif
let old_gopath = $GOPATH
let $GOPATH = go#path#Detect()
if a:needs_scope
call go#util#EchoProgress("analysing with scope ". l:scope . " ...")
elseif a:mode !=# 'what'
" the query might take time, let us give some feedback
call go#util#EchoProgress("analysing ...")
endif
" run, forrest run!!!
let command = join(result.cmd, " ")
if &modified
let out = go#util#System(command, in)
let out = go#util#System(command, result.stdin_content)
else
let out = go#util#System(command)
endif
let $GOPATH = old_gopath
if go#util#ShellError() != 0
" the output contains the error message
return {'err' : out}
if has_key(a:args, 'custom_parse')
call a:args.custom_parse(go#util#ShellError(), out)
else
call s:parse_guru_output(go#util#ShellError(), out, a:args.mode)
endif
return {'out': out}
return out
endfunc
" This uses Vim's errorformat to parse the output from Guru's 'plain output
" and put it into location list. I believe using errorformat is much more
" easier to use. If we need more power we can always switch back to parse it
" via regex.
func! s:loclistSecond(output)
" backup users errorformat, will be restored once we are finished
let old_errorformat = &errorformat
" match two possible styles of errorformats:
"
" 'file:line.col-line2.col2: message'
" 'file:line:col: message'
"
" We discard line2 and col2 for the first errorformat, because it's not
" useful and location only has the ability to show one line and column
" number
let errformat = "%f:%l.%c-%[%^:]%#:\ %m,%f:%l:%c:\ %m"
call go#list#ParseFormat("locationlist", errformat, split(a:output, "\n"))
let errors = go#list#Get("locationlist")
call go#list#Window("locationlist", len(errors))
endfun
function! go#guru#Scope(...)
if a:0
if a:0 == 1 && a:1 == '""'
unlet g:go_guru_scope
call go#util#EchoSuccess("guru scope is cleared")
else
let g:go_guru_scope = a:000
call go#util#EchoSuccess("guru scope changed to: ". join(a:000, ","))
endif
" async_guru runs guru in async mode with the given arguments
function! s:async_guru(args) abort
let result = s:guru_cmd(a:args)
if has_key(result, 'err')
call go#util#EchoError(result.err)
return
endif
if !exists('g:go_guru_scope')
call go#util#EchoError("guru scope is not set")
else
call go#util#EchoSuccess("current guru scope: ". join(g:go_guru_scope, ","))
let status_dir = expand('%:p:h')
let statusline_type = printf("%s", a:args.mode)
if !has_key(a:args, 'disable_progress')
if a:args.needs_scope
call go#util#EchoProgress("analysing with scope ". result.scope . " ...")
endif
endif
function! s:close_cb(chan) closure
let messages = []
while ch_status(a:chan, {'part': 'out'}) == 'buffered'
let msg = ch_read(a:chan, {'part': 'out'})
call add(messages, msg)
endwhile
while ch_status(a:chan, {'part': 'err'}) == 'buffered'
let msg = ch_read(a:chan, {'part': 'err'})
call add(messages, msg)
endwhile
let l:job = ch_getjob(a:chan)
let l:info = job_info(l:job)
let out = join(messages, "\n")
let status = {
\ 'desc': 'last status',
\ 'type': statusline_type,
\ 'state': "finished",
\ }
if l:info.exitval
let status.state = "failed"
endif
call go#statusline#Update(status_dir, status)
if has_key(a:args, 'custom_parse')
call a:args.custom_parse(l:info.exitval, out)
else
call s:parse_guru_output(l:info.exitval, out, a:args.mode)
endif
endfunction
let start_options = {
\ 'close_cb': function("s:close_cb"),
\ }
if &modified
let l:tmpname = tempname()
call writefile(split(result.stdin_content, "\n"), l:tmpname, "b")
let l:start_options.in_io = "file"
let l:start_options.in_name = l:tmpname
endif
call go#statusline#Update(status_dir, {
\ 'desc': "current status",
\ 'type': statusline_type,
\ 'state': "analysing",
\})
return job_start(result.cmd, start_options)
endfunc
" run_guru runs the given guru argument
function! s:run_guru(args) abort
if go#util#has_job()
return s:async_guru(a:args)
endif
return s:sync_guru(a:args)
endfunction
function! go#guru#Tags(...)
if a:0
if a:0 == 1 && a:1 == '""'
unlet g:go_guru_tags
call go#util#EchoSuccess("guru tags is cleared")
else
let g:go_guru_tags = a:1
call go#util#EchoSuccess("guru tags changed to: ". a:1)
endif
" Show 'implements' relation for selected package
function! go#guru#Implements(selected) abort
let args = {
\ 'mode': 'implements',
\ 'format': 'plain',
\ 'selected': a:selected,
\ 'needs_scope': 1,
\ }
return
endif
if !exists('g:go_guru_tags')
call go#util#EchoSuccess("guru tags is not set")
else
call go#util#EchoSuccess("current guru tags: ". a:1)
endif
call s:run_guru(args)
endfunction
" Report the possible constants, global variables, and concrete types that may
" appear in a value of type error
function! go#guru#Whicherrs(selected)
let out = s:RunGuru('whicherrs', 'plain', a:selected, 1)
if has_key(out, 'err')
call go#util#EchoError(out.err)
return
endif
function! go#guru#Whicherrs(selected) abort
let args = {
\ 'mode': 'whicherrs',
\ 'format': 'plain',
\ 'selected': a:selected,
\ 'needs_scope': 1,
\ }
if empty(out.out)
call go#util#EchoSuccess("no error variables found. Try to change the scope with :GoGuruScope")
return
endif
call s:loclistSecond(out.out)
endfunction
" Show 'implements' relation for selected package
function! go#guru#Implements(selected)
let out = s:RunGuru('implements', 'plain', a:selected, 1)
if has_key(out, 'err')
call go#util#EchoError(out.err)
return
endif
call s:loclistSecond(out.out)
" TODO(arslan): handle empty case for both sync/async
" if empty(out.out)
" call go#util#EchoSuccess("no error variables found. Try to change the scope with :GoGuruScope")
" return
" endif
call s:run_guru(args)
endfunction
" Describe selected syntax: definition, methods, etc
function! go#guru#Describe(selected)
let out = s:RunGuru('describe', 'plain', a:selected, 0)
if has_key(out, 'err')
call go#util#EchoError(out.err)
function! go#guru#Describe(selected) abort
let args = {
\ 'mode': 'describe',
\ 'format': 'plain',
\ 'selected': a:selected,
\ 'needs_scope': 1,
\ }
call s:run_guru(args)
endfunction
function! go#guru#DescribeInfo() abort
" json_encode() and friends are introduced with this patch (7.4.1304)
" vim: https://groups.google.com/d/msg/vim_dev/vLupTNhQhZ8/cDGIk0JEDgAJ
" nvim: https://github.com/neovim/neovim/pull/4131
if !exists("*json_decode")
call go#util#EchoError("requires 'json_decode'. Update your Vim/Neovim version.")
return
endif
call s:loclistSecond(out.out)
function! s:info(exit_val, output)
if a:exit_val != 0
return
endif
if a:output[0] !=# '{'
return
endif
if empty(a:output) || type(a:output) != type("")
return
endif
let result = json_decode(a:output)
if type(result) != type({})
call go#util#EchoError(printf("malformed output from guru: %s", a:output))
return
endif
if !has_key(result, 'detail')
" if there is no detail check if there is a description and print it
if has_key(result, "desc")
call go#util#EchoInfo(result["desc"])
return
endif
call go#util#EchoError("detail key is missing. Please open a bug report on vim-go repo.")
return
endif
let detail = result['detail']
let info = ""
" guru gives different information based on the detail mode. Let try to
" extract the most useful information
if detail == "value"
if !has_key(result, 'value')
call go#util#EchoError("value key is missing. Please open a bug report on vim-go repo.")
return
endif
let val = result["value"]
if !has_key(val, 'type')
call go#util#EchoError("type key is missing (value.type). Please open a bug report on vim-go repo.")
return
endif
let info = val["type"]
elseif detail == "type"
if !has_key(result, 'type')
call go#util#EchoError("type key is missing. Please open a bug report on vim-go repo.")
return
endif
let type = result["type"]
if !has_key(type, 'type')
call go#util#EchoError("type key is missing (type.type). Please open a bug report on vim-go repo.")
return
endif
let info = type["type"]
elseif detail == "package"
if !has_key(result, 'package')
call go#util#EchoError("package key is missing. Please open a bug report on vim-go repo.")
return
endif
let package = result["package"]
if !has_key(package, 'path')
call go#util#EchoError("path key is missing (package.path). Please open a bug report on vim-go repo.")
return
endif
let info = printf("package %s", package["path"])
elseif detail == "unknown"
let info = result["desc"]
else
call go#util#EchoError(printf("unknown detail mode found '%s'. Please open a bug report on vim-go repo", detail))
return
endif
call go#util#EchoInfo(info)
endfunction
let args = {
\ 'mode': 'describe',
\ 'format': 'json',
\ 'selected': -1,
\ 'needs_scope': 1,
\ 'custom_parse': function('s:info'),
\ 'disable_progress': 1,
\ }
call s:run_guru(args)
endfunction
" Show possible targets of selected function call
function! go#guru#Callees(selected)
let out = s:RunGuru('callees', 'plain', a:selected, 1)
if has_key(out, 'err')
call go#util#EchoError(out.err)
return
endif
function! go#guru#Callees(selected) abort
let args = {
\ 'mode': 'callees',
\ 'format': 'plain',
\ 'selected': a:selected,
\ 'needs_scope': 1,
\ }
call s:loclistSecond(out.out)
call s:run_guru(args)
endfunction
" Show possible callers of selected function
function! go#guru#Callers(selected)
let out = s:RunGuru('callers', 'plain', a:selected, 1)
if has_key(out, 'err')
call go#util#EchoError(out.err)
return
endif
function! go#guru#Callers(selected) abort
let args = {
\ 'mode': 'callers',
\ 'format': 'plain',
\ 'selected': a:selected,
\ 'needs_scope': 1,
\ }
call s:loclistSecond(out.out)
call s:run_guru(args)
endfunction
" Show path from callgraph root to selected function
function! go#guru#Callstack(selected)
let out = s:RunGuru('callstack', 'plain', a:selected, 1)
if has_key(out, 'err')
call go#util#EchoError(out.err)
return
endif
function! go#guru#Callstack(selected) abort
let args = {
\ 'mode': 'callstack',
\ 'format': 'plain',
\ 'selected': a:selected,
\ 'needs_scope': 1,
\ }
call s:loclistSecond(out.out)
call s:run_guru(args)
endfunction
" Show free variables of selection
function! go#guru#Freevars(selected)
function! go#guru#Freevars(selected) abort
" Freevars requires a selection
if a:selected == -1
call go#util#EchoError("GoFreevars requires a selection (range) of code")
return
endif
let out = s:RunGuru('freevars', 'plain', a:selected, 0)
if has_key(out, 'err')
call go#util#EchoError(out.err)
return
endif
let args = {
\ 'mode': 'freevars',
\ 'format': 'plain',
\ 'selected': 1,
\ 'needs_scope': 0,
\ }
call s:loclistSecond(out.out)
call s:run_guru(args)
endfunction
" Show send/receive corresponding to selected channel op
function! go#guru#ChannelPeers(selected)
let out = s:RunGuru('peers', 'plain', a:selected, 1)
if has_key(out, 'err')
call go#util#EchoError(out.err)
return
endif
function! go#guru#ChannelPeers(selected) abort
let args = {
\ 'mode': 'peers',
\ 'format': 'plain',
\ 'selected': a:selected,
\ 'needs_scope': 1,
\ }
call s:loclistSecond(out.out)
call s:run_guru(args)
endfunction
" Show all refs to entity denoted by selected identifier
function! go#guru#Referrers(selected)
let out = s:RunGuru('referrers', 'plain', a:selected, 0)
if has_key(out, 'err')
call go#util#EchoError(out.err)
function! go#guru#Referrers(selected) abort
let args = {
\ 'mode': 'referrers',
\ 'format': 'plain',
\ 'selected': a:selected,
\ 'needs_scope': 0,
\ }
call s:run_guru(args)
endfunction
function! go#guru#SameIdsTimer() abort
call timer_start(200, function('go#guru#SameIds'), {'repeat': -1})
endfunction
function! go#guru#SameIds() abort
" we use matchaddpos() which was introduce with 7.4.330, be sure we have
" it: http://ftp.vim.org/vim/patches/7.4/7.4.330
if !exists("*matchaddpos")
call go#util#EchoError("GoSameIds requires 'matchaddpos'. Update your Vim/Neovim version.")
return
endif
call s:loclistSecond(out.out)
endfunction
function! go#guru#What(selected)
" json_encode() and friends are introduced with this patch (7.4.1304)
" vim: https://groups.google.com/d/msg/vim_dev/vLupTNhQhZ8/cDGIk0JEDgAJ
" nvim: https://github.com/neovim/neovim/pull/4131
if !exists("*json_decode")
return {'err': "GoWhat is not supported due old version of Vim/Neovim"}
endif
let out = s:RunGuru('what', 'json', a:selected, 0)
if has_key(out, 'err')
return {'err': out.err}
endif
let result = json_decode(out.out)
if type(result) != type({})
return {'err': "malformed output from guru"}
endif
return result
endfunction
function! go#guru#AutoToogleSameIds()
if get(g:, "go_auto_sameids", 0)
call go#util#EchoProgress("sameids auto highlighting disabled")
call go#guru#ClearSameIds()
let g:go_auto_sameids = 0
call go#util#EchoError("GoSameIds requires 'json_decode'. Update your Vim/Neovim version.")
return
endif
call go#util#EchoSuccess("sameids auto highlighting enabled")
let g:go_auto_sameids = 1
let args = {
\ 'mode': 'what',
\ 'format': 'json',
\ 'selected': -1,
\ 'needs_scope': 0,
\ 'custom_parse': function('s:same_ids_highlight'),
\ }
call s:run_guru(args)
endfunction
function! go#guru#SameIds(selected)
" we use matchaddpos() which was introduce with 7.4.330, be sure we have
" it: http://ftp.vim.org/vim/patches/7.4/7.4.330
if !exists("*matchaddpos")
call go#util#EchoError("GoSameIds is supported with Vim version 7.4-330 or later")
return
endif
let result = go#guru#What(a:selected)
function! s:same_ids_highlight(exit_val, output) abort
call go#guru#ClearSameIds() " run after calling guru to reduce flicker.
if has_key(result, 'err') && !get(g:, 'go_auto_sameids', 0)
" only echo if it's called via `:GoSameIds, but not if it's in automode
call go#util#EchoError(result.err)
if a:output[0] !=# '{'
if !get(g:, 'go_auto_sameids', 0)
call go#util#EchoError(a:output)
endif
return
endif
let result = json_decode(a:output)
if type(result) != type({}) && !get(g:, 'go_auto_sameids', 0)
call go#util#EchoError("malformed output from guru")
return
endif
@ -367,11 +530,11 @@ function! go#guru#SameIds(selected)
if get(g:, "go_auto_sameids", 0)
" re-apply SameIds at the current cursor position at the time the buffer
" is redisplayed: e.g. :edit, :GoRename, etc.
autocmd BufWinEnter <buffer> nested call go#guru#SameIds(-1)
autocmd BufWinEnter <buffer> nested call go#guru#SameIds()
endif
endfunction
function! go#guru#ClearSameIds()
function! go#guru#ClearSameIds() abort
let m = getmatches()
for item in m
if item['group'] == 'goSameId'
@ -385,11 +548,94 @@ function! go#guru#ClearSameIds()
endif
endfunction
function! go#guru#ToggleSameIds(selected)
function! go#guru#ToggleSameIds() abort
if len(getmatches()) != 0
call go#guru#ClearSameIds()
else
call go#guru#SameIds(a:selected)
call go#guru#SameIds()
endif
endfunction
function! go#guru#AutoToogleSameIds() abort
if get(g:, "go_auto_sameids", 0)
call go#util#EchoProgress("sameids auto highlighting disabled")
call go#guru#ClearSameIds()
let g:go_auto_sameids = 0
return
endif
call go#util#EchoSuccess("sameids auto highlighting enabled")
let g:go_auto_sameids = 1
endfunction
""""""""""""""""""""""""""""""""""""""""
"" HELPER FUNCTIONS
""""""""""""""""""""""""""""""""""""""""
" This uses Vim's errorformat to parse the output from Guru's 'plain output
" and put it into location list. I believe using errorformat is much more
" easier to use. If we need more power we can always switch back to parse it
" via regex. Match two possible styles of errorformats:
"
" 'file:line.col-line2.col2: message'
" 'file:line:col: message'
"
" We discard line2 and col2 for the first errorformat, because it's not
" useful and location only has the ability to show one line and column
" number
function! s:parse_guru_output(exit_val, output, title) abort
if a:exit_val
call go#util#EchoError(a:output)
return
endif
let old_errorformat = &errorformat
let errformat = "%f:%l.%c-%[%^:]%#:\ %m,%f:%l:%c:\ %m"
call go#list#ParseFormat("locationlist", errformat, a:output, a:title)
let &errorformat = old_errorformat
let errors = go#list#Get("locationlist")
call go#list#Window("locationlist", len(errors))
endfun
function! go#guru#Scope(...) abort
if a:0
if a:0 == 1 && a:1 == '""'
unlet g:go_guru_scope
call go#util#EchoSuccess("guru scope is cleared")
else
let g:go_guru_scope = a:000
call go#util#EchoSuccess("guru scope changed to: ". join(a:000, ","))
endif
return
endif
if !exists('g:go_guru_scope')
call go#util#EchoError("guru scope is not set")
else
call go#util#EchoSuccess("current guru scope: ". join(g:go_guru_scope, ","))
endif
endfunction
function! go#guru#Tags(...) abort
if a:0
if a:0 == 1 && a:1 == '""'
unlet g:go_guru_tags
call go#util#EchoSuccess("guru tags is cleared")
else
let g:go_guru_tags = a:1
call go#util#EchoSuccess("guru tags changed to: ". a:1)
endif
return
endif
if !exists('g:go_guru_tags')
call go#util#EchoSuccess("guru tags is not set")
else
call go#util#EchoSuccess("current guru tags: ". a:1)
endif
endfunction