mirror of
				https://github.com/amix/vimrc
				synced 2025-10-31 06:33:35 +08:00 
			
		
		
		
	Updated plugins
This commit is contained in:
		| @ -1,4 +1,5 @@ | ||||
| .local/ | ||||
| .config/ | ||||
| .cache/ | ||||
| .dlv/ | ||||
| .git/ | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| language: go | ||||
| go: | ||||
|   - 1.11.x | ||||
|   - 1.12.1 | ||||
| notifications: | ||||
|   email: false | ||||
| matrix: | ||||
|  | ||||
| @ -1,7 +1,17 @@ | ||||
| ## unplanned | ||||
|  | ||||
| FEATURES: | ||||
| * ***gopls support!*** | ||||
|   * use gopls for autocompletion by default in Vim8 and Neovim. | ||||
|   * use gopls for `:GoDef` by setting `g:go_def_mode='gopls'`. | ||||
| * Add support for golangci-lint. | ||||
|   * set `g:go_metalinter_command='golanci-lint'` to use golangci-lint instead | ||||
|     of gometalinter. | ||||
| * New `:GoDefType` command to jump to a type definition from an instance of the | ||||
|   type. | ||||
|  | ||||
| BACKWARDS INCOMPATABILITIES: | ||||
| * g:go_highlight_function_arguments is renamed to g:go_highlight_function_parameters | ||||
| * `g:go_highlight_function_arguments` is renamed to `g:go_highlight_function_parameters` | ||||
|   [[GH-2117]](https://github.com/fatih/vim-go/pull/2117) | ||||
|  | ||||
| IMPROVEMENTS: | ||||
| @ -19,12 +29,12 @@ IMPROVEMENTS: | ||||
| * Do not require `'autowrite'` or `'autowriteall'` to be set when using | ||||
|   autocompletion in module mode. | ||||
|   [[GH-2091]](https://github.com/fatih/vim-go/pull/2091) | ||||
| * Fix use of g:go_metalinter_command _and_ apply it even when autosaving. | ||||
| * Fix use of `g:go_metalinter_command` _and_ apply it even when autosaving. | ||||
|   [[GH-2101]](https://github.com/fatih/vim-go/pull/2101) | ||||
| * Report errors in quickfix when Delve fails to start (e.g. compiler errors). | ||||
|   [[GH-2111]](https://github.com/fatih/vim-go/pull/2111) | ||||
| * Support undo_ftplugin, make most autocmd's buffer-local, and only do the bare | ||||
|   minimum based on file names alone. | ||||
| * Support `'undo_ftplugin'`, make most autocmds buffer-local, and only do the | ||||
|   bare minimum based on file names alone. | ||||
|   [[GH-2108]](https://github.com/fatih/vim-go/pull/2108) | ||||
| * Write a message when `:GoInfo` can't display any results when `g:go_info_mode='gocode'`. | ||||
|   [[GH-2122]](https://github.com/fatih/vim-go/pull/2122) | ||||
| @ -35,8 +45,21 @@ IMPROVEMENTS: | ||||
| * Run `godef` from the current buffer's directory to make sure it works with modules. | ||||
|   [[GH-2150]](https://github.com/fatih/vim-go/pull/2150) | ||||
| * Add a function, `go#tool#DescribeBalloon`, to show information in a balloon | ||||
|   with `'balloonexpr`. (Vim8 only). | ||||
|   with `'balloonexpr'`. (Vim8 only). | ||||
|   [[GH-1975]](https://github.com/fatih/vim-go/pull/1975) | ||||
| * Add initial support for `gopls`. | ||||
|   [[GH-2163]](https://github.com/fatih/vim-go/pull/2163). | ||||
| * Add `:GoDefType` to jump to the type definition of the identifier under the | ||||
|   cursor. | ||||
|   [[GH-2165]](https://github.com/fatih/vim-go/pull/2165) | ||||
| * Notify gopls about changes. | ||||
|   [[GH-2171]](https://github.com/fatih/vim-go/pull/2171) | ||||
| * Respect `g:go_jump_to_error` when running `gometalinter` automatically on | ||||
|   save.  [[GH-2176]](https://github.com/fatih/vim-go/pull/2176) | ||||
| * Use gopls for code completion by default in Vim8 and Neovim. | ||||
|   [[GH-2172]](https://github.com/fatih/vim-go/pull/2172) | ||||
| * Add support for golangci-lint. | ||||
|   [[GH-2182]](https://github.com/fatih/vim-go/pull/2182) | ||||
|  | ||||
| BUG FIXES: | ||||
| * Fix opening of non-existent file from `:GoDeclsDir` when the current | ||||
| @ -55,10 +78,10 @@ BUG FIXES: | ||||
|   [[GH-2097]](https://github.com/fatih/vim-go/pull/2097) | ||||
| * Do not clear buffer-local autocmds of other buffers.  | ||||
|   [[GH-2109]](https://github.com/fatih/vim-go/pull/2109) | ||||
| * Highlight return parameter types when g:go_highlight_function_arguments is set. | ||||
|   [[GH-2116]](https://github.com/fatih/vim-go/pull/2116) | ||||
| * Fix lockup in Neovim when trying to run `:GoDebugTest` when there are no tests. | ||||
|   [[GH-2125]](https://github.com/fatih/vim-go/pull/2125) | ||||
| * Highlight return parameter types when g:go_highlight_function_arguments is | ||||
|   set.  [[GH-2116]](https://github.com/fatih/vim-go/pull/2116) | ||||
| * Fix lockup in Neovim when trying to run `:GoDebugTest` when there are no | ||||
|   tests.  [[GH-2125]](https://github.com/fatih/vim-go/pull/2125) | ||||
| * Keep track of breakpoints correctly when buffer is edited after breakpoints | ||||
|   are set. | ||||
|   [[GH-2126]](https://github.com/fatih/vim-go/pull/2126) | ||||
| @ -66,6 +89,10 @@ BUG FIXES: | ||||
|   [[GH-2127]](https://github.com/fatih/vim-go/pull/2127) | ||||
| * Fix jumping to module or package using godef. | ||||
|   [[GH-2141]](https://github.com/fatih/vim-go/pull/2141) | ||||
| * Fix errors caused by redefining functions within functions. | ||||
|   [[GH-2189]](https://github.com/fatih/vim-go/pull/2189) | ||||
| * Highlight pre-release and metadata in versions in go.mod. | ||||
|   [[GH-2192]](https://github.com/fatih/vim-go/pull/2192) | ||||
|  | ||||
| ## 1.19 - (November 4, 2018) | ||||
|  | ||||
| @ -80,7 +107,7 @@ FEATURES: | ||||
|   * Auto format on save feature for `:GoModFmt`, enabled automatically. Can be | ||||
|     toggled of with the setting `g:go_mod_fmt_autosave` or with the command: | ||||
|     `GoModFmtAutoSaveToggle` | ||||
|   [[GH-1931]](https://github.com/fatih/vim-go/pull/1931) | ||||
|     [[GH-1931]](https://github.com/fatih/vim-go/pull/1931) | ||||
|  | ||||
| IMPROVEMENTS: | ||||
| * Unify async job handling for Vim8 and Neovim. | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| FROM golang:1.11 | ||||
| FROM golang:1.12.1 | ||||
|  | ||||
| RUN apt-get update -y && \ | ||||
|   apt-get install -y build-essential curl git libncurses5-dev python3-pip && \ | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| VIMS ?= vim-7.4 vim-8.0 nvim | ||||
|  | ||||
| all: install test lint | ||||
| all: install lint test | ||||
|  | ||||
| install: | ||||
| 	@echo "==> Installing Vims: $(VIMS)" | ||||
|  | ||||
| @ -13,7 +13,7 @@ This plugin adds Go language support for Vim, with the following main features: | ||||
| * Quickly execute your current file(s) with `:GoRun`. | ||||
| * Improved syntax highlighting and folding. | ||||
| * Debug programs with integrated `delve` support with `:GoDebugStart`. | ||||
| * Completion support via `gocode`. | ||||
| * Completion support via `gocode` and `gopls`. | ||||
| * `gofmt` or `goimports` on save keeps the cursor position and undo history. | ||||
| * Go to symbol/declaration with `:GoDef`. | ||||
| * Look up documentation with `:GoDoc` or `:GoDocBrowser`. | ||||
|  | ||||
| @ -65,7 +65,7 @@ function! go#auto#metalinter_autosave() | ||||
|   endif | ||||
|  | ||||
|   " run gometalinter on save | ||||
|   call go#lint#Gometa(0, 1) | ||||
|   call go#lint#Gometa(!g:go_jump_to_error, 1) | ||||
| endfunction | ||||
|  | ||||
| function! go#auto#modfmt_autosave() | ||||
|  | ||||
| @ -219,12 +219,22 @@ function! s:trim_bracket(val) abort | ||||
|   return a:val | ||||
| endfunction | ||||
|  | ||||
| let s:completions = "" | ||||
| function! go#complete#Complete(findstart, base) abort | ||||
| let s:completions = [] | ||||
|  | ||||
| function! go#complete#GocodeComplete(findstart, base) abort | ||||
|   "findstart = 1 when we need to get the text length | ||||
|   if a:findstart == 1 | ||||
|     execute "silent let s:completions = " . s:gocodeAutocomplete() | ||||
|     return col('.') - s:completions[0] - 1 | ||||
|     let l:completions = [] | ||||
|     execute "silent let l:completions = " . s:gocodeAutocomplete() | ||||
|  | ||||
|     if len(l:completions) == 0 || len(l:completions) >= 2 && len(l:completions[1]) == 0 | ||||
|       " no matches. cancel and leave completion mode. | ||||
|       call go#util#EchoInfo("no matches") | ||||
|       return -3 | ||||
|     endif | ||||
|  | ||||
|     let s:completions = l:completions[1] | ||||
|     return col('.') - l:completions[0] - 1 | ||||
|     "findstart = 0 when we need to return the list of completions | ||||
|   else | ||||
|     let s = getline(".")[col('.') - 1] | ||||
| @ -236,6 +246,36 @@ function! go#complete#Complete(findstart, base) abort | ||||
|   endif | ||||
| endfunction | ||||
|  | ||||
| function! go#complete#Complete(findstart, base) abort | ||||
|   let l:state = {'done': 0, 'matches': []} | ||||
|  | ||||
|   function! s:handler(state, matches) abort dict | ||||
|     let a:state.matches = a:matches | ||||
|     let a:state.done = 1 | ||||
|   endfunction | ||||
|  | ||||
|   "findstart = 1 when we need to get the start of the match | ||||
|   if a:findstart == 1 | ||||
|     call go#lsp#Completion(expand('%:p'), line('.'), col('.'), funcref('s:handler', [l:state])) | ||||
|  | ||||
|     while !l:state.done | ||||
|       sleep 10m | ||||
|     endwhile | ||||
|  | ||||
|     let s:completions = l:state.matches | ||||
|  | ||||
|     if len(l:state.matches) == 0 | ||||
|       " no matches. cancel and leave completion mode. | ||||
|       call go#util#EchoInfo("no matches") | ||||
|       return -3 | ||||
|     endif | ||||
|  | ||||
|     return col('.') | ||||
|   else "findstart = 0 when we need to return the list of completions | ||||
|     return s:completions | ||||
|   endif | ||||
| endfunction | ||||
|  | ||||
| function! go#complete#ToggleAutoTypeInfo() abort | ||||
|   if go#config#AutoTypeInfo() | ||||
|     call go#config#SetAutoTypeInfo(0) | ||||
|  | ||||
| @ -210,6 +210,12 @@ function! go#config#DebugCommands() abort | ||||
|   return g:go_debug_commands | ||||
| endfunction | ||||
|  | ||||
| function! go#config#LspLog() abort | ||||
|   " make sure g:go_lsp_log is set so that it can be added to easily. | ||||
|   let g:go_lsp_log = get(g:, 'go_lsp_log', []) | ||||
|   return g:go_lsp_log | ||||
| endfunction | ||||
|  | ||||
| function! go#config#SetDebugDiag(value) abort | ||||
|   let g:go_debug_diag = a:value | ||||
| endfunction | ||||
| @ -235,15 +241,27 @@ function! go#config#SetTemplateAutocreate(value) abort | ||||
| endfunction | ||||
|  | ||||
| function! go#config#MetalinterCommand() abort | ||||
|   return get(g:, "go_metalinter_command", "") | ||||
|   return get(g:, "go_metalinter_command", "gometalinter") | ||||
| endfunction | ||||
|  | ||||
| function! go#config#MetalinterAutosaveEnabled() abort | ||||
|   return get(g:, 'go_metalinter_autosave_enabled', ['vet', 'golint']) | ||||
|   let l:default_enabled = ["vet", "golint"] | ||||
|  | ||||
|   if go#config#MetalinterCommand() == "golangci-lint" | ||||
|     let l:default_enabled = ["govet", "golint"] | ||||
|   endif | ||||
|  | ||||
|   return get(g:, "go_metalinter_autosave_enabled", default_enabled) | ||||
| endfunction | ||||
|  | ||||
| function! go#config#MetalinterEnabled() abort | ||||
|   return get(g:, "go_metalinter_enabled", ['vet', 'golint', 'errcheck']) | ||||
|   let l:default_enabled = ["vet", "golint", "errcheck"] | ||||
|  | ||||
|   if go#config#MetalinterCommand() == "golangci-lint" | ||||
|     let l:default_enabled = ["govet", "golint"] | ||||
|   endif | ||||
|  | ||||
|   return get(g:, "go_metalinter_enabled", default_enabled) | ||||
| endfunction | ||||
|  | ||||
| function! go#config#MetalinterDisabled() abort | ||||
| @ -444,7 +462,6 @@ function! go#config#EchoGoInfo() abort | ||||
|   return get(g:, "go_echo_go_info", 1) | ||||
| endfunction | ||||
|  | ||||
|  | ||||
| " Set the default value. A value of "1" is a shortcut for this, for | ||||
| " compatibility reasons. | ||||
| if exists("g:go_gorename_prefill") && g:go_gorename_prefill == 1 | ||||
|  | ||||
| @ -507,23 +507,7 @@ function! s:out_cb(ch, msg) abort | ||||
|     if has('nvim') | ||||
|       let s:state['data'] = [] | ||||
|       let l:state = {'databuf': ''} | ||||
|       function! s:on_data(ch, data, event) dict abort closure | ||||
|         let l:data = self.databuf | ||||
|         for msg in a:data | ||||
|           let l:data .= l:msg | ||||
|         endfor | ||||
|  | ||||
|         try | ||||
|           let l:res = json_decode(l:data) | ||||
|           let s:state['data'] = add(s:state['data'], l:res) | ||||
|           let self.databuf = '' | ||||
|         catch | ||||
|           " there isn't a complete message in databuf: buffer l:data and try | ||||
|           " again when more data comes in. | ||||
|           let self.databuf = l:data | ||||
|         finally | ||||
|         endtry | ||||
|       endfunction | ||||
|        | ||||
|       " explicitly bind callback to state so that within it, self will | ||||
|       " always refer to state. See :help Partial for more information. | ||||
|       let l:state.on_data = function('s:on_data', [], l:state) | ||||
| @ -560,6 +544,24 @@ function! s:out_cb(ch, msg) abort | ||||
|   endif | ||||
| endfunction | ||||
|  | ||||
| function! s:on_data(ch, data, event) dict abort | ||||
|   let l:data = self.databuf | ||||
|   for l:msg in a:data | ||||
|     let l:data .= l:msg | ||||
|   endfor | ||||
|  | ||||
|   try | ||||
|     let l:res = json_decode(l:data) | ||||
|     let s:state['data'] = add(s:state['data'], l:res) | ||||
|     let self.databuf = '' | ||||
|   catch | ||||
|     " there isn't a complete message in databuf: buffer l:data and try | ||||
|     " again when more data comes in. | ||||
|     let self.databuf = l:data | ||||
|   finally | ||||
|   endtry | ||||
| endfunction | ||||
|  | ||||
| " Start the debug mode. The first argument is the package name to compile and | ||||
| " debug, anything else will be passed to the running program. | ||||
| function! go#debug#Start(is_test, ...) abort | ||||
|  | ||||
| @ -5,7 +5,7 @@ set cpo&vim | ||||
| let s:go_stack = [] | ||||
| let s:go_stack_level = 0 | ||||
|  | ||||
| function! go#def#Jump(mode) abort | ||||
| function! go#def#Jump(mode, type) abort | ||||
|   let fname = fnamemodify(expand("%"), ':p:gs?\\?/?') | ||||
|  | ||||
|   " so guru right now is slow for some people. previously we were using | ||||
| @ -65,8 +65,18 @@ function! go#def#Jump(mode) abort | ||||
|     else | ||||
|       let [l:out, l:err] = go#util#ExecInDir(l:cmd) | ||||
|     endif | ||||
|   elseif bin_name == 'gopls' | ||||
|     let [l:line, l:col] = getpos('.')[1:2] | ||||
|     " delegate to gopls, with an empty job object and an exit status of 0 | ||||
|     " (they're irrelevant for gopls). | ||||
|     if a:type | ||||
|       call go#lsp#TypeDef(l:fname, l:line, l:col, function('s:jump_to_declaration_cb', [a:mode, 'gopls', {}, 0])) | ||||
|     else | ||||
|       call go#lsp#Definition(l:fname, l:line, l:col, function('s:jump_to_declaration_cb', [a:mode, 'gopls', {}, 0])) | ||||
|     endif | ||||
|     return | ||||
|   else | ||||
|     call go#util#EchoError('go_def_mode value: '. bin_name .' is not valid. Valid values are: [godef, guru]') | ||||
|     call go#util#EchoError('go_def_mode value: '. bin_name .' is not valid. Valid values are: [godef, guru, gopls]') | ||||
|     return | ||||
|   endif | ||||
|  | ||||
| @ -85,15 +95,19 @@ function! s:jump_to_declaration_cb(mode, bin_name, job, exit_status, data) abort | ||||
|  | ||||
|   call go#def#jump_to_declaration(a:data[0], a:mode, a:bin_name) | ||||
|  | ||||
|   " capture the active window so that after the exit_cb and close_cb callbacks | ||||
|   " can return to it when a:mode caused a split. | ||||
|   " capture the active window so that callbacks for jobs, exit_cb and | ||||
|   " close_cb, and callbacks for gopls can return to it when a:mode caused a | ||||
|   " split. | ||||
|   let self.winid = win_getid(winnr()) | ||||
| endfunction | ||||
|  | ||||
| " go#def#jump_to_declaration parses out (expected to be | ||||
| " 'filename:line:col: message'). | ||||
| function! go#def#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. | ||||
|     " append the type information to the same line so it will be parsed | ||||
|     " correctly using guru's output format. | ||||
|     " This makes it compatible with guru output. | ||||
|     let final_out = join(split(a:out, '\n'), ':') | ||||
|   endif | ||||
|  | ||||
| @ -50,7 +50,7 @@ func! Test_Jump_leaves_lists() abort | ||||
|  | ||||
|     let l:bufnr = bufnr('%') | ||||
|     call cursor(6, 7) | ||||
|     call go#def#Jump('') | ||||
|     call go#def#Jump('', 0) | ||||
|  | ||||
|     let start = reltime() | ||||
|     while bufnr('%') == l:bufnr && reltimefloat(reltime(start)) < 10 | ||||
|  | ||||
| @ -128,10 +128,6 @@ function! s:async_guru(args) abort | ||||
|         \ 'parse' : get(a:args, 'custom_parse', funcref("s:parse_guru_output")) | ||||
|       \ } | ||||
|  | ||||
|   function! s:complete(job, exit_status, messages) dict abort | ||||
|     let output = join(a:messages, "\n") | ||||
|     call self.parse(a:exit_status, output, self.mode) | ||||
|   endfunction | ||||
|   " explicitly bind complete to state so that within it, self will | ||||
|   " always refer to state. See :help Partial for more information. | ||||
|   let state.complete = function('s:complete', [], state) | ||||
| @ -164,6 +160,11 @@ function! s:async_guru(args) abort | ||||
|   endif | ||||
| endfunc | ||||
|  | ||||
| function! s:complete(job, exit_status, messages) dict abort | ||||
|   let output = join(a:messages, "\n") | ||||
|   call self.parse(a:exit_status, output, self.mode) | ||||
| endfunction | ||||
|  | ||||
| " run_guru runs the given guru argument | ||||
| function! s:run_guru(args) abort | ||||
|   if go#util#has_job() | ||||
| @ -239,91 +240,6 @@ function! go#guru#DescribeInfo(showstatus) abort | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   function! s:info(exit_val, output, mode) | ||||
|     if a:exit_val != 0 | ||||
|       return | ||||
|     endif | ||||
|  | ||||
|     if a:output[0] !=# '{' | ||||
|       return | ||||
|     endif | ||||
|  | ||||
|     if empty(a:output) || type(a:output) != type("") | ||||
|       return | ||||
|     endif | ||||
|  | ||||
|     let result = json_decode(a:output) | ||||
|     if type(result) != type({}) | ||||
|       call go#util#EchoError(printf("malformed output from guru: %s", a:output)) | ||||
|       return | ||||
|     endif | ||||
|  | ||||
|     if !has_key(result, 'detail') | ||||
|       " if 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#ShowInfo(info) | ||||
|   endfunction | ||||
|  | ||||
|   let args = { | ||||
|         \ 'mode': 'describe', | ||||
|         \ 'format': 'json', | ||||
| @ -336,6 +252,91 @@ function! go#guru#DescribeInfo(showstatus) abort | ||||
|   call s:run_guru(args) | ||||
| endfunction | ||||
|  | ||||
| function! s:info(exit_val, output, mode) | ||||
|   if a:exit_val != 0 | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   if a:output[0] !=# '{' | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   if empty(a:output) || type(a:output) != type("") | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   let result = json_decode(a:output) | ||||
|   if type(result) != type({}) | ||||
|     call go#util#EchoError(printf("malformed output from guru: %s", a:output)) | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   if !has_key(result, 'detail') | ||||
|     " if 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#ShowInfo(info) | ||||
| endfunction | ||||
|  | ||||
| " Show possible targets of selected function call | ||||
| function! go#guru#Callees(selected) abort | ||||
|   let args = { | ||||
| @ -609,105 +610,6 @@ function! go#guru#DescribeBalloon() abort | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   function! s:describe_balloon(exit_val, output, mode) | ||||
|     if a:exit_val != 0 | ||||
|       return | ||||
|     endif | ||||
|  | ||||
|     if a:output[0] !=# '{' | ||||
|       return | ||||
|     endif | ||||
|  | ||||
|     if empty(a:output) || type(a:output) != type("") | ||||
|       return | ||||
|     endif | ||||
|  | ||||
|     let l:result = json_decode(a:output) | ||||
|     if type(l:result) != type({}) | ||||
|       call go#util#EchoError(printf('malformed output from guru: %s', a:output)) | ||||
|       return | ||||
|     endif | ||||
|  | ||||
|     let l:info = [] | ||||
|     if has_key(l:result, 'desc') | ||||
|       if l:result['desc'] != 'identifier' | ||||
|         let l:info = add(l:info, l:result['desc']) | ||||
|       endif | ||||
|     endif | ||||
|  | ||||
|     if has_key(l:result, 'detail') | ||||
|       let l:detail = l:result['detail'] | ||||
|  | ||||
|       " guru gives different information based on the detail mode. Let try to | ||||
|       " extract the most useful information | ||||
|  | ||||
|       if l:detail == 'value' | ||||
|         if !has_key(l:result, 'value') | ||||
|           call go#util#EchoError('value key is missing. Please open a bug report on vim-go repo.') | ||||
|           return | ||||
|         endif | ||||
|  | ||||
|         let l:val = l:result['value'] | ||||
|         if !has_key(l:val, 'type') | ||||
|           call go#util#EchoError('type key is missing (value.type). Please open a bug report on vim-go repo.') | ||||
|           return | ||||
|         endif | ||||
|  | ||||
|         let l:info = add(l:info, printf('type: %s', l:val['type'])) | ||||
|         if has_key(l:val, 'value') | ||||
|           let l:info = add(l:info, printf('value: %s', l:val['value'])) | ||||
|         endif | ||||
|       elseif l:detail == 'type' | ||||
|         if !has_key(l:result, 'type') | ||||
|           call go#util#EchoError('type key is missing. Please open a bug report on vim-go repo.') | ||||
|           return | ||||
|         endif | ||||
|  | ||||
|         let l:type = l:result['type'] | ||||
|         if !has_key(l:type, 'type') | ||||
|           call go#util#EchoError('type key is missing (type.type). Please open a bug report on vim-go repo.') | ||||
|           return | ||||
|         endif | ||||
|  | ||||
|         let l:info = add(l:info, printf('type: %s', l:type['type'])) | ||||
|  | ||||
|         if has_key(l:type, 'methods') | ||||
|           let l:info = add(l:info, 'methods:') | ||||
|           for l:m in l:type.methods | ||||
|             let l:info = add(l:info, printf("\t%s", l:m['name'])) | ||||
|           endfor | ||||
|         endif | ||||
|       elseif l:detail == 'package' | ||||
|         if !has_key(l:result, 'package') | ||||
|           call go#util#EchoError('package key is missing. Please open a bug report on vim-go repo.') | ||||
|           return | ||||
|         endif | ||||
|  | ||||
|         let l:package = result['package'] | ||||
|         if !has_key(l:package, 'path') | ||||
|           call go#util#EchoError('path key is missing (package.path). Please open a bug report on vim-go repo.') | ||||
|           return | ||||
|         endif | ||||
|  | ||||
|         let l:info = add(l:info, printf('package: %s', l:package["path"])) | ||||
|       elseif l:detail == 'unknown' | ||||
|         " the description is already included in l:info, and there's no other | ||||
|         " information on unknowns. | ||||
|       else | ||||
|         call go#util#EchoError(printf('unknown detail mode (%s) found. Please open a bug report on vim-go repo', l:detail)) | ||||
|         return | ||||
|       endif | ||||
|     endif | ||||
|  | ||||
|     if has('balloon_eval') | ||||
|       call balloon_show(join(l:info, "\n")) | ||||
|       return | ||||
|     endif | ||||
|  | ||||
|     call balloon_show(l:info) | ||||
|   endfunction | ||||
|  | ||||
|  | ||||
|   " change the active window to the window where the cursor is. | ||||
|   let l:winid = win_getid(winnr()) | ||||
|   call win_gotoid(v:beval_winid) | ||||
| @ -730,6 +632,104 @@ function! go#guru#DescribeBalloon() abort | ||||
|   return '' | ||||
| endfunction | ||||
|  | ||||
| function! s:describe_balloon(exit_val, output, mode) | ||||
|   if a:exit_val != 0 | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   if a:output[0] !=# '{' | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   if empty(a:output) || type(a:output) != type("") | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   let l:result = json_decode(a:output) | ||||
|   if type(l:result) != type({}) | ||||
|     call go#util#EchoError(printf('malformed output from guru: %s', a:output)) | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   let l:info = [] | ||||
|   if has_key(l:result, 'desc') | ||||
|     if l:result['desc'] != 'identifier' | ||||
|       let l:info = add(l:info, l:result['desc']) | ||||
|     endif | ||||
|   endif | ||||
|  | ||||
|   if has_key(l:result, 'detail') | ||||
|     let l:detail = l:result['detail'] | ||||
|  | ||||
|     " guru gives different information based on the detail mode. Let try to | ||||
|     " extract the most useful information | ||||
|  | ||||
|     if l:detail == 'value' | ||||
|       if !has_key(l:result, 'value') | ||||
|         call go#util#EchoError('value key is missing. Please open a bug report on vim-go repo.') | ||||
|         return | ||||
|       endif | ||||
|  | ||||
|       let l:val = l:result['value'] | ||||
|       if !has_key(l:val, 'type') | ||||
|         call go#util#EchoError('type key is missing (value.type). Please open a bug report on vim-go repo.') | ||||
|         return | ||||
|       endif | ||||
|  | ||||
|       let l:info = add(l:info, printf('type: %s', l:val['type'])) | ||||
|       if has_key(l:val, 'value') | ||||
|         let l:info = add(l:info, printf('value: %s', l:val['value'])) | ||||
|       endif | ||||
|     elseif l:detail == 'type' | ||||
|       if !has_key(l:result, 'type') | ||||
|         call go#util#EchoError('type key is missing. Please open a bug report on vim-go repo.') | ||||
|         return | ||||
|       endif | ||||
|  | ||||
|       let l:type = l:result['type'] | ||||
|       if !has_key(l:type, 'type') | ||||
|         call go#util#EchoError('type key is missing (type.type). Please open a bug report on vim-go repo.') | ||||
|         return | ||||
|       endif | ||||
|  | ||||
|       let l:info = add(l:info, printf('type: %s', l:type['type'])) | ||||
|  | ||||
|       if has_key(l:type, 'methods') | ||||
|         let l:info = add(l:info, 'methods:') | ||||
|         for l:m in l:type.methods | ||||
|           let l:info = add(l:info, printf("\t%s", l:m['name'])) | ||||
|         endfor | ||||
|       endif | ||||
|     elseif l:detail == 'package' | ||||
|       if !has_key(l:result, 'package') | ||||
|         call go#util#EchoError('package key is missing. Please open a bug report on vim-go repo.') | ||||
|         return | ||||
|       endif | ||||
|  | ||||
|       let l:package = result['package'] | ||||
|       if !has_key(l:package, 'path') | ||||
|         call go#util#EchoError('path key is missing (package.path). Please open a bug report on vim-go repo.') | ||||
|         return | ||||
|       endif | ||||
|  | ||||
|       let l:info = add(l:info, printf('package: %s', l:package["path"])) | ||||
|     elseif l:detail == 'unknown' | ||||
|       " the description is already included in l:info, and there's no other | ||||
|       " information on unknowns. | ||||
|     else | ||||
|       call go#util#EchoError(printf('unknown detail mode (%s) found. Please open a bug report on vim-go repo', l:detail)) | ||||
|       return | ||||
|     endif | ||||
|   endif | ||||
|  | ||||
|   if has('balloon_eval') | ||||
|     call balloon_show(join(l:info, "\n")) | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   call balloon_show(l:info) | ||||
| endfunction | ||||
|  | ||||
| " restore Vi compatibility settings | ||||
| let &cpo = s:cpo_save | ||||
| unlet s:cpo_save | ||||
|  | ||||
| @ -6,11 +6,14 @@ function! Test_gomodVersion_highlight() abort | ||||
|   try | ||||
|     syntax on | ||||
|  | ||||
|     let l:dir= gotest#write_file('gomodtest/go.mod', [ | ||||
|     let l:dir = gotest#write_file('gomodtest/go.mod', [ | ||||
|           \ 'module github.com/fatih/vim-go', | ||||
|           \ '', | ||||
|           \ '\x1frequire (', | ||||
|           \ '\tversion/simple v1.0.0', | ||||
|           \ '\tversion/simple-pre-release v1.0.0-rc', | ||||
|           \ '\tversion/simple-pre-release v1.0.0+meta', | ||||
|           \ '\tversion/simple-pre-release v1.0.0-rc+meta', | ||||
|           \ '\tversion/pseudo/premajor v1.0.0-20060102150405-0123456789abcdef', | ||||
|           \ '\tversion/pseudo/prerelease v1.0.0-prerelease.0.20060102150405-0123456789abcdef', | ||||
|           \ '\tversion/pseudo/prepatch v1.0.1-0.20060102150405-0123456789abcdef', | ||||
| @ -55,11 +58,10 @@ function! Test_gomodVersion_incompatible_highlight() abort | ||||
|   try | ||||
|     syntax on | ||||
|  | ||||
|     let l:dir= gotest#write_file('gomodtest/go.mod', [ | ||||
|     let l:dir = gotest#write_file('gomodtest/go.mod', [ | ||||
|           \ 'module github.com/fatih/vim-go', | ||||
|           \ '', | ||||
|           \ '\x1frequire (', | ||||
|           \ '\tversion/invalid/incompatible v1.0.0+incompatible', | ||||
|           \ '\tversion/invalid/premajor/incompatible v1.0.0-20060102150405-0123456789abcdef+incompatible', | ||||
|           \ '\tversion/invalid/prerelease/incompatible v1.0.0-prerelease.0.20060102150405-0123456789abcdef+incompatible', | ||||
|           \ '\tversion/invalid/prepatch/incompatible v1.0.1-0.20060102150405-0123456789abcdef+incompatible', | ||||
|  | ||||
| @ -5,7 +5,7 @@ set cpo&vim | ||||
| let s:templatepath = go#util#Join(expand('<sfile>:p:h:h:h'), '.github', 'ISSUE_TEMPLATE.md') | ||||
|  | ||||
| function! go#issue#New() abort | ||||
|   let body = substitute(s:issuebody(), '[^A-Za-z0-9_.~-]', '\="%".printf("%02X",char2nr(submatch(0)))', 'g') | ||||
|   let body = go#uriEncode(s:issuebody()) | ||||
|   let url = "https://github.com/fatih/vim-go/issues/new?body=" . l:body | ||||
|   call go#util#OpenBrowser(l:url) | ||||
| endfunction | ||||
|  | ||||
| @ -145,23 +145,6 @@ function! go#job#Options(args) | ||||
|     let state.custom_complete = a:args.complete | ||||
|   endif | ||||
|  | ||||
|   function! s:start(args) dict | ||||
|     if go#config#EchoCommandInfo() && self.statustype != "" | ||||
|       let prefix = '[' . self.statustype . '] ' | ||||
|       call go#util#EchoSuccess(prefix . "dispatched") | ||||
|     endif | ||||
|  | ||||
|     if self.statustype != '' | ||||
|       let status = { | ||||
|             \ 'desc': 'current status', | ||||
|             \ 'type': self.statustype, | ||||
|             \ 'state': "started", | ||||
|             \ } | ||||
|  | ||||
|       call go#statusline#Update(self.jobdir, status) | ||||
|     endif | ||||
|     let self.started_at = reltime() | ||||
|   endfunction | ||||
|   " explicitly bind _start to state so that within it, self will | ||||
|   " always refer to state. See :help Partial for more information. | ||||
|   " | ||||
| @ -169,35 +152,14 @@ function! go#job#Options(args) | ||||
|   " outside of this file. | ||||
|   let cbs._start = function('s:start', [''], state) | ||||
|  | ||||
|   function! s:callback(chan, msg) dict | ||||
|     call add(self.messages, a:msg) | ||||
|   endfunction | ||||
|   " explicitly bind callback to state so that within it, self will | ||||
|   " always refer to state. See :help Partial for more information. | ||||
|   let cbs.callback = function('s:callback', [], state) | ||||
|  | ||||
|   function! s:exit_cb(job, exitval) dict | ||||
|     let self.exit_status = a:exitval | ||||
|     let self.exited = 1 | ||||
|  | ||||
|     call self.show_status(a:job, a:exitval) | ||||
|  | ||||
|     if self.closed || has('nvim') | ||||
|       call self.complete(a:job, self.exit_status, self.messages) | ||||
|     endif | ||||
|   endfunction | ||||
|   " explicitly bind exit_cb to state so that within it, self will always refer | ||||
|   " to state. See :help Partial for more information. | ||||
|   let cbs.exit_cb = function('s:exit_cb', [], state) | ||||
|  | ||||
|   function! s:close_cb(ch) dict | ||||
|     let self.closed = 1 | ||||
|  | ||||
|     if self.exited | ||||
|       let job = ch_getjob(a:ch) | ||||
|       call self.complete(job, self.exit_status, self.messages) | ||||
|     endif | ||||
|   endfunction | ||||
|   " explicitly bind close_cb to state so that within it, self will | ||||
|   " always refer to state. See :help Partial for more information. | ||||
|   let cbs.close_cb = function('s:close_cb', [], state) | ||||
| @ -261,6 +223,48 @@ function! go#job#Options(args) | ||||
|   return cbs | ||||
| endfunction | ||||
|  | ||||
| function! s:start(args) dict | ||||
|   if go#config#EchoCommandInfo() && self.statustype != "" | ||||
|     let prefix = '[' . self.statustype . '] ' | ||||
|     call go#util#EchoSuccess(prefix . "dispatched") | ||||
|   endif | ||||
|  | ||||
|   if self.statustype != '' | ||||
|     let status = { | ||||
|           \ 'desc': 'current status', | ||||
|           \ 'type': self.statustype, | ||||
|           \ 'state': "started", | ||||
|           \ } | ||||
|  | ||||
|     call go#statusline#Update(self.jobdir, status) | ||||
|   endif | ||||
|   let self.started_at = reltime() | ||||
| endfunction | ||||
|  | ||||
| function! s:callback(chan, msg) dict | ||||
|   call add(self.messages, a:msg) | ||||
| endfunction | ||||
|  | ||||
| function! s:exit_cb(job, exitval) dict | ||||
|   let self.exit_status = a:exitval | ||||
|   let self.exited = 1 | ||||
|  | ||||
|   call self.show_status(a:job, a:exitval) | ||||
|  | ||||
|   if self.closed || has('nvim') | ||||
|     call self.complete(a:job, self.exit_status, self.messages) | ||||
|   endif | ||||
| endfunction | ||||
|  | ||||
| function! s:close_cb(ch) dict | ||||
|   let self.closed = 1 | ||||
|  | ||||
|   if self.exited | ||||
|     let job = ch_getjob(a:ch) | ||||
|     call self.complete(job, self.exit_status, self.messages) | ||||
|   endif | ||||
| endfunction | ||||
|  | ||||
| " go#job#Start runs a job. The options are expected to be the options | ||||
| " suitable for Vim8 jobs. When called from Neovim, Vim8 options will be | ||||
| " transformed to their Neovim equivalents. | ||||
| @ -276,17 +280,24 @@ function! go#job#Start(cmd, options) | ||||
|   " early if the directory does not exist. This helps avoid errors when | ||||
|   " working with plugins that use virtual files that don't actually exist on | ||||
|   " the file system. | ||||
|   let filedir = expand("%:p:h") | ||||
|   let l:filedir = expand("%:p:h") | ||||
|   if has_key(l:options, 'cwd') && !isdirectory(l:options.cwd) | ||||
|       return | ||||
|   elseif !isdirectory(filedir) | ||||
|   elseif !isdirectory(l:filedir) | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   let l:manualcd = 0 | ||||
|   if !has_key(l:options, 'cwd') | ||||
|     " pre start | ||||
|     let l:manualcd = 1 | ||||
|     let dir = getcwd() | ||||
|     execute l:cd fnameescape(filedir) | ||||
|   elseif !(has("patch-8.0.0902") || has('nvim')) | ||||
|     let l:manualcd = 1 | ||||
|     let l:dir = l:options.cwd | ||||
|     execute l:cd fnameescape(l:dir) | ||||
|     call remove(l:options, 'cwd') | ||||
|   endif | ||||
|  | ||||
|   if has_key(l:options, '_start') | ||||
| @ -296,6 +307,11 @@ function! go#job#Start(cmd, options) | ||||
|     unlet l:options._start | ||||
|   endif | ||||
|  | ||||
|   " noblock was added in 8.1.350; remove it if it's not supported. | ||||
|   if has_key(l:options, 'noblock') && (has('nvim') || !has("patch-8.1.350")) | ||||
|     call remove(l:options, 'noblock') | ||||
|   endif | ||||
|  | ||||
|   if go#util#HasDebug('shell-commands') | ||||
|     call go#util#EchoInfo('job command: ' . string(a:cmd)) | ||||
|   endif | ||||
| @ -322,9 +338,9 @@ function! go#job#Start(cmd, options) | ||||
|     let job = job_start(l:cmd, l:options) | ||||
|   endif | ||||
|  | ||||
|   if !has_key(l:options, 'cwd') | ||||
|   if l:manualcd | ||||
|     " post start | ||||
|     execute l:cd fnameescape(dir) | ||||
|     execute l:cd fnameescape(l:dir) | ||||
|   endif | ||||
|  | ||||
|   return job | ||||
| @ -337,6 +353,9 @@ function! s:neooptions(options) | ||||
|   let l:options['stdout_buf'] = '' | ||||
|   let l:options['stderr_buf'] = '' | ||||
|  | ||||
|   let l:err_mode = get(a:options, 'err_mode', get(a:options, 'mode', '')) | ||||
|   let l:out_mode = get(a:options, 'out_mode', get(a:options, 'mode', '')) | ||||
|  | ||||
|   for key in keys(a:options) | ||||
|       if key == 'cwd' | ||||
|         let l:options['cwd'] = a:options['cwd'] | ||||
| @ -347,17 +366,11 @@ function! s:neooptions(options) | ||||
|         let l:options['callback'] = a:options['callback'] | ||||
|  | ||||
|         if !has_key(a:options, 'out_cb') | ||||
|           function! s:callback2on_stdout(ch, data, event) dict | ||||
|             let self.stdout_buf = s:neocb(a:ch, self.stdout_buf, a:data, self.callback) | ||||
|           endfunction | ||||
|           let l:options['on_stdout'] = function('s:callback2on_stdout', [], l:options) | ||||
|           let l:options['on_stdout'] = function('s:callback2on_stdout', [l:out_mode], l:options) | ||||
|         endif | ||||
|  | ||||
|         if !has_key(a:options, 'err_cb') | ||||
|           function! s:callback2on_stderr(ch, data, event) dict | ||||
|             let self.stderr_buf = s:neocb(a:ch, self.stderr_buf, a:data, self.callback) | ||||
|           endfunction | ||||
|           let l:options['on_stderr'] = function('s:callback2on_stderr', [], l:options) | ||||
|           let l:options['on_stderr'] = function('s:callback2on_stderr', [l:err_mode], l:options) | ||||
|         endif | ||||
|  | ||||
|         continue | ||||
| @ -365,29 +378,20 @@ function! s:neooptions(options) | ||||
|  | ||||
|       if key == 'out_cb' | ||||
|         let l:options['out_cb'] = a:options['out_cb'] | ||||
|         function! s:on_stdout(ch, data, event) dict | ||||
|           let self.stdout_buf = s:neocb(a:ch, self.stdout_buf, a:data, self.out_cb) | ||||
|         endfunction | ||||
|         let l:options['on_stdout'] = function('s:on_stdout', [], l:options) | ||||
|         let l:options['on_stdout'] = function('s:on_stdout', [l:out_mode], l:options) | ||||
|  | ||||
|         continue | ||||
|       endif | ||||
|  | ||||
|       if key == 'err_cb' | ||||
|         let l:options['err_cb'] = a:options['err_cb'] | ||||
|         function! s:on_stderr(ch, data, event) dict | ||||
|           let self.stderr_buf = s:neocb(a:ch, self.stderr_buf, a:data, self.err_cb ) | ||||
|         endfunction | ||||
|         let l:options['on_stderr'] = function('s:on_stderr', [], l:options) | ||||
|         let l:options['on_stderr'] = function('s:on_stderr', [l:err_mode], l:options) | ||||
|  | ||||
|         continue | ||||
|       endif | ||||
|  | ||||
|       if key == 'exit_cb' | ||||
|         let l:options['exit_cb'] = a:options['exit_cb'] | ||||
|         function! s:on_exit(jobid, exitval, event) dict | ||||
|           call self.exit_cb(a:jobid, a:exitval) | ||||
|         endfunction | ||||
|         let l:options['on_exit'] = function('s:on_exit', [], l:options) | ||||
|  | ||||
|         continue | ||||
| @ -407,6 +411,26 @@ function! s:neooptions(options) | ||||
|   return l:options | ||||
| endfunction | ||||
|  | ||||
| function! s:callback2on_stdout(mode, ch, data, event) dict | ||||
|   let self.stdout_buf = s:neocb(a:mode, a:ch, self.stdout_buf, a:data, self.callback) | ||||
| endfunction | ||||
|  | ||||
| function! s:callback2on_stderr(mode, ch, data, event) dict | ||||
|   let self.stderr_buf = s:neocb(a:mode, a:ch, self.stderr_buf, a:data, self.callback) | ||||
| endfunction | ||||
|  | ||||
| function! s:on_stdout(mode, ch, data, event) dict | ||||
|   let self.stdout_buf = s:neocb(a:mode, a:ch, self.stdout_buf, a:data, self.out_cb) | ||||
| endfunction | ||||
|  | ||||
| function! s:on_stderr(mode, ch, data, event) dict | ||||
|   let self.stderr_buf = s:neocb(a:mode, a:ch, self.stderr_buf, a:data, self.err_cb ) | ||||
| endfunction | ||||
|  | ||||
| function! s:on_exit(jobid, exitval, event) dict | ||||
|   call self.exit_cb(a:jobid, a:exitval) | ||||
| endfunction | ||||
|  | ||||
| function! go#job#Stop(job) abort | ||||
|   if has('nvim') | ||||
|     call jobstop(a:job) | ||||
| @ -436,15 +460,34 @@ function! s:winjobarg(idx, val) abort | ||||
|   return a:val | ||||
| endfunction | ||||
|  | ||||
| function! s:neocb(ch, buf, data, callback) | ||||
| function! s:neocb(mode, ch, buf, data, callback) | ||||
|   " dealing with the channel lines of Neovim is awful. The docs (:help | ||||
|   " channel-lines) say: | ||||
|   " stream event handlers may receive partial (incomplete) lines. For a | ||||
|   " given invocation of on_stdout etc, `a:data` is not guaranteed to end | ||||
|   " with a newline. | ||||
|   "   - `abcdefg` may arrive as `['abc']`, `['defg']`. | ||||
|   "   - `abc\nefg` may arrive as `['abc', '']`, `['efg']` or `['abc']`, | ||||
|   "     `['','efg']`, or even `['ab']`, `['c','efg']`. | ||||
|   "     stream event handlers may receive partial (incomplete) lines. For a | ||||
|   "     given invocation of on_stdout etc, `a:data` is not guaranteed to end | ||||
|   "     with a newline. | ||||
|   "       - `abcdefg` may arrive as `['abc']`, `['defg']`. | ||||
|   "       - `abc\nefg` may arrive as `['abc', '']`, `['efg']` or `['abc']`, | ||||
|   "         `['','efg']`, or even `['ab']`, `['c','efg']`. | ||||
|   " | ||||
|   " Thankfully, though, this is explained a bit better in an issue: | ||||
|   " https://github.com/neovim/neovim/issues/3555. Specifically in these two | ||||
|   " comments: | ||||
|   "     * https://github.com/neovim/neovim/issues/3555#issuecomment-152290804 | ||||
|   "     * https://github.com/neovim/neovim/issues/3555#issuecomment-152588749 | ||||
|   " | ||||
|   " The key is | ||||
|   "     Every item in the list passed to job control callbacks represents a | ||||
|   "     string after a newline(Except the first, of course). If the program | ||||
|   "     outputs: "hello\nworld" the corresponding list is ["hello", "world"]. | ||||
|   "     If the program outputs "hello\nworld\n", the corresponding list is | ||||
|   "     ["hello", "world", ""]. In other words, you can always determine if | ||||
|   "     the last line received is complete or not. | ||||
|   " and | ||||
|   "     for every list you receive in a callback, all items except the first | ||||
|   "     represent newlines. | ||||
|  | ||||
|   let l:buf = '' | ||||
|  | ||||
|   " a single empty string means EOF was reached. | ||||
|   if len(a:data) == 1 && a:data[0] == '' | ||||
| @ -455,20 +498,28 @@ function! s:neocb(ch, buf, data, callback) | ||||
|     endif | ||||
|  | ||||
|     let l:data = [a:buf] | ||||
|     let l:buf = '' | ||||
|   else | ||||
|     let l:data = copy(a:data) | ||||
|     let l:data[0] = a:buf . l:data[0] | ||||
|  | ||||
|     " The last element may be a partial line; save it for next time. | ||||
|     let l:buf = l:data[-1] | ||||
|  | ||||
|     let l:data = l:data[:-2] | ||||
|     if a:mode != 'raw' | ||||
|       let l:buf = l:data[-1] | ||||
|       let l:data = l:data[:-2] | ||||
|     endif | ||||
|   endif | ||||
|  | ||||
|   for l:msg in l:data | ||||
|   let l:i = 0 | ||||
|   let l:last = len(l:data) - 1 | ||||
|   while l:i <= l:last | ||||
|     let l:msg = l:data[l:i] | ||||
|     if a:mode == 'raw' && l:i < l:last | ||||
|       let l:msg = l:msg . "\n" | ||||
|     endif | ||||
|     call a:callback(a:ch, l:msg) | ||||
|   endfor | ||||
|  | ||||
|     let l:i += 1 | ||||
|   endwhile | ||||
|  | ||||
|   return l:buf | ||||
| endfunction | ||||
|  | ||||
| @ -9,22 +9,14 @@ function! go#lint#Gometa(bang, autosave, ...) abort | ||||
|     let goargs = a:000 | ||||
|   endif | ||||
|  | ||||
|   if empty(go#config#MetalinterCommand()) | ||||
|     let bin_path = go#path#CheckBinPath("gometalinter") | ||||
|     if empty(bin_path) | ||||
|   let l:metalinter = go#config#MetalinterCommand() | ||||
|  | ||||
|   if l:metalinter == 'gometalinter' || l:metalinter == 'golangci-lint' | ||||
|     let cmd = s:metalintercmd(l:metalinter) | ||||
|     if empty(cmd) | ||||
|       return | ||||
|     endif | ||||
|  | ||||
|     let cmd = [bin_path] | ||||
|     let cmd += ["--disable-all"] | ||||
|  | ||||
|     " gometalinter has a --tests flag to tell its linters whether to run | ||||
|     " against tests. While not all of its linters respect this flag, for those | ||||
|     " that do, it means if we don't pass --tests, the linter won't run against | ||||
|     " test files. One example of a linter that will not run against tests if | ||||
|     " we do not specify this flag is errcheck. | ||||
|     let cmd += ["--tests"] | ||||
|  | ||||
|     " linters | ||||
|     let linters = a:autosave ? go#config#MetalinterAutosaveEnabled() : go#config#MetalinterEnabled() | ||||
|     for linter in linters | ||||
| @ -44,15 +36,19 @@ function! go#lint#Gometa(bang, autosave, ...) abort | ||||
|     " will be cleared | ||||
|     redraw | ||||
|  | ||||
|     " Include only messages for the active buffer for autosave. | ||||
|     let include = [printf('--include=^%s:.*$', fnamemodify(expand('%:p'), ":."))] | ||||
|     if go#util#has_job() | ||||
|       let include = [printf('--include=^%s:.*$', expand('%:p:t'))] | ||||
|     if l:metalinter == "gometalinter" | ||||
|       " Include only messages for the active buffer for autosave. | ||||
|       let include = [printf('--include=^%s:.*$', fnamemodify(expand('%:p'), ":."))] | ||||
|       if go#util#has_job() | ||||
|         let include = [printf('--include=^%s:.*$', expand('%:p:t'))] | ||||
|       endif | ||||
|       let cmd += include | ||||
|     elseif l:metalinter == "golangci-lint" | ||||
|       let goargs[0] = expand('%:p') | ||||
|     endif | ||||
|     let cmd += include | ||||
|   endif | ||||
|  | ||||
|   " Call gometalinter asynchronously. | ||||
|   " Call metalinter asynchronously. | ||||
|   let deadline = go#config#MetalinterDeadline() | ||||
|   if deadline != '' | ||||
|     let cmd += ["--deadline=" . deadline] | ||||
| @ -60,8 +56,21 @@ function! go#lint#Gometa(bang, autosave, ...) abort | ||||
|  | ||||
|   let cmd += goargs | ||||
|  | ||||
|   if l:metalinter == "gometalinter" | ||||
|     " Gometalinter can output one of the two, so we look for both: | ||||
|     "   <file>:<line>:<column>:<severity>: <message> (<linter>) | ||||
|     "   <file>:<line>::<severity>: <message> (<linter>) | ||||
|     " This can be defined by the following errorformat: | ||||
|     let errformat = "%f:%l:%c:%t%*[^:]:\ %m,%f:%l::%t%*[^:]:\ %m" | ||||
|   else | ||||
|     " Golangci-lint can output the following: | ||||
|     "   <file>:<line>:<column>: <message> (<linter>) | ||||
|     " This can be defined by the following errorformat: | ||||
|     let errformat = "%f:%l:%c:\ %m" | ||||
|   endif | ||||
|  | ||||
|   if go#util#has_job() | ||||
|     call s:lint_job({'cmd': cmd}, a:bang, a:autosave) | ||||
|     call s:lint_job({'cmd': cmd, 'statustype': l:metalinter, 'errformat': errformat}, a:bang, a:autosave) | ||||
|     return | ||||
|   endif | ||||
|  | ||||
| @ -77,12 +86,6 @@ function! go#lint#Gometa(bang, autosave, ...) abort | ||||
|     call go#list#Clean(l:listtype) | ||||
|     echon "vim-go: " | echohl Function | echon "[metalinter] PASS" | echohl None | ||||
|   else | ||||
|     " GoMetaLinter can output one of the two, so we look for both: | ||||
|     "   <file>:<line>:<column>:<severity>: <message> (<linter>) | ||||
|     "   <file>:<line>::<severity>: <message> (<linter>) | ||||
|     " This can be defined by the following errorformat: | ||||
|     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"), 'GoMetaLinter') | ||||
|  | ||||
| @ -205,8 +208,8 @@ endfunction | ||||
|  | ||||
| function! s:lint_job(args, bang, autosave) | ||||
|   let l:opts = { | ||||
|         \ 'statustype': "gometalinter", | ||||
|         \ 'errorformat': '%f:%l:%c:%t%*[^:]:\ %m,%f:%l::%t%*[^:]:\ %m', | ||||
|         \ 'statustype': a:args.statustype, | ||||
|         \ 'errorformat': a:args.errformat, | ||||
|         \ 'for': "GoMetaLinter", | ||||
|         \ 'bang': a:bang, | ||||
|         \ } | ||||
| @ -221,6 +224,45 @@ function! s:lint_job(args, bang, autosave) | ||||
|   call go#job#Spawn(a:args.cmd, l:opts) | ||||
| endfunction | ||||
|  | ||||
| function! s:metalintercmd(metalinter) | ||||
|   let l:cmd = [] | ||||
|   let bin_path = go#path#CheckBinPath(a:metalinter) | ||||
|   if !empty(bin_path) | ||||
|     if a:metalinter == "gometalinter" | ||||
|       let l:cmd = s:gometalintercmd(bin_path) | ||||
|     elseif a:metalinter == "golangci-lint" | ||||
|       let l:cmd = s:golangcilintcmd(bin_path) | ||||
|     endif | ||||
|   endif | ||||
|  | ||||
|   return cmd | ||||
| endfunction | ||||
|  | ||||
| function! s:gometalintercmd(bin_path) | ||||
|   let cmd = [a:bin_path] | ||||
|   let cmd += ["--disable-all"] | ||||
|  | ||||
|   " gometalinter has a --tests flag to tell its linters whether to run | ||||
|   " against tests. While not all of its linters respect this flag, for those | ||||
|   " that do, it means if we don't pass --tests, the linter won't run against | ||||
|   " test files. One example of a linter that will not run against tests if | ||||
|   " we do not specify this flag is errcheck. | ||||
|   let cmd += ["--tests"] | ||||
|   return cmd | ||||
| endfunction | ||||
|  | ||||
| function! s:golangcilintcmd(bin_path) | ||||
|   let cmd = [a:bin_path] | ||||
|   let cmd += ["run"] | ||||
|   let cmd += ["--print-issued-lines=false"] | ||||
|   let cmd += ["--disable-all"] | ||||
|   " do not use the default exclude patterns, because doing so causes golint | ||||
|   " problems about missing doc strings to be ignored and other things that | ||||
|   " golint identifies. | ||||
|   let cmd += ["--exclude-use-default=false"] | ||||
|   return cmd | ||||
| endfunction | ||||
|  | ||||
| " restore Vi compatibility settings | ||||
| let &cpo = s:cpo_save | ||||
| unlet s:cpo_save | ||||
|  | ||||
| @ -3,92 +3,128 @@ let s:cpo_save = &cpo | ||||
| set cpo&vim | ||||
|  | ||||
| func! Test_Gometa() abort | ||||
|   call s:gometa('gometaliner') | ||||
| endfunc | ||||
|  | ||||
| func! Test_GometaGolangciLint() abort | ||||
|   call s:gometa('golangci-lint') | ||||
| endfunc | ||||
|  | ||||
| func! s:gometa(metalinter) abort | ||||
|   let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint' | ||||
|   silent exe 'e ' . $GOPATH . '/src/lint/lint.go' | ||||
|  | ||||
|   let expected = [ | ||||
|         \ {'lnum': 5, 'bufnr': bufnr('%')+1, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'pattern': '', 'text': 'exported function MissingFooDoc should have comment or be unexported (golint)'} | ||||
|       \ ] | ||||
|   try | ||||
|     let g:go_metalinter_comand = a:metalinter | ||||
|     let expected = [ | ||||
|           \ {'lnum': 5, 'bufnr': bufnr('%')+1, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'pattern': '', 'text': 'exported function MissingFooDoc should have comment or be unexported (golint)'} | ||||
|         \ ] | ||||
|  | ||||
|   " clear the quickfix lists | ||||
|   call setqflist([], 'r') | ||||
|     " clear the quickfix lists | ||||
|     call setqflist([], 'r') | ||||
|  | ||||
|   let g:go_metalinter_enabled = ['golint'] | ||||
|     let g:go_metalinter_enabled = ['golint'] | ||||
|  | ||||
|   call go#lint#Gometa(0, 0, $GOPATH . '/src/foo') | ||||
|     call go#lint#Gometa(0, 0, $GOPATH . '/src/foo') | ||||
|  | ||||
|   let actual = getqflist() | ||||
|   let start = reltime() | ||||
|   while len(actual) == 0 && reltimefloat(reltime(start)) < 10 | ||||
|     sleep 100m | ||||
|     let actual = getqflist() | ||||
|   endwhile | ||||
|     let start = reltime() | ||||
|     while len(actual) == 0 && reltimefloat(reltime(start)) < 10 | ||||
|       sleep 100m | ||||
|       let actual = getqflist() | ||||
|     endwhile | ||||
|  | ||||
|   call gotest#assert_quickfix(actual, expected) | ||||
|   unlet g:go_metalinter_enabled | ||||
|     call gotest#assert_quickfix(actual, expected) | ||||
|   finally | ||||
|       unlet g:go_metalinter_enabled | ||||
|   endtry | ||||
| endfunc | ||||
|  | ||||
| func! Test_GometaWithDisabled() abort | ||||
|   call s:gometawithdisabled('gometalinter') | ||||
| endfunc | ||||
|  | ||||
| func! Test_GometaWithDisabledGolangciLint() abort | ||||
|   call s:gometawithdisabled('golangci-lint') | ||||
| endfunc | ||||
|  | ||||
| func! s:gometawithdisabled(metalinter) abort | ||||
|   let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint' | ||||
|   silent exe 'e ' . $GOPATH . '/src/lint/lint.go' | ||||
|  | ||||
|   let expected = [ | ||||
|         \ {'lnum': 5, 'bufnr': bufnr('%')+1, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'pattern': '', 'text': 'exported function MissingFooDoc should have comment or be unexported (golint)'} | ||||
|       \ ] | ||||
|   try | ||||
|     let g:go_metalinter_comand = a:metalinter | ||||
|     let expected = [ | ||||
|           \ {'lnum': 5, 'bufnr': bufnr('%')+1, 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'pattern': '', 'text': 'exported function MissingFooDoc should have comment or be unexported (golint)'} | ||||
|         \ ] | ||||
|  | ||||
|   " clear the quickfix lists | ||||
|   call setqflist([], 'r') | ||||
|     " clear the quickfix lists | ||||
|     call setqflist([], 'r') | ||||
|  | ||||
|   let g:go_metalinter_disabled = ['vet'] | ||||
|     let g:go_metalinter_disabled = ['vet'] | ||||
|  | ||||
|   call go#lint#Gometa(0, 0, $GOPATH . '/src/foo') | ||||
|     call go#lint#Gometa(0, 0, $GOPATH . '/src/foo') | ||||
|  | ||||
|   let actual = getqflist() | ||||
|   let start = reltime() | ||||
|   while len(actual) == 0 && reltimefloat(reltime(start)) < 10 | ||||
|     sleep 100m | ||||
|     let actual = getqflist() | ||||
|   endwhile | ||||
|     let start = reltime() | ||||
|     while len(actual) == 0 && reltimefloat(reltime(start)) < 10 | ||||
|       sleep 100m | ||||
|       let actual = getqflist() | ||||
|     endwhile | ||||
|  | ||||
|   call gotest#assert_quickfix(actual, expected) | ||||
|   unlet g:go_metalinter_disabled | ||||
|     call gotest#assert_quickfix(actual, expected) | ||||
|   finally | ||||
|     unlet g:go_metalinter_disabled | ||||
|   endtry | ||||
| endfunc | ||||
|  | ||||
| func! Test_GometaAutoSave() abort | ||||
|   call s:gometaautosave('gometalinter') | ||||
| endfunc | ||||
|  | ||||
| func! Test_GometaAutoSaveGolangciLint() abort | ||||
|   call s:gometaautosave('golangci-lint') | ||||
| endfunc | ||||
|  | ||||
| func! s:gometaautosave(metalinter) abort | ||||
|   let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint' | ||||
|   silent exe 'e ' . $GOPATH . '/src/lint/lint.go' | ||||
|  | ||||
|   let expected = [ | ||||
|         \ {'lnum': 5, 'bufnr': bufnr('%'), 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'pattern': '', 'text': 'exported function MissingDoc should have comment or be unexported (golint)'} | ||||
|       \ ] | ||||
|   try | ||||
|     let g:go_metalinter_comand = a:metalinter | ||||
|     let expected = [ | ||||
|           \ {'lnum': 5, 'bufnr': bufnr('%'), 'col': 1, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': 'w', 'pattern': '', 'text': 'exported function MissingDoc should have comment or be unexported (golint)'} | ||||
|         \ ] | ||||
|  | ||||
|   let winnr = winnr() | ||||
|     let winnr = winnr() | ||||
|  | ||||
|   " clear the location lists | ||||
|   call setloclist(l:winnr, [], 'r') | ||||
|     " clear the location lists | ||||
|     call setloclist(l:winnr, [], 'r') | ||||
|  | ||||
|   let g:go_metalinter_autosave_enabled = ['golint'] | ||||
|     let g:go_metalinter_autosave_enabled = ['golint'] | ||||
|  | ||||
|   call go#lint#Gometa(0, 1) | ||||
|     call go#lint#Gometa(0, 1) | ||||
|  | ||||
|   let actual = getloclist(l:winnr) | ||||
|   let start = reltime() | ||||
|   while len(actual) == 0 && reltimefloat(reltime(start)) < 10 | ||||
|     sleep 100m | ||||
|     let actual = getloclist(l:winnr) | ||||
|   endwhile | ||||
|     let start = reltime() | ||||
|     while len(actual) == 0 && reltimefloat(reltime(start)) < 10 | ||||
|       sleep 100m | ||||
|       let actual = getloclist(l:winnr) | ||||
|     endwhile | ||||
|  | ||||
|   call gotest#assert_quickfix(actual, expected) | ||||
|   unlet g:go_metalinter_autosave_enabled | ||||
|     call gotest#assert_quickfix(actual, expected) | ||||
|   finally | ||||
|     unlet g:go_metalinter_autosave_enabled | ||||
|   endtry | ||||
| endfunc | ||||
|  | ||||
| func! Test_Vet() | ||||
| func! Test_Vet() abort | ||||
|   let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/lint' | ||||
|   silent exe 'e ' . $GOPATH . '/src/vet/vet.go' | ||||
|   compiler go | ||||
|  | ||||
|   let expected = [ | ||||
|         \ {'lnum': 7, 'bufnr': bufnr('%'), 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', | ||||
|         \ {'lnum': 7, 'bufnr': bufnr('%'), 'col': 2, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', | ||||
|         \ 'text': 'Printf format %d has arg str of wrong type string'} | ||||
|       \ ] | ||||
|  | ||||
|  | ||||
							
								
								
									
										444
									
								
								sources_non_forked/vim-go/autoload/go/lsp.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										444
									
								
								sources_non_forked/vim-go/autoload/go/lsp.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,444 @@ | ||||
| " don't spam the user when Vim is started in Vi compatibility mode | ||||
| let s:cpo_save = &cpo | ||||
| set cpo&vim | ||||
|  | ||||
| scriptencoding utf-8 | ||||
|  | ||||
| let s:lspfactory = {} | ||||
|  | ||||
| function! s:lspfactory.get() dict abort | ||||
|   if !has_key(self, 'current') | ||||
|     " TODO(bc): check that the lsp is still running. | ||||
|     let self.current = s:newlsp() | ||||
|   endif | ||||
|  | ||||
|   return self.current | ||||
| endfunction | ||||
|  | ||||
| function! s:lspfactory.reset() dict abort | ||||
|   if has_key(self, 'current') | ||||
|     call remove(self, 'current') | ||||
|   endif | ||||
| endfunction | ||||
|  | ||||
| function! s:newlsp() | ||||
|   if !go#util#has_job() | ||||
|     " TODO(bc): start the server in the background using a shell that waits for the right output before returning. | ||||
|     call go#util#EchoError('This feature requires either Vim 8.0.0087 or newer with +job or Neovim.') | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   " job is the job used to talk to the backing instance of gopls. | ||||
|   " ready is 0 until the initialize response has been received. 1 afterwards. | ||||
|   " queue is messages to send after initialization | ||||
|   " last_request_id is id of the most recently sent request. | ||||
|   " buf is unprocessed/incomplete responses | ||||
|   " handlers is a mapping of request ids to dictionaries of functions. | ||||
|   "   request id -> {start, requestComplete, handleResult, error} | ||||
|   "   * start is a function that takes no arguments | ||||
|   "   * requestComplete is a function that takes 1 argument. The parameter will be 1 | ||||
|   "     if the call was succesful. | ||||
|   "   * handleResult takes a single argument, the result message received from gopls | ||||
|   "   * error takes a single argument, the error message received from gopls. | ||||
|   "     The error method is optional. | ||||
|   let l:lsp = { | ||||
|         \ 'job':  '', | ||||
|         \ 'ready': 0, | ||||
|         \ 'queue': [], | ||||
|         \ 'last_request_id': 0, | ||||
|         \ 'buf': '', | ||||
|         \ 'handlers': {}, | ||||
|         \ } | ||||
|  | ||||
|   function! l:lsp.readMessage(data) dict abort | ||||
|     let l:responses = [] | ||||
|     let l:rest = a:data | ||||
|  | ||||
|     while 1 | ||||
|       " Look for the end of the HTTP headers | ||||
|       let l:body_start_idx = matchend(l:rest, "\r\n\r\n") | ||||
|  | ||||
|       if l:body_start_idx < 0 | ||||
|         " incomplete header | ||||
|         break | ||||
|       endif | ||||
|  | ||||
|       " Parse the Content-Length header. | ||||
|       let l:header = l:rest[:l:body_start_idx - 4] | ||||
|       let l:length_match = matchlist( | ||||
|       \   l:header, | ||||
|       \   '\vContent-Length: *(\d+)' | ||||
|       \) | ||||
|  | ||||
|       if empty(l:length_match) | ||||
|         " TODO(bc): shutdown gopls? | ||||
|         throw "invalid JSON-RPC header:\n" . l:header | ||||
|       endif | ||||
|  | ||||
|       " get the start of the rest | ||||
|       let l:rest_start_idx = l:body_start_idx + str2nr(l:length_match[1]) | ||||
|  | ||||
|       if len(l:rest) < l:rest_start_idx | ||||
|         " incomplete response body | ||||
|         break | ||||
|       endif | ||||
|  | ||||
|       if go#util#HasDebug('lsp') | ||||
|         let g:go_lsp_log = add(go#config#LspLog(), "<-\n" . l:rest[:l:rest_start_idx - 1]) | ||||
|       endif | ||||
|  | ||||
|       let l:body = l:rest[l:body_start_idx : l:rest_start_idx - 1] | ||||
|       let l:rest = l:rest[l:rest_start_idx :] | ||||
|  | ||||
|       try | ||||
|         " add the json body to the list. | ||||
|         call add(l:responses, json_decode(l:body)) | ||||
|       catch | ||||
|         " TODO(bc): log the message and/or show an error message. | ||||
|       finally | ||||
|         " intentionally left blank. | ||||
|       endtry | ||||
|     endwhile | ||||
|  | ||||
|     return [l:rest, l:responses] | ||||
|   endfunction | ||||
|  | ||||
|   function! l:lsp.handleMessage(ch, data) dict abort | ||||
|       let self.buf .= a:data | ||||
|  | ||||
|       let [self.buf, l:responses] = self.readMessage(self.buf) | ||||
|  | ||||
|       " TODO(bc): handle notifications (e.g. window/showMessage). | ||||
|  | ||||
|       for l:response in l:responses | ||||
|         if has_key(l:response, 'id') && has_key(self.handlers, l:response.id) | ||||
|           try | ||||
|             let l:handler = self.handlers[l:response.id] | ||||
|  | ||||
|             if has_key(l:response, 'error') | ||||
|               call l:handler.requestComplete(0) | ||||
|               call go#util#EchoError(l:response.error.message) | ||||
|               if has_key(l:handler, 'error') | ||||
|                 call call(l:handler.error, [l:response.error.message]) | ||||
|               endif | ||||
|               return | ||||
|             endif | ||||
|             call l:handler.requestComplete(1) | ||||
|             call call(l:handler.handleResult, [l:response.result]) | ||||
|           finally | ||||
|             call remove(self.handlers, l:response.id) | ||||
|           endtry | ||||
|         endif | ||||
|       endfor | ||||
|   endfunction | ||||
|  | ||||
|   function! l:lsp.handleInitializeResult(result) dict abort | ||||
|     let self.ready = 1 | ||||
|     " TODO(bc): send initialized message to the server? | ||||
|  | ||||
|     " send messages queued while waiting for ready. | ||||
|     for l:item in self.queue | ||||
|       call self.sendMessage(l:item.data, l:item.handler) | ||||
|     endfor | ||||
|  | ||||
|     " reset the queue | ||||
|     let self.queue = [] | ||||
|   endfunction | ||||
|  | ||||
|   function! l:lsp.sendMessage(data, handler) dict abort | ||||
|     if !self.last_request_id | ||||
|       " TODO(bc): run a server per module and one per GOPATH? (may need to | ||||
|       " keep track of servers by rootUri). | ||||
|       let l:msg = self.newMessage(go#lsp#message#Initialize(getcwd())) | ||||
|  | ||||
|       let l:state = s:newHandlerState('gopls') | ||||
|       let l:state.handleResult = funcref('self.handleInitializeResult', [], l:self) | ||||
|       let self.handlers[l:msg.id] = l:state | ||||
|  | ||||
|       call l:state.start() | ||||
|       call self.write(l:msg) | ||||
|     endif | ||||
|  | ||||
|     if !self.ready | ||||
|       call add(self.queue, {'data': a:data, 'handler': a:handler}) | ||||
|       return | ||||
|     endif | ||||
|  | ||||
|     let l:msg = self.newMessage(a:data) | ||||
|     if has_key(l:msg, 'id') | ||||
|       let self.handlers[l:msg.id] = a:handler | ||||
|     endif | ||||
|  | ||||
|     call a:handler.start() | ||||
|     call self.write(l:msg) | ||||
|   endfunction | ||||
|  | ||||
|   " newMessage returns a message constructed from data. data should be a dict | ||||
|   " with 2 or 3 keys: notification, method, and optionally params. | ||||
|   function! l:lsp.newMessage(data) dict abort | ||||
|     let l:msg = { | ||||
|           \ 'method': a:data.method, | ||||
|           \ 'jsonrpc': '2.0', | ||||
|           \ } | ||||
|  | ||||
|     if !a:data.notification | ||||
|       let self.last_request_id += 1 | ||||
|       let l:msg.id = self.last_request_id | ||||
|     endif | ||||
|  | ||||
|     if has_key(a:data, 'params') | ||||
|       let l:msg.params = a:data.params | ||||
|     endif | ||||
|  | ||||
|     return l:msg | ||||
|   endfunction | ||||
|  | ||||
|   function! l:lsp.write(msg) dict abort | ||||
|       let l:body = json_encode(a:msg) | ||||
|       let l:data = 'Content-Length: ' . strlen(l:body) . "\r\n\r\n" . l:body | ||||
|  | ||||
|     if go#util#HasDebug('lsp') | ||||
|       let g:go_lsp_log = add(go#config#LspLog(), "->\n" . l:data) | ||||
|     endif | ||||
|  | ||||
|     if has('nvim') | ||||
|       call chansend(self.job, l:data) | ||||
|       return | ||||
|     endif | ||||
|  | ||||
|     call ch_sendraw(self.job, l:data) | ||||
|   endfunction | ||||
|  | ||||
|   function! l:lsp.exit_cb(job, exit_status) dict abort | ||||
|     call s:lspfactory.reset() | ||||
|   endfunction | ||||
|   " explicitly bind close_cb to state so that within it, self will always refer | ||||
|  | ||||
|   function! l:lsp.close_cb(ch) dict abort | ||||
|     " TODO(bc): does anything need to be done here? | ||||
|   endfunction | ||||
|  | ||||
|   function! l:lsp.err_cb(ch, msg) dict abort | ||||
|     if go#util#HasDebug('lsp') | ||||
|       let g:go_lsp_log = add(go#config#LspLog(), "<-stderr\n" .  a:msg) | ||||
|     endif | ||||
|   endfunction | ||||
|  | ||||
|   " explicitly bind callbacks to l:lsp so that within it, self will always refer | ||||
|   " to l:lsp instead of l:opts. See :help Partial for more information. | ||||
|   let l:opts = { | ||||
|         \ 'in_mode': 'raw', | ||||
|         \ 'out_mode': 'raw', | ||||
|         \ 'err_mode': 'nl', | ||||
|         \ 'noblock': 1, | ||||
|         \ 'err_cb': funcref('l:lsp.err_cb', [], l:lsp), | ||||
|         \ 'out_cb': funcref('l:lsp.handleMessage', [], l:lsp), | ||||
|         \ 'close_cb': funcref('l:lsp.close_cb', [], l:lsp), | ||||
|         \ 'exit_cb': funcref('l:lsp.exit_cb', [], l:lsp), | ||||
|         \ 'cwd': getcwd(), | ||||
|         \} | ||||
|  | ||||
|   let l:bin_path = go#path#CheckBinPath("gopls") | ||||
|   if empty(l:bin_path) | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   " TODO(bc): output a message indicating which directory lsp is going to | ||||
|   " start in. | ||||
|   let l:lsp.job = go#job#Start([l:bin_path], l:opts) | ||||
|  | ||||
|   " TODO(bc): send the initialize message now? | ||||
|   return l:lsp | ||||
| endfunction | ||||
|  | ||||
| function! s:noop() | ||||
| endfunction | ||||
|  | ||||
| function! s:newHandlerState(statustype) | ||||
|   let l:state = { | ||||
|         \ 'winid': win_getid(winnr()), | ||||
|         \ 'statustype': a:statustype, | ||||
|         \ 'jobdir': getcwd(), | ||||
|       \ } | ||||
|  | ||||
|   " explicitly bind requestComplete to state so that within it, self will | ||||
|   " always refer to state. See :help Partial for more information. | ||||
|   let l:state.requestComplete = funcref('s:requestComplete', [], l:state) | ||||
|  | ||||
|   " explicitly bind start to state so that within it, self will | ||||
|   " always refer to state. See :help Partial for more information. | ||||
|   let l:state.start = funcref('s:start', [], l:state) | ||||
|  | ||||
|   return l:state | ||||
| endfunction | ||||
|  | ||||
| function! s:requestComplete(ok) abort dict | ||||
|   if self.statustype == '' | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   if go#config#EchoCommandInfo() | ||||
|     let prefix = '[' . self.statustype . '] ' | ||||
|     if a:ok | ||||
|       call go#util#EchoSuccess(prefix . "SUCCESS") | ||||
|     else | ||||
|       call go#util#EchoError(prefix . "FAIL") | ||||
|     endif | ||||
|   endif | ||||
|  | ||||
|   let status = { | ||||
|         \ 'desc': 'last status', | ||||
|         \ 'type': self.statustype, | ||||
|         \ 'state': "success", | ||||
|         \ } | ||||
|  | ||||
|   if !a:ok | ||||
|     let status.state = "failed" | ||||
|   endif | ||||
|  | ||||
|   if has_key(self, 'started_at') | ||||
|     let elapsed_time = reltimestr(reltime(self.started_at)) | ||||
|     " strip whitespace | ||||
|     let elapsed_time = substitute(elapsed_time, '^\s*\(.\{-}\)\s*$', '\1', '') | ||||
|     let status.state .= printf(" (%ss)", elapsed_time) | ||||
|   endif | ||||
|  | ||||
|   call go#statusline#Update(self.jobdir, status) | ||||
| endfunction | ||||
|  | ||||
| function! s:start() abort dict | ||||
|   if self.statustype != '' | ||||
|     let status = { | ||||
|           \ 'desc': 'current status', | ||||
|           \ 'type': self.statustype, | ||||
|           \ 'state': "started", | ||||
|           \ } | ||||
|  | ||||
|     call go#statusline#Update(self.jobdir, status) | ||||
|   endif | ||||
|   let self.started_at = reltime() | ||||
| endfunction | ||||
|  | ||||
| " go#lsp#Definition calls gopls to get the definition of the identifier at | ||||
| " line and col in fname. handler should be a dictionary function that takes a | ||||
| " list of strings in the form 'file:line:col: message'. handler will be | ||||
| " attached to a dictionary that manages state (statuslines, sets the winid, | ||||
| " etc.) | ||||
| function! go#lsp#Definition(fname, line, col, handler) | ||||
|   call go#lsp#DidChange(a:fname) | ||||
|  | ||||
|   let l:lsp = s:lspfactory.get() | ||||
|   let l:state = s:newHandlerState('definition') | ||||
|   let l:state.handleResult = funcref('s:definitionHandler', [function(a:handler, [], l:state)], l:state) | ||||
|   let l:msg = go#lsp#message#Definition(fnamemodify(a:fname, ':p'), a:line, a:col) | ||||
|   call l:lsp.sendMessage(l:msg, l:state) | ||||
| endfunction | ||||
|  | ||||
| function! s:definitionHandler(next, msg) abort dict | ||||
|   " gopls returns a []Location; just take the first one. | ||||
|   let l:msg = a:msg[0] | ||||
|   let l:args = [[printf('%s:%d:%d: %s', go#path#FromURI(l:msg.uri), l:msg.range.start.line+1, l:msg.range.start.character+1, 'lsp does not supply a description')]] | ||||
|   call call(a:next, l:args) | ||||
| endfunction | ||||
|  | ||||
| " go#lsp#Type calls gopls to get the type definition of the identifier at | ||||
| " line and col in fname. handler should be a dictionary function that takes a | ||||
| " list of strings in the form 'file:line:col: message'. handler will be | ||||
| " attached to a dictionary that manages state (statuslines, sets the winid, | ||||
| " etc.) | ||||
| function! go#lsp#TypeDef(fname, line, col, handler) | ||||
|   call go#lsp#DidChange(a:fname) | ||||
|  | ||||
|   let l:lsp = s:lspfactory.get() | ||||
|   let l:state = s:newHandlerState('type definition') | ||||
|   let l:msg = go#lsp#message#TypeDefinition(fnamemodify(a:fname, ':p'), a:line, a:col) | ||||
|   let l:state.handleResult = funcref('s:typeDefinitionHandler', [function(a:handler, [], l:state)], l:state) | ||||
|   call l:lsp.sendMessage(l:msg, l:state) | ||||
| endfunction | ||||
|  | ||||
| function! s:typeDefinitionHandler(next, msg) abort dict | ||||
|   " gopls returns a []Location; just take the first one. | ||||
|   let l:msg = a:msg[0] | ||||
|   let l:args = [[printf('%s:%d:%d: %s', go#path#FromURI(l:msg.uri), l:msg.range.start.line+1, l:msg.range.start.character+1, 'lsp does not supply a description')]] | ||||
|   call call(a:next, l:args) | ||||
| endfunction | ||||
|  | ||||
| function! go#lsp#DidOpen(fname) | ||||
|   if get(b:, 'go_lsp_did_open', 0) | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   let l:lsp = s:lspfactory.get() | ||||
|   let l:msg = go#lsp#message#DidOpen(fnamemodify(a:fname, ':p'), join(go#util#GetLines(), "\n") . "\n") | ||||
|   let l:state = s:newHandlerState('') | ||||
|   let l:state.handleResult = funcref('s:noop') | ||||
|   call l:lsp.sendMessage(l:msg, l:state) | ||||
|  | ||||
|   let b:go_lsp_did_open = 1 | ||||
| endfunction | ||||
|  | ||||
| function! go#lsp#DidChange(fname) | ||||
|   if get(b:, 'go_lsp_did_open', 0) | ||||
|     return go#lsp#DidOpen(a:fname) | ||||
|   endif | ||||
|  | ||||
|   let l:lsp = s:lspfactory.get() | ||||
|   let l:msg = go#lsp#message#DidChange(fnamemodify(a:fname, ':p'), join(go#util#GetLines(), "\n") . "\n") | ||||
|   let l:state = s:newHandlerState('') | ||||
|   let l:state.handleResult = funcref('s:noop') | ||||
|   call l:lsp.sendMessage(l:msg, l:state) | ||||
| endfunction | ||||
|  | ||||
| function! go#lsp#DidClose(fname) | ||||
|   if !get(b:, 'go_lsp_did_open', 0) | ||||
|     return | ||||
|   endif | ||||
|  | ||||
|   let l:lsp = s:lspfactory.get() | ||||
|   let l:msg = go#lsp#message#DidClose(fnamemodify(a:fname, ':p')) | ||||
|   let l:state = s:newHandlerState('') | ||||
|   let l:state.handleResult = funcref('s:noop') | ||||
|   call l:lsp.sendMessage(l:msg, l:state) | ||||
|  | ||||
|   let b:go_lsp_did_open = 0 | ||||
| endfunction | ||||
|  | ||||
| function! go#lsp#Completion(fname, line, col, handler) | ||||
|   call go#lsp#DidChange(a:fname) | ||||
|  | ||||
|   let l:lsp = s:lspfactory.get() | ||||
|   let l:msg = go#lsp#message#Completion(a:fname, a:line, a:col) | ||||
|   let l:state = s:newHandlerState('completion') | ||||
|   let l:state.handleResult = funcref('s:completionHandler', [function(a:handler, [], l:state)], l:state) | ||||
|   let l:state.error = funcref('s:completionErrorHandler', [function(a:handler, [], l:state)], l:state) | ||||
|   call l:lsp.sendMessage(l:msg, l:state) | ||||
| endfunction | ||||
|  | ||||
| function! s:completionHandler(next, msg) abort dict | ||||
|   " gopls returns a CompletionList. | ||||
|   let l:matches = [] | ||||
|   for l:item in a:msg.items | ||||
|     let l:match = {'abbr': l:item.label, 'word': l:item.textEdit.newText, 'info': '', 'kind': go#lsp#completionitemkind#Vim(l:item.kind)} | ||||
|     if has_key(l:item, 'detail') | ||||
|         let l:item.info = l:item.detail | ||||
|     endif | ||||
|  | ||||
|     if has_key(l:item, 'documentation') | ||||
|       let l:match.info .= "\n\n" . l:item.documentation | ||||
|     endif | ||||
|  | ||||
|     let l:matches = add(l:matches, l:match) | ||||
|   endfor | ||||
|   let l:args = [l:matches] | ||||
|   call call(a:next, l:args) | ||||
| endfunction | ||||
|  | ||||
| function! s:completionErrorHandler(next, error) abort dict | ||||
|   call call(a:next, [[]]) | ||||
| endfunction | ||||
|  | ||||
| " restore Vi compatibility settings | ||||
| let &cpo = s:cpo_save | ||||
| unlet s:cpo_save | ||||
|  | ||||
| " vim: sw=2 ts=2 et | ||||
| @ -0,0 +1,47 @@ | ||||
| " don't spam the user when Vim is started in Vi compatibility mode | ||||
| let s:cpo_save = &cpo | ||||
| set cpo&vim | ||||
|  | ||||
| let s:Text = 1 | ||||
| let s:Method = 2 | ||||
| let s:Function = 3 | ||||
| let s:Constructor = 4 | ||||
| let s:Field = 5 | ||||
| let s:Variable = 6 | ||||
| let s:Class = 7 | ||||
| let s:Interface = 8 | ||||
| let s:Module = 9 | ||||
| let s:Property = 10 | ||||
| let s:Unit = 11 | ||||
| let s:Value = 12 | ||||
| let s:Enum = 13 | ||||
| let s:Keyword = 14 | ||||
| let s:Snippet = 15 | ||||
| let s:Color = 16 | ||||
| let s:File = 17 | ||||
| let s:Reference = 18 | ||||
| let s:Folder = 19 | ||||
| let s:EnumMember = 20 | ||||
| let s:Constant = 21 | ||||
| let s:Struct = 22 | ||||
| let s:Event = 23 | ||||
| let s:Operator = 24 | ||||
| let s:TypeParameter = 25 | ||||
|  | ||||
| function! go#lsp#completionitemkind#Vim(kind) | ||||
|   if a:kind == s:Method || a:kind == s:Function || a:kind == s:Constructor | ||||
|     return 'f' | ||||
|   elseif a:kind == s:Variable || a:kind == s:Constant | ||||
|     return 'v' | ||||
|   elseif a:kind == s:Field || a:kind == s:Property | ||||
|     return 'm' | ||||
|   elseif a:kind == s:Class || a:kind == s:Interface || a:kind == s:Struct | ||||
|     return 't' | ||||
|   endif | ||||
| endfunction | ||||
|  | ||||
| " restore Vi compatibility settings | ||||
| let &cpo = s:cpo_save | ||||
| unlet s:cpo_save | ||||
|  | ||||
| " vim: sw=2 ts=2 et | ||||
							
								
								
									
										111
									
								
								sources_non_forked/vim-go/autoload/go/lsp/message.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								sources_non_forked/vim-go/autoload/go/lsp/message.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,111 @@ | ||||
| " don't spam the user when Vim is started in Vi compatibility mode | ||||
| let s:cpo_save = &cpo | ||||
| set cpo&vim | ||||
|  | ||||
| function! go#lsp#message#Initialize(wd) | ||||
|   return { | ||||
|           \ 'notification': 0, | ||||
|           \ 'method': 'initialize', | ||||
|           \ 'params': { | ||||
|             \ 'processId': getpid(), | ||||
|             \ 'rootUri': go#path#ToURI(a:wd), | ||||
|             \ 'capabilities': { | ||||
|               \ 'workspace': {}, | ||||
|               \ 'textDocument': {} | ||||
|             \ } | ||||
|           \ } | ||||
|        \ } | ||||
| endfunction | ||||
|  | ||||
| function! go#lsp#message#Definition(file, line, col) | ||||
|   return { | ||||
|           \ 'notification': 0, | ||||
|           \ 'method': 'textDocument/definition', | ||||
|           \ 'params': { | ||||
|           \   'textDocument': { | ||||
|           \       'uri': go#path#ToURI(a:file) | ||||
|           \   }, | ||||
|           \   'position': s:position(a:line, a:col) | ||||
|           \ } | ||||
|        \ } | ||||
| endfunction | ||||
|  | ||||
|  | ||||
| function! go#lsp#message#TypeDefinition(file, line, col) | ||||
|   return { | ||||
|           \ 'notification': 0, | ||||
|           \ 'method': 'textDocument/typeDefinition', | ||||
|           \ 'params': { | ||||
|           \   'textDocument': { | ||||
|           \       'uri': go#path#ToURI(a:file) | ||||
|           \   }, | ||||
|           \   'position': s:position(a:line, a:col) | ||||
|           \ } | ||||
|        \ } | ||||
| endfunction | ||||
|  | ||||
| function! go#lsp#message#DidOpen(file, content) | ||||
|   return { | ||||
|           \ 'notification': 1, | ||||
|           \ 'method': 'textDocument/didOpen', | ||||
|           \ 'params': { | ||||
|           \     'textDocument': { | ||||
|           \         'uri': go#path#ToURI(a:file), | ||||
|           \         'languageId': 'go', | ||||
|           \         'text': a:content, | ||||
|           \     } | ||||
|           \ } | ||||
|        \ } | ||||
| endfunction | ||||
|  | ||||
| function! go#lsp#message#DidChange(file, content) | ||||
|   return { | ||||
|           \ 'notification': 1, | ||||
|           \ 'method': 'textDocument/didChange', | ||||
|           \ 'params': { | ||||
|           \     'textDocument': { | ||||
|           \         'uri': go#path#ToURI(a:file), | ||||
|           \     }, | ||||
|           \     'contentChanges': [ | ||||
|           \       { | ||||
|           \         'text': a:content, | ||||
|           \       } | ||||
|           \     ] | ||||
|           \ } | ||||
|        \ } | ||||
| endfunction | ||||
|  | ||||
| function! go#lsp#message#DidClose(file) | ||||
|   return { | ||||
|           \ 'notification': 1, | ||||
|           \ 'method': 'textDocument/didClose', | ||||
|           \ 'params': { | ||||
|           \     'textDocument': { | ||||
|           \         'uri': go#path#ToURI(a:file), | ||||
|           \     } | ||||
|           \ } | ||||
|        \ } | ||||
| endfunction | ||||
|  | ||||
| function! go#lsp#message#Completion(file, line, col) | ||||
|   return { | ||||
|           \ 'notification': 0, | ||||
|           \ 'method': 'textDocument/completion', | ||||
|           \ 'params': { | ||||
|           \   'textDocument': { | ||||
|           \       'uri': go#path#ToURI(a:file) | ||||
|           \   }, | ||||
|           \   'position': s:position(a:line, a:col), | ||||
|           \ } | ||||
|        \ } | ||||
| endfunction | ||||
|  | ||||
| function! s:position(line, col) | ||||
|   return {'line': a:line - 1, 'character': a:col-1} | ||||
| endfunction | ||||
|  | ||||
| " restore Vi compatibility settings | ||||
| let &cpo = s:cpo_save | ||||
| unlet s:cpo_save | ||||
|  | ||||
| " vim: sw=2 ts=2 et | ||||
| @ -205,6 +205,37 @@ function! s:CygwinPath(path) | ||||
|    return substitute(a:path, '\\', '/', "g") | ||||
| endfunction | ||||
|  | ||||
| " go#path#ToURI converts path to a file URI. path should be an absolute path. | ||||
| " Relative paths cannot be properly converted to a URI; when path is a | ||||
| " relative path, the file scheme will not be prepended. | ||||
| function! go#path#ToURI(path) | ||||
|   let l:path = a:path | ||||
|   if l:path[1:2] is# ':\' | ||||
|     let l:path = '/' . l:path[0:1] . l:path[3:] | ||||
|   endif | ||||
|  | ||||
|   return substitute( | ||||
|   \   (l:path[0] is# '/' ? 'file://' : '') . go#uri#EncodePath(l:path), | ||||
|   \   '\\', | ||||
|   \   '/', | ||||
|   \   'g', | ||||
|   \) | ||||
| endfunction | ||||
|  | ||||
| function! go#path#FromURI(uri) abort | ||||
|     let l:i = len('file://') | ||||
|     let l:encoded_path = a:uri[: l:i - 1] is# 'file://' ? a:uri[l:i :] : a:uri | ||||
|  | ||||
|     let l:path = go#uri#Decode(l:encoded_path) | ||||
|  | ||||
|     " If the path is like /C:/foo/bar, it should be C:\foo\bar instead. | ||||
|     if l:path =~# '^/[a-zA-Z]:' | ||||
|         let l:path = substitute(l:path[1:], '/', '\\', 'g') | ||||
|     endif | ||||
|  | ||||
|     return l:path | ||||
| endfunction | ||||
|  | ||||
| " restore Vi compatibility settings | ||||
| let &cpo = s:cpo_save | ||||
| unlet s:cpo_save | ||||
|  | ||||
| @ -241,7 +241,7 @@ function! s:errorformat() abort | ||||
|   " e.g.: | ||||
|   "   '\t/usr/local/go/src/time.go:1313 +0x5d' | ||||
|  | ||||
|   " panicaddress, and readyaddress are identical except for | ||||
|   " panicaddress and readyaddress are identical except for | ||||
|   " panicaddress sets the filename and line number. | ||||
|   let panicaddress = "%\\t%f:%l +0x%[0-9A-Fa-f]%\\+" | ||||
|   let readyaddress = "%\\t%\\f%\\+:%\\d%\\+ +0x%[0-9A-Fa-f]%\\+" | ||||
| @ -264,6 +264,11 @@ function! s:errorformat() abort | ||||
|   " the running goroutine's stack. | ||||
|   let format .= ",%Z" . panicaddress | ||||
|  | ||||
|   " Match and ignore errors from runtime.goparkunlock(). These started | ||||
|   " appearing in stack traces from Go 1.12 test timeouts. | ||||
|   let format .= ",%-Gruntime.goparkunlock(%.%#" | ||||
|   let format .= ",%-G%\\t" . goroot . "%\\f%\\+:%\\d%\\+" | ||||
|  | ||||
|   " Match and ignore panic address without being part of a multi-line message. | ||||
|   " This is to catch those lines that come after the top most non-standard | ||||
|   " library line in stack traces. | ||||
| @ -290,8 +295,8 @@ function! s:errorformat() abort | ||||
|   " It would be nice if this weren't necessary, but panic lines from tests are | ||||
|   " prefixed with a single leading tab, making them very similar to 2nd and | ||||
|   " later lines of a multi-line compiler error. Swallow it so that it doesn't | ||||
|   " cause a quickfix entry since the next entry can add a quickfix entry for | ||||
|   " 2nd and later lines of a multi-line compiler error. | ||||
|   " cause a quickfix entry since the next %G entry can add a quickfix entry | ||||
|   " for 2nd and later lines of a multi-line compiler error. | ||||
|   let format .= ",%-C%\\tpanic: %.%#" | ||||
|   let format .= ",%G%\\t%m" | ||||
|  | ||||
|  | ||||
| @ -78,7 +78,7 @@ endfunc | ||||
|  | ||||
| func! Test_GoTestVet() abort | ||||
|   let expected = [ | ||||
|         \ {'lnum': 6, 'bufnr': 16, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'Errorf format %v reads arg #1, but call has 0 args'}, | ||||
|         \ {'lnum': 6, 'bufnr': 16, 'col': 2, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'Errorf format %v reads arg #1, but call has 0 args'}, | ||||
|       \ ] | ||||
|   call s:test('veterror/veterror.go', expected) | ||||
| endfunc | ||||
|  | ||||
							
								
								
									
										34
									
								
								sources_non_forked/vim-go/autoload/go/uri.vim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								sources_non_forked/vim-go/autoload/go/uri.vim
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| " don't spam the user when Vim is started in Vi compatibility mode | ||||
| let s:cpo_save = &cpo | ||||
| set cpo&vim | ||||
|  | ||||
| function! go#uri#Encode(value) abort | ||||
|     return s:encode(a:value, '[^A-Za-z0-9_.~-]') | ||||
| endfunction | ||||
|  | ||||
| function! go#uri#EncodePath(value) abort | ||||
|     return s:encode(a:value, '[^/A-Za-z0-9_.~-]') | ||||
| endfunction | ||||
|  | ||||
| function! s:encode(value, unreserved) | ||||
|     return substitute( | ||||
|     \   a:value, | ||||
|     \   a:unreserved, | ||||
|     \   '\="%".printf(''%02X'', char2nr(submatch(0)))', | ||||
|     \   'g' | ||||
|     \) | ||||
| endfunction | ||||
|  | ||||
| function! go#uri#Decode(value) abort | ||||
|     return substitute( | ||||
|     \   a:value, | ||||
|     \   '%\(\x\x\)', | ||||
|     \   '\=nr2char(''0X'' . submatch(1))', | ||||
|     \   'g' | ||||
|     \) | ||||
| endfunction | ||||
| " restore Vi compatibility settings | ||||
| let &cpo = s:cpo_save | ||||
| unlet s:cpo_save | ||||
|  | ||||
| " vim: sw=2 ts=2 et | ||||
| @ -42,7 +42,7 @@ tools developed by the Go community to provide a seamless Vim experience. | ||||
|   * Quickly execute your current file(s) with |:GoRun|. | ||||
|   * Improved syntax highlighting and folding. | ||||
|   * Debug programs with integrated `delve` support with |:GoDebugStart|. | ||||
|   * Completion support via `gocode`. | ||||
|   * Completion support via `gocode` and `gopls`. | ||||
|   * `gofmt` or `goimports` on save keeps the cursor position and undo history. | ||||
|   * Go to symbol/declaration with |:GoDef|. | ||||
|   * Look up documentation with |:GoDoc| or |:GoDocBrowser|. | ||||
| @ -260,7 +260,7 @@ CTRL-] | ||||
| g<C-LeftMouse> | ||||
| <C-LeftMouse> | ||||
|  | ||||
|     Goto declaration/definition for the declaration under the cursor. By | ||||
|     Go to declaration/definition for the identifier under the cursor. By | ||||
|     default the CTRL-] shortcut, the mapping `gd` and <C-LeftMouse>, | ||||
|     g<LeftMouse> are enabled to invoke :GoDef for the identifier under the | ||||
|     cursor. See |'g:go_def_mapping_enabled'| to disable them. No explicit | ||||
| @ -272,6 +272,14 @@ g<C-LeftMouse> | ||||
|     list of file locations you have visited with :GoDef that is retained to | ||||
|     help you navigate software. | ||||
|  | ||||
|     The per-window location stack is shared with |:GoDefType|. | ||||
|  | ||||
|                                                                   *:GoDefType* | ||||
| :GoDefType | ||||
|  | ||||
|     Go to type definition for the identifier under the cursor. | ||||
|  | ||||
|     The per-window location stack is shared with |:GoDef|. | ||||
|                                                                  *:GoDefStack* | ||||
| :GoDefStack [number] | ||||
|  | ||||
| @ -1176,6 +1184,15 @@ cleaned for each package after `60` seconds. This can be changed with the | ||||
| Returns the description of the identifer under the cursor. Can be used to plug | ||||
| into the statusline. | ||||
|  | ||||
|                                                       *go#complete#Complete()* | ||||
|  | ||||
| Uses `gopls` for autocompletion. By default, it is hooked up to |'omnifunc'| | ||||
| for Vim8 and Neovim. | ||||
|  | ||||
|                                                 *go#complete#GocodeComplete()* | ||||
|  | ||||
| Uses `gocode` for autocompletion. By default, it is hooked up to |'omnifunc'| | ||||
| for Vim 7.4. | ||||
|  | ||||
|                                                    *go#tool#DescribeBalloon()* | ||||
|  | ||||
| @ -1350,7 +1367,7 @@ a private internal service. Default is 'https://godoc.org'. | ||||
|  | ||||
| Use this option to define the command to be used for |:GoDef|. By default | ||||
| `guru` is being used as it covers all edge cases. But one might also use | ||||
| `godef` as it's faster. Current valid options are: `[guru, godef]` > | ||||
| `godef` as it's faster. Current valid options are: `[guru, godef, gopls]` > | ||||
|  | ||||
|   let g:go_def_mode = 'guru' | ||||
| < | ||||
| @ -1498,11 +1515,12 @@ it's empty | ||||
| < | ||||
|                                                    *'g:go_metalinter_command'* | ||||
|  | ||||
| Overrides the command to be executed when |:GoMetaLinter| is called. This is | ||||
| an advanced settings and is for users who want to have a complete control | ||||
| over how `gometalinter` should be executed. By default it's empty. | ||||
| Overrides the command to be executed when |:GoMetaLinter| is called.  By | ||||
| default it's `gometalinter`. `golangci-lint` is also supported. It can also be | ||||
| used as an advanced setting for users who want to have more control over | ||||
| the metalinter. | ||||
| > | ||||
|   let g:go_metalinter_command = "" | ||||
|   let g:go_metalinter_command = "gometalinter" | ||||
| < | ||||
|                                                   *'g:go_metalinter_deadline'* | ||||
|  | ||||
| @ -1761,6 +1779,7 @@ Currently accepted values: | ||||
|   debugger-state     Expose debugger state in 'g:go_debug_diag'. | ||||
|   debugger-commands  Echo communication between vim-go and `dlv`; requests and | ||||
|                      responses are recorded in `g:go_debug_commands`. | ||||
|   lsp                Record lsp requests and responses in g:go_lsp_log. | ||||
| > | ||||
|       let g:go_debug = [] | ||||
| < | ||||
|  | ||||
| @ -25,8 +25,11 @@ setlocal noexpandtab | ||||
|  | ||||
| compiler go | ||||
|  | ||||
| " Set gocode completion | ||||
| " Set autocompletion | ||||
| setlocal omnifunc=go#complete#Complete | ||||
| if !go#util#has_job() | ||||
|   setlocal omnifunc=go#complete#GocodeComplete | ||||
| endif | ||||
|  | ||||
| if get(g:, "go_doc_keywordprg_enabled", 1) | ||||
|   " keywordprg doesn't allow to use vim commands, override it | ||||
| @ -40,8 +43,8 @@ if get(g:, "go_def_mapping_enabled", 1) | ||||
|   nnoremap <buffer> <silent> <C-]> :GoDef<cr> | ||||
|   nnoremap <buffer> <silent> <C-LeftMouse> <LeftMouse>:GoDef<cr> | ||||
|   nnoremap <buffer> <silent> g<LeftMouse> <LeftMouse>:GoDef<cr> | ||||
|   nnoremap <buffer> <silent> <C-w><C-]> :<C-u>call go#def#Jump("split")<CR> | ||||
|   nnoremap <buffer> <silent> <C-w>] :<C-u>call go#def#Jump("split")<CR> | ||||
|   nnoremap <buffer> <silent> <C-w><C-]> :<C-u>call go#def#Jump("split", 0)<CR> | ||||
|   nnoremap <buffer> <silent> <C-w>] :<C-u>call go#def#Jump("split", 0)<CR> | ||||
|   nnoremap <buffer> <silent> <C-t> :<C-U>call go#def#StackPop(v:count1)<cr> | ||||
| endif | ||||
|  | ||||
| @ -79,6 +82,10 @@ endif | ||||
| augroup vim-go-buffer | ||||
|   autocmd! * <buffer> | ||||
|  | ||||
|   " TODO(bc): notify gopls about changes on CursorHold when the buffer is | ||||
|   " modified. | ||||
|   " TODO(bc): notify gopls that the file on disk is correct on BufWritePost | ||||
|  | ||||
|   autocmd CursorHold <buffer> call go#auto#auto_type_info() | ||||
|   autocmd CursorHold <buffer> call go#auto#auto_sameids() | ||||
|  | ||||
|  | ||||
| @ -54,7 +54,8 @@ command! -nargs=* -bang GoCoverageBrowser call go#coverage#Browser(<bang>0, <f-a | ||||
| command! -nargs=0 -range=% GoPlay call go#play#Share(<count>, <line1>, <line2>) | ||||
|  | ||||
| " -- def | ||||
| command! -nargs=* -range GoDef :call go#def#Jump('') | ||||
| command! -nargs=* -range GoDef :call go#def#Jump('', 0) | ||||
| command! -nargs=* -range GoDefType :call go#def#Jump('', 1) | ||||
| command! -nargs=? GoDefPop :call go#def#StackPop(<f-args>) | ||||
| command! -nargs=? GoDefStack :call go#def#Stack(<f-args>) | ||||
| command! -nargs=? GoDefStackClear :call go#def#StackClear(<f-args>) | ||||
|  | ||||
| @ -53,10 +53,15 @@ nnoremap <silent> <Plug>(go-rename) :<C-u>call go#rename#Rename(!g:go_jump_to_er | ||||
| nnoremap <silent> <Plug>(go-decls) :<C-u>call go#decls#Decls(0, '')<CR> | ||||
| nnoremap <silent> <Plug>(go-decls-dir) :<C-u>call go#decls#Decls(1, '')<CR> | ||||
|  | ||||
| nnoremap <silent> <Plug>(go-def) :<C-u>call go#def#Jump('')<CR> | ||||
| nnoremap <silent> <Plug>(go-def-vertical) :<C-u>call go#def#Jump("vsplit")<CR> | ||||
| nnoremap <silent> <Plug>(go-def-split) :<C-u>call go#def#Jump("split")<CR> | ||||
| nnoremap <silent> <Plug>(go-def-tab) :<C-u>call go#def#Jump("tab")<CR> | ||||
| nnoremap <silent> <Plug>(go-def) :<C-u>call go#def#Jump('', 0)<CR> | ||||
| nnoremap <silent> <Plug>(go-def-vertical) :<C-u>call go#def#Jump("vsplit", 0)<CR> | ||||
| nnoremap <silent> <Plug>(go-def-split) :<C-u>call go#def#Jump("split", 0)<CR> | ||||
| nnoremap <silent> <Plug>(go-def-tab) :<C-u>call go#def#Jump("tab", 0)<CR> | ||||
|  | ||||
| nnoremap <silent> <Plug>(go-def-type) :<C-u>call go#def#Jump('', 1)<CR> | ||||
| nnoremap <silent> <Plug>(go-def-type-vertical) :<C-u>call go#def#Jump("vsplit", 1)<CR> | ||||
| nnoremap <silent> <Plug>(go-def-type-split) :<C-u>call go#def#Jump("split", 1)<CR> | ||||
| nnoremap <silent> <Plug>(go-def-type-tab) :<C-u>call go#def#Jump("tab", 1)<CR> | ||||
|  | ||||
| nnoremap <silent> <Plug>(go-def-pop) :<C-u>call go#def#StackPop()<CR> | ||||
| nnoremap <silent> <Plug>(go-def-stack) :<C-u>call go#def#Stack()<CR> | ||||
|  | ||||
| @ -56,7 +56,9 @@ let s:packages = { | ||||
|       \ 'gogetdoc':      ['github.com/zmb3/gogetdoc'], | ||||
|       \ 'goimports':     ['golang.org/x/tools/cmd/goimports'], | ||||
|       \ 'golint':        ['golang.org/x/lint/golint'], | ||||
|       \ 'gopls':         ['golang.org/x/tools/cmd/gopls'], | ||||
|       \ 'gometalinter':  ['github.com/alecthomas/gometalinter'], | ||||
|       \ 'golangci-lint': ['github.com/golangci/golangci-lint/cmd/golangci-lint'], | ||||
|       \ 'gomodifytags':  ['github.com/fatih/gomodifytags'], | ||||
|       \ 'gorename':      ['golang.org/x/tools/cmd/gorename'], | ||||
|       \ 'gotags':        ['github.com/jstemmer/gotags'], | ||||
|  | ||||
| @ -38,25 +38,48 @@ highlight default link gomodReplaceOperator Operator | ||||
|  | ||||
|  | ||||
| " highlight versions: | ||||
| "  * vX.Y.Z-pre | ||||
| "  * vX.Y.Z | ||||
| "  * vX.0.0-yyyyymmddhhmmss-abcdefabcdef | ||||
| "  * vX.Y.Z-pre.0.yyyymmddhhmmss-abcdefabcdef | ||||
| "  * vX.Y.(Z+1)-0.yyyymmddhhss-abcdefabcdef | ||||
| "  * +incompatible suffix when X > 1 | ||||
| "  see https://godoc.org/golang.org/x/tools/internal/semver for more | ||||
| "  information about how semantic versions are parsed and | ||||
| "  https://golang.org/cmd/go/ for how pseudo-versions and +incompatible | ||||
| "  are applied. | ||||
|  | ||||
|  | ||||
| " match vX.Y.Z and their prereleases | ||||
| syntax match gomodVersion "v\d\+\.\d\+\.\d\+\%(-\%(\w\+\.\)\+0\.\d\{14}-\x\+\)\?" | ||||
| " match target when most recent version before the target is X.Y.Z | ||||
| syntax match gomodVersion "v\d\+\.\d\+\.[1-9]\{1}\d*\%(-0\.\%(\d\{14}-\x\+\)\)\?" | ||||
| " match target without a major version before the commit (e.g.  vX.0.0-yyyymmddhhmmss-abcdefabcdef) | ||||
| syntax match gomodVersion "v\d\+\.0\.0-\d\{14\}-\x\+" | ||||
| syntax match gomodVersion "v\d\+\.\d\+\.\d\+\%(-\%([0-9A-Za-z-]\+\)\%(\.[0-9A-Za-z-]\+\)*\)\?\%(+\%([0-9A-Za-z-]\+\)\(\.[0-9A-Za-z-]\+\)*\)\?" | ||||
| "                          ^--- version ---^^------------ pre-release  ---------------------^^--------------- metadata ---------------------^ | ||||
| "   	                     ^--------------------------------------- semantic version -------------------------------------------------------^ | ||||
|  | ||||
| " match vX.Y.Z and their prereleases for X>1 | ||||
| syntax match gomodVersion "v[2-9]\{1}\d\?\.\d\+\.\d\+\%(-\%(\w\+\.\)\+0\.\d\{14\}-\x\+\)\?\%(+incompatible\>\)\?" | ||||
| " match target when most recent version before the target is X.Y.Z for X>1 | ||||
| syntax match gomodVersion "v[2-9]\{1}\d\?\.\d\+\.[1-9]\{1}\d*\%(-0\.\%(\d\{14\}-\x\+\)\)\?\%(+incompatible\>\)\?" | ||||
| " match target without a major version before the commit (e.g.  vX.0.0-yyyymmddhhmmss-abcdefabcdef) for X>1 | ||||
| syntax match gomodVersion "v[2-9]\{1}\d\?\.0\.0-\d\{14\}-\x\+\%(+incompatible\>\)\?" | ||||
| " match pseudo versions | ||||
| " without a major version before the commit (e.g.  vX.0.0-yyyymmddhhmmss-abcdefabcdef) | ||||
| syntax match gomodVersion  "v\d\+\.0\.0-\d\{14\}-\x\+" | ||||
| " when most recent version before target is a pre-release | ||||
| syntax match gomodVersion  "v\d\+\.\d\+\.\d\+-\%([0-9A-Za-z-]\+\)\%(\.[0-9A-Za-z-]\+\)*\%(+\%([0-9A-Za-z-]\+\)\(\.[0-9A-Za-z-]\+\)*\)\?\.0\.\d\{14}-\x\+" | ||||
| "                          ^--- version ---^^--- ------ pre-release -----------------^^--------------- metadata ---------------------^ | ||||
| "                     	   ^------------------------------------- semantic version --------------------------------------------------^ | ||||
| " most recent version before the target is X.Y.Z | ||||
| syntax match gomodVersion "v\d\+\.\d\+\.\d\+\%(+\%([0-9A-Za-z-]\+\)\(\.[0-9A-Za-z-]\+\)*\)\?-0\.\d\{14}-\x\+" | ||||
| "                          ^--- version ---^^--------------- metadata ---------------------^ | ||||
|  | ||||
| " match incompatible vX.Y.Z and their prereleases | ||||
| syntax match gomodVersion "v[2-9]\{1}\d*\.\d\+\.\d\+\%(-\%([0-9A-Za-z-]\+\)\%(\.[0-9A-Za-z-]\+\)*\)\?\%(+\%([0-9A-Za-z-]\+\)\(\.[0-9A-Za-z-]\+\)*\)\?+incompatible" | ||||
| "                          ^------- version -------^^------------- pre-release ---------------------^^--------------- metadata ---------------------^ | ||||
| "               	         ^------------------------------------------- semantic version -----------------------------------------------------------^ | ||||
|  | ||||
| " match incompatible pseudo versions | ||||
| " incompatible without a major version before the commit (e.g.  vX.0.0-yyyymmddhhmmss-abcdefabcdef) | ||||
| syntax match gomodVersion "v[2-9]\{1}\d*\.0\.0-\d\{14\}-\x\++incompatible" | ||||
| " when most recent version before target is a pre-release | ||||
| syntax match gomodVersion "v[2-9]\{1}\d*\.\d\+\.\d\+-\%([0-9A-Za-z-]\+\)\%(\.[0-9A-Za-z-]\+\)*\%(+\%([0-9A-Za-z-]\+\)\(\.[0-9A-Za-z-]\+\)*\)\?\.0\.\d\{14}-\x\++incompatible" | ||||
| "                          ^------- version -------^^---------- pre-release -----------------^^--------------- metadata ---------------------^ | ||||
| "                     	   ^---------------------------------------- semantic version ------------------------------------------------------^ | ||||
| " most recent version before the target is X.Y.Z | ||||
| syntax match gomodVersion "v[2-9]\{1}\d*\.\d\+\.\d\+\%(+\%([0-9A-Za-z-]\+\)\%(\.[0-9A-Za-z-]\+\)*\)\?-0\.\d\{14}-\x\++incompatible" | ||||
| "                          ^------- version -------^^---------------- metadata ---------------------^ | ||||
| highlight default link gomodVersion Identifier | ||||
|  | ||||
| let b:current_syntax = "gomod" | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Amir Salihefendic
					Amir Salihefendic