123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669 |
- 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 pkg = go#package#ImportPath()
-
- if pkg == -1 && needs_scope
- return {'err': "current directory is not inside of a valid GOPATH"}
- endif
-
- let bin_path = go#path#CheckBinPath("guru")
- if empty(bin_path)
- return {'err': "bin path not found"}
- endif
-
- let cmd = [bin_path]
- let filename = fnamemodify(expand("%"), ':p:gs?\\?/?')
- if &modified
- let result.stdin_content = go#util#archive()
- call add(cmd, "-modified")
- endif
-
- if format == "json"
- call add(cmd, "-json")
- endif
-
- if exists('g:go_build_tags')
- let tags = get(g:, 'go_build_tags')
- call extend(cmd, ["-tags", tags])
- let result.tags = tags
- endif
-
-
- let scopes = []
- if needs_scope
- let scopes = [pkg]
- endif
-
-
-
-
-
- if exists('g:go_guru_scope')
-
- if type(get(g:, 'go_guru_scope')) != type([])
- return {'err' : "go_guru_scope should of type list"}
- endif
- let scopes = get(g:, 'go_guru_scope')
- endif
-
- if !empty(scopes)
-
-
- let scopes = go#util#StripTrailingSlash(scopes)
-
- if !has("nvim") && !go#util#has_job() | let scopes = go#util#Shelllist(scopes) | endif
-
- let l:scope = join(scopes, ",")
- let result.scope = l:scope
- call extend(cmd, ["-scope", l:scope])
- endif
- let pos = printf("#%s", go#util#OffsetCursor())
- if selected != -1
-
- let pos1 = go#util#Offset(line("'<"), col("'<"))
- let pos2 = go#util#Offset(line("'>"), col("'>"))
- let pos = printf("#%s,#%s", pos1, pos2)
- endif
- let filename .= ':'.pos
- call extend(cmd, [mode, filename])
- let result.cmd = cmd
- return result
- endfunction
- 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 .
- \ " (see ':help go-guru-scope' if this doesn't work)...")
- elseif a:args.mode !=# 'what'
-
- call go#util#EchoProgress("analysing ...")
- endif
- endif
-
- let command = join(result.cmd, " ")
- if has_key(result, 'stdin_content')
- let out = go#util#System(command, result.stdin_content)
- else
- let out = go#util#System(command)
- endif
- if has_key(a:args, 'custom_parse')
- call a:args.custom_parse(go#util#ShellError(), out, a:args.mode)
- else
- call s:parse_guru_output(go#util#ShellError(), out, a:args.mode)
- endif
- return out
- endfunc
- function! s:job_start(cmd, start_options) abort
- if go#util#has_job()
- return job_start(a:cmd, a:start_options)
- endif
- let opts = {'stdout_buffered': v:true, 'stderr_buffered': v:true}
- function opts.on_stdout(job_id, data, event) closure
- call a:start_options.callback(a:job_id, join(a:data, "\n"))
- endfunction
- function opts.on_stderr(job_id, data, event) closure
- call a:start_options.callback(a:job_id, join(a:data, "\n"))
- endfunction
- function opts.on_exit(job_id, exit_code, event) closure
- call a:start_options.exit_cb(a:job_id, a:exit_code)
- call a:start_options.close_cb(a:job_id)
- endfunction
-
- let cmd = a:cmd
- if has_key(a:start_options, 'in_io') && a:start_options.in_io ==# 'file' && !empty(a:start_options.in_name)
- let cmd = ['/bin/sh', '-c', join(a:cmd, ' ') . ' <' . a:start_options.in_name]
- endif
- return jobstart(cmd, opts)
- endfunction
- 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 !has_key(a:args, 'disable_progress')
- if a:args.needs_scope
- call go#util#EchoProgress("analysing with scope " . result.scope .
- \ " (see ':help go-guru-scope' if this doesn't work)...")
- endif
- endif
- let state = {
- \ 'status_dir': expand('%:p:h'),
- \ 'statusline_type': printf("%s", a:args.mode),
- \ 'mode': a:args.mode,
- \ 'status': {},
- \ 'exitval': 0,
- \ 'closed': 0,
- \ 'exited': 0,
- \ 'messages': [],
- \ 'parse' : get(a:args, 'custom_parse', funcref("s:parse_guru_output"))
- \ }
- function! s:callback(chan, msg) dict
- call add(self.messages, a:msg)
- endfunction
- function! s:exit_cb(job, exitval) dict
- let self.exited = 1
- let status = {
- \ 'desc': 'last status',
- \ 'type': self.statusline_type,
- \ 'state': "finished",
- \ }
- if a:exitval
- let self.exitval = a:exitval
- let status.state = "failed"
- endif
- call go#statusline#Update(self.status_dir, status)
- if self.closed
- call self.complete()
- endif
- endfunction
- function! s:close_cb(ch) dict
- let self.closed = 1
- if self.exited
- call self.complete()
- endif
- endfunction
- function state.complete() dict
- let out = join(self.messages, "\n")
- call self.parse(self.exitval, out, self.mode)
- endfunction
-
-
- let start_options = {
- \ 'callback': function('s:callback', [], state),
- \ 'exit_cb': function('s:exit_cb', [], state),
- \ 'close_cb': function('s:close_cb', [], state)
- \ }
- if has_key(result, 'stdin_content')
- 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(state.status_dir, {
- \ 'desc': "current status",
- \ 'type': state.statusline_type,
- \ 'state': "analysing",
- \})
- return s:job_start(result.cmd, start_options)
- endfunc
- function! s:run_guru(args) abort
- if has('nvim') || go#util#has_job()
- let res = s:async_guru(a:args)
- else
- let res = s:sync_guru(a:args)
- endif
- return res
- endfunction
- function! go#guru#Implements(selected) abort
- let args = {
- \ 'mode': 'implements',
- \ 'format': 'plain',
- \ 'selected': a:selected,
- \ 'needs_scope': 1,
- \ }
- call s:run_guru(args)
- endfunction
- function! go#guru#Whicherrs(selected) abort
- let args = {
- \ 'mode': 'whicherrs',
- \ 'format': 'plain',
- \ 'selected': a:selected,
- \ 'needs_scope': 1,
- \ }
-
-
- " call go#util#EchoSuccess("no error variables found. Try to change the scope with :GoGuruScope
-
-
- call s:run_guru(args)
- endfunction
- 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
-
-
-
- if !exists("*json_decode")
- call go#util#EchoError("requires 'json_decode'. Update your Vim/Neovim version.")
- return
- endif
- function! s:info(exit_val, output, mode)
- 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 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 = ""
-
-
- 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': 0,
- \ 'custom_parse': function('s:info'),
- \ 'disable_progress': 1,
- \ }
- call s:run_guru(args)
- endfunction
- function! go#guru#Callees(selected) abort
- let args = {
- \ 'mode': 'callees',
- \ 'format': 'plain',
- \ 'selected': a:selected,
- \ 'needs_scope': 1,
- \ }
- call s:run_guru(args)
- endfunction
- function! go#guru#Callers(selected) abort
- let args = {
- \ 'mode': 'callers',
- \ 'format': 'plain',
- \ 'selected': a:selected,
- \ 'needs_scope': 1,
- \ }
- call s:run_guru(args)
- endfunction
- function! go#guru#Callstack(selected) abort
- let args = {
- \ 'mode': 'callstack',
- \ 'format': 'plain',
- \ 'selected': a:selected,
- \ 'needs_scope': 1,
- \ }
- call s:run_guru(args)
- endfunction
- function! go#guru#Freevars(selected) abort
-
- if a:selected == -1
- call go#util#EchoError("GoFreevars requires a selection (range) of code")
- return
- endif
- let args = {
- \ 'mode': 'freevars',
- \ 'format': 'plain',
- \ 'selected': 1,
- \ 'needs_scope': 0,
- \ }
- call s:run_guru(args)
- endfunction
- function! go#guru#ChannelPeers(selected) abort
- let args = {
- \ 'mode': 'peers',
- \ 'format': 'plain',
- \ 'selected': a:selected,
- \ 'needs_scope': 1,
- \ }
- call s:run_guru(args)
- endfunction
- 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#SameIds() abort
-
-
- if !exists("*matchaddpos")
- call go#util#EchoError("GoSameIds requires 'matchaddpos'. Update your Vim/Neovim version.")
- return
- endif
-
-
-
- if !exists("*json_decode")
- call go#util#EchoError("GoSameIds requires 'json_decode'. Update your Vim/Neovim version.")
- return
- endif
- 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! s:same_ids_highlight(exit_val, output, mode) abort
- call go#guru#ClearSameIds()
- 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
- if !has_key(result, 'sameids')
- if !get(g:, 'go_auto_sameids', 0)
- call go#util#EchoError("no same_ids founds for the given identifier")
- endif
- return
- endif
- let poslen = 0
- for enclosing in result['enclosing']
- if enclosing['desc'] == 'identifier'
- let poslen = enclosing['end'] - enclosing['start']
- break
- endif
- endfor
-
- if poslen == 0
- return
- endif
- let same_ids = result['sameids']
-
- for item in same_ids
- let pos = split(item, ':')
- call matchaddpos('goSameId', [[str2nr(pos[-2]), str2nr(pos[-1]), str2nr(poslen)]])
- endfor
- if get(g:, "go_auto_sameids", 0)
-
-
- augroup vim-go-sameids
- autocmd!
- autocmd BufWinEnter <buffer> nested call go#guru#SameIds()
- augroup end
- endif
- endfunction
- function! go#guru#ClearSameIds() abort
- let l:cleared = 0
- let m = getmatches()
- for item in m
- if item['group'] == 'goSameId'
- call matchdelete(item['id'])
- let l:cleared = 1
- endif
- endfor
- if !l:cleared
- return 1
- endif
-
- augroup vim-go-sameids
- autocmd!
- augroup end
- return 0
- endfunction
- function! go#guru#ToggleSameIds() abort
- if go#guru#ClearSameIds() != 0
- 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
- """"""""""""""""""""""""""""""""""""""""
- function! s:parse_guru_output(exit_val, output, title) abort
- if a:exit_val
- call go#util#EchoError(a:output)
- return
- endif
- let errformat = "%f:%l.%c-%[%^:]%#:\ %m,%f:%l:%c:\ %m"
- let l:listtype = go#list#Type("_guru")
- call go#list#ParseFormat(l:listtype, errformat, a:output, a:title)
- let errors = go#list#Get(l:listtype)
- call go#list#Window(l:listtype, 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
|