mirror of
				https://github.com/amix/vimrc
				synced 2025-10-31 14:43:35 +08:00 
			
		
		
		
	Updated plugins
This commit is contained in:
		| @ -14,12 +14,12 @@ else | ||||
|   let g:ctrlp_ext_vars = [s:go_decls_var] | ||||
| endif | ||||
|  | ||||
| function! ctrlp#decls#init() | ||||
| function! ctrlp#decls#init() abort | ||||
|   cal s:enable_syntax() | ||||
|   return s:decls | ||||
| endfunction | ||||
|  | ||||
| function! ctrlp#decls#exit() | ||||
| function! ctrlp#decls#exit() abort | ||||
|   unlet! s:decls s:current_dir s:target | ||||
| endfunction | ||||
|  | ||||
| @ -28,7 +28,7 @@ endfunction | ||||
| "  a:mode   the mode that has been chosen by pressing <cr> <c-v> <c-t> or <c-x> | ||||
| "           the values are 'e', 'v', 't' and 'h', respectively | ||||
| "  a:str    the selected string | ||||
| function! ctrlp#decls#accept(mode, str) | ||||
| function! ctrlp#decls#accept(mode, str) abort | ||||
|   let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' | ||||
|   let dir = getcwd() | ||||
|   try | ||||
| @ -56,7 +56,7 @@ function! ctrlp#decls#accept(mode, str) | ||||
|   endtry | ||||
| endfunction | ||||
|  | ||||
| function! ctrlp#decls#enter() | ||||
| function! ctrlp#decls#enter() abort | ||||
|   let s:current_dir = fnameescape(expand('%:p:h')) | ||||
|   let s:decls = [] | ||||
|  | ||||
| @ -130,7 +130,7 @@ function! ctrlp#decls#enter() | ||||
|   endfor | ||||
| endfunc | ||||
|  | ||||
| function! s:enable_syntax() | ||||
| function! s:enable_syntax() abort | ||||
|   if !(has('syntax') && exists('g:syntax_on')) | ||||
|     return | ||||
|   endif | ||||
| @ -148,7 +148,7 @@ endfunction | ||||
|  | ||||
| let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars) | ||||
|  | ||||
| function! ctrlp#decls#cmd(mode, ...) | ||||
| function! ctrlp#decls#cmd(mode, ...) abort | ||||
|   let s:mode = a:mode | ||||
|   if a:0 && !empty(a:1) | ||||
|     let s:target = a:1 | ||||
|  | ||||
| @ -4,7 +4,7 @@ if !exists("g:go_alternate_mode") | ||||
| endif | ||||
|  | ||||
| " Test alternates between the implementation of code and the test code. | ||||
| function! go#alternate#Switch(bang, cmd) | ||||
| function! go#alternate#Switch(bang, cmd) abort | ||||
|   let file = expand('%') | ||||
|   if empty(file) | ||||
|     call go#util#EchoError("no buffer name") | ||||
|  | ||||
| @ -11,7 +11,7 @@ | ||||
| " | ||||
| " Options: | ||||
| " | ||||
| "   g:go_asmfmt_autosave [default=1] | ||||
| "   g:go_asmfmt_autosave [default=0] | ||||
| " | ||||
| "       Flag to automatically call :Fmt when file is saved. | ||||
|  | ||||
| @ -19,7 +19,7 @@ let s:got_fmt_error = 0 | ||||
|  | ||||
| " This is a trimmed-down version of the logic in fmt.vim. | ||||
|  | ||||
| function! go#asmfmt#Format() | ||||
| function! go#asmfmt#Format() abort | ||||
|   " Save state. | ||||
|   let l:curw = winsaveview() | ||||
|  | ||||
| @ -55,15 +55,15 @@ function! go#asmfmt#Format() | ||||
|   call winrestview(l:curw) | ||||
| endfunction | ||||
|  | ||||
| function! go#asmfmt#ToggleAsmFmtAutoSave() | ||||
|   if get(g:, "go_asmfmt_autosave", 1) | ||||
|     let g:go_asmfmt_autosave = 0 | ||||
|     call go#util#EchoProgress("auto asmfmt disabled") | ||||
| function! go#asmfmt#ToggleAsmFmtAutoSave() abort | ||||
|   if get(g:, "go_asmfmt_autosave", 0) | ||||
|     let g:go_asmfmt_autosave = 1 | ||||
|     call go#util#EchoProgress("auto asmfmt enabled") | ||||
|     return | ||||
|   end | ||||
|  | ||||
|   let g:go_asmfmt_autosave = 1 | ||||
|   call go#util#EchoProgress("auto asmfmt enabled") | ||||
|   let g:go_asmfmt_autosave = 0 | ||||
|   call go#util#EchoProgress("auto asmfmt disabled") | ||||
| endfunction | ||||
|  | ||||
| " vim: sw=2 ts=2 et | ||||
|  | ||||
| @ -1,19 +1,14 @@ | ||||
| if !exists("g:go_dispatch_enabled") | ||||
|   let g:go_dispatch_enabled = 0 | ||||
| endif | ||||
|  | ||||
| function! go#cmd#autowrite() | ||||
| function! go#cmd#autowrite() abort | ||||
|   if &autowrite == 1 | ||||
|     silent wall | ||||
|     silent! wall | ||||
|   endif | ||||
| endfunction | ||||
|  | ||||
|  | ||||
| " Build builds the source code without producting any output binary. We live in | ||||
| " an editor so the best is to build it to catch errors and fix them. By | ||||
| " default it tries to call simply 'go build', but it first tries to get all | ||||
| " dependent files for the current folder and passes it to go build. | ||||
| function! go#cmd#Build(bang, ...) | ||||
| function! go#cmd#Build(bang, ...) abort | ||||
|   " expand all wildcards(i.e: '%' to the current file name) | ||||
|   let goargs = map(copy(a:000), "expand(v:val)") | ||||
|  | ||||
| @ -26,8 +21,18 @@ function! go#cmd#Build(bang, ...) | ||||
|   " placeholder with the current folder (indicated with '.') | ||||
|   let args = ["build"]  + goargs + [".", "errors"] | ||||
|  | ||||
|   " if we have nvim, call it asynchronously and return early ;) | ||||
|   if has('nvim') | ||||
|   if go#util#has_job() | ||||
|     if get(g:, 'go_echo_command_info', 1) | ||||
|       call go#util#EchoProgress("building dispatched ...") | ||||
|     endif | ||||
|  | ||||
|     call s:cmd_job({ | ||||
|           \ 'cmd': ['go'] + args, | ||||
|           \ 'bang': a:bang, | ||||
|           \}) | ||||
|     return | ||||
|   elseif has('nvim') | ||||
|     " if we have nvim, call it asynchronously and return early ;) | ||||
|     call go#util#EchoProgress("building dispatched ...") | ||||
|     call go#jobcontrol#Spawn(a:bang, "build", args) | ||||
|     return | ||||
| @ -45,10 +50,7 @@ function! go#cmd#Build(bang, ...) | ||||
|   let dir = getcwd() | ||||
|   try | ||||
|     execute cd . fnameescape(expand("%:p:h")) | ||||
|     if g:go_dispatch_enabled && exists(':Make') == 2 | ||||
|       call go#util#EchoProgress("building dispatched ...") | ||||
|       silent! exe 'Make' | ||||
|     elseif l:listtype == "locationlist" | ||||
|     if l:listtype == "locationlist" | ||||
|       silent! exe 'lmake!' | ||||
|     else | ||||
|       silent! exe 'make!' | ||||
| @ -60,11 +62,8 @@ function! go#cmd#Build(bang, ...) | ||||
|  | ||||
|   let errors = go#list#Get(l:listtype) | ||||
|   call go#list#Window(l:listtype, len(errors)) | ||||
|  | ||||
|   if !empty(errors) | ||||
|     if !a:bang | ||||
|       call go#list#JumpToFirst(l:listtype) | ||||
|     endif | ||||
|   if !empty(errors) && !a:bang | ||||
|     call go#list#JumpToFirst(l:listtype) | ||||
|   else | ||||
|     call go#util#EchoSuccess("[build] SUCCESS") | ||||
|   endif | ||||
| @ -75,7 +74,7 @@ endfunction | ||||
|  | ||||
|  | ||||
| " Run runs the current file (and their dependencies if any) in a new terminal. | ||||
| function! go#cmd#RunTerm(bang, mode, files) | ||||
| function! go#cmd#RunTerm(bang, mode, files) abort | ||||
|   if empty(a:files) | ||||
|     let cmd = "go run ".  go#util#Shelljoin(go#tool#Files()) | ||||
|   else | ||||
| @ -88,12 +87,18 @@ endfunction | ||||
| " This is intented to test small programs and play with them. It's not | ||||
| " suitable for long running apps, because vim is blocking by default and | ||||
| " calling long running apps will block the whole UI. | ||||
| function! go#cmd#Run(bang, ...) | ||||
| function! go#cmd#Run(bang, ...) abort | ||||
|   if has('nvim') | ||||
|     call go#cmd#RunTerm(a:bang, '', a:000) | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   if go#util#has_job() | ||||
|     " NOTE(arslan): 'term': 'open' case is not implement for +jobs. This means | ||||
|     " executions waiting for stdin will not work. That's why we don't do | ||||
|     " anything. Once this is implemented we're going to make :GoRun async | ||||
|   endif | ||||
|  | ||||
|   let old_gopath = $GOPATH | ||||
|   let $GOPATH = go#path#Detect() | ||||
|  | ||||
| @ -119,9 +124,7 @@ function! go#cmd#Run(bang, ...) | ||||
|  | ||||
|   let l:listtype = go#list#Type("quickfix") | ||||
|  | ||||
|   if g:go_dispatch_enabled && exists(':Make') == 2 | ||||
|     silent! exe 'Make' | ||||
|   elseif l:listtype == "locationlist" | ||||
|   if l:listtype == "locationlist" | ||||
|     exe 'lmake!' | ||||
|   else | ||||
|     exe 'make!' | ||||
| @ -130,7 +133,7 @@ function! go#cmd#Run(bang, ...) | ||||
|   let items = go#list#Get(l:listtype) | ||||
|   let errors = go#tool#FilterValids(items) | ||||
|  | ||||
|   call go#list#Populate(l:listtype, errors) | ||||
|   call go#list#Populate(l:listtype, errors, &makeprg) | ||||
|   call go#list#Window(l:listtype, len(errors)) | ||||
|   if !empty(errors) && !a:bang | ||||
|     call go#list#JumpToFirst(l:listtype) | ||||
| @ -141,9 +144,28 @@ function! go#cmd#Run(bang, ...) | ||||
| endfunction | ||||
|  | ||||
| " Install installs the package by simple calling 'go install'. If any argument | ||||
| " is given(which are passed directly to 'go install') it tries to install those | ||||
| " packages. Errors are populated in the location window. | ||||
| function! go#cmd#Install(bang, ...) | ||||
| " is given(which are passed directly to 'go install') it tries to install | ||||
| " those packages. Errors are populated in the location window. | ||||
| function! go#cmd#Install(bang, ...) abort | ||||
|   " use vim's job functionality to call it asynchronously | ||||
|   if go#util#has_job() | ||||
|     " expand all wildcards(i.e: '%' to the current file name) | ||||
|     let goargs = map(copy(a:000), "expand(v:val)") | ||||
|  | ||||
|     " escape all shell arguments before we pass it to make | ||||
|     let goargs = go#util#Shelllist(goargs, 1) | ||||
|  | ||||
|     if get(g:, 'go_echo_command_info', 1) | ||||
|       call go#util#EchoProgress("installing dispatched ...") | ||||
|     endif | ||||
|  | ||||
|     call s:cmd_job({ | ||||
|           \ 'cmd': ['go', 'install'] + goargs, | ||||
|           \ 'bang': a:bang, | ||||
|           \}) | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   let old_gopath = $GOPATH | ||||
|   let $GOPATH = go#path#Detect() | ||||
|   let default_makeprg = &makeprg | ||||
| @ -159,10 +181,7 @@ function! go#cmd#Install(bang, ...) | ||||
|   let dir = getcwd() | ||||
|   try | ||||
|     execute cd . fnameescape(expand("%:p:h")) | ||||
|     if g:go_dispatch_enabled && exists(':Make') == 2 | ||||
|       call go#util#EchoProgress("building dispatched ...") | ||||
|       silent! exe 'Make' | ||||
|     elseif l:listtype == "locationlist" | ||||
|     if l:listtype == "locationlist" | ||||
|       silent! exe 'lmake!' | ||||
|     else | ||||
|       silent! exe 'make!' | ||||
| @ -174,12 +193,10 @@ function! go#cmd#Install(bang, ...) | ||||
|  | ||||
|   let errors = go#list#Get(l:listtype) | ||||
|   call go#list#Window(l:listtype, len(errors)) | ||||
|   if !empty(errors) | ||||
|     if !a:bang | ||||
|       call go#list#JumpToFirst(l:listtype) | ||||
|     endif | ||||
|   if !empty(errors) && !a:bang | ||||
|     call go#list#JumpToFirst(l:listtype) | ||||
|   else | ||||
|     redraws! | echon "vim-go: " | echohl Function | echon "installed to ". $GOPATH | echohl None | ||||
|     call go#util#EchoSuccess("installed to ". $GOPATH) | ||||
|   endif | ||||
|  | ||||
|   let $GOPATH = old_gopath | ||||
| @ -189,7 +206,7 @@ endfunction | ||||
| " Test runs `go test` in the current directory. If compile is true, it'll | ||||
| " compile the tests instead of running them (useful to catch errors in the | ||||
| " test files). Any other argument is appendend to the final `go test` command | ||||
| function! go#cmd#Test(bang, compile, ...) | ||||
| function! go#cmd#Test(bang, compile, ...) abort | ||||
|   let args = ["test"] | ||||
|  | ||||
|   " don't run the test, only compile it. Useful to capture and fix errors. | ||||
| @ -199,9 +216,15 @@ function! go#cmd#Test(bang, compile, ...) | ||||
|   endif | ||||
|  | ||||
|   if a:0 | ||||
|     " expand all wildcards(i.e: '%' to the current file name) | ||||
|     let goargs = map(copy(a:000), "expand(v:val)") | ||||
|     if !has('nvim') | ||||
|     let goargs = a:000 | ||||
|  | ||||
|     " do not expand for coverage mode as we're passing the arg ourself | ||||
|     if a:1 != '-coverprofile' | ||||
|       " expand all wildcards(i.e: '%' to the current file name) | ||||
|       let goargs = map(copy(a:000), "expand(v:val)") | ||||
|     endif | ||||
|  | ||||
|     if !(has('nvim') || go#util#has_job()) | ||||
|       let goargs = go#util#Shelllist(goargs, 1) | ||||
|     endif | ||||
|  | ||||
| @ -212,13 +235,29 @@ function! go#cmd#Test(bang, compile, ...) | ||||
|     call add(args, printf("-timeout=%s", timeout)) | ||||
|   endif | ||||
|  | ||||
|   if a:compile | ||||
|     echon "vim-go: " | echohl Identifier | echon "compiling tests ..." | echohl None | ||||
|   else | ||||
|     echon "vim-go: " | echohl Identifier | echon "testing ..." | echohl None | ||||
|   if get(g:, 'go_echo_command_info', 1) | ||||
|     if a:compile | ||||
|       echon "vim-go: " | echohl Identifier | echon "compiling tests ..." | echohl None | ||||
|     else | ||||
|       echon "vim-go: " | echohl Identifier | echon "testing ..." | echohl None | ||||
|     endif | ||||
|   endif | ||||
|  | ||||
|   if has('nvim') | ||||
|   if go#util#has_job() | ||||
|     " use vim's job functionality to call it asynchronously | ||||
|     let job_args = { | ||||
|           \ 'cmd': ['go'] + args, | ||||
|           \ 'bang': a:bang, | ||||
|           \ } | ||||
|  | ||||
|     if a:compile | ||||
|       let job_args['custom_cb'] = function('s:test_compile', [compile_file]) | ||||
|     endif | ||||
|  | ||||
|     call s:cmd_job(job_args) | ||||
|     return | ||||
|   elseif has('nvim') | ||||
|     " use nvims's job functionality | ||||
|     if get(g:, 'go_term_enabled', 0) | ||||
|       let id = go#term#new(a:bang, ["go"] + args) | ||||
|     else | ||||
| @ -252,7 +291,7 @@ function! go#cmd#Test(bang, compile, ...) | ||||
|     let errors = go#tool#ParseErrors(split(out, '\n')) | ||||
|     let errors = go#tool#FilterValids(errors) | ||||
|  | ||||
|     call go#list#Populate(l:listtype, errors) | ||||
|     call go#list#Populate(l:listtype, errors, command) | ||||
|     call go#list#Window(l:listtype, len(errors)) | ||||
|     if !empty(errors) && !a:bang | ||||
|       call go#list#JumpToFirst(l:listtype) | ||||
| @ -276,7 +315,7 @@ endfunction | ||||
|  | ||||
| " Testfunc runs a single test that surrounds the current cursor position. | ||||
| " Arguments are passed to the `go test` command. | ||||
| function! go#cmd#TestFunc(bang, ...) | ||||
| function! go#cmd#TestFunc(bang, ...) abort | ||||
|   " search flags legend (used only) | ||||
|   " 'b' search backward instead of forward | ||||
|   " 'c' accept a match at the cursor position | ||||
| @ -304,7 +343,7 @@ function! go#cmd#TestFunc(bang, ...) | ||||
| endfunction | ||||
|  | ||||
| " Generate runs 'go generate' in similar fashion to go#cmd#Build() | ||||
| function! go#cmd#Generate(bang, ...) | ||||
| function! go#cmd#Generate(bang, ...) abort | ||||
|   let default_makeprg = &makeprg | ||||
|  | ||||
|   let old_gopath = $GOPATH | ||||
| @ -322,9 +361,7 @@ function! go#cmd#Generate(bang, ...) | ||||
|   let l:listtype = go#list#Type("quickfix") | ||||
|  | ||||
|   echon "vim-go: " | echohl Identifier | echon "generating ..."| echohl None | ||||
|   if g:go_dispatch_enabled && exists(':Make') == 2 | ||||
|     silent! exe 'Make' | ||||
|   elseif l:listtype == "locationlist" | ||||
|   if l:listtype == "locationlist" | ||||
|     silent! exe 'lmake!' | ||||
|   else | ||||
|     silent! exe 'make!' | ||||
| @ -346,12 +383,79 @@ function! go#cmd#Generate(bang, ...) | ||||
| endfunction | ||||
|  | ||||
|  | ||||
| " --------------------- | ||||
| " | Vim job callbacks | | ||||
| " --------------------- | ||||
|  | ||||
| function s:cmd_job(args) abort | ||||
|   let status_dir = expand('%:p:h') | ||||
|   let started_at = reltime() | ||||
|  | ||||
|   call go#statusline#Update(status_dir, { | ||||
|         \ 'desc': "current status", | ||||
|         \ 'type': a:args.cmd[1], | ||||
|         \ 'state': "started", | ||||
|         \}) | ||||
|  | ||||
|   " autowrite is not enabled for jobs | ||||
|   call go#cmd#autowrite() | ||||
|  | ||||
|   function! s:error_info_cb(job, exit_status, data) closure abort | ||||
|     let status = { | ||||
|           \ 'desc': 'last status', | ||||
|           \ 'type': a:args.cmd[1], | ||||
|           \ 'state': "success", | ||||
|           \ } | ||||
|  | ||||
|     if a:exit_status | ||||
|       let status.state = "failed" | ||||
|     endif | ||||
|  | ||||
|     let elapsed_time = reltimestr(reltime(started_at)) | ||||
|     " strip whitespace | ||||
|     let elapsed_time = substitute(elapsed_time, '^\s*\(.\{-}\)\s*$', '\1', '') | ||||
|     let status.state .= printf(" (%ss)", elapsed_time) | ||||
|  | ||||
|     call go#statusline#Update(status_dir, status) | ||||
|   endfunction | ||||
|  | ||||
|   let a:args.error_info_cb = function('s:error_info_cb') | ||||
|   let callbacks = go#job#Spawn(a:args) | ||||
|  | ||||
|   let start_options = { | ||||
|         \ 'callback': callbacks.callback, | ||||
|         \ 'close_cb': callbacks.close_cb, | ||||
|         \ } | ||||
|  | ||||
|   " modify GOPATH if needed | ||||
|   let old_gopath = $GOPATH | ||||
|   let $GOPATH = go#path#Detect() | ||||
|  | ||||
|   " pre start | ||||
|   let dir = getcwd() | ||||
|   let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' | ||||
|   let jobdir = fnameescape(expand("%:p:h")) | ||||
|   execute cd . jobdir | ||||
|  | ||||
|   call job_start(a:args.cmd, start_options) | ||||
|  | ||||
|   " post start | ||||
|   execute cd . fnameescape(dir) | ||||
|   let $GOPATH = old_gopath | ||||
| endfunction | ||||
|  | ||||
|  | ||||
| " test_compile is called when a GoTestCompile call is finished | ||||
| function! s:test_compile(test_file, job, exit_status, data) abort | ||||
|   call delete(a:test_file) | ||||
| endfunction | ||||
|  | ||||
| " ----------------------- | ||||
| " | Neovim job handlers | | ||||
| " ----------------------- | ||||
| let s:test_compile_handlers = {} | ||||
|  | ||||
| function! s:test_compile_handler(job, exit_status, data) | ||||
| function! s:test_compile_handler(job, exit_status, data) abort | ||||
|   if !has_key(s:test_compile_handlers, a:job.id) | ||||
|     return | ||||
|   endif | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| let s:sock_type = (has('win32') || has('win64')) ? 'tcp' : 'unix' | ||||
|  | ||||
| function! s:gocodeCurrentBuffer() | ||||
| function! s:gocodeCurrentBuffer() abort | ||||
|   let buf = getline(1, '$') | ||||
|   if &encoding != 'utf-8' | ||||
|     let buf = map(buf, 'iconv(v:val, &encoding, "utf-8")') | ||||
| @ -16,7 +16,7 @@ function! s:gocodeCurrentBuffer() | ||||
|   return file | ||||
| endfunction | ||||
|  | ||||
| function! s:gocodeCommand(cmd, preargs, args) | ||||
| function! s:gocodeCommand(cmd, preargs, args) abort | ||||
|   for i in range(0, len(a:args) - 1) | ||||
|     let a:args[i] = go#util#Shellescape(a:args[i]) | ||||
|   endfor | ||||
| @ -59,12 +59,12 @@ function! s:gocodeCommand(cmd, preargs, args) | ||||
|   endif | ||||
| endfunction | ||||
|  | ||||
| function! s:gocodeCurrentBufferOpt(filename) | ||||
| function! s:gocodeCurrentBufferOpt(filename) abort | ||||
|   return '-in=' . a:filename | ||||
| endfunction | ||||
|  | ||||
| let s:optionsEnabled = 0 | ||||
| function! s:gocodeEnableOptions() | ||||
| function! s:gocodeEnableOptions() abort | ||||
|   if s:optionsEnabled  | ||||
|     return | ||||
|   endif | ||||
| @ -78,14 +78,14 @@ function! s:gocodeEnableOptions() | ||||
|  | ||||
|   call go#util#System(printf('%s set propose-builtins %s', go#util#Shellescape(bin_path), s:toBool(get(g:, 'go_gocode_propose_builtins', 1)))) | ||||
|   call go#util#System(printf('%s set autobuild %s', go#util#Shellescape(bin_path), s:toBool(get(g:, 'go_gocode_autobuild', 1)))) | ||||
|   call go#util#System(printf('%s set unimported-packages %s', go#util#Shellescape(bin_path), s:toBool(get(g:, 'go_gocode_unimported_packages', 1)))) | ||||
|   call go#util#System(printf('%s set unimported-packages %s', go#util#Shellescape(bin_path), s:toBool(get(g:, 'go_gocode_unimported_packages', 0)))) | ||||
| endfunction | ||||
|  | ||||
| function! s:toBool(val) | ||||
| function! s:toBool(val) abort | ||||
|   if a:val | return 'true ' | else | return 'false' | endif | ||||
| endfunction | ||||
|  | ||||
| function! s:gocodeAutocomplete() | ||||
| function! s:gocodeAutocomplete() abort | ||||
|   call s:gocodeEnableOptions() | ||||
|  | ||||
|   let filename = s:gocodeCurrentBuffer() | ||||
| @ -96,7 +96,7 @@ function! s:gocodeAutocomplete() | ||||
|   return result | ||||
| endfunction | ||||
|  | ||||
| function! go#complete#GetInfo() | ||||
| function! go#complete#GetInfo() abort | ||||
|   let offset = go#util#OffsetCursor()+1 | ||||
|   let filename = s:gocodeCurrentBuffer() | ||||
|   let result = s:gocodeCommand('autocomplete', | ||||
| @ -137,7 +137,7 @@ function! go#complete#GetInfo() | ||||
|   return "" | ||||
| endfunction | ||||
|  | ||||
| function! go#complete#Info(auto) | ||||
| function! go#complete#Info(auto) abort | ||||
|   " auto is true if we were called by g:go_auto_type_info's autocmd | ||||
|   let result = go#complete#GetInfo() | ||||
|   if !empty(result) | ||||
| @ -147,12 +147,12 @@ function! go#complete#Info(auto) | ||||
|   endif | ||||
| endfunction | ||||
|  | ||||
| function! s:trim_bracket(val) | ||||
| function! s:trim_bracket(val) abort | ||||
|   let a:val.word = substitute(a:val.word, '[(){}\[\]]\+$', '', '') | ||||
|   return a:val | ||||
| endfunction | ||||
|  | ||||
| function! go#complete#Complete(findstart, base) | ||||
| function! go#complete#Complete(findstart, base) abort | ||||
|   "findstart = 1 when we need to get the text length | ||||
|   if a:findstart == 1 | ||||
|     execute "silent let g:gocomplete_completions = " . s:gocodeAutocomplete() | ||||
| @ -167,7 +167,7 @@ function! go#complete#Complete(findstart, base) | ||||
|   endif | ||||
| endf | ||||
|  | ||||
| function! go#complete#ToggleAutoTypeInfo() | ||||
| function! go#complete#ToggleAutoTypeInfo() abort | ||||
|   if get(g:, "go_auto_type_info", 0) | ||||
|     let g:go_auto_type_info = 0 | ||||
|     call go#util#EchoProgress("auto type info disabled") | ||||
|  | ||||
| @ -3,7 +3,7 @@ let s:toggle = 0 | ||||
| " Buffer creates a new cover profile with 'go test -coverprofile' and changes | ||||
| " the current buffers highlighting to show covered and uncovered sections of | ||||
| " the code. If run again it clears the annotation. | ||||
| function! go#coverage#BufferToggle(bang, ...) | ||||
| function! go#coverage#BufferToggle(bang, ...) abort | ||||
|   if s:toggle | ||||
|     call go#coverage#Clear() | ||||
|     return | ||||
| @ -20,7 +20,7 @@ endfunction | ||||
| " teh current buffers highlighting to show covered and uncovered sections of | ||||
| " the code. Calling it again reruns the tests and shows the last updated | ||||
| " coverage. | ||||
| function! go#coverage#Buffer(bang, ...) | ||||
| function! go#coverage#Buffer(bang, ...) 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") | ||||
| @ -43,8 +43,17 @@ function! go#coverage#Buffer(bang, ...) | ||||
|  | ||||
|   let s:toggle = 1 | ||||
|   let l:tmpname = tempname() | ||||
|   let args = [a:bang, 0, "-coverprofile", l:tmpname] | ||||
|  | ||||
|   if go#util#has_job() | ||||
|     call s:coverage_job({ | ||||
|           \ 'cmd': ['go', 'test', '-coverprofile', l:tmpname], | ||||
|           \ 'custom_cb': function('s:coverage_callback', [l:tmpname]), | ||||
|           \ 'bang': a:bang, | ||||
|           \ }) | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   let args = [a:bang, 0, "-coverprofile", l:tmpname] | ||||
|   if a:0 | ||||
|     call extend(args, a:000) | ||||
|   endif | ||||
| @ -75,11 +84,8 @@ function! go#coverage#Buffer(bang, ...) | ||||
| endfunction | ||||
|  | ||||
| " Clear clears and resets the buffer annotation matches | ||||
| function! go#coverage#Clear() | ||||
|   " only reset the syntax if the user has syntax enabled | ||||
|   if !empty(&syntax) | ||||
|     if exists("g:syntax_on") | syntax enable | endif | ||||
|   endif | ||||
| function! go#coverage#Clear() abort | ||||
|   call clearmatches() | ||||
|  | ||||
|   if exists("s:toggle") | let s:toggle = 0 | endif | ||||
|  | ||||
| @ -87,25 +93,34 @@ function! go#coverage#Clear() | ||||
|   if exists("#BufWinLeave#<buffer>")  | ||||
|     autocmd! BufWinLeave <buffer> | ||||
|   endif | ||||
|  | ||||
|   call clearmatches() | ||||
| endfunction | ||||
|  | ||||
| " Browser creates a new cover profile with 'go test -coverprofile' and opens | ||||
| " a new HTML coverage page from that profile in a new browser | ||||
| function! go#coverage#Browser(bang, ...) | ||||
| function! go#coverage#Browser(bang, ...) abort | ||||
|   let l:tmpname = tempname() | ||||
|   let args = [a:bang, 0, "-coverprofile", l:tmpname] | ||||
|   if go#util#has_job() | ||||
|     call s:coverage_job({ | ||||
|           \ 'cmd': ['go', 'test', '-coverprofile', l:tmpname], | ||||
|           \ 'custom_cb': function('s:coverage_browser_callback', [l:tmpname]), | ||||
|           \ 'bang': a:bang, | ||||
|           \ }) | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   let args = [a:bang, 0, "-coverprofile", l:tmpname] | ||||
|   if a:0 | ||||
|     call extend(args, a:000) | ||||
|   endif | ||||
|  | ||||
|   let id = call('go#cmd#Test', args) | ||||
|   if has('nvim') | ||||
|     call go#jobcontrol#AddHandler(function('s:coverage_browser_handler')) | ||||
|     let s:coverage_browser_handler_jobs[id] = l:tmpname | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|  | ||||
|   if go#util#ShellError() == 0 | ||||
|     let openHTML = 'go tool cover -html='.l:tmpname | ||||
|     call go#tool#ExecuteInDir(openHTML) | ||||
| @ -116,7 +131,7 @@ endfunction | ||||
|  | ||||
| " Parses a single line from the cover file generated via go test -coverprofile | ||||
| " and returns a single coverage profile block. | ||||
| function! go#coverage#parsegocoverline(line) | ||||
| function! go#coverage#parsegocoverline(line) abort | ||||
|   " file:startline.col,endline.col numstmt count | ||||
|   let mx = '\([^:]\+\):\(\d\+\)\.\(\d\+\),\(\d\+\)\.\(\d\+\)\s\(\d\+\)\s\(\d\+\)' | ||||
|   let tokens = matchlist(a:line, mx) | ||||
| @ -133,7 +148,7 @@ endfunction | ||||
|  | ||||
| " Generates matches to be added to matchaddpos for the given coverage profile | ||||
| " block | ||||
| function! go#coverage#genmatch(cov) | ||||
| function! go#coverage#genmatch(cov) abort | ||||
|   let color = 'goCoverageCovered' | ||||
|   if a:cov.cnt == 0 | ||||
|     let color = 'goCoverageUncover' | ||||
| @ -183,7 +198,7 @@ function! go#coverage#genmatch(cov) | ||||
| endfunction | ||||
|  | ||||
| " Reads the given coverprofile file and annotates the current buffer | ||||
| function! go#coverage#overlay(file) | ||||
| function! go#coverage#overlay(file) abort | ||||
|   if !filereadable(a:file) | ||||
|     return | ||||
|   endif | ||||
| @ -204,7 +219,7 @@ function! go#coverage#overlay(file) | ||||
|     let cnt += 1 | ||||
|   endwhile | ||||
|  | ||||
|   let fname = expand('%:t') | ||||
|   let fname = expand('%') | ||||
|  | ||||
|   " when called for a _test.go file, run the coverage for the actuall file | ||||
|   " file | ||||
| @ -221,6 +236,9 @@ function! go#coverage#overlay(file) | ||||
|     exe ":edit ". fnamemodify(fname, ":p") | ||||
|   endif | ||||
|  | ||||
|   " cov.file includes only the filename itself, without full path | ||||
|   let fname = fnamemodify(fname, ":t") | ||||
|  | ||||
|   for line in lines[1:] | ||||
|     let cov = go#coverage#parsegocoverline(line) | ||||
|  | ||||
| @ -233,8 +251,6 @@ function! go#coverage#overlay(file) | ||||
|     call extend(matches, go#coverage#genmatch(cov)) | ||||
|   endfor | ||||
|  | ||||
|   syntax manual | ||||
|  | ||||
|   " clear the matches if we leave the buffer | ||||
|   autocmd BufWinLeave <buffer> call go#coverage#Clear() | ||||
|  | ||||
| @ -244,6 +260,78 @@ function! go#coverage#overlay(file) | ||||
| endfunction | ||||
|  | ||||
|  | ||||
| " --------------------- | ||||
| " | Vim job callbacks | | ||||
| " --------------------- | ||||
| " | ||||
| function s:coverage_job(args) | ||||
|   " autowrite is not enabled for jobs | ||||
|   call go#cmd#autowrite() | ||||
|  | ||||
|   let status_dir =  expand('%:p:h') | ||||
|   function! s:error_info_cb(job, exit_status, data) closure | ||||
|     let status = { | ||||
|           \ 'desc': 'last status', | ||||
|           \ 'type': "coverage", | ||||
|           \ 'state': "finished", | ||||
|           \ } | ||||
|  | ||||
|     if a:exit_status | ||||
|       let status.state = "failed" | ||||
|     endif | ||||
|  | ||||
|     call go#statusline#Update(status_dir, status) | ||||
|   endfunction | ||||
|  | ||||
|   let a:args.error_info_cb = function('s:error_info_cb') | ||||
|   let callbacks = go#job#Spawn(a:args) | ||||
|  | ||||
|   let start_options = { | ||||
|         \ 'callback': callbacks.callback, | ||||
|         \ 'close_cb': callbacks.close_cb, | ||||
|         \ } | ||||
|  | ||||
|   " modify GOPATH if needed | ||||
|   let old_gopath = $GOPATH | ||||
|   let $GOPATH = go#path#Detect() | ||||
|  | ||||
|   " pre start | ||||
|   let dir = getcwd() | ||||
|   let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' | ||||
|   let jobdir = fnameescape(expand("%:p:h")) | ||||
|   execute cd . jobdir | ||||
|  | ||||
|   call go#statusline#Update(status_dir, { | ||||
|         \ 'desc': "current status", | ||||
|         \ 'type': "coverage", | ||||
|         \ 'state': "started", | ||||
|         \}) | ||||
|  | ||||
|   call job_start(a:args.cmd, start_options) | ||||
|  | ||||
|   " post start | ||||
|   execute cd . fnameescape(dir) | ||||
|   let $GOPATH = old_gopath | ||||
| endfunction | ||||
|  | ||||
| " coverage_callback is called when the coverage execution is finished | ||||
| function! s:coverage_callback(coverfile, job, exit_status, data) | ||||
|   if a:exit_status == 0 | ||||
|     call go#coverage#overlay(a:coverfile) | ||||
|   endif | ||||
|  | ||||
|   call delete(a:coverfile) | ||||
| endfunction | ||||
|  | ||||
| function! s:coverage_browser_callback(coverfile, job, exit_status, data) | ||||
|   if a:exit_status == 0 | ||||
|     let openHTML = 'go tool cover -html='.a:coverfile | ||||
|     call go#tool#ExecuteInDir(openHTML) | ||||
|   endif | ||||
|  | ||||
|   call delete(a:coverfile) | ||||
| endfunction | ||||
|  | ||||
| " ----------------------- | ||||
| " | Neovim job handlers | | ||||
| " ----------------------- | ||||
| @ -251,7 +339,7 @@ endfunction | ||||
| let s:coverage_handler_jobs = {} | ||||
| let s:coverage_browser_handler_jobs = {} | ||||
|  | ||||
| function! s:coverage_handler(job, exit_status, data) | ||||
| function! s:coverage_handler(job, exit_status, data) abort | ||||
|   if !has_key(s:coverage_handler_jobs, a:job.id) | ||||
|     return | ||||
|   endif | ||||
| @ -264,7 +352,7 @@ function! s:coverage_handler(job, exit_status, data) | ||||
|   unlet s:coverage_handler_jobs[a:job.id] | ||||
| endfunction | ||||
|  | ||||
| function! s:coverage_browser_handler(job, exit_status, data) | ||||
| function! s:coverage_browser_handler(job, exit_status, data) abort | ||||
|   if !has_key(s:coverage_browser_handler_jobs, a:job.id) | ||||
|     return | ||||
|   endif | ||||
| @ -279,4 +367,5 @@ function! s:coverage_browser_handler(job, exit_status, data) | ||||
|   unlet s:coverage_browser_handler_jobs[a:job.id] | ||||
| endfunction | ||||
|  | ||||
|  | ||||
| " vim: sw=2 ts=2 et | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| let s:go_stack = [] | ||||
| let s:go_stack_level = 0 | ||||
|  | ||||
| function! go#def#Jump(mode) | ||||
| function! go#def#Jump(mode) abort | ||||
|   let old_gopath = $GOPATH | ||||
|   let $GOPATH = go#path#Detect() | ||||
|  | ||||
| @ -27,42 +27,53 @@ function! go#def#Jump(mode) | ||||
|     endif | ||||
|     let command = printf("%s -f=%s -o=%s -t", bin_path, fname, go#util#OffsetCursor()) | ||||
|     let out = go#util#System(command) | ||||
|  | ||||
|     " append the type information to the same line so our | ||||
|     " jump_to_declaration() function can parse it. This makes it | ||||
|     " compatible with guru definition as well too | ||||
|     let out = join(split(out, '\n'), ':') | ||||
|     if exists("l:tmpname") | ||||
|       call delete(l:tmpname) | ||||
|     endif | ||||
|  | ||||
|   elseif bin_name == 'guru' | ||||
|     let flags = "" | ||||
|     let in = "" | ||||
|  | ||||
|     if &modified | ||||
|       let sep = go#util#LineEnding() | ||||
|       let content  = join(getline(1, '$'), sep) | ||||
|       let in = fname . "\n" . strlen(content) . "\n" . content | ||||
|       let flags .= " -modified" | ||||
|     endif | ||||
|  | ||||
|     let bin_path = go#path#CheckBinPath("guru") | ||||
|     if empty(bin_path) | ||||
|       let $GOPATH = old_gopath | ||||
|       return | ||||
|     endif | ||||
|  | ||||
|     if exists('g:go_guru_tags') | ||||
|       let tags = get(g:, 'go_guru_tags') | ||||
|       let flags .= printf(" -tags %s", tags) | ||||
|     endif | ||||
|  | ||||
|     let fname = shellescape(fname.':#'.go#util#OffsetCursor()) | ||||
|     let command = printf("%s %s definition %s", bin_path, flags, fname) | ||||
|     let cmd = [bin_path] | ||||
|     let stdin_content = "" | ||||
|  | ||||
|     if &modified | ||||
|       let out = go#util#System(command, in) | ||||
|       let sep = go#util#LineEnding() | ||||
|       let content  = join(getline(1, '$'), sep) | ||||
|       let stdin_content = fname . "\n" . strlen(content) . "\n" . content | ||||
|       call add(cmd, "-modified") | ||||
|     endif | ||||
|  | ||||
|     if exists('g:go_guru_tags') | ||||
|       let tags = get(g:, 'go_guru_tags') | ||||
|       call extend(cmd, ["-tags", tags]) | ||||
|     endif | ||||
|  | ||||
|     let fname = fname.':#'.go#util#OffsetCursor() | ||||
|     call extend(cmd, ["definition", fname]) | ||||
|  | ||||
|     if go#util#has_job() | ||||
|       let l:spawn_args = { | ||||
|             \ 'cmd': cmd, | ||||
|             \ 'custom_cb': function('s:jump_to_declaration_cb', [a:mode, bin_name]), | ||||
|             \ } | ||||
|  | ||||
|       if &modified | ||||
|         let l:spawn_args.input = stdin_content | ||||
|       endif | ||||
|  | ||||
|       call go#util#EchoProgress("searching declaration ...") | ||||
|  | ||||
|       call s:def_job(spawn_args) | ||||
|       return | ||||
|     endif | ||||
|  | ||||
|     let command = join(cmd, " ") | ||||
|     if &modified | ||||
|       let out = go#util#System(command, stdin_content) | ||||
|     else | ||||
|       let out = go#util#System(command) | ||||
|     endif | ||||
| @ -76,13 +87,28 @@ function! go#def#Jump(mode) | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   call s:jump_to_declaration(out, a:mode) | ||||
|   call s:jump_to_declaration(out, a:mode, bin_name) | ||||
|   let $GOPATH = old_gopath | ||||
| endfunction | ||||
|  | ||||
| function! s:jump_to_declaration(out, mode) | ||||
| function! s:jump_to_declaration_cb(mode, bin_name, job, exit_status, data) abort | ||||
|   if a:exit_status != 0 | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   call s:jump_to_declaration(a:data[0], a:mode, a:bin_name) | ||||
| endfunction | ||||
|  | ||||
| function! s:jump_to_declaration(out, mode, bin_name) abort | ||||
|   let final_out = a:out | ||||
|   if a:bin_name == "godef" | ||||
|     " append the type information to the same line so our we can parse it. | ||||
|     " This makes it compatible with guru output. | ||||
|     let final_out = join(split(a:out, '\n'), ':') | ||||
|   endif | ||||
|  | ||||
|   " strip line ending | ||||
|   let out = split(a:out, go#util#LineEnding())[0] | ||||
|   let out = split(final_out, go#util#LineEnding())[0] | ||||
|   if go#util#IsWin() | ||||
|     let parts = split(out, '\(^[a-zA-Z]\)\@<!:') | ||||
|   else | ||||
| @ -120,19 +146,27 @@ function! s:jump_to_declaration(out, mode) | ||||
|     if get(g:, 'go_def_reuse_buffer', 0) && bufloaded(filename) != 0 && bufwinnr(filename) != -1 | ||||
|       " jumpt to existing buffer if it exists | ||||
|       execute bufwinnr(filename) . 'wincmd w' | ||||
|     elseif a:mode == "tab" | ||||
|       let &switchbuf = "usetab" | ||||
|       if bufloaded(filename) == 0 | ||||
|         tab split | ||||
|     else | ||||
|       if &modified | ||||
|         let cmd = 'hide edit' | ||||
|       else | ||||
|         let cmd = 'edit' | ||||
|       endif | ||||
|     elseif a:mode == "split" | ||||
|       split | ||||
|     elseif a:mode == "vsplit" | ||||
|       vsplit | ||||
|     endif | ||||
|  | ||||
|     " open the file and jump to line and column | ||||
|     exec 'edit' filename | ||||
|       if a:mode == "tab" | ||||
|         let &switchbuf = "usetab" | ||||
|         if bufloaded(filename) == 0 | ||||
|           tab split | ||||
|         endif | ||||
|       elseif a:mode == "split" | ||||
|         split | ||||
|       elseif a:mode == "vsplit" | ||||
|         vsplit | ||||
|       endif | ||||
|  | ||||
|       " open the file and jump to line and column | ||||
|       exec cmd filename | ||||
|     endif | ||||
|   endif | ||||
|   call cursor(line, col) | ||||
|  | ||||
| @ -142,7 +176,7 @@ function! s:jump_to_declaration(out, mode) | ||||
|   let &switchbuf = old_switchbuf | ||||
| endfunction | ||||
|  | ||||
| function! go#def#SelectStackEntry() | ||||
| function! go#def#SelectStackEntry() abort | ||||
|   let target_window = go#ui#GetReturnWindow() | ||||
|   if empty(target_window) | ||||
|     let target_window = winnr() | ||||
| @ -157,7 +191,7 @@ function! go#def#SelectStackEntry() | ||||
|   call go#ui#CloseWindow() | ||||
| endfunction | ||||
|  | ||||
| function! go#def#StackUI() | ||||
| function! go#def#StackUI() abort | ||||
|   if len(s:go_stack) == 0 | ||||
|     call go#util#EchoError("godef stack empty") | ||||
|     return | ||||
| @ -192,12 +226,12 @@ function! go#def#StackUI() | ||||
|   noremap <buffer> <silent> q     :<C-U>call go#ui#CloseWindow()<CR> | ||||
| endfunction | ||||
|  | ||||
| function! go#def#StackClear(...) | ||||
| function! go#def#StackClear(...) abort | ||||
|   let s:go_stack = [] | ||||
|   let s:go_stack_level = 0 | ||||
| endfunction | ||||
|  | ||||
| function! go#def#StackPop(...) | ||||
| function! go#def#StackPop(...) abort | ||||
|   if len(s:go_stack) == 0 | ||||
|     call go#util#EchoError("godef stack empty") | ||||
|     return | ||||
| @ -218,7 +252,7 @@ function! go#def#StackPop(...) | ||||
|   call go#def#Stack(newLevel + 1) | ||||
| endfunction | ||||
|  | ||||
| function! go#def#Stack(...) | ||||
| function! go#def#Stack(...) abort | ||||
|   if len(s:go_stack) == 0 | ||||
|     call go#util#EchoError("godef stack empty") | ||||
|     return | ||||
| @ -246,7 +280,13 @@ function! go#def#Stack(...) | ||||
|     let target = s:go_stack[s:go_stack_level] | ||||
|  | ||||
|     " jump | ||||
|     exec 'edit' target["file"] | ||||
|     if expand('%:p') != target["file"] | ||||
|       if &modified | ||||
|         exec 'hide edit' target["file"] | ||||
|       else | ||||
|         exec 'edit' target["file"] | ||||
|       endif | ||||
|     endif | ||||
|     call cursor(target["line"], target["col"]) | ||||
|     normal! zz | ||||
|   else | ||||
| @ -254,4 +294,27 @@ function! go#def#Stack(...) | ||||
|   endif | ||||
| endfunction | ||||
|  | ||||
| function s:def_job(args) abort | ||||
|   function! s:error_info_cb(job, exit_status, data) closure | ||||
|     " do not print anything during async definition search&jump | ||||
|   endfunction | ||||
|  | ||||
|   let a:args.error_info_cb = function('s:error_info_cb') | ||||
|   let callbacks = go#job#Spawn(a:args) | ||||
|  | ||||
|   let start_options = { | ||||
|         \ 'callback': callbacks.callback, | ||||
|         \ 'close_cb': callbacks.close_cb, | ||||
|         \ } | ||||
|  | ||||
|   if &modified | ||||
|     let l:tmpname = tempname() | ||||
|     call writefile(split(a:args.input, "\n"), l:tmpname, "b") | ||||
|     let l:start_options.in_io = "file" | ||||
|     let l:start_options.in_name = l:tmpname | ||||
|   endif | ||||
|  | ||||
|   call job_start(a:args.cmd, start_options) | ||||
| endfunction | ||||
|  | ||||
| " vim: sw=2 ts=2 et | ||||
|  | ||||
| @ -12,57 +12,39 @@ if !exists("g:go_doc_options") | ||||
|   let g:go_doc_options = "" | ||||
| endif | ||||
|  | ||||
| " returns the package and exported name. exported name might be empty. | ||||
| " ie: fmt and Println | ||||
| " ie: github.com/fatih/set and New | ||||
| function! s:godocWord(args) | ||||
|   if !executable('godoc') | ||||
|     let msg = "godoc command not found." | ||||
|     let msg .= "  install with: go get golang.org/x/tools/cmd/godoc" | ||||
|     call go#util#EchoWarning(msg) | ||||
|     return [] | ||||
| function! go#doc#OpenBrowser(...) abort | ||||
|   " check if we have gogetdoc as it gives us more and accurate information. | ||||
|   " Only supported if we have json_decode as it's not worth to parse the plain | ||||
|   " non-json output of gogetdoc | ||||
|   let bin_path = go#path#CheckBinPath('gogetdoc') | ||||
|   if !empty(bin_path) && exists('*json_decode') | ||||
|     let json_out = s:gogetdoc(1) | ||||
|     if go#util#ShellError() != 0 | ||||
|       call go#util#EchoError(json_out) | ||||
|       return | ||||
|     endif | ||||
|  | ||||
|     let out = json_decode(json_out) | ||||
|     if type(out) != type({}) | ||||
|       call go#util#EchoError("gogetdoc output is malformed") | ||||
|     endif | ||||
|  | ||||
|     let import = out["import"] | ||||
|     let name = out["name"] | ||||
|  | ||||
|     " if import is empty, it means we selected a package name | ||||
|     if import ==# "" | ||||
|       let godoc_url = "https://godoc.org/" . name  | ||||
|     else | ||||
|       let godoc_url = "https://godoc.org/" . import . "#" . name | ||||
|     endif | ||||
|  | ||||
|     echo godoc_url | ||||
|  | ||||
|     call go#tool#OpenBrowser(godoc_url) | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   if !len(a:args) | ||||
|     let oldiskeyword = &iskeyword | ||||
|     setlocal iskeyword+=. | ||||
|     let word = expand('<cword>') | ||||
|     let &iskeyword = oldiskeyword | ||||
|     let word = substitute(word, '[^a-zA-Z0-9\\/._~-]', '', 'g') | ||||
|     let words = split(word, '\.\ze[^./]\+$') | ||||
|   else | ||||
|     let words = a:args | ||||
|   endif | ||||
|  | ||||
|   if !len(words) | ||||
|     return [] | ||||
|   endif | ||||
|  | ||||
|   let pkg = words[0] | ||||
|   if len(words) == 1 | ||||
|     let exported_name = "" | ||||
|   else | ||||
|     let exported_name = words[1] | ||||
|   endif | ||||
|  | ||||
|   let packages = go#tool#Imports() | ||||
|  | ||||
|   if has_key(packages, pkg) | ||||
|     let pkg = packages[pkg] | ||||
|   endif | ||||
|  | ||||
|   return [pkg, exported_name] | ||||
| endfunction | ||||
|  | ||||
| function! s:godocNotFound(content) | ||||
|   if len(a:content) == 0 | ||||
|     return 1 | ||||
|   endif | ||||
|  | ||||
|   return a:content =~# '^.*: no such file or directory\n$' | ||||
| endfunction | ||||
|  | ||||
| function! go#doc#OpenBrowser(...) | ||||
|   let pkgs = s:godocWord(a:000) | ||||
|   if empty(pkgs) | ||||
|     return | ||||
| @ -76,7 +58,7 @@ function! go#doc#OpenBrowser(...) | ||||
|   call go#tool#OpenBrowser(godoc_url) | ||||
| endfunction | ||||
|  | ||||
| function! go#doc#Open(newmode, mode, ...) | ||||
| function! go#doc#Open(newmode, mode, ...) abort | ||||
|   if len(a:000) | ||||
|     " check if we have 'godoc' and use it automatically | ||||
|     let bin_path = go#path#CheckBinPath('godoc') | ||||
| @ -87,34 +69,7 @@ function! go#doc#Open(newmode, mode, ...) | ||||
|     let command = printf("%s %s", bin_path, join(a:000, ' ')) | ||||
|     let out = go#util#System(command) | ||||
|   else | ||||
|     " check if we have 'gogetdoc' and use it automatically | ||||
|     let bin_path = go#path#CheckBinPath('gogetdoc') | ||||
|     if empty(bin_path) | ||||
|       return | ||||
|     endif | ||||
|  | ||||
|     let offset = go#util#OffsetCursor() | ||||
|     let fname = expand("%:p:gs!\\!/!") | ||||
|     let pos = shellescape(fname.':#'.offset) | ||||
|     let command = printf("%s -pos %s", bin_path, pos) | ||||
|  | ||||
|     if &modified | ||||
|       " gogetdoc supports the same archive format as guru for dealing with | ||||
|       " modified buffers. | ||||
|       "   use the -modified flag | ||||
|       "   write each archive entry on stdin as: | ||||
|       "     filename followed by newline | ||||
|       "     file size followed by newline | ||||
|       "     file contents | ||||
|       let in = "" | ||||
|       let sep = go#util#LineEnding() | ||||
|       let content = join(getline(1, '$'), sep) | ||||
|       let in = fname . "\n" . strlen(content) . "\n" . content | ||||
|       let command .= " -modified" | ||||
|       let out = go#util#System(command, in) | ||||
|     else | ||||
|       let out = go#util#System(command) | ||||
|     endif | ||||
|     let out = s:gogetdoc(0) | ||||
|   endif | ||||
|  | ||||
|   if go#util#ShellError() != 0 | ||||
| @ -125,7 +80,7 @@ function! go#doc#Open(newmode, mode, ...) | ||||
|   call s:GodocView(a:newmode, a:mode, out) | ||||
| endfunction | ||||
|  | ||||
| function! s:GodocView(newposition, position, content) | ||||
| function! s:GodocView(newposition, position, content) abort | ||||
|   " reuse existing buffer window if it exists otherwise create a new one | ||||
|   if !bufexists(s:buf_nr) | ||||
|     execute a:newposition | ||||
| @ -169,4 +124,96 @@ function! s:GodocView(newposition, position, content) | ||||
|   noremap <buffer> <silent> <Esc> :<C-U>close<CR> | ||||
| endfunction | ||||
|  | ||||
| function! s:gogetdoc(json) abort | ||||
|   " check if we have 'gogetdoc' and use it automatically | ||||
|   let bin_path = go#path#CheckBinPath('gogetdoc') | ||||
|   if empty(bin_path) | ||||
|     return -1 | ||||
|   endif | ||||
|  | ||||
|   let cmd =  [bin_path] | ||||
|  | ||||
|   let offset = go#util#OffsetCursor() | ||||
|   let fname = expand("%:p:gs!\\!/!") | ||||
|   let pos = shellescape(fname.':#'.offset) | ||||
|  | ||||
|   let cmd += ["-pos", pos] | ||||
|   if a:json | ||||
|     let cmd += ["-json"] | ||||
|   endif | ||||
|  | ||||
|   let command = join(cmd, " ") | ||||
|  | ||||
|   if &modified | ||||
|     " gogetdoc supports the same archive format as guru for dealing with | ||||
|     " modified buffers. | ||||
|     "   use the -modified flag | ||||
|     "   write each archive entry on stdin as: | ||||
|     "     filename followed by newline | ||||
|     "     file size followed by newline | ||||
|     "     file contents | ||||
|     let in = "" | ||||
|     let sep = go#util#LineEnding() | ||||
|     let content = join(getline(1, '$'), sep) | ||||
|     let in = fname . "\n" . strlen(content) . "\n" . content | ||||
|     let command .= " -modified" | ||||
|     let out = go#util#System(command, in) | ||||
|   else | ||||
|     let out = go#util#System(command) | ||||
|   endif | ||||
|  | ||||
|   return out | ||||
| endfunction | ||||
|  | ||||
| " returns the package and exported name. exported name might be empty. | ||||
| " ie: fmt and Println | ||||
| " ie: github.com/fatih/set and New | ||||
| function! s:godocWord(args) abort | ||||
|   if !executable('godoc') | ||||
|     let msg = "godoc command not found." | ||||
|     let msg .= "  install with: go get golang.org/x/tools/cmd/godoc" | ||||
|     call go#util#EchoWarning(msg) | ||||
|     return [] | ||||
|   endif | ||||
|  | ||||
|   if !len(a:args) | ||||
|     let oldiskeyword = &iskeyword | ||||
|     setlocal iskeyword+=. | ||||
|     let word = expand('<cword>') | ||||
|     let &iskeyword = oldiskeyword | ||||
|     let word = substitute(word, '[^a-zA-Z0-9\\/._~-]', '', 'g') | ||||
|     let words = split(word, '\.\ze[^./]\+$') | ||||
|   else | ||||
|     let words = a:args | ||||
|   endif | ||||
|  | ||||
|   if !len(words) | ||||
|     return [] | ||||
|   endif | ||||
|  | ||||
|   let pkg = words[0] | ||||
|   if len(words) == 1 | ||||
|     let exported_name = "" | ||||
|   else | ||||
|     let exported_name = words[1] | ||||
|   endif | ||||
|  | ||||
|   let packages = go#tool#Imports() | ||||
|  | ||||
|   if has_key(packages, pkg) | ||||
|     let pkg = packages[pkg] | ||||
|   endif | ||||
|  | ||||
|   return [pkg, exported_name] | ||||
| endfunction | ||||
|  | ||||
| function! s:godocNotFound(content) abort | ||||
|   if len(a:content) == 0 | ||||
|     return 1 | ||||
|   endif | ||||
|  | ||||
|   return a:content =~# '^.*: no such file or directory\n$' | ||||
| endfunction | ||||
|  | ||||
|  | ||||
| " vim: sw=2 ts=2 et | ||||
|  | ||||
| @ -51,7 +51,7 @@ endif | ||||
| "  it doesn't undo changes and break undo history.  If you are here reading | ||||
| "  this and have VimL experience, please look at the function for | ||||
| "  improvements, patches are welcome :) | ||||
| function! go#fmt#Format(withGoimport) | ||||
| function! go#fmt#Format(withGoimport) abort | ||||
|   if g:go_fmt_experimental == 1 | ||||
|     " Using winsaveview to save/restore cursor state has the problem of | ||||
|     " closing folds on save: | ||||
| @ -185,7 +185,7 @@ function! go#fmt#Format(withGoimport) | ||||
|       % | " Couldn't detect gofmt error format, output errors | ||||
|     endif | ||||
|     if !empty(errors) | ||||
|       call go#list#Populate(l:listtype, errors) | ||||
|       call go#list#Populate(l:listtype, errors, 'Format') | ||||
|       echohl Error | echomsg "Gofmt returned error" | echohl None | ||||
|     endif | ||||
|  | ||||
| @ -215,7 +215,7 @@ function! go#fmt#Format(withGoimport) | ||||
|   endif | ||||
| endfunction | ||||
|  | ||||
| function! go#fmt#ToggleFmtAutoSave() | ||||
| function! go#fmt#ToggleFmtAutoSave() abort | ||||
|   if get(g:, "go_fmt_autosave", 1) | ||||
|     let g:go_fmt_autosave = 0 | ||||
|     call go#util#EchoProgress("auto fmt disabled") | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| function! go#impl#Impl(...) | ||||
| function! go#impl#Impl(...) abort | ||||
|   let binpath = go#path#CheckBinPath('impl') | ||||
|   if empty(binpath) | ||||
|     return | ||||
| @ -69,7 +69,7 @@ else | ||||
|   endfunction | ||||
| endif | ||||
|  | ||||
| function! s:root_dirs() | ||||
| function! s:root_dirs() abort | ||||
|   let dirs = [] | ||||
|   let root = go#util#goroot() | ||||
|   if root !=# '' && isdirectory(root) | ||||
| @ -88,7 +88,7 @@ function! s:root_dirs() | ||||
|   return dirs | ||||
| endfunction | ||||
|  | ||||
| function! s:go_packages(dirs) | ||||
| function! s:go_packages(dirs) abort | ||||
|   let pkgs = [] | ||||
|   for d in a:dirs | ||||
|     let pkg_root = expand(d . '/pkg/' . go#util#osarch()) | ||||
| @ -97,7 +97,7 @@ function! s:go_packages(dirs) | ||||
|   return map(pkgs, "fnamemodify(v:val, ':t:r')") | ||||
| endfunction | ||||
|  | ||||
| function! s:interface_list(pkg) | ||||
| function! s:interface_list(pkg) abort | ||||
|   let contents = split(go#util#System('go doc ' . a:pkg), "\n") | ||||
|   if go#util#ShellError() | ||||
|     return [] | ||||
| @ -108,7 +108,7 @@ function! s:interface_list(pkg) | ||||
| endfunction | ||||
|  | ||||
| " Complete package and interface for {interface} | ||||
| function! go#impl#Complete(arglead, cmdline, cursorpos) | ||||
| function! go#impl#Complete(arglead, cmdline, cursorpos) abort | ||||
|   let words = split(a:cmdline, '\s\+', 1) | ||||
|   if words[-1] ==# '' | ||||
|     return s:uniq(sort(s:go_packages(s:root_dirs()))) | ||||
|  | ||||
| @ -4,7 +4,7 @@ | ||||
| " | ||||
| " Check out the docs for more information at /doc/vim-go.txt | ||||
| " | ||||
| function! go#import#SwitchImport(enabled, localname, path, bang) | ||||
| function! go#import#SwitchImport(enabled, localname, path, bang) abort | ||||
|   let view = winsaveview() | ||||
|   let path = substitute(a:path, '^\s*\(.\{-}\)\s*$', '\1', '') | ||||
|  | ||||
| @ -205,7 +205,7 @@ function! go#import#SwitchImport(enabled, localname, path, bang) | ||||
| endfunction | ||||
|  | ||||
|  | ||||
| function! s:Error(s) | ||||
| function! s:Error(s) abort | ||||
|   echohl Error | echo a:s | echohl None | ||||
| endfunction | ||||
|  | ||||
|  | ||||
							
								
								
									
										109
									
								
								sources_non_forked/vim-go/autoload/go/job.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								sources_non_forked/vim-go/autoload/go/job.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,109 @@ | ||||
| " Spawn returns callbacks to be used with job_start.  It's abstracted to be | ||||
| " used with various go command, such as build, test, install, etc.. This avoid | ||||
| " us to write the same callback over and over for some commands. It's fully | ||||
| " customizable so each command can change it to it's own logic. | ||||
| function go#job#Spawn(args) | ||||
|   let cbs = { | ||||
|         \ 'winnr': winnr(), | ||||
|         \ 'dir': getcwd(), | ||||
|         \ 'jobdir': fnameescape(expand("%:p:h")), | ||||
|         \ 'messages': [], | ||||
|         \ 'args': a:args.cmd, | ||||
|         \ 'bang': 0, | ||||
|         \ } | ||||
|  | ||||
|   if has_key(a:args, 'bang') | ||||
|     let cbs.bang = a:args.bang | ||||
|   endif | ||||
|  | ||||
|   " add final callback to be called if async job is finished | ||||
|   " The signature should be in form: func(job, exit_status, messages) | ||||
|   if has_key(a:args, 'custom_cb') | ||||
|     let cbs.custom_cb = a:args.custom_cb | ||||
|   endif | ||||
|  | ||||
|   if has_key(a:args, 'error_info_cb') | ||||
|     let cbs.error_info_cb = a:args.error_info_cb | ||||
|   endif | ||||
|  | ||||
|   function cbs.callback(chan, msg) dict | ||||
|     call add(self.messages, a:msg) | ||||
|   endfunction | ||||
|  | ||||
|   function cbs.close_cb(chan) dict | ||||
|     let l:job = ch_getjob(a:chan) | ||||
|     let l:status = job_status(l:job) | ||||
|  | ||||
|     " the job might be in fail status, we assume by default it's failed. | ||||
|     " However if it's dead, we can use the real exitval | ||||
|     let exitval = 1 | ||||
|     if l:status == "dead" | ||||
|       let l:info = job_info(l:job) | ||||
|       let exitval = l:info.exitval | ||||
|     endif | ||||
|  | ||||
|     if has_key(self, 'custom_cb') | ||||
|       call self.custom_cb(l:job, exitval, self.messages) | ||||
|     endif | ||||
|  | ||||
|     if has_key(self, 'error_info_cb') | ||||
|       call self.error_info_cb(l:job, exitval, self.messages) | ||||
|     endif | ||||
|  | ||||
|     if get(g:, 'go_echo_command_info', 1) | ||||
|       if exitval == 0 | ||||
|         call go#util#EchoSuccess("SUCCESS") | ||||
|       else | ||||
|         call go#util#EchoError("FAILED") | ||||
|       endif | ||||
|     endif | ||||
|  | ||||
|     let l:listtype = go#list#Type("quickfix") | ||||
|     if exitval == 0 | ||||
|       call go#list#Clean(l:listtype) | ||||
|       call go#list#Window(l:listtype) | ||||
|       return | ||||
|     endif | ||||
|  | ||||
|     call self.show_errors(l:listtype) | ||||
|   endfunction | ||||
|  | ||||
|   function cbs.show_errors(listtype) dict | ||||
|     let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' | ||||
|     try | ||||
|       execute cd self.jobdir | ||||
|       let errors = go#tool#ParseErrors(self.messages) | ||||
|       let errors = go#tool#FilterValids(errors) | ||||
|     finally | ||||
|       execute cd . fnameescape(self.dir) | ||||
|     endtry | ||||
|  | ||||
|     if !len(errors) | ||||
|       " failed to parse errors, output the original content | ||||
|       call go#util#EchoError(join(self.messages, " ")) | ||||
|       call go#util#EchoError(self.dir) | ||||
|       return | ||||
|     endif | ||||
|  | ||||
|     if self.winnr == winnr() | ||||
|       call go#list#Populate(a:listtype, errors, join(self.args)) | ||||
|       call go#list#Window(a:listtype, len(errors)) | ||||
|       if !empty(errors) && !self.bang | ||||
|         call go#list#JumpToFirst(a:listtype) | ||||
|       endif | ||||
|     endif | ||||
|   endfunction | ||||
|  | ||||
|   " override callback handler if user provided it | ||||
|   if has_key(a:args, 'callback') | ||||
|     let cbs.callback = a:args.callback | ||||
|   endif | ||||
|  | ||||
|   " override close callback handler if user provided it | ||||
|   if has_key(a:args, 'close_cb') | ||||
|     let cbs.close_cb = a:args.close_cb | ||||
|   endif | ||||
|  | ||||
|   return cbs | ||||
| endfunction | ||||
| " vim: sw=2 ts=2 et | ||||
| @ -9,7 +9,7 @@ let s:handlers = {} | ||||
| " Spawn is a wrapper around s:spawn. It can be executed by other files and | ||||
| " scripts if needed. Desc defines the description for printing the status | ||||
| " during the job execution (useful for statusline integration). | ||||
| function! go#jobcontrol#Spawn(bang, desc, args) | ||||
| function! go#jobcontrol#Spawn(bang, desc, args) abort | ||||
|   " autowrite is not enabled for jobs | ||||
|   call go#cmd#autowrite() | ||||
|  | ||||
| @ -17,31 +17,8 @@ function! go#jobcontrol#Spawn(bang, desc, args) | ||||
|   return job.id | ||||
| endfunction | ||||
|  | ||||
| " Statusline returns the current status of the job | ||||
| function! go#jobcontrol#Statusline() abort | ||||
|   if empty(s:jobs) | ||||
|     return '' | ||||
|   endif | ||||
|  | ||||
|   let import_path =  go#package#ImportPath(expand('%:p:h')) | ||||
|  | ||||
|   for job in values(s:jobs) | ||||
|     if job.importpath != import_path | ||||
|       continue | ||||
|     endif | ||||
|  | ||||
|     if job.state == "SUCCESS" | ||||
|       return '' | ||||
|     endif | ||||
|  | ||||
|     return printf("%s ... [%s]", job.desc, job.state) | ||||
|   endfor | ||||
|  | ||||
|   return '' | ||||
| endfunction | ||||
|  | ||||
| " AddHandler adds a on_exit callback handler and returns the id. | ||||
| function! go#jobcontrol#AddHandler(handler) | ||||
| function! go#jobcontrol#AddHandler(handler) abort | ||||
|   let i = len(s:handlers) | ||||
|   while has_key(s:handlers, string(i)) | ||||
|     let i += 1 | ||||
| @ -52,7 +29,7 @@ function! go#jobcontrol#AddHandler(handler) | ||||
| endfunction | ||||
|  | ||||
| " RemoveHandler removes a callback handler by id. | ||||
| function! go#jobcontrol#RemoveHandler(id) | ||||
| function! go#jobcontrol#RemoveHandler(id) abort | ||||
|   unlet s:handlers[a:id] | ||||
| endfunction | ||||
|  | ||||
| @ -60,10 +37,10 @@ endfunction | ||||
| " a job is started a reference will be stored inside s:jobs. spawn changes the | ||||
| " GOPATH when g:go_autodetect_gopath is enabled. The job is started inside the | ||||
| " current files folder. | ||||
| function! s:spawn(bang, desc, args) | ||||
|   let job = {  | ||||
|         \ 'desc': a:desc,  | ||||
|         \ 'bang': a:bang,  | ||||
| function! s:spawn(bang, desc, args) abort | ||||
|   let job = { | ||||
|         \ 'desc': a:desc, | ||||
|         \ 'bang': a:bang, | ||||
|         \ 'winnr': winnr(), | ||||
|         \ 'importpath': go#package#ImportPath(expand('%:p:h')), | ||||
|         \ 'state': "RUNNING", | ||||
| @ -113,7 +90,7 @@ endfunction | ||||
| " references and also displaying errors in the quickfix window collected by | ||||
| " on_stderr handler. If there are no errors and a quickfix window is open, | ||||
| " it'll be closed. | ||||
| function! s:on_exit(job_id, exit_status) | ||||
| function! s:on_exit(job_id, exit_status, event) dict abort | ||||
|   let std_combined = self.stderr + self.stdout | ||||
|  | ||||
|   let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' | ||||
| @ -122,9 +99,10 @@ function! s:on_exit(job_id, exit_status) | ||||
|  | ||||
|   call s:callback_handlers_on_exit(s:jobs[a:job_id], a:exit_status, std_combined) | ||||
|  | ||||
|   let l:listtype = go#list#Type("quickfix") | ||||
|   if a:exit_status == 0 | ||||
|     call go#list#Clean(0) | ||||
|     call go#list#Window(0) | ||||
|     call go#list#Clean(l:listtype) | ||||
|     call go#list#Window(l:listtype) | ||||
|  | ||||
|     let self.state = "SUCCESS" | ||||
|     call go#util#EchoSuccess("SUCCESS") | ||||
| @ -149,8 +127,7 @@ function! s:on_exit(job_id, exit_status) | ||||
|  | ||||
|   " if we are still in the same windows show the list | ||||
|   if self.winnr == winnr() | ||||
|     let l:listtype = "locationlist" | ||||
|     call go#list#Populate(l:listtype, errors) | ||||
|     call go#list#Populate(l:listtype, errors, self.desc) | ||||
|     call go#list#Window(l:listtype, len(errors)) | ||||
|     if !empty(errors) && !self.bang | ||||
|       call go#list#JumpToFirst(l:listtype) | ||||
| @ -159,7 +136,7 @@ function! s:on_exit(job_id, exit_status) | ||||
| endfunction | ||||
|  | ||||
| " callback_handlers_on_exit runs all handlers for job on exit event. | ||||
| function! s:callback_handlers_on_exit(job, exit_status, data) | ||||
| function! s:callback_handlers_on_exit(job, exit_status, data) abort | ||||
|   if empty(s:handlers) | ||||
|     return | ||||
|   endif | ||||
| @ -170,45 +147,15 @@ function! s:callback_handlers_on_exit(job, exit_status, data) | ||||
| endfunction | ||||
|  | ||||
| " on_stdout is the stdout handler for jobstart(). It collects the output of | ||||
| " stderr and stores them to the jobs internal stdout list.  | ||||
| function! s:on_stdout(job_id, data) | ||||
| " stderr and stores them to the jobs internal stdout list. | ||||
| function! s:on_stdout(job_id, data) dict abort | ||||
|   call extend(self.stdout, a:data) | ||||
| endfunction | ||||
|  | ||||
| " on_stderr is the stderr handler for jobstart(). It collects the output of | ||||
| " stderr and stores them to the jobs internal stderr list. | ||||
| function! s:on_stderr(job_id, data) | ||||
| function! s:on_stderr(job_id, data) dict abort | ||||
|   call extend(self.stderr, a:data) | ||||
| endfunction | ||||
|  | ||||
| " abort_all aborts all current jobs created with s:spawn() | ||||
| function! s:abort_all() | ||||
|   if empty(s:jobs) | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   for id in keys(s:jobs) | ||||
|     if id > 0 | ||||
|       silent! call jobstop(id) | ||||
|     endif | ||||
|   endfor | ||||
|  | ||||
|   let s:jobs = {} | ||||
| endfunction | ||||
|  | ||||
| " abort aborts the job with the given name, where name is the first argument | ||||
| " passed to s:spawn() | ||||
| function! s:abort(path) | ||||
|   if empty(s:jobs) | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   for job in values(s:jobs) | ||||
|     if job.importpath == path && job.id > 0 | ||||
|       silent! call jobstop(job.id) | ||||
|       unlet s:jobs['job.id'] | ||||
|     endif | ||||
|   endfor | ||||
| endfunction | ||||
|  | ||||
| " vim: sw=2 ts=2 et | ||||
|  | ||||
| @ -29,37 +29,42 @@ function! go#lint#Gometa(autosave, ...) abort | ||||
|     let goargs = go#util#Shelljoin(a:000) | ||||
|   endif | ||||
|  | ||||
|   let meta_command = "gometalinter --disable-all" | ||||
|   let bin_path = go#path#CheckBinPath("gometalinter") | ||||
|   if empty(bin_path) | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   let cmd = [bin_path] | ||||
|   let cmd += ["--disable-all"] | ||||
|  | ||||
|   if a:autosave || empty(g:go_metalinter_command) | ||||
|     let bin_path = go#path#CheckBinPath("gometalinter") | ||||
|     if empty(bin_path) | ||||
|       return | ||||
|     endif | ||||
|  | ||||
|     if a:autosave | ||||
|       " include only messages for the active buffer | ||||
|       let meta_command .= " --include='^" . expand('%:p') . ".*$'" | ||||
|     endif | ||||
|  | ||||
|     " linters | ||||
|     let linters = a:autosave ? g:go_metalinter_autosave_enabled : g:go_metalinter_enabled | ||||
|     for linter in linters | ||||
|       let meta_command .= " --enable=".linter | ||||
|       let cmd += ["--enable=".linter] | ||||
|     endfor | ||||
|  | ||||
|     " deadline | ||||
|     let meta_command .= " --deadline=" . g:go_metalinter_deadline | ||||
|  | ||||
|     " path | ||||
|     let meta_command .=  " " . goargs | ||||
|     let cmd += [expand('%:p:h')] | ||||
|   else | ||||
|     " the user wants something else, let us use it. | ||||
|     let meta_command = g:go_metalinter_command | ||||
|     let cmd += [split(g:go_metalinter_command, " ")] | ||||
|   endif | ||||
|  | ||||
|   " comment out the following two lines for debugging | ||||
|   " echo meta_command | ||||
|   " return | ||||
|   if go#util#has_job() && has('lambda') | ||||
|     call s:lint_job({'cmd': cmd}) | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   " we add deadline only for sync mode | ||||
|   let cmd += ["--deadline=" . g:go_metalinter_deadline] | ||||
|   if a:autosave | ||||
|     " include only messages for the active buffer | ||||
|     let cmd += ["--include='^" . expand('%:p') . ".*$'"] | ||||
|   endif | ||||
|  | ||||
|  | ||||
|   let meta_command = join(cmd, " ") | ||||
|  | ||||
|   let out = go#tool#ExecuteInDir(meta_command) | ||||
|  | ||||
| @ -77,7 +82,7 @@ function! go#lint#Gometa(autosave, ...) abort | ||||
|     let errformat = "%f:%l:%c:%t%*[^:]:\ %m,%f:%l::%t%*[^:]:\ %m" | ||||
|  | ||||
|     " Parse and populate our location list | ||||
|     call go#list#ParseFormat(l:listtype, errformat, split(out, "\n")) | ||||
|     call go#list#ParseFormat(l:listtype, errformat, split(out, "\n"), 'GoMetaLinter') | ||||
|  | ||||
|     let errors = go#list#Get(l:listtype) | ||||
|     call go#list#Window(l:listtype, len(errors)) | ||||
| @ -117,7 +122,7 @@ endfunction | ||||
|  | ||||
| " Vet calls 'go vet' on the current directory. Any warnings are populated in | ||||
| " the location list | ||||
| function! go#lint#Vet(bang, ...) | ||||
| function! go#lint#Vet(bang, ...) abort | ||||
|   call go#cmd#autowrite() | ||||
|   echon "vim-go: " | echohl Identifier | echon "calling vet..." | echohl None | ||||
|   if a:0 == 0 | ||||
| @ -129,7 +134,7 @@ function! go#lint#Vet(bang, ...) | ||||
|   let l:listtype = "quickfix" | ||||
|   if go#util#ShellError() != 0 | ||||
|     let errors = go#tool#ParseErrors(split(out, '\n')) | ||||
|     call go#list#Populate(l:listtype, errors) | ||||
|     call go#list#Populate(l:listtype, errors, 'Vet') | ||||
|     call go#list#Window(l:listtype, len(errors)) | ||||
|     if !empty(errors) && !a:bang | ||||
|       call go#list#JumpToFirst(l:listtype) | ||||
| @ -171,7 +176,7 @@ function! go#lint#Errcheck(...) abort | ||||
|     let errformat = "%f:%l:%c:\ %m, %f:%l:%c\ %#%m" | ||||
|  | ||||
|     " Parse and populate our location list | ||||
|     call go#list#ParseFormat(l:listtype, errformat, split(out, "\n")) | ||||
|     call go#list#ParseFormat(l:listtype, errformat, split(out, "\n"), 'Errcheck') | ||||
|  | ||||
|     let errors = go#list#Get(l:listtype) | ||||
|  | ||||
| @ -182,7 +187,7 @@ function! go#lint#Errcheck(...) abort | ||||
|     endif | ||||
|  | ||||
|     if !empty(errors) | ||||
|       call go#list#Populate(l:listtype, errors) | ||||
|       call go#list#Populate(l:listtype, errors, 'Errcheck') | ||||
|       call go#list#Window(l:listtype, len(errors)) | ||||
|       if !empty(errors) | ||||
|         call go#list#JumpToFirst(l:listtype) | ||||
| @ -196,7 +201,7 @@ function! go#lint#Errcheck(...) abort | ||||
|  | ||||
| endfunction | ||||
|  | ||||
| function! go#lint#ToggleMetaLinterAutoSave() | ||||
| function! go#lint#ToggleMetaLinterAutoSave() abort | ||||
|   if get(g:, "go_metalinter_autosave", 0) | ||||
|     let g:go_metalinter_autosave = 0 | ||||
|     call go#util#EchoProgress("auto metalinter disabled") | ||||
| @ -207,4 +212,88 @@ function! go#lint#ToggleMetaLinterAutoSave() | ||||
|   call go#util#EchoProgress("auto metalinter enabled") | ||||
| endfunction | ||||
|  | ||||
| function s:lint_job(args) | ||||
|   let status_dir = expand('%:p:h') | ||||
|   let started_at = reltime() | ||||
|  | ||||
|   call go#statusline#Update(status_dir, { | ||||
|         \ 'desc': "current status", | ||||
|         \ 'type': "gometalinter", | ||||
|         \ 'state': "analysing", | ||||
|         \}) | ||||
|  | ||||
|   " autowrite is not enabled for jobs | ||||
|   call go#cmd#autowrite() | ||||
|  | ||||
|   let l:listtype = go#list#Type("quickfix") | ||||
|   let l:errformat = '%f:%l:%c:%t%*[^:]:\ %m,%f:%l::%t%*[^:]:\ %m' | ||||
|  | ||||
|   function! s:callback(chan, msg) closure | ||||
|     let old_errorformat = &errorformat | ||||
|     let &errorformat = l:errformat | ||||
|     caddexpr a:msg | ||||
|     let &errorformat = old_errorformat | ||||
|  | ||||
|     " TODO(arslan): cursor still jumps to first error even If I don't want | ||||
|     " it. Seems like there is a regression somewhere, but not sure where. | ||||
|     copen | ||||
|   endfunction | ||||
|  | ||||
|   function! s:close_cb(chan) closure | ||||
|     let l:job = ch_getjob(a:chan) | ||||
|     let l:status = job_status(l:job) | ||||
|  | ||||
|     let exitval = 1 | ||||
|     if l:status == "dead" | ||||
|       let l:info = job_info(l:job) | ||||
|       let exitval = l:info.exitval | ||||
|     endif | ||||
|  | ||||
|     let status = { | ||||
|           \ 'desc': 'last status', | ||||
|           \ 'type': "gometaliner", | ||||
|           \ 'state': "finished", | ||||
|           \ } | ||||
|  | ||||
|     if exitval | ||||
|       let status.state = "failed" | ||||
|     endif | ||||
|  | ||||
|     let elapsed_time = reltimestr(reltime(started_at)) | ||||
|     " strip whitespace | ||||
|     let elapsed_time = substitute(elapsed_time, '^\s*\(.\{-}\)\s*$', '\1', '') | ||||
|     let status.state .= printf(" (%ss)", elapsed_time) | ||||
|  | ||||
|     call go#statusline#Update(status_dir, status) | ||||
|  | ||||
|     let errors = go#list#Get(l:listtype) | ||||
|     if empty(errors)  | ||||
|       call go#list#Window(l:listtype, len(errors)) | ||||
|     elseif has("patch-7.4.2200") | ||||
|       if l:listtype == 'quickfix' | ||||
|         call setqflist([], 'a', {'title': 'GoMetaLinter'}) | ||||
|       else | ||||
|         call setloclist(0, [], 'a', {'title': 'GoMetaLinter'}) | ||||
|       endif | ||||
|     endif | ||||
|  | ||||
|     if get(g:, 'go_echo_command_info', 1) | ||||
|       call go#util#EchoSuccess("linting finished") | ||||
|     endif | ||||
|   endfunction | ||||
|  | ||||
|   let start_options = { | ||||
|         \ 'callback': function("s:callback"), | ||||
|         \ 'close_cb': function("s:close_cb"), | ||||
|         \ } | ||||
|  | ||||
|   call job_start(a:args.cmd, start_options) | ||||
|  | ||||
|   call go#list#Clean(l:listtype) | ||||
|  | ||||
|   if get(g:, 'go_echo_command_info', 1) | ||||
|     call go#util#EchoProgress("linting started ...") | ||||
|   endif | ||||
| endfunction | ||||
|  | ||||
| " vim: sw=2 ts=2 et | ||||
|  | ||||
| @ -5,7 +5,7 @@ endif | ||||
| " Window opens the list with the given height up to 10 lines maximum. | ||||
| " Otherwise g:go_loclist_height is used. If no or zero height is given it | ||||
| " closes the window | ||||
| function! go#list#Window(listtype, ...) | ||||
| function! go#list#Window(listtype, ...) abort | ||||
|   let l:listtype = go#list#Type(a:listtype) | ||||
|   " we don't use lwindow to close the location list as we need also the | ||||
|   " ability to resize the window. So, we are going to use lopen and lclose | ||||
| @ -40,7 +40,7 @@ endfunction | ||||
|  | ||||
|  | ||||
| " Get returns the current list of items from the location list | ||||
| function! go#list#Get(listtype) | ||||
| function! go#list#Get(listtype) abort | ||||
|   let l:listtype = go#list#Type(a:listtype) | ||||
|   if l:listtype == "locationlist" | ||||
|     return getloclist(0) | ||||
| @ -50,22 +50,27 @@ function! go#list#Get(listtype) | ||||
| endfunction | ||||
|  | ||||
| " Populate populate the location list with the given items | ||||
| function! go#list#Populate(listtype, items) | ||||
| function! go#list#Populate(listtype, items, title) abort | ||||
|   let l:listtype = go#list#Type(a:listtype) | ||||
|   if l:listtype == "locationlist" | ||||
|     call setloclist(0, a:items, 'r') | ||||
|  | ||||
|     " The last argument ({what}) is introduced with 7.4.2200: | ||||
|     " https://github.com/vim/vim/commit/d823fa910cca43fec3c31c030ee908a14c272640 | ||||
|     if has("patch-7.4.2200") | call setloclist(0, [], 'a', {'title': a:title}) | endif | ||||
|   else | ||||
|     call setqflist(a:items, 'r') | ||||
|     if has("patch-7.4.2200") | call setqflist([], 'a', {'title': a:title}) | endif | ||||
|   endif | ||||
| endfunction | ||||
|  | ||||
| function! go#list#PopulateWin(winnr, items) | ||||
| function! go#list#PopulateWin(winnr, items) abort | ||||
|   call setloclist(a:winnr, a:items, 'r') | ||||
| endfunction | ||||
|  | ||||
| " Parse parses the given items based on the specified errorformat nad | ||||
| " populates the location list. | ||||
| function! go#list#ParseFormat(listtype, errformat, items) | ||||
| function! go#list#ParseFormat(listtype, errformat, items, title) abort | ||||
|   let l:listtype = go#list#Type(a:listtype) | ||||
|   " backup users errorformat, will be restored once we are finished | ||||
|   let old_errorformat = &errorformat | ||||
| @ -74,8 +79,10 @@ function! go#list#ParseFormat(listtype, errformat, items) | ||||
|   let &errorformat = a:errformat | ||||
|   if l:listtype == "locationlist" | ||||
|     lgetexpr a:items | ||||
|     if has("patch-7.4.2200") | call setloclist(0, [], 'a', {'title': a:title}) | endif | ||||
|   else | ||||
|     cgetexpr a:items | ||||
|     if has("patch-7.4.2200") | call setqflist([], 'a', {'title': a:title}) | endif | ||||
|   endif | ||||
|  | ||||
|   "restore back | ||||
| @ -84,7 +91,7 @@ endfunction | ||||
|  | ||||
| " Parse parses the given items based on the global errorformat and | ||||
| " populates the location list. | ||||
| function! go#list#Parse(listtype, items) | ||||
| function! go#list#Parse(listtype, items) abort | ||||
|   let l:listtype = go#list#Type(a:listtype) | ||||
|   if l:listtype == "locationlist" | ||||
|     lgetexpr a:items | ||||
| @ -94,7 +101,7 @@ function! go#list#Parse(listtype, items) | ||||
| endfunction | ||||
|  | ||||
| " JumpToFirst jumps to the first item in the location list | ||||
| function! go#list#JumpToFirst(listtype) | ||||
| function! go#list#JumpToFirst(listtype) abort | ||||
|   let l:listtype = go#list#Type(a:listtype) | ||||
|   if l:listtype == "locationlist" | ||||
|     ll 1 | ||||
| @ -104,7 +111,7 @@ function! go#list#JumpToFirst(listtype) | ||||
| endfunction | ||||
|  | ||||
| " Clean cleans the location list | ||||
| function! go#list#Clean(listtype) | ||||
| function! go#list#Clean(listtype) abort | ||||
|   let l:listtype = go#list#Type(a:listtype) | ||||
|   if l:listtype == "locationlist" | ||||
|     lex [] | ||||
| @ -113,7 +120,7 @@ function! go#list#Clean(listtype) | ||||
|   endif | ||||
| endfunction | ||||
|  | ||||
| function! go#list#Type(listtype) | ||||
| function! go#list#Type(listtype) abort | ||||
|   if g:go_list_type == "locationlist" | ||||
|     return "locationlist" | ||||
|   elseif g:go_list_type == "quickfix" | ||||
|  | ||||
| @ -28,7 +28,7 @@ if len(s:goarch) == 0 | ||||
|   endif | ||||
| endif | ||||
|  | ||||
| function! go#package#Paths() | ||||
| function! go#package#Paths() abort | ||||
|   let dirs = [] | ||||
|  | ||||
|   if !exists("s:goroot") | ||||
| @ -54,7 +54,7 @@ function! go#package#Paths() | ||||
|   return dirs | ||||
| endfunction | ||||
|  | ||||
| function! go#package#ImportPath(arg) | ||||
| function! go#package#ImportPath(arg) abort | ||||
|   let path = fnamemodify(resolve(a:arg), ':p') | ||||
|   let dirs = go#package#Paths() | ||||
|  | ||||
| @ -77,7 +77,7 @@ function! go#package#ImportPath(arg) | ||||
|   endif | ||||
| endfunction | ||||
|  | ||||
| function! go#package#FromPath(arg) | ||||
| function! go#package#FromPath(arg) abort | ||||
|   let path = fnamemodify(resolve(a:arg), ':p') | ||||
|   let dirs = go#package#Paths() | ||||
|  | ||||
| @ -99,7 +99,7 @@ function! go#package#FromPath(arg) | ||||
|   endif | ||||
| endfunction | ||||
|  | ||||
| function! go#package#CompleteMembers(package, member) | ||||
| function! go#package#CompleteMembers(package, member) abort | ||||
|   silent! let content = go#util#System('godoc ' . a:package) | ||||
|   if go#util#ShellError() || !len(content) | ||||
|     return [] | ||||
| @ -118,7 +118,7 @@ function! go#package#CompleteMembers(package, member) | ||||
|   endtry | ||||
| endfunction | ||||
|  | ||||
| function! go#package#Complete(ArgLead, CmdLine, CursorPos) | ||||
| function! go#package#Complete(ArgLead, CmdLine, CursorPos) abort | ||||
|   let words = split(a:CmdLine, '\s\+', 1) | ||||
|  | ||||
|   " do not complete package members for these commands | ||||
|  | ||||
| @ -8,7 +8,7 @@ let s:initial_go_path = "" | ||||
| " echoes the current GOPATH, if an argument is passed it replaces the current | ||||
| " GOPATH with it. If two double quotes are passed (the empty string in go), | ||||
| " it'll clear the GOPATH and will restore to the initial GOPATH. | ||||
| function! go#path#GoPath(...) | ||||
| function! go#path#GoPath(...) abort | ||||
|   " we have an argument, replace GOPATH | ||||
|   if len(a:000) | ||||
|     " clears the current manually set GOPATH and restores it to the | ||||
| @ -35,7 +35,7 @@ endfunction | ||||
| " Default returns the default GOPATH. If there is a single GOPATH it returns | ||||
| " it. For multiple GOPATHS separated with a the OS specific separator, only | ||||
| " the first one is returned | ||||
| function! go#path#Default() | ||||
| function! go#path#Default() abort | ||||
|   let go_paths = split($GOPATH, go#util#PathListSep()) | ||||
|  | ||||
|   if len(go_paths) == 1 | ||||
| @ -47,7 +47,7 @@ endfunction | ||||
|  | ||||
| " HasPath checks whether the given path exists in GOPATH environment variable | ||||
| " or not | ||||
| function! go#path#HasPath(path) | ||||
| function! go#path#HasPath(path) abort | ||||
|   let go_paths = split($GOPATH, go#util#PathListSep()) | ||||
|   let last_char = strlen(a:path) - 1 | ||||
|  | ||||
| @ -69,7 +69,7 @@ endfunction | ||||
| " Godeps, GB, it will modify the GOPATH so those directories take precedence | ||||
| " over the current GOPATH. It also detects diretories whose are outside | ||||
| " GOPATH. | ||||
| function! go#path#Detect() | ||||
| function! go#path#Detect() abort | ||||
|   let gopath = $GOPATH | ||||
|  | ||||
|   " don't lookup for godeps if autodetect is disabled. | ||||
| @ -115,7 +115,7 @@ endfunction | ||||
|  | ||||
|  | ||||
| " BinPath returns the binary path of installed go tools. | ||||
| function! go#path#BinPath() | ||||
| function! go#path#BinPath() abort | ||||
|   let bin_path = "" | ||||
|  | ||||
|   " check if our global custom path is set, if not check if $GOBIN is set so | ||||
| @ -135,7 +135,7 @@ endfunction | ||||
|  | ||||
| " CheckBinPath checks whether the given binary exists or not and returns the | ||||
| " path of the binary. It returns an empty string doesn't exists. | ||||
| function! go#path#CheckBinPath(binpath) | ||||
| function! go#path#CheckBinPath(binpath) abort | ||||
|     " remove whitespaces if user applied something like 'goimports   ' | ||||
|     let binpath = substitute(a:binpath, '^\s*\(.\{-}\)\s*$', '\1', '') | ||||
|     " save off original path | ||||
| @ -161,7 +161,7 @@ function! go#path#CheckBinPath(binpath) | ||||
|     " just get the basename | ||||
|     let basename = fnamemodify(binpath, ":t") | ||||
|     if !executable(basename) | ||||
|         echo "vim-go: could not find '" . basename . "'. Run :GoInstallBinaries to fix it." | ||||
|         echom "vim-go: could not find '" . basename . "'. Run :GoInstallBinaries to fix it." | ||||
|         " restore back! | ||||
|         let $PATH = old_path | ||||
|         return "" | ||||
|  | ||||
| @ -3,7 +3,7 @@ if !exists("g:go_play_open_browser") | ||||
| endif | ||||
|  | ||||
|  | ||||
| function! go#play#Share(count, line1, line2) | ||||
| function! go#play#Share(count, line1, line2) abort | ||||
|   if !executable('curl') | ||||
|     echohl ErrorMsg | echomsg "vim-go: require 'curl' command" | echohl None | ||||
|     return | ||||
| @ -42,7 +42,7 @@ function! go#play#Share(count, line1, line2) | ||||
| endfunction | ||||
|  | ||||
|  | ||||
| function! s:get_visual_content() | ||||
| function! s:get_visual_content() abort | ||||
|   let save_regcont = @" | ||||
|   let save_regtype = getregtype('"') | ||||
|   silent! normal! gvy | ||||
| @ -55,7 +55,7 @@ endfunction | ||||
| " http://stackoverflow.com/questions/1533565/how-to-get-visually-selected-text-in-vimscript | ||||
| " another function that returns the content of visual selection, it's not used | ||||
| " but might be useful in the future | ||||
| function! s:get_visual_selection() | ||||
| function! s:get_visual_selection() abort | ||||
|   let [lnum1, col1] = getpos("'<")[1:2] | ||||
|   let [lnum2, col2] = getpos("'>")[1:2] | ||||
|  | ||||
| @ -72,7 +72,7 @@ endfunction | ||||
|  | ||||
| " following two functions are from: https://github.com/mattn/gist-vim  | ||||
| " thanks  @mattn | ||||
| function! s:get_browser_command() | ||||
| function! s:get_browser_command() abort | ||||
|   let go_play_browser_command = get(g:, 'go_play_browser_command', '') | ||||
|   if go_play_browser_command == '' | ||||
|     if has('win32') || has('win64') | ||||
|  | ||||
| @ -6,22 +6,22 @@ if !exists("g:go_gorename_prefill") | ||||
|   let g:go_gorename_prefill = 1 | ||||
| endif | ||||
|  | ||||
| function! go#rename#Rename(bang, ...) | ||||
|   let to = "" | ||||
| function! go#rename#Rename(bang, ...) abort | ||||
|   let to_identifier = "" | ||||
|   if a:0 == 0 | ||||
|     let from = expand("<cword>") | ||||
|     let ask = printf("vim-go: rename '%s' to: ", from) | ||||
|     if g:go_gorename_prefill | ||||
|       let to = input(ask, from) | ||||
|       let to_identifier = input(ask, from) | ||||
|     else | ||||
|       let to = input(ask) | ||||
|       let to_identifier = input(ask) | ||||
|     endif | ||||
|     redraw! | ||||
|     if empty(to) | ||||
|     if empty(to_identifier) | ||||
|       return | ||||
|     endif | ||||
|   else | ||||
|     let to = a:1 | ||||
|     let to_identifier = a:1 | ||||
|   endif | ||||
|  | ||||
|   "return with a warning if the bin doesn't exist | ||||
| @ -32,10 +32,79 @@ function! go#rename#Rename(bang, ...) | ||||
|  | ||||
|   let fname = expand('%:p') | ||||
|   let pos = go#util#OffsetCursor() | ||||
|   let cmd = printf('%s -offset %s -to %s', shellescape(bin_path), shellescape(printf('%s:#%d', fname, pos)), shellescape(to)) | ||||
|   let offset = printf('%s:#%d', fname, pos) | ||||
|  | ||||
|   let out = go#tool#ExecuteInDir(cmd) | ||||
|   " no need to escape for job call | ||||
|   let bin_path = go#util#has_job() ? bin_path : shellescape(bin_path) | ||||
|   let offset = go#util#has_job() ? offset : shellescape(offset) | ||||
|   let to_identifier = go#util#has_job() ? to_identifier : shellescape(to_identifier) | ||||
|  | ||||
|   let cmd = [bin_path, "-offset", offset, "-to", to_identifier] | ||||
|  | ||||
|   if go#util#has_job() | ||||
|     call go#util#EchoProgress(printf("renaming to '%s' ...", to_identifier)) | ||||
|     call s:rename_job({ | ||||
|           \ 'cmd': cmd, | ||||
|           \ 'bang': a:bang, | ||||
|           \}) | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   let command = join(cmd, " ") | ||||
|   let out = go#tool#ExecuteInDir(command) | ||||
|  | ||||
|   let splitted = split(out, '\n') | ||||
|   call s:parse_errors(go#util#ShellError(), a:bang, splitted) | ||||
| endfunction | ||||
|  | ||||
| function s:rename_job(args) | ||||
|   let messages = [] | ||||
|   function! s:callback(chan, msg) closure | ||||
|     call add(messages, a:msg) | ||||
|   endfunction | ||||
|  | ||||
|   let status_dir =  expand('%:p:h') | ||||
|  | ||||
|   function! s:close_cb(chan) closure | ||||
|     let l:job = ch_getjob(a:chan) | ||||
|     let l:info = job_info(l:job) | ||||
|  | ||||
|     let status = { | ||||
|           \ 'desc': 'last status', | ||||
|           \ 'type': "gorename", | ||||
|           \ 'state': "finished", | ||||
|           \ } | ||||
|  | ||||
|     if l:info.exitval | ||||
|       let status.state = "failed" | ||||
|     endif | ||||
|  | ||||
|     call go#statusline#Update(status_dir, status) | ||||
|  | ||||
|     call s:parse_errors(l:info.exitval, a:args.bang, messages) | ||||
|   endfunction | ||||
|  | ||||
|   let start_options = { | ||||
|         \ 'callback': function("s:callback"), | ||||
|         \ 'close_cb': function("s:close_cb"), | ||||
|         \ } | ||||
|  | ||||
|   " modify GOPATH if needed | ||||
|   let old_gopath = $GOPATH | ||||
|   let $GOPATH = go#path#Detect() | ||||
|  | ||||
|   call go#statusline#Update(status_dir, { | ||||
|         \ 'desc': "current status", | ||||
|         \ 'type': "gorename", | ||||
|         \ 'state': "started", | ||||
|         \}) | ||||
|  | ||||
|   call job_start(a:args.cmd, start_options) | ||||
|  | ||||
|   let $GOPATH = old_gopath | ||||
| endfunction | ||||
|  | ||||
| function s:parse_errors(exit_val, bang, out) | ||||
|   " reload all files to reflect the new changes. We explicitly call | ||||
|   " checktime to trigger a reload of all files. See | ||||
|   " http://www.mail-archive.com/vim@vim.org/msg05900.html for more info | ||||
| @ -45,28 +114,28 @@ function! go#rename#Rename(bang, ...) | ||||
|   silent! checktime | ||||
|   let &autoread = current_autoread | ||||
|  | ||||
|   " strip out newline on the end that gorename puts. If we don't remove, it | ||||
|   " will trigger the 'Hit ENTER to continue' prompt | ||||
|   let clean = split(out, '\n') | ||||
|  | ||||
|   let l:listtype = "quickfix" | ||||
|   if go#util#ShellError() != 0 | ||||
|     let errors = go#tool#ParseErrors(split(out, '\n')) | ||||
|     call go#list#Populate(l:listtype, errors) | ||||
|   if a:exit_val != 0 | ||||
|     call go#util#EchoError("FAILED") | ||||
|     let errors = go#tool#ParseErrors(a:out) | ||||
|     call go#list#Populate(l:listtype, errors, 'Rename') | ||||
|     call go#list#Window(l:listtype, len(errors)) | ||||
|     if !empty(errors) && !a:bang | ||||
|       call go#list#JumpToFirst(l:listtype) | ||||
|     elseif empty(errors) | ||||
|       " failed to parse errors, output the original content | ||||
|       call go#util#EchoError(out) | ||||
|       call go#util#EchoError(join(a:out, "")) | ||||
|     endif | ||||
|  | ||||
|     return | ||||
|   else | ||||
|     call go#list#Clean(l:listtype) | ||||
|     call go#list#Window(l:listtype) | ||||
|     redraw | echon "vim-go: " | echohl Function | echon clean[0] | echohl None | ||||
|   endif | ||||
|  | ||||
|   " strip out newline on the end that gorename puts. If we don't remove, it | ||||
|   " will trigger the 'Hit ENTER to continue' prompt | ||||
|   call go#list#Clean(l:listtype) | ||||
|   call go#list#Window(l:listtype) | ||||
|   call go#util#EchoSuccess(a:out[0]) | ||||
|  | ||||
|   " refresh the buffer so we can see the new content | ||||
|   " TODO(arslan): also find all other buffers and refresh them too. For this | ||||
|   " we need a way to get the list of changes from gorename upon an success | ||||
|  | ||||
							
								
								
									
										112
									
								
								sources_non_forked/vim-go/autoload/go/statusline.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								sources_non_forked/vim-go/autoload/go/statusline.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,112 @@ | ||||
| " Statusline | ||||
| """""""""""""""""""""""""""""""" | ||||
|  | ||||
| " s:statuses is a global reference to all statuses. It stores the statuses per | ||||
| " import paths (map[string]status), where each status is unique per its | ||||
| " type. Current status dict is in form: | ||||
| " {  | ||||
| "   'desc'        : 'Job description', | ||||
| "   'state'       : 'Job state, such as success, failure, etc..', | ||||
| "   'type'        : 'Job type, such as build, test, etc..' | ||||
| "   'created_at'  : 'Time it was created as seconds since 1st Jan 1970' | ||||
| " } | ||||
| let s:statuses = {} | ||||
|  | ||||
| " timer_id for cleaner | ||||
| let s:timer_id = 0 | ||||
|  | ||||
| " last_status stores the last generated text per status | ||||
| let s:last_status = "" | ||||
|  | ||||
| " Show returns the current status of the job for 20 seconds (configurable). It | ||||
| " displays it in form of 'desc: [type|state]' if there is any state available, | ||||
| " if not it returns an empty string. This function should be plugged directly | ||||
| " into the statusline. | ||||
| function! go#statusline#Show() abort | ||||
|   " lazy initialiation of the cleaner | ||||
|   if !s:timer_id | ||||
|     " clean every 60 seconds all statuses | ||||
|     let interval = get(g:, 'go_statusline_duration', 60000) | ||||
|     let s:timer_id = timer_start(interval, function('go#statusline#Clear'), {'repeat': -1}) | ||||
|   endif | ||||
|  | ||||
|   " nothing to show | ||||
|   if empty(s:statuses) | ||||
|     return '' | ||||
|   endif | ||||
|  | ||||
|   let status_dir =  expand('%:p:h') | ||||
|  | ||||
|   if !has_key(s:statuses, status_dir) | ||||
|     return '' | ||||
|   endif | ||||
|  | ||||
|   let status = s:statuses[status_dir] | ||||
|   if !has_key(status, 'desc') || !has_key(status, 'state') || !has_key(status, 'type') | ||||
|     return '' | ||||
|   endif | ||||
|  | ||||
|   let status_text = printf("[%s|%s]", status.type, status.state) | ||||
|   if empty(status_text) | ||||
|     return '' | ||||
|   endif | ||||
|  | ||||
|   " only update highlight if status has changed. | ||||
|   if status_text != s:last_status | ||||
|     if status.state =~ "success" || status.state =~ "finished" | ||||
|       hi goStatusLineColor cterm=bold ctermbg=76 ctermfg=22 | ||||
|     elseif status.state =~ "started" || status.state =~ "analysing" | ||||
|       hi goStatusLineColor cterm=bold ctermbg=208 ctermfg=88 | ||||
|     elseif status.state =~ "failed" | ||||
|       hi goStatusLineColor cterm=bold ctermbg=196 ctermfg=52 | ||||
|     endif | ||||
|   endif | ||||
|  | ||||
|   let s:last_status = status_text | ||||
|   return status_text | ||||
| endfunction | ||||
|  | ||||
| " Update updates (adds) the statusline for the given status_dir with the | ||||
| " given status dict. It overrides any previously set status. | ||||
| function! go#statusline#Update(status_dir, status) abort | ||||
|   let a:status.created_at = reltime() | ||||
|   let s:statuses[a:status_dir] = a:status | ||||
|  | ||||
|   " force to update the statusline, otherwise the user needs to move the | ||||
|   " cursor | ||||
|   exe 'let &ro = &ro' | ||||
|  | ||||
|   " before we stop the timer, check if we have any previous jobs to be cleaned | ||||
|   " up. Otherwise every job will reset the timer when this function is called | ||||
|   " and thus old jobs will never be cleaned | ||||
|   call go#statusline#Clear(0) | ||||
|  | ||||
|   " also reset the timer, so the user has time to see it in the statusline. | ||||
|   " Setting the timer_id to 0 will trigger a new cleaner routine. | ||||
|   call timer_stop(s:timer_id) | ||||
|   let s:timer_id = 0 | ||||
| endfunction | ||||
|  | ||||
| " Clear clears all currently stored statusline data. The timer_id argument is | ||||
| " just a placeholder so we can pass it to a timer_start() function if needed. | ||||
| function! go#statusline#Clear(timer_id) abort | ||||
|   for [status_dir, status] in items(s:statuses) | ||||
|     let elapsed_time = reltimestr(reltime(status.created_at)) | ||||
|     " strip whitespace | ||||
|     let elapsed_time = substitute(elapsed_time, '^\s*\(.\{-}\)\s*$', '\1', '') | ||||
|  | ||||
|     if str2nr(elapsed_time) > 10 | ||||
|       call remove(s:statuses, status_dir) | ||||
|     endif | ||||
|   endfor | ||||
|  | ||||
|   if len(s:statuses) == 0 | ||||
|     let s:statuses = {} | ||||
|   endif | ||||
|  | ||||
|   " force to update the statusline, otherwise the user needs to move the | ||||
|   " cursor | ||||
|   exe 'let &ro = &ro' | ||||
| endfunction | ||||
|  | ||||
| " vim: sw=2 ts=2 et | ||||
| @ -1,6 +1,7 @@ | ||||
| let s:current_file = expand("<sfile>") | ||||
|  | ||||
| function! go#template#create() | ||||
| function! go#template#create() abort | ||||
|   let l:go_template_use_pkg = get(g:, 'go_template_use_pkg', 0) | ||||
|   let l:root_dir = fnamemodify(s:current_file, ':h:h:h') | ||||
|  | ||||
|   let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' | ||||
| @ -10,12 +11,19 @@ function! go#template#create() | ||||
|   let l:package_name = go#tool#PackageName() | ||||
|  | ||||
|   " if we can't figure out any package name(no Go files or non Go package | ||||
|   " files) from the directory create the template | ||||
|   if l:package_name == -1 | ||||
|   " files) from the directory create the template or use the cwd | ||||
|   " as the name | ||||
|   if l:package_name == -1 && l:go_template_use_pkg != 1 | ||||
|     let l:template_file = get(g:, 'go_template_file', "hello_world.go") | ||||
|     let l:template_path = go#util#Join(l:root_dir, "templates", l:template_file) | ||||
|     exe '0r ' . fnameescape(l:template_path) | ||||
|     $delete _ | ||||
|   elseif l:package_name == -1 && l:go_template_use_pkg == 1 | ||||
|     " cwd is now the dir of the package | ||||
|     let l:path = fnamemodify(getcwd(), ':t') | ||||
|     let l:content = printf("package %s", l:path) | ||||
|     call append(0, l:content) | ||||
|     $delete _ | ||||
|   else | ||||
|     let l:content = printf("package %s", l:package_name) | ||||
|     call append(0, l:content) | ||||
| @ -28,7 +36,7 @@ function! go#template#create() | ||||
|   execute cd . fnameescape(dir) | ||||
| endfunction | ||||
|  | ||||
| function! go#template#ToggleAutoCreate() | ||||
| function! go#template#ToggleAutoCreate() abort | ||||
|   if get(g:, "go_template_autocreate", 1) | ||||
|     let g:go_template_autocreate = 0 | ||||
|     call go#util#EchoProgress("auto template create disabled") | ||||
|  | ||||
| @ -7,12 +7,12 @@ let s:jobs = {} | ||||
|  | ||||
| " new creates a new terminal with the given command. Mode is set based on the | ||||
| " global variable g:go_term_mode, which is by default set to :vsplit | ||||
| function! go#term#new(bang, cmd) | ||||
| function! go#term#new(bang, cmd) abort | ||||
|   return go#term#newmode(a:bang, a:cmd, g:go_term_mode) | ||||
| endfunction | ||||
|  | ||||
| " new creates a new terminal with the given command and window mode. | ||||
| function! go#term#newmode(bang, cmd, mode) | ||||
| function! go#term#newmode(bang, cmd, mode) abort | ||||
|   let mode = a:mode | ||||
|   if empty(mode) | ||||
|     let mode = g:go_term_mode | ||||
| @ -36,7 +36,7 @@ function! go#term#newmode(bang, cmd, mode) | ||||
|   setlocal noswapfile | ||||
|   setlocal nobuflisted | ||||
|  | ||||
|   let job = {  | ||||
|   let job = { | ||||
|         \ 'stderr' : [], | ||||
|         \ 'stdout' : [], | ||||
|         \ 'bang' : a:bang, | ||||
| @ -53,6 +53,7 @@ function! go#term#newmode(bang, cmd, mode) | ||||
|   let $GOPATH = old_gopath | ||||
|  | ||||
|   let job.id = id | ||||
|   let job.cmd = a:cmd | ||||
|   startinsert | ||||
|  | ||||
|   " resize new term if needed. | ||||
| @ -74,7 +75,7 @@ function! go#term#newmode(bang, cmd, mode) | ||||
|   return id | ||||
| endfunction | ||||
|  | ||||
| function! s:on_stdout(job_id, data) | ||||
| function! s:on_stdout(job_id, data, event) dict abort | ||||
|   if !has_key(s:jobs, a:job_id) | ||||
|     return | ||||
|   endif | ||||
| @ -83,7 +84,7 @@ function! s:on_stdout(job_id, data) | ||||
|   call extend(job.stdout, a:data) | ||||
| endfunction | ||||
|  | ||||
| function! s:on_stderr(job_id, data) | ||||
| function! s:on_stderr(job_id, data, event) dict abort | ||||
|   if !has_key(s:jobs, a:job_id) | ||||
|     return | ||||
|   endif | ||||
| @ -92,7 +93,7 @@ function! s:on_stderr(job_id, data) | ||||
|   call extend(job.stderr, a:data) | ||||
| endfunction | ||||
|  | ||||
| function! s:on_exit(job_id, exit_status) | ||||
| function! s:on_exit(job_id, exit_status, event) dict abort | ||||
|   if !has_key(s:jobs, a:job_id) | ||||
|     return | ||||
|   endif | ||||
| @ -113,9 +114,9 @@ function! s:on_exit(job_id, exit_status) | ||||
|  | ||||
|   if !empty(errors) | ||||
|     " close terminal we don't need it anymore | ||||
|     close  | ||||
|     close | ||||
|  | ||||
|     call go#list#Populate(l:listtype, errors) | ||||
|     call go#list#Populate(l:listtype, errors, job.cmd) | ||||
|     call go#list#Window(l:listtype, len(errors)) | ||||
|     if !self.bang | ||||
|       call go#list#JumpToFirst(l:listtype) | ||||
|  | ||||
| @ -13,7 +13,7 @@ endif | ||||
| " < > | ||||
| " t for tag | ||||
|  | ||||
| function! go#textobj#Function(mode) | ||||
| function! go#textobj#Function(mode) abort | ||||
|   let offset = go#util#OffsetCursor() | ||||
|  | ||||
|   let fname = shellescape(expand("%:p")) | ||||
| @ -84,7 +84,7 @@ function! go#textobj#Function(mode) | ||||
|   call cursor(info.rbrace.line-1, 1) | ||||
| endfunction | ||||
|  | ||||
| function! go#textobj#FunctionJump(mode, direction) | ||||
| function! go#textobj#FunctionJump(mode, direction) abort | ||||
|   " get count of the motion. This should be done before all the normal | ||||
|   " expressions below as those reset this value(because they have zero | ||||
|   " count!). We abstract -1 because the index starts from 0 in motion. | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| function! go#tool#Files() | ||||
| function! go#tool#Files() abort | ||||
|   if go#util#IsWin() | ||||
|     let format = '{{range $f := .GoFiles}}{{$.Dir}}\{{$f}}{{printf \"\n\"}}{{end}}{{range $f := .CgoFiles}}{{$.Dir}}\{{$f}}{{printf \"\n\"}}{{end}}' | ||||
|   else | ||||
| @ -9,7 +9,7 @@ function! go#tool#Files() | ||||
|   return split(out, '\n') | ||||
| endfunction | ||||
|  | ||||
| function! go#tool#Deps() | ||||
| function! go#tool#Deps() abort | ||||
|   if go#util#IsWin() | ||||
|     let format = '{{range $f := .Deps}}{{$f}}{{printf \"\n\"}}{{end}}' | ||||
|   else | ||||
| @ -20,7 +20,7 @@ function! go#tool#Deps() | ||||
|   return split(out, '\n') | ||||
| endfunction | ||||
|  | ||||
| function! go#tool#Imports() | ||||
| function! go#tool#Imports() abort | ||||
|   let imports = {} | ||||
|   if go#util#IsWin() | ||||
|     let format = '{{range $f := .Imports}}{{$f}}{{printf \"\n\"}}{{end}}' | ||||
| @ -43,7 +43,18 @@ function! go#tool#Imports() | ||||
|   return imports | ||||
| endfunction | ||||
|  | ||||
| function! go#tool#PackageName() | ||||
| function! go#tool#Info(auto) abort | ||||
|   let l:mode = get(g:, 'go_info_mode', 'gocode') | ||||
|   if l:mode == 'gocode' | ||||
|     call go#complete#Info(a:auto) | ||||
|   elseif l:mode == 'guru' | ||||
|     call go#guru#DescribeInfo() | ||||
|   else | ||||
|     call go#util#EchoError('go_info_mode value: '. l:mode .' is not valid. Valid values are: [gocode, guru]') | ||||
|   endif | ||||
| endfunction | ||||
|  | ||||
| function! go#tool#PackageName() abort | ||||
|   let command = "go list -f \"{{.Name}}\"" | ||||
|   let out = go#tool#ExecuteInDir(command) | ||||
|   if go#util#ShellError() != 0 | ||||
| @ -53,7 +64,7 @@ function! go#tool#PackageName() | ||||
|   return split(out, '\n')[0] | ||||
| endfunction | ||||
|  | ||||
| function! go#tool#ParseErrors(lines) | ||||
| function! go#tool#ParseErrors(lines) abort | ||||
|   let errors = [] | ||||
|  | ||||
|   for line in a:lines | ||||
| @ -85,7 +96,7 @@ endfunction | ||||
|  | ||||
| "FilterValids filters the given items with only items that have a valid | ||||
| "filename. Any non valid filename is filtered out. | ||||
| function! go#tool#FilterValids(items) | ||||
| function! go#tool#FilterValids(items) abort | ||||
|   " Remove any nonvalid filename from the location list to avoid opening an | ||||
|   " empty buffer. See https://github.com/fatih/vim-go/issues/287 for | ||||
|   " details. | ||||
| @ -141,7 +152,7 @@ endfunction | ||||
|  | ||||
| " Exists checks whether the given importpath exists or not. It returns 0 if | ||||
| " the importpath exists under GOPATH. | ||||
| function! go#tool#Exists(importpath) | ||||
| function! go#tool#Exists(importpath) abort | ||||
|     let command = "go list ". a:importpath | ||||
|     let out = go#tool#ExecuteInDir(command) | ||||
|  | ||||
| @ -155,7 +166,7 @@ endfunction | ||||
|  | ||||
| " following two functions are from: https://github.com/mattn/gist-vim  | ||||
| " thanks  @mattn | ||||
| function! s:get_browser_command() | ||||
| function! s:get_browser_command() abort | ||||
|     let go_play_browser_command = get(g:, 'go_play_browser_command', '') | ||||
|     if go_play_browser_command == '' | ||||
|         if go#util#IsWin() | ||||
| @ -173,7 +184,7 @@ function! s:get_browser_command() | ||||
|     return go_play_browser_command | ||||
| endfunction | ||||
|  | ||||
| function! go#tool#OpenBrowser(url) | ||||
| function! go#tool#OpenBrowser(url) abort | ||||
|     let cmd = s:get_browser_command() | ||||
|     if len(cmd) == 0 | ||||
|         redraw | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| let s:buf_nr = -1 | ||||
|  | ||||
| "OpenWindow opens a new scratch window and put's the content into the window | ||||
| function! go#ui#OpenWindow(title, content, filetype) | ||||
| function! go#ui#OpenWindow(title, content, filetype) abort | ||||
|   " Ensure there's only one return window in this session/tabpage | ||||
|   call go#util#Windo("unlet! w:vim_go_return_window") | ||||
|   " Mark the window we're leaving as such | ||||
| @ -54,7 +54,7 @@ function! go#ui#OpenWindow(title, content, filetype) | ||||
|   echon | ||||
| endfunction | ||||
|  | ||||
| function! go#ui#GetReturnWindow() | ||||
| function! go#ui#GetReturnWindow() abort | ||||
|   for l:wn in range(1, winnr("$")) | ||||
|     if !empty(getwinvar(l:wn, "vim_go_return_window")) | ||||
|       return l:wn | ||||
| @ -63,7 +63,7 @@ function! go#ui#GetReturnWindow() | ||||
| endfunction | ||||
|  | ||||
| " CloseWindow closes the current window | ||||
| function! go#ui#CloseWindow() | ||||
| function! go#ui#CloseWindow() abort | ||||
|   " Close any window associated with the ui buffer, if it's there | ||||
|   if bufexists(s:buf_nr) | ||||
|     let ui_window_number = bufwinnr(s:buf_nr) | ||||
| @ -82,7 +82,7 @@ endfunction | ||||
|  | ||||
| " OpenDefinition parses the current line and jumps to it by openening a new | ||||
| " tab | ||||
| function! go#ui#OpenDefinition(filter) | ||||
| function! go#ui#OpenDefinition(filter) abort | ||||
|   let curline = getline('.') | ||||
|  | ||||
|   " don't touch our first line or any blank line | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| " PathSep returns the appropriate OS specific path separator. | ||||
| function! go#util#PathSep() | ||||
| function! go#util#PathSep() abort | ||||
|   if go#util#IsWin() | ||||
|     return '\' | ||||
|   endif | ||||
| @ -7,7 +7,7 @@ function! go#util#PathSep() | ||||
| endfunction | ||||
|  | ||||
| " PathListSep returns the appropriate OS specific path list separator. | ||||
| function! go#util#PathListSep() | ||||
| function! go#util#PathListSep() abort | ||||
|   if go#util#IsWin() | ||||
|     return ";" | ||||
|   endif | ||||
| @ -15,7 +15,7 @@ function! go#util#PathListSep() | ||||
| endfunction | ||||
|  | ||||
| " LineEnding returns the correct line ending, based on the current fileformat | ||||
| function! go#util#LineEnding() | ||||
| function! go#util#LineEnding() abort | ||||
|   if &fileformat == 'dos' | ||||
|     return "\r\n" | ||||
|   elseif &fileformat == 'mac' | ||||
| @ -27,12 +27,12 @@ endfunction | ||||
|  | ||||
| " Join joins any number of path elements into a single path, adding a | ||||
| " Separator if necessary and returns the result | ||||
| function! go#util#Join(...) | ||||
| function! go#util#Join(...) abort | ||||
|   return join(a:000, go#util#PathSep()) | ||||
| endfunction | ||||
|  | ||||
| " IsWin returns 1 if current OS is Windows or 0 otherwise | ||||
| function! go#util#IsWin() | ||||
| function! go#util#IsWin() abort | ||||
|   let win = ['win16', 'win32', 'win64', 'win95'] | ||||
|   for w in win | ||||
|     if (has(w)) | ||||
| @ -43,12 +43,18 @@ function! go#util#IsWin() | ||||
|   return 0 | ||||
| endfunction | ||||
|  | ||||
| function! go#util#has_job() abort | ||||
|   " job was introduced in 7.4.xxx however there are multiple bug fixes and one | ||||
|   " of the latest is 8.0.0087 which is required for a stable async API. | ||||
|   return has('job') && has("patch-8.0.0087") | ||||
| endfunction | ||||
|  | ||||
| let s:env_cache = {} | ||||
|  | ||||
| " env returns the go environment variable for the given key. Where key can be | ||||
| " GOARCH, GOOS, GOROOT, etc... It caches the result and returns the cached | ||||
| " version.  | ||||
| function! go#util#env(key) | ||||
| function! go#util#env(key) abort | ||||
|   let l:key = tolower(a:key) | ||||
|   if has_key(s:env_cache, l:key) | ||||
|     return s:env_cache[l:key] | ||||
| @ -68,81 +74,49 @@ function! go#util#env(key) | ||||
|   return l:var | ||||
| endfunction | ||||
|  | ||||
| function! go#util#goarch() | ||||
| function! go#util#goarch() abort | ||||
|   return substitute(go#util#System('go env GOARCH'), '\n', '', 'g') | ||||
| endfunction | ||||
|  | ||||
| function! go#util#goos() | ||||
| function! go#util#goos() abort | ||||
|   return substitute(go#util#System('go env GOOS'), '\n', '', 'g') | ||||
| endfunction | ||||
|  | ||||
| function! go#util#goroot() | ||||
| function! go#util#goroot() abort | ||||
|   return substitute(go#util#System('go env GOROOT'), '\n', '', 'g') | ||||
| endfunction | ||||
|  | ||||
| function! go#util#gopath() | ||||
| function! go#util#gopath() abort | ||||
|   return substitute(go#util#System('go env GOPATH'), '\n', '', 'g') | ||||
| endfunction | ||||
|  | ||||
| function! go#util#osarch() | ||||
| function! go#util#osarch() abort | ||||
|   return go#util#goos() . '_' . go#util#goarch() | ||||
| endfunction | ||||
|  | ||||
| "Check if has vimproc | ||||
| function! s:has_vimproc() | ||||
|   if !exists('g:go#use_vimproc') | ||||
|     if go#util#IsWin() | ||||
|       try | ||||
|         call vimproc#version() | ||||
|         let exists_vimproc = 1 | ||||
|       catch | ||||
|         let exists_vimproc = 0 | ||||
|       endtry | ||||
|     else | ||||
|       let exists_vimproc = 0 | ||||
|     endif | ||||
|  | ||||
|     let g:go#use_vimproc = exists_vimproc | ||||
|   endif | ||||
|  | ||||
|   return g:go#use_vimproc | ||||
| endfunction | ||||
|  | ||||
| if s:has_vimproc() | ||||
|   let s:vim_system = get(g:, 'gocomplete#system_function', 'vimproc#system2') | ||||
|   let s:vim_shell_error = get(g:, 'gocomplete#shell_error_function', 'vimproc#get_last_status') | ||||
| else | ||||
|   let s:vim_system = get(g:, 'gocomplete#system_function', 'system') | ||||
|   let s:vim_shell_error = '' | ||||
| endif | ||||
|  | ||||
| " System runs a shell command. It will reset the shell to /bin/sh for Unix-like | ||||
| " systems if it is executable. | ||||
| function! go#util#System(str, ...) | ||||
| function! go#util#System(str, ...) abort | ||||
|   let l:shell = &shell | ||||
|   if !go#util#IsWin() && executable('/bin/sh') | ||||
|     let &shell = '/bin/sh' | ||||
|   endif | ||||
|  | ||||
|   try | ||||
|     let l:output = call(s:vim_system, [a:str] + a:000) | ||||
|     let l:output = call('system', [a:str] + a:000) | ||||
|     return l:output | ||||
|   finally | ||||
|     let &shell = l:shell | ||||
|   endtry | ||||
| endfunction | ||||
|  | ||||
| function! go#util#ShellError() | ||||
|   if empty(s:vim_shell_error) | ||||
|     return v:shell_error | ||||
|   endif | ||||
|   return call(s:vim_shell_error, []) | ||||
| function! go#util#ShellError() abort | ||||
|   return v:shell_error | ||||
| endfunction | ||||
|  | ||||
|  | ||||
| " StripPath strips the path's last character if it's a path separator. | ||||
| " example: '/foo/bar/'  -> '/foo/bar' | ||||
| function! go#util#StripPathSep(path) | ||||
| function! go#util#StripPathSep(path) abort | ||||
|   let last_char = strlen(a:path) - 1 | ||||
|   if a:path[last_char] == go#util#PathSep() | ||||
|     return strpart(a:path, 0, last_char) | ||||
| @ -153,13 +127,13 @@ endfunction | ||||
|  | ||||
| " StripTrailingSlash strips the trailing slash from the given path list. | ||||
| " example: ['/foo/bar/']  -> ['/foo/bar'] | ||||
| function! go#util#StripTrailingSlash(paths) | ||||
| function! go#util#StripTrailingSlash(paths) abort | ||||
|   return map(copy(a:paths), 'go#util#StripPathSep(v:val)') | ||||
| endfunction | ||||
|  | ||||
| " Shelljoin returns a shell-safe string representation of arglist. The | ||||
| " {special} argument of shellescape() may optionally be passed. | ||||
| function! go#util#Shelljoin(arglist, ...) | ||||
| function! go#util#Shelljoin(arglist, ...) abort | ||||
|   try | ||||
|     let ssl_save = &shellslash | ||||
|     set noshellslash | ||||
| @ -174,9 +148,6 @@ function! go#util#Shelljoin(arglist, ...) | ||||
| endfunction | ||||
|  | ||||
| fu! go#util#Shellescape(arg) | ||||
|   if s:has_vimproc() | ||||
|     return vimproc#shellescape(a:arg) | ||||
|   endif | ||||
|   try | ||||
|     let ssl_save = &shellslash | ||||
|     set noshellslash | ||||
| @ -188,7 +159,7 @@ endf | ||||
|  | ||||
| " Shelllist returns a shell-safe representation of the items in the given | ||||
| " arglist. The {special} argument of shellescape() may optionally be passed. | ||||
| function! go#util#Shelllist(arglist, ...) | ||||
| function! go#util#Shelllist(arglist, ...) abort | ||||
|   try | ||||
|     let ssl_save = &shellslash | ||||
|     set noshellslash | ||||
| @ -202,7 +173,7 @@ function! go#util#Shelllist(arglist, ...) | ||||
| endfunction | ||||
|  | ||||
| " Returns the byte offset for line and column | ||||
| function! go#util#Offset(line, col) | ||||
| function! go#util#Offset(line, col) abort | ||||
|   if &encoding != 'utf-8' | ||||
|     let sep = go#util#LineEnding() | ||||
|     let buf = a:line == 1 ? '' : (join(getline(1, a:line-1), sep) . sep) | ||||
| @ -213,13 +184,13 @@ function! go#util#Offset(line, col) | ||||
| endfunction | ||||
| " | ||||
| " Returns the byte offset for the cursor | ||||
| function! go#util#OffsetCursor() | ||||
| function! go#util#OffsetCursor() abort | ||||
|   return go#util#Offset(line('.'), col('.')) | ||||
| endfunction | ||||
|  | ||||
| " Windo is like the built-in :windo, only it returns to the window the command | ||||
| " was issued from | ||||
| function! go#util#Windo(command) | ||||
| function! go#util#Windo(command) abort | ||||
|   let s:currentWindow = winnr() | ||||
|   try | ||||
|     execute "windo " . a:command | ||||
| @ -231,7 +202,7 @@ endfunction | ||||
|  | ||||
| " snippetcase converts the given word to given preferred snippet setting type | ||||
| " case. | ||||
| function! go#util#snippetcase(word) | ||||
| function! go#util#snippetcase(word) abort | ||||
|   let l:snippet_case = get(g:, 'go_snippet_case_type', "snakecase") | ||||
|   if l:snippet_case == "snakecase" | ||||
|     return go#util#snakecase(a:word) | ||||
| @ -244,7 +215,7 @@ endfunction | ||||
|  | ||||
| " snakecase converts a string to snake case. i.e: FooBar -> foo_bar | ||||
| " Copied from tpope/vim-abolish | ||||
| function! go#util#snakecase(word) | ||||
| function! go#util#snakecase(word) abort | ||||
|   let word = substitute(a:word,'::','/','g') | ||||
|   let word = substitute(word,'\(\u\+\)\(\u\l\)','\1_\2','g') | ||||
|   let word = substitute(word,'\(\l\|\d\)\(\u\)','\1_\2','g') | ||||
| @ -255,7 +226,7 @@ endfunction | ||||
|  | ||||
| " camelcase converts a string to camel case. i.e: FooBar -> fooBar | ||||
| " Copied from tpope/vim-abolish | ||||
| function! go#util#camelcase(word) | ||||
| function! go#util#camelcase(word) abort | ||||
|   let word = substitute(a:word, '-', '_', 'g') | ||||
|   if word !~# '_' && word =~# '\l' | ||||
|     return substitute(word,'^.','\l&','') | ||||
| @ -264,7 +235,7 @@ function! go#util#camelcase(word) | ||||
|   endif | ||||
| endfunction | ||||
|  | ||||
| function! go#util#AddTags(line1, line2, ...) | ||||
| function! go#util#AddTags(line1, line2, ...) abort | ||||
|   " default is json | ||||
|   let l:keys = ["json"] | ||||
|   if a:0 | ||||
| @ -311,21 +282,27 @@ endfunction | ||||
|  | ||||
| " TODO(arslan): I couldn't parameterize the highlight types. Check if we can | ||||
| " simplify the following functions | ||||
|  | ||||
| " | ||||
| " NOTE(arslan): echon doesn't work well with redraw, thus echo doesn't print | ||||
| " even though we order it. However echom seems to be work fine. | ||||
| function! go#util#EchoSuccess(msg) | ||||
|   redraw | echon "vim-go: " | echohl Function | echon a:msg | echohl None | ||||
|   redraw | echohl Function | echom "vim-go: " . a:msg | echohl None | ||||
| endfunction | ||||
|  | ||||
| function! go#util#EchoError(msg) | ||||
|   redraw | echon "vim-go: " | echohl ErrorMsg | echon a:msg | echohl None | ||||
|   redraw | echohl ErrorMsg | echom "vim-go: " . a:msg | echohl None | ||||
| endfunction | ||||
|  | ||||
| function! go#util#EchoWarning(msg) | ||||
|   redraw | echon "vim-go: " | echohl WarningMsg | echon a:msg | echohl None | ||||
|   redraw | echohl WarningMsg | echom "vim-go: " . a:msg | echohl None | ||||
| endfunction | ||||
|  | ||||
| function! go#util#EchoProgress(msg) | ||||
|   redraw | echon "vim-go: " | echohl Identifier | echon a:msg | echohl None | ||||
|   redraw | echohl Identifier | echom "vim-go: " . a:msg | echohl None | ||||
| endfunction | ||||
|  | ||||
| function! go#util#EchoInfo(msg) | ||||
|   redraw | echohl Debug | echom "vim-go: " . a:msg | echohl None | ||||
| endfunction | ||||
|  | ||||
| " vim: sw=2 ts=2 et | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 amix
					amix