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

Updated plugins

This commit is contained in:
Amir Salihefendic
2018-09-24 21:40:17 -03:00
parent 6bd9eda8c3
commit a6b64938eb
199 changed files with 2897 additions and 980 deletions

View File

@ -6,6 +6,7 @@ coverage:
target: auto
threshold: 1
base: auto
patch: off
comment: false
ignore:
- "!autoload/go/*.vim$"

View File

@ -1,6 +1,6 @@
language: go
go:
- 1.10.x
- 1.11.x
notifications:
email: false
matrix:

View File

@ -1,5 +1,18 @@
## unplanned
FEATURES:
* **go.mod file support!** This is the first feature for upcoming Go modules
support. The followings are added:
* Syntax highlighting for the `go.mod` file.
* A new `gomod` filetype is set if a `go.mod` file has been opened and starts
with the line `module `
* New **:GoModFmt** command that formats the `go.mod` file
* 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)
IMPROVEMENTS:
* Unify async job handling for Vim8 and Neovim.
[[GH-1864]](https://github.com/fatih/vim-go/pull/1864)
@ -13,6 +26,36 @@ IMPROVEMENTS:
[[GH-1894]](https://github.com/fatih/vim-go/pull/1894)
* Install keyify from its canonical import path.
[[GH-1924]](https://github.com/fatih/vim-go/pull/1924)
* Update the tested version of Neovim to v0.3.1.
[[GH-1923]](https://github.com/fatih/vim-go/pull/1923)
* Run autocompletion asynchronously in Vim8 and Neovim.
[[GH-1926]](https://github.com/fatih/vim-go/pull/1926)
* Show statusline update when running `:GoInfo` with `g:go_info_mode='gocode'`.
[[GH-1937]](https://github.com/fatih/vim-go/pull/1937)
* Do not update statusline when highlighting sameids or showing type info via
an autocmd.
[[GH-1937]](https://github.com/fatih/vim-go/pull/1937)
* Do not indent within a raw string literal.
[[GH-1858]](https://github.com/fatih/vim-go/pull/1858)
* Highlight Go's predeclared function identifiers (the functions in `builtins`)
using keyword groups and highlight them using the `Identifiers` group.
[[GH-1939]](https://github.com/fatih/vim-go/pull/1939)
* Add a new FAQ entry to instruct users how to modify the vim-go highlight
groups.
[[GH-1939]](https://github.com/fatih/vim-go/pull/1939)
* Improve use of statusline and progress messages.
[[GH-1948]](https://github.com/fatih/vim-go/pull/1948)
* Add `tt` snippet to create a table test boilerplate (see
https://github.com/golang/go/wiki/TableDrivenTests for more information on
how to use a table driven test).
[[GH-1956]](https://github.com/fatih/vim-go/pull/1956)
* Add `<Plug>(go-decls)` and `<Plug>(go-decls-dir)` mappings.
[[GH-1964]](https://github.com/fatih/vim-go/pull/1964)
* Handle go1.11 test output.
[[GH-1978]](https://github.com/fatih/vim-go/pull/1978)
* Internal: install tools by their custom names
[[GH-1984]](https://github.com/fatih/vim-go/pull/1984)
BUG FIXES:
* Fix `:GoRun %` on Windows.
@ -23,10 +66,17 @@ BUG FIXES:
[[GH-1895]](https://github.com/fatih/vim-go/pull/1895)
* Fix `:GoInfo` when `g:go_info_mode` is `gocode`
[[GH-1915]](https://github.com/fatih/vim-go/pull/1915)
* Fix highlighting of pointer type in var blocks.
[[GH-1794]](https://github.com/fatih/vim-go/pull/1794)
* Fix `:GoImport` when adding to an empty import block (i.e`import ()`)
[[GH-1938]](https://github.com/fatih/vim-go/pull/1938)
BACKWARDS INCOMPATIBILITIES:
* Bump minimum required version of Vim to 7.4.2009.
[[GH-1899]](https://github.com/fatih/vim-go/pull/1899)
* Switch gocode to github.com/mdempsky/gocode. Several gocode options have been
removed and a new one has been added.
[[GH-1853]](https://github.com/fatih/vim-go/pull/1853)
## 1.18 - (July 18, 2018)
@ -42,7 +92,7 @@ FEATURES:
f, err := os.Open("file")
}
```
Becomes:
```

View File

@ -1,4 +1,4 @@
FROM golang:1.10.1
FROM golang:1.11
RUN apt-get update -y && \
apt-get install -y build-essential curl git libncurses5-dev python3-pip && \

View File

@ -33,7 +33,7 @@ This plugin adds Go language support for Vim, with the following main features:
## Install
vim-go requires at least Vim 7.4.2009 or Neovim 0.2.2.
vim-go requires at least Vim 7.4.2009 or Neovim 0.3.1.
The [**latest stable release**](https://github.com/fatih/vim-go/releases/latest) is the
recommended version to use. If you choose to use the master branch instead,

View File

@ -31,15 +31,12 @@ function! go#cmd#Build(bang, ...) abort
\ [".", "errors"]
" Vim and Neovim async.
if go#util#has_job() || has('nvim')
if go#config#EchoCommandInfo()
call go#util#EchoProgress("building dispatched ...")
endif
if go#util#has_job()
call s:cmd_job({
\ 'cmd': ['go'] + args,
\ 'bang': a:bang,
\ 'for': 'GoBuild',
\ 'statustype': 'build'
\})
" Vim 7.4 without async
@ -195,14 +192,11 @@ function! go#cmd#Install(bang, ...) abort
" expand all wildcards(i.e: '%' to the current file name)
let goargs = map(copy(a:000), "expand(v:val)")
if go#config#EchoCommandInfo()
call go#util#EchoProgress("installing dispatched ...")
endif
call s:cmd_job({
\ 'cmd': ['go', 'install', '-tags', go#config#BuildTags()] + goargs,
\ 'bang': a:bang,
\ 'for': 'GoInstall',
\ 'statustype': 'install'
\})
return
endif
@ -281,16 +275,7 @@ endfunction
" | Vim job callbacks |
" ---------------------
function s:cmd_job(args) abort
let status_dir = expand('%:p:h')
let started_at = reltime()
call go#statusline#Update(status_dir, {
\ 'desc': "current status",
\ 'type': a:args.cmd[1],
\ 'state': "started",
\})
function! s:cmd_job(args) abort
" autowrite is not enabled for jobs
call go#cmd#autowrite()

View File

@ -9,6 +9,15 @@ function! s:gocodeCommand(cmd, args) abort
let cmd = [bin_path]
let cmd = extend(cmd, ['-sock', socket_type])
let cmd = extend(cmd, ['-f', 'vim'])
if go#config#GocodeProposeBuiltins()
let cmd = extend(cmd, ['-builtin'])
endif
if go#config#GocodeProposeSource()
let cmd = extend(cmd, ['-source'])
endif
let cmd = extend(cmd, [a:cmd])
let cmd = extend(cmd, a:args)
@ -43,31 +52,7 @@ function! s:sync_gocode(cmd, args, input) abort
return l:result
endfunction
let s:optionsEnabled = 0
function! s:gocodeEnableOptions() abort
if s:optionsEnabled
return
endif
let l:bin_path = go#path#CheckBinPath("gocode")
if empty(l:bin_path)
return
endif
let s:optionsEnabled = 1
call go#util#Exec(['gocode', 'set', 'propose-builtins', s:toBool(go#config#GocodeProposeBuiltins())])
call go#util#Exec(['gocode', 'set', 'autobuild', s:toBool(go#config#GocodeAutobuild())])
call go#util#Exec(['gocode', 'set', 'unimported-packages', s:toBool(go#config#GocodeUnimportedPackages())])
endfunction
function! s:toBool(val) abort
if a:val | return 'true' | else | return 'false' | endif
endfunction
function! s:gocodeAutocomplete() abort
call s:gocodeEnableOptions()
" use the offset as is, because the cursor position is the position for
" which autocomplete candidates are needed.
return s:sync_gocode('autocomplete',
@ -81,60 +66,36 @@ function! go#complete#GetInfo() abort
return s:sync_info(0)
endfunction
function! go#complete#Info() abort
function! go#complete#Info(showstatus) abort
if go#util#has_job(1)
return s:async_info(1)
return s:async_info(1, a:showstatus)
else
return s:sync_info(1)
endif
endfunction
function! s:async_info(echo)
if exists("s:async_info_job")
call job_stop(s:async_info_job)
unlet s:async_info_job
endif
function! s:async_info(echo, showstatus)
let state = {'echo': a:echo}
let state = {
\ 'exited': 0,
\ 'exit_status': 0,
\ 'closed': 0,
\ 'messages': [],
\ 'echo': a:echo
\ }
function! s:callback(chan, msg) dict
let l:msg = a:msg
if &encoding != 'utf-8'
let l:msg = iconv(l:msg, 'utf-8', &encoding)
endif
call add(self.messages, l:msg)
endfunction
function! s:exit_cb(job, exitval) dict
let self.exit_status = a:exitval
let self.exited = 1
if self.closed
call self.complete()
endif
endfunction
function! s:close_cb(ch) dict
let self.closed = 1
if self.exited
call self.complete()
endif
endfunction
function state.complete() dict
if self.exit_status != 0
function! s:complete(job, exit_status, messages) abort dict
if a:exit_status != 0
return
endif
let result = s:info_filter(self.echo, join(self.messages, "\n"))
if &encoding != 'utf-8'
let i = 0
while i < len(a:messages)
let a:messages[i] = iconv(a:messages[i], 'utf-8', &encoding)
let i += 1
endwhile
endif
let result = s:info_filter(self.echo, join(a:messages, "\n"))
call s:info_complete(self.echo, result)
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)
" add 1 to the offset, so that the position at the cursor will be included
" in gocode's search
@ -146,23 +107,32 @@ function! s:async_info(echo)
\ "GOROOT": go#util#env("goroot")
\ }
let opts = {
\ 'bang': 1,
\ 'complete': state.complete,
\ 'for': '_',
\ }
if a:showstatus
let opts.statustype = 'gocode'
endif
let opts = go#job#Options(l:opts)
let cmd = s:gocodeCommand('autocomplete',
\ [expand('%:p'), offset])
" TODO(bc): Don't write the buffer to a file; pass the buffer directrly to
" TODO(bc): Don't write the buffer to a file; pass the buffer directly to
" gocode's stdin. It shouldn't be necessary to use {in_io: 'file', in_name:
" s:gocodeFile()}, but unfortunately {in_io: 'buffer', in_buf: bufnr('%')}
" should work.
let options = {
" doesn't work.
call extend(opts, {
\ 'env': env,
\ 'in_io': 'file',
\ 'in_name': s:gocodeFile(),
\ 'callback': funcref("s:callback", [], state),
\ 'exit_cb': funcref("s:exit_cb", [], state),
\ 'close_cb': funcref("s:close_cb", [], state)
\ }
\ })
let s:async_info_job = job_start(cmd, options)
call go#job#Start(cmd, opts)
endfunction
function! s:gocodeFile()

View File

@ -0,0 +1,20 @@
func! Test_GetInfo()
let l:filename = 'complete/complete.go'
let l:tmp = gotest#load_fixture(l:filename)
call cursor(8, 3)
let g:go_info_mode = 'gocode'
let expected = 'func Example(s string)'
let actual = go#complete#GetInfo()
call assert_equal(expected, actual)
let g:go_info_mode = 'guru'
call go#config#InfoMode()
let actual = go#complete#GetInfo()
call assert_equal(expected, actual)
unlet g:go_info_mode
endfunction
" vim: sw=2 ts=2 et

View File

@ -135,10 +135,6 @@ function! go#config#SetGuruScope(scope) abort
endif
endfunction
function! go#config#GocodeUnimportedPackages() abort
return get(g:, 'go_gocode_unimported_packages', 0)
endfunction
let s:sock_type = (has('win32') || has('win64')) ? 'tcp' : 'unix'
function! go#config#GocodeSocketType() abort
return get(g:, 'go_gocode_socket_type', s:sock_type)
@ -148,8 +144,8 @@ function! go#config#GocodeProposeBuiltins() abort
return get(g:, 'go_gocode_propose_builtins', 1)
endfunction
function! go#config#GocodeAutobuild() abort
return get(g:, 'go_gocode_autobuild', 1)
function! go#config#GocodeProposeSource() abort
return get(g:, 'go_gocode_propose_source', 1)
endfunction
function! go#config#EchoCommandInfo() abort
@ -282,6 +278,14 @@ function! go#config#SetAsmfmtAutosave(value) abort
let g:go_asmfmt_autosave = a:value
endfunction
function! go#config#ModFmtAutosave() abort
return get(g:, "go_mod_fmt_autosave", 1)
endfunction
function! go#config#SetModFmtAutosave(value) abort
let g:go_mod_fmt_autosave = a:value
endfunction
function! go#config#DocMaxHeight() abort
return get(g:, "go_doc_max_height", 20)
endfunction
@ -416,7 +420,7 @@ function! go#config#HighlightVariableDeclarations() abort
return get(g:, 'go_highlight_variable_declarations', 0)
endfunction
function go#config#FoldEnable(...) abort
function! go#config#FoldEnable(...) abort
if a:0 > 0
return index(go#config#FoldEnable(), a:1) > -1
endif

View File

@ -44,11 +44,7 @@ function! go#coverage#Buffer(bang, ...) abort
let s:toggle = 1
let l:tmpname = tempname()
if go#config#EchoCommandInfo()
call go#util#EchoProgress("testing...")
endif
if go#util#has_job() || has('nvim')
if go#util#has_job()
call s:coverage_job({
\ 'cmd': ['go', 'test', '-tags', go#config#BuildTags(), '-coverprofile', l:tmpname] + a:000,
\ 'complete': function('s:coverage_callback', [l:tmpname]),
@ -59,6 +55,10 @@ function! go#coverage#Buffer(bang, ...) abort
return
endif
if go#config#EchoCommandInfo()
call go#util#EchoProgress("testing...")
endif
let args = [a:bang, 0, "-coverprofile", l:tmpname]
if a:0
call extend(args, a:000)
@ -89,12 +89,13 @@ endfunction
" a new HTML coverage page from that profile in a new browser
function! go#coverage#Browser(bang, ...) abort
let l:tmpname = tempname()
if go#util#has_job() || has('nvim')
if go#util#has_job()
call s:coverage_job({
\ 'cmd': ['go', 'test', '-tags', go#config#BuildTags(), '-coverprofile', l:tmpname],
\ 'complete': function('s:coverage_browser_callback', [l:tmpname]),
\ 'bang': a:bang,
\ 'for': 'GoTest',
\ 'statustype': 'coverage',
\ })
return
endif

View File

@ -25,12 +25,12 @@ function! s:groutineID() abort
return s:state['currentThread'].goroutineID
endfunction
function! s:exit(job, status) abort
function! s:complete(job, exit_status, data) abort
if has_key(s:state, 'job')
call remove(s:state, 'job')
endif
call s:clearState()
if a:status > 0
if a:exit_status > 0
call go#util#EchoError(s:state['message'])
endif
endfunction
@ -567,14 +567,18 @@ function! go#debug#Start(is_test, ...) abort
endif
let l:cmd += l:args
call go#util#EchoProgress('Starting GoDebug...')
let s:state['message'] = []
let s:state['job'] = job_start(l:cmd, {
\ 'out_cb': function('s:out_cb'),
\ 'err_cb': function('s:err_cb'),
\ 'exit_cb': function('s:exit'),
\ 'stoponexit': 'kill',
\})
let l:opts = {
\ 'for': '_',
\ 'statustype': 'debug',
\ 'complete': function('s:complete'),
\ }
let l:opts = go#job#Options(l:opts)
let l:opts.out_cb = function('s:out_cb')
let l:opts.err_cb = function('s:err_cb')
let l:opts.stoponexit = 'kill'
let s:state['job'] = go#job#Start(l:cmd, l:opts)
catch
call go#util#EchoError(v:exception)
endtry

View File

@ -42,20 +42,20 @@ function! go#def#Jump(mode) abort
call extend(cmd, ["definition", fname . ':#' . go#util#OffsetCursor()])
if go#util#has_job() || has('nvim')
if go#util#has_job()
let l:state = {}
let l:spawn_args = {
\ 'cmd': cmd,
\ 'complete': function('s:jump_to_declaration_cb', [a:mode, bin_name]),
\ 'complete': function('s:jump_to_declaration_cb', [a:mode, bin_name], l:state),
\ 'for': '_',
\ 'statustype': 'searching declaration',
\ }
if &modified
let l:spawn_args.input = stdin_content
endif
call go#util#EchoProgress("searching declaration ...")
call s:def_job(spawn_args)
call s:def_job(spawn_args, l:state)
return
endif
@ -77,13 +77,17 @@ function! go#def#Jump(mode) abort
call go#def#jump_to_declaration(out, a:mode, bin_name)
endfunction
function! s:jump_to_declaration_cb(mode, bin_name, job, exit_status, data) abort
function! s:jump_to_declaration_cb(mode, bin_name, job, exit_status, data) abort dict
if a:exit_status != 0
return
endif
call go#def#jump_to_declaration(a:data[0], a:mode, a:bin_name)
call go#util#EchoSuccess(fnamemodify(a:data[0], ":t"))
" capture the active window so that after the exit_cb and close_cb callbacks
" can return to it when a:mode caused a split.
let self.winid = win_getid(winnr())
endfunction
function! go#def#jump_to_declaration(out, mode, bin_name) abort
@ -283,9 +287,26 @@ function! go#def#Stack(...) abort
endif
endfunction
function s:def_job(args) abort
function s:def_job(args, state) abort
let l:start_options = go#job#Options(a:args)
let l:state = a:state
function! s:exit_cb(next, job, exitval) dict
call call(a:next, [a:job, a:exitval])
if has_key(self, 'winid')
call win_gotoid(self.winid)
endif
endfunction
let l:start_options.exit_cb = funcref('s:exit_cb', [l:start_options.exit_cb], l:state)
function! s:close_cb(next, ch) dict
call call(a:next, [a:ch])
if has_key(self, 'winid')
call win_gotoid(self.winid)
endif
endfunction
let l:start_options.close_cb = funcref('s:close_cb', [l:start_options.close_cb], l:state)
if &modified
let l:tmpname = tempname()
call writefile(split(a:args.input, "\n"), l:tmpname, "b")
@ -293,7 +314,7 @@ function s:def_job(args) abort
let l:start_options.in_name = l:tmpname
endif
call go#job#Start(a:args.cmd, start_options)
call go#job#Start(a:args.cmd, l:start_options)
endfunction
" vim: sw=2 ts=2 et

View File

@ -45,7 +45,7 @@ func! Test_Jump_leaves_lists() abort
call setqflist(copy(expected), 'r' )
let l:bufnr = bufnr('%')
call cursor(6, 3)
call cursor(6, 7)
call go#def#Jump('')
let start = reltime()

View File

@ -106,64 +106,6 @@ function! s:sync_guru(args) abort
return l:out
endfunc
" use vim or neovim job api as appropriate
function! s:job_start(cmd, start_options) abort
if go#util#has_job()
return job_start(a:cmd, a:start_options)
endif
let opts = {'stdout_buffered': v:true, 'stderr_buffered': v:true}
let stdout_buf = ""
function opts.on_stdout(job_id, data, event) closure
let l:data = a:data
let l:data[0] = stdout_buf . l:data[0]
let stdout_buf = ""
if l:data[-1] != ""
let stdout_buf = l:data[-1]
endif
let l:data = l:data[:-2]
if len(l:data) == 0
return
endif
call a:start_options.callback(a:job_id, join(l:data, "\n"))
endfunction
let stderr_buf = ""
function opts.on_stderr(job_id, data, event) closure
let l:data = a:data
let l:data[0] = stderr_buf . l:data[0]
let stderr_buf = ""
if l:data[-1] != ""
let stderr_buf = l:data[-1]
endif
let l:data = l:data[:-2]
if len(l:data) == 0
return
endif
call a:start_options.callback(a:job_id, join(l:data, "\n"))
endfunction
function opts.on_exit(job_id, exit_code, event) closure
call a:start_options.exit_cb(a:job_id, a:exit_code)
call a:start_options.close_cb(a:job_id)
endfunction
" use a shell for input redirection if needed
let cmd = a:cmd
if has_key(a:start_options, 'in_io') && a:start_options.in_io ==# 'file' && !empty(a:start_options.in_name)
let cmd = ['/bin/sh', '-c', go#util#Shelljoin(a:cmd) . ' <' . a:start_options.in_name]
endif
return jobstart(cmd, opts)
endfunction
" async_guru runs guru in async mode with the given arguments
function! s:async_guru(args) abort
let result = s:guru_cmd(a:args)
@ -172,91 +114,50 @@ function! s:async_guru(args) abort
return
endif
if !has_key(a:args, 'disable_progress')
if a:args.needs_scope
call go#util#EchoProgress("analysing with scope " . result.scope .
\ " (see ':help go-guru-scope' if this doesn't work)...")
endif
endif
let state = {
\ 'status_dir': expand('%:p:h'),
\ 'statusline_type': printf("%s", a:args.mode),
\ 'mode': a:args.mode,
\ 'status': {},
\ 'exitval': 0,
\ 'closed': 0,
\ 'exited': 0,
\ 'messages': [],
\ 'parse' : get(a:args, 'custom_parse', funcref("s:parse_guru_output"))
\ }
function! s:callback(chan, msg) dict
call add(self.messages, a:msg)
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)
function! s:exit_cb(job, exitval) dict
let self.exited = 1
let opts = {
\ 'statustype': get(a:args, 'statustype', a:args.mode),
\ 'for': '_',
\ 'errorformat': "%f:%l.%c-%[%^:]%#:\ %m,%f:%l:%c:\ %m",
\ 'complete': state.complete,
\ }
let status = {
\ 'desc': 'last status',
\ 'type': self.statusline_type,
\ 'state': "finished",
\ }
if has_key(a:args, 'disable_progress')
let opts.statustype = ''
endif
if a:exitval
let self.exitval = a:exitval
let status.state = "failed"
endif
call go#statusline#Update(self.status_dir, status)
if self.closed
call self.complete()
endif
endfunction
function! s:close_cb(ch) dict
let self.closed = 1
if self.exited
call self.complete()
endif
endfunction
function state.complete() dict
let out = join(self.messages, "\n")
call self.parse(self.exitval, out, self.mode)
endfunction
" explicitly bind the callbacks to state so that self within them always
" refers to state. See :help Partial for more information.
let start_options = {
\ 'callback': function('s:callback', [], state),
\ 'exit_cb': function('s:exit_cb', [], state),
\ 'close_cb': function('s:close_cb', [], state)
\ }
let opts = go#job#Options(l:opts)
if has_key(result, 'stdin_content')
let l:tmpname = tempname()
call writefile(split(result.stdin_content, "\n"), l:tmpname, "b")
let l:start_options.in_io = "file"
let l:start_options.in_name = l:tmpname
let l:opts.in_io = "file"
let l:opts.in_name = l:tmpname
endif
call go#statusline#Update(state.status_dir, {
\ 'desc': "current status",
\ 'type': state.statusline_type,
\ 'state': "analysing",
\})
call go#job#Start(result.cmd, opts)
return s:job_start(result.cmd, start_options)
if a:args.needs_scope && go#config#EchoCommandInfo() && !has_key(a:args, 'disable_progress')
call go#util#EchoProgress("analysing with scope " . result.scope .
\ " (see ':help go-guru-scope' if this doesn't work)...")
endif
endfunc
" run_guru runs the given guru argument
function! s:run_guru(args) abort
if has('nvim') || go#util#has_job()
if go#util#has_job()
let res = s:async_guru(a:args)
else
let res = s:sync_guru(a:args)
@ -320,7 +221,7 @@ function! go#guru#Describe(selected) abort
call s:run_guru(args)
endfunction
function! go#guru#DescribeInfo() abort
function! go#guru#DescribeInfo(showstatus) abort
" json_encode() and friends are introduced with this patch (7.4.1304)
" vim: https://groups.google.com/d/msg/vim_dev/vLupTNhQhZ8/cDGIk0JEDgAJ
" nvim: https://github.com/neovim/neovim/pull/4131
@ -411,7 +312,7 @@ function! go#guru#DescribeInfo() abort
return
endif
call go#util#EchoInfo(info)
echo "vim-go: " | echohl Function | echon info | echohl None
endfunction
let args = {
@ -504,7 +405,7 @@ function! go#guru#Referrers(selected) abort
call s:run_guru(args)
endfunction
function! go#guru#SameIds() abort
function! go#guru#SameIds(showstatus) abort
" we use matchaddpos() which was introduce with 7.4.330, be sure we have
" it: http://ftp.vim.org/vim/patches/7.4/7.4.330
if !exists("*matchaddpos")
@ -527,6 +428,9 @@ function! go#guru#SameIds() abort
\ 'needs_scope': 0,
\ 'custom_parse': function('s:same_ids_highlight'),
\ }
if !a:showstatus
let args.disable_progress = 1
endif
call s:run_guru(args)
endfunction

View File

@ -65,6 +65,9 @@ function! go#import#SwitchImport(enabled, localname, path, bang) abort
let packageline = line
let appendline = line
elseif linestr =~# '^import\s\+(\+)'
let appendline = line
let appendstr = qlocalpath
elseif linestr =~# '^import\s\+('
let appendstr = qlocalpath
let indentstr = 1
@ -161,8 +164,16 @@ function! go#import#SwitchImport(enabled, localname, path, bang) abort
let linesdelta += 3
let appendstr = qlocalpath
let indentstr = 1
call append(appendline, appendstr)
elseif getline(appendline) =~# '^import\s\+(\+)'
call setline(appendline, 'import (')
call append(appendline + 0, appendstr)
call append(appendline + 1, ')')
let linesdelta -= 1
let indentstr = 1
else
call append(appendline, appendstr)
endif
call append(appendline, appendstr)
execute appendline + 1
if indentstr
execute 'normal! >>'

View File

@ -0,0 +1,22 @@
func! Test_indent_raw_string() abort
try
let l:dir= gotest#write_file('indent/indent.go', [
\ 'package main',
\ '',
\ 'import "fmt"',
\ '',
\ 'func main() {',
\ "\t\x1fconst msg = `",
\ '`',
\ '\tfmt.Println(msg)',
\ '}'])
silent execute "normal o" . "not indented\<Esc>"
let l:indent = indent(line('.'))
call assert_equal(0, l:indent)
finally
call delete(l:dir, 'rf')
endtry
endfunc
" vim: sw=2 ts=2 et

View File

@ -33,7 +33,10 @@ endfunction
" function will be passed three arguments: the job, its exit code, and the
" list of messages received from the channel. The default is a no-op. A
" custom value can modify the messages before they are processed by the
" returned exit_cb and close_cb callbacks.
" returned exit_cb and close_cb callbacks. When the function is called,
" the current window will be the window that was hosting the buffer when
" the job was started. After it returns, the current window will be
" restored to what it was before the function was called.
" The return value is a dictionary with these keys:
" 'callback':
@ -87,14 +90,27 @@ function! go#job#Options(args)
" do nothing in state.complete by default.
function state.complete(job, exit_status, data)
if has_key(self, 'custom_complete')
let l:winid = win_getid(winnr())
" Always set the active window to the window that was active when the job
" was started. Among other things, this makes sure that the correct
" window's location list will be populated when the list type is
" 'location' and the user has moved windows since starting the job.
call win_gotoid(self.winid)
call self.custom_complete(a:job, a:exit_status, a:data)
call win_gotoid(l:winid)
endif
call self.show_errors(a:job, a:exit_status, a:data)
endfunction
function state.show_status(job, exit_status) dict
if self.statustype == ''
return
endif
if go#config#EchoCommandInfo()
let prefix = ""
if self.statustype != ''
let prefix = '[' . self.statustype . '] '
endif
let prefix = '[' . self.statustype . '] '
if a:exit_status == 0
call go#util#EchoSuccess(prefix . "SUCCESS")
else
@ -102,10 +118,6 @@ function! go#job#Options(args)
endif
endif
if self.statustype == ''
return
endif
let status = {
\ 'desc': 'last status',
\ 'type': self.statustype,
@ -127,10 +139,15 @@ function! go#job#Options(args)
endfunction
if has_key(a:args, 'complete')
let state.complete = a:args.complete
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',
@ -164,7 +181,6 @@ function! go#job#Options(args)
if self.closed || has('nvim')
call self.complete(a:job, self.exit_status, self.messages)
call self.show_errors(a:job, self.exit_status, self.messages)
endif
endfunction
" explicitly bind exit_cb to state so that within it, self will always refer
@ -177,7 +193,6 @@ function! go#job#Options(args)
if self.exited
let job = ch_getjob(a:ch)
call self.complete(job, self.exit_status, self.messages)
call self.show_errors(job, self.exit_status, self.messages)
endif
endfunction
" explicitly bind close_cb to state so that within it, self will
@ -225,7 +240,7 @@ function! go#job#Options(args)
if empty(errors)
" failed to parse errors, output the original content
call go#util#EchoError(self.messages + [self.dir])
call go#util#EchoError([self.dir] + self.messages)
call win_gotoid(l:winid)
return
endif
@ -254,10 +269,21 @@ function! go#job#Start(cmd, options)
let l:options = s:neooptions(l:options)
endif
" Verify that the working directory for the job actually exists. Return
" 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")
if has_key(l:options, 'cwd') && !isdirectory(l:options.cwd)
return
elseif !isdirectory(filedir)
return
endif
if !has_key(l:options, 'cwd')
" pre start
let dir = getcwd()
execute l:cd fnameescape(expand("%:p:h"))
execute l:cd fnameescape(filedir)
endif
if has_key(l:options, '_start')
@ -267,11 +293,10 @@ function! go#job#Start(cmd, options)
unlet l:options._start
endif
if has('nvim')
let l:input = []
if has_key(l:options, 'in_io') && l:options.in_io ==# 'file' && !empty(l:options.in_name)
let l:input = readfile(l:options.in_name, 1)
if has_key(a:options, 'in_io') && a:options.in_io ==# 'file' && !empty(a:options.in_name)
let l:input = readfile(a:options.in_name, "b")
endif
let job = jobstart(a:cmd, l:options)
@ -306,49 +331,77 @@ function! s:neooptions(options)
continue
endif
" dealing with the channel lines of Neovim sucks. 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']`.
if key == 'callback'
let l:options['callback'] = a:options['callback']
if !has_key(a:options, 'out_cb')
let l:options['stdout_buffered'] = v:true
function! s:callback2on_stdout(ch, data, event) dict
let l:data = a:data
let l:data[0] = self.stdout_buf . l:data[0]
let self.stdout_buf = ""
" a single empty string means EOF was reached.
if len(a:data) == 1 && a:data[0] == ''
" when there's nothing buffered, return early so that an
" erroneous message will not be added.
if self.stdout_buf == ''
return
endif
if l:data[-1] != ""
let l:data = [self.stdout_buf]
let self.stdout_buf = ''
else
let l:data = copy(a:data)
let l:data[0] = self.stdout_buf . l:data[0]
" The last element may be a partial line; save it for next time.
let self.stdout_buf = l:data[-1]
let l:data = l:data[:-2]
if len(l:data) == 0
return
endif
endif
let l:data = l:data[:-2]
if len(l:data) == 0
return
endif
call self.callback(a:ch, join(l:data, "\n"))
for l:msg in l:data
call self.callback(a:ch, l:msg)
endfor
endfunction
let l:options['on_stdout'] = function('s:callback2on_stdout', [], l:options)
endif
if !has_key(a:options, 'err_cb')
let l:options['stderr_buffered'] = v:true
function! s:callback2on_stderr(ch, data, event) dict
let l:data = a:data
let l:data[0] = self.stderr_buf . l:data[0]
let self.stderr_buf = ""
" a single empty string means EOF was reached.
if len(a:data) == 1 && a:data[0] == ''
" when there's nothing buffered, return early so that an
" erroneous message will not be added.
if self.stderr_buf == ''
return
endif
let l:data = [self.stderr_buf]
let self.stderr_buf = ''
else
let l:data = copy(a:data)
let l:data[0] = self.stderr_buf . l:data[0]
if l:data[-1] != ""
" The last element may be a partial line; save it for next time.
let self.stderr_buf = l:data[-1]
let l:data = l:data[:-2]
if len(l:data) == 0
return
endif
endif
let l:data = l:data[:-2]
if len(l:data) == 0
return
endif
call self.callback(a:ch, join(l:data, "\n"))
for l:msg in l:data
call self.callback(a:ch, l:msg)
endfor
endfunction
let l:options['on_stderr'] = function('s:callback2on_stderr', [], l:options)
endif
@ -358,22 +411,32 @@ function! s:neooptions(options)
if key == 'out_cb'
let l:options['out_cb'] = a:options['out_cb']
let l:options['stdout_buffered'] = v:true
function! s:on_stdout(ch, data, event) dict
let l:data = a:data
let l:data[0] = self.stdout_buf . l:data[0]
let self.stdout_buf = ""
" a single empty string means EOF was reached.
if len(a:data) == 1 && a:data[0] == ''
" when there's nothing buffered, return early so that an
" erroneous message will not be added.
if self.stdout_buf == ''
return
endif
let l:data = [self.stdout_buf]
let self.stdout_buf = ''
else
let l:data = copy(a:data)
let l:data[0] = self.stdout_buf . l:data[0]
if l:data[-1] != ""
" The last element may be a partial line; save it for next time.
let self.stdout_buf = l:data[-1]
let l:data = l:data[:-2]
if len(l:data) == 0
return
endif
endif
let l:data = l:data[:-2]
if len(l:data) == 0
return
endif
call self.out_cb(a:ch, join(l:data, "\n"))
for l:msg in l:data
call self.out_cb(a:ch, l:msg)
endfor
endfunction
let l:options['on_stdout'] = function('s:on_stdout', [], l:options)
@ -382,22 +445,32 @@ function! s:neooptions(options)
if key == 'err_cb'
let l:options['err_cb'] = a:options['err_cb']
let l:options['stderr_buffered'] = v:true
function! s:on_stderr(ch, data, event) dict
let l:data = a:data
let l:data[0] = self.stderr_buf . l:data[0]
let self.stderr_buf = ""
" a single empty string means EOF was reached.
if len(a:data) == 1 && a:data[0] == ''
" when there's nothing buffered, return early so that an
" erroneous message will not be added.
if self.stderr_buf == ''
return
endif
let l:data = [self.stderr_buf]
let self.stderr_buf = ''
else
let l:data = copy(a:data)
let l:data[0] = self.stderr_buf . l:data[0]
if l:data[-1] != ""
" The last element may be a partial line; save it for next time.
let self.stderr_buf = l:data[-1]
let l:data = l:data[:-2]
if len(l:data) == 0
return
endif
endif
let l:data = l:data[:-2]
if len(l:data) == 0
return
endif
call self.err_cb(a:ch, join(l:data, "\n"))
for l:msg in l:data
call self.err_cb(a:ch, l:msg)
endfor
endfunction
let l:options['on_stderr'] = function('s:on_stderr', [], l:options)
@ -418,6 +491,12 @@ function! s:neooptions(options)
continue
endif
if key == 'stoponexit'
if a:options['stoponexit'] == ''
let l:options['detach'] = 1
endif
continue
endif
endfor
return l:options
endfunction

View File

@ -42,7 +42,7 @@ function! go#lint#Gometa(autosave, ...) abort
" Include only messages for the active buffer for autosave.
let include = [printf('--include=^%s:.*$', fnamemodify(expand('%:p'), ":."))]
if go#util#has_job() || has('nvim')
if go#util#has_job()
let include = [printf('--include=^%s:.*$', expand('%:p:t'))]
endif
let cmd += include
@ -56,7 +56,7 @@ function! go#lint#Gometa(autosave, ...) abort
let cmd += goargs
if go#util#has_job() || has('nvim')
if go#util#has_job()
call s:lint_job({'cmd': cmd}, a:autosave)
return
endif
@ -207,36 +207,10 @@ function! s:lint_job(args, autosave)
let l:opts.for = "GoMetaLinterAutoSave"
endif
let l:cbs = go#job#Options(l:opts)
if a:autosave
" move to the window that was active before processing the errors, because
" the user may have moved around within the window or even moved to a
" different window since saving. Moving back to current window as of the
" start of this function avoids the perception that the quickfix window
" steals focus when linting takes a while.
function! s:exit_cb(next, job, exitval)
let l:winid = win_getid(winnr())
call call(a:next, [a:job, a:exitval])
call win_gotoid(l:winid)
endfunction
" wrap l:cbs.exit_cb in s:exit_cb.
let l:cbs.exit_cb = funcref('s:exit_cb', [l:cbs.exit_cb])
function! s:close_cb(next, ch)
let l:winid = win_getid(winnr())
call call(a:next, [a:ch])
call win_gotoid(l:winid)
endfunction
" wrap l:cbs.close_cb in s:close_cb.
let l:cbs.close_cb = funcref('s:close_cb', [l:cbs.close_cb])
endif
" autowrite is not enabled for jobs
call go#cmd#autowrite()
call go#job#Start(a:args.cmd, l:cbs)
call go#job#Spawn(a:args.cmd, l:opts)
endfunction
" vim: sw=2 ts=2 et

View File

@ -141,6 +141,7 @@ let s:default_list_type_commands = {
\ "GoLint": "quickfix",
\ "GoMetaLinter": "quickfix",
\ "GoMetaLinterAutoSave": "locationlist",
\ "GoModFmt": "locationlist",
\ "GoModifyTags": "locationlist",
\ "GoRename": "quickfix",
\ "GoRun": "quickfix",

View File

@ -0,0 +1,140 @@
let s:go_major_version = ""
function! go#mod#Format() abort
" go mod only exists in `v1.11`
if empty(s:go_major_version)
let tokens = matchlist(go#util#System("go version"), '\d\+.\(\d\+\) ')
let s:go_major_version = str2nr(tokens[1])
endif
if s:go_major_version < "11"
call go#util#EchoError("Go v1.11 is required to format go.mod file")
return
endif
let fname = fnamemodify(expand("%"), ':p:gs?\\?/?')
" Save cursor position and many other things.
let l:curw = winsaveview()
" Write current unsaved buffer to a temp file
let l:tmpname = tempname() . '.mod'
call writefile(go#util#GetLines(), l:tmpname)
if go#util#IsWin()
let l:tmpname = tr(l:tmpname, '\', '/')
endif
let current_col = col('.')
let l:args = ['go', 'mod', 'edit', '--fmt', l:tmpname]
let [l:out, l:err] = go#util#Exec(l:args)
let diff_offset = len(readfile(l:tmpname)) - line('$')
if l:err == 0
call go#mod#update_file(l:tmpname, fname)
else
let errors = s:parse_errors(fname, l:out)
call s:show_errors(errors)
endif
" We didn't use the temp file, so clean up
call delete(l:tmpname)
" Restore our cursor/windows positions.
call winrestview(l:curw)
" be smart and jump to the line the new statement was added/removed
call cursor(line('.') + diff_offset, current_col)
" Syntax highlighting breaks less often.
syntax sync fromstart
endfunction
" update_file updates the target file with the given formatted source
function! go#mod#update_file(source, target)
" remove undo point caused via BufWritePre
try | silent undojoin | catch | endtry
let old_fileformat = &fileformat
if exists("*getfperm")
" save file permissions
let original_fperm = getfperm(a:target)
endif
call rename(a:source, a:target)
" restore file permissions
if exists("*setfperm") && original_fperm != ''
call setfperm(a:target , original_fperm)
endif
" reload buffer to reflect latest changes
silent edit!
let &fileformat = old_fileformat
let &syntax = &syntax
let l:listtype = go#list#Type("GoModFmt")
" the title information was introduced with 7.4-2200
" https://github.com/vim/vim/commit/d823fa910cca43fec3c31c030ee908a14c272640
if has('patch-7.4.2200')
" clean up previous list
if l:listtype == "quickfix"
let l:list_title = getqflist({'title': 1})
else
let l:list_title = getloclist(0, {'title': 1})
endif
else
" can't check the title, so assume that the list was for go fmt.
let l:list_title = {'title': 'Format'}
endif
if has_key(l:list_title, "title") && l:list_title['title'] == "Format"
call go#list#Clean(l:listtype)
endif
endfunction
" parse_errors parses the given errors and returns a list of parsed errors
function! s:parse_errors(filename, content) abort
let splitted = split(a:content, '\n')
" list of errors to be put into location list
let errors = []
for line in splitted
let tokens = matchlist(line, '^\(.\{-}\):\(\d\+\):\s*\(.*\)')
if !empty(tokens)
call add(errors,{
\"filename": a:filename,
\"lnum": tokens[2],
\"text": tokens[3],
\ })
endif
endfor
return errors
endfunction
" show_errors opens a location list and shows the given errors. If the given
" errors is empty, it closes the the location list
function! s:show_errors(errors) abort
let l:listtype = go#list#Type("GoModFmt")
if !empty(a:errors)
call go#list#Populate(l:listtype, a:errors, 'Format')
call go#util#EchoError("GoModFmt returned error")
endif
" this closes the window if there are no errors or it opens
" it if there is any
call go#list#Window(l:listtype, len(a:errors))
endfunction
function! go#mod#ToggleModFmtAutoSave() abort
if go#config#ModFmtAutosave()
call go#config#SetModFmtAutosave(0)
call go#util#EchoProgress("auto mod fmt disabled")
return
end
call go#config#SetModFmtAutosave(1)
call go#util#EchoProgress("auto mod fmt enabled")
endfunction

View File

@ -27,8 +27,7 @@ function! go#rename#Rename(bang, ...) abort
let offset = printf('%s:#%d', fname, pos)
let cmd = [bin_path, "-offset", offset, "-to", to_identifier, '-tags', go#config#BuildTags()]
if go#util#has_job() || has('nvim')
call go#util#EchoProgress(printf("renaming to '%s' ...", to_identifier))
if go#util#has_job()
call s:rename_job({
\ 'cmd': cmd,
\ 'bang': a:bang,

View File

@ -0,0 +1,9 @@
package complete
type T struct {
V string
}
func Example(s string) {
Example("")
}

View File

@ -26,19 +26,11 @@ function! go#test#Test(bang, compile, ...) abort
call add(args, printf("-timeout=%s", timeout))
endif
if go#config#EchoCommandInfo()
if a:compile
call go#util#EchoProgress("compiling tests ...")
else
call go#util#EchoProgress("testing...")
endif
endif
if has('nvim') && go#config#TermEnabled()
call go#term#new(a:bang, ["go"] + args)
endif
if go#util#has_job() || has('nvim')
if go#util#has_job()
" use vim's job functionality to call it asynchronously
let job_options = {
\ 'bang': a:bang,
@ -55,6 +47,14 @@ function! go#test#Test(bang, compile, ...) abort
return
endif
if go#config#EchoCommandInfo()
if a:compile
call go#util#EchoProgress("compiling tests ...")
else
call go#util#EchoProgress("testing...")
endif
endif
call go#cmd#autowrite()
redraw
@ -152,12 +152,12 @@ function! s:errorformat() abort
" each level of test indents the test output 4 spaces. Capturing groups
" (e.g. \(\)) cannot be used in an errorformat, but non-capturing groups can
" (e.g. \%(\)).
let indent = '%\\%( %\\)%#'
let indent = '%\\%( %\\)'
" ignore `go test -v` output for starting tests
let format = "%-G=== RUN %.%#"
" ignore `go test -v` output for passing tests
let format .= ",%-G" . indent . "--- PASS: %.%#"
let format .= ",%-G" . indent . "%#--- PASS: %.%#"
" Match failure lines.
"
@ -167,24 +167,25 @@ function! s:errorformat() abort
" e.g.:
" '--- FAIL: TestSomething (0.00s)'
if show_name
let format .= ",%G" . indent . "--- FAIL: %m (%.%#)"
let format .= ",%G" . indent . "%#--- FAIL: %m (%.%#)"
else
let format .= ",%-G" . indent . "--- FAIL: %.%#"
let format .= ",%-G" . indent . "%#--- FAIL: %.%#"
endif
" Go 1.10 test output {{{1
" Matches test output lines.
"
" All test output lines start with the test indentation and a tab, followed
" by the filename, a colon, the line number, another colon, a space, and the
" message. e.g.:
" '\ttime_test.go:30: Likely problem: the time zone files have not been installed.'
let format .= ",%A" . indent . "%\\t%\\+%f:%l: %m"
let format .= ",%A" . indent . "%#%\\t%\\+%f:%l: %m"
" also match lines that don't have a message (i.e. the message begins with a
" newline or is the empty string):
" e.g.:
" t.Errorf("\ngot %v; want %v", actual, expected)
" t.Error("")
let format .= ",%A" . indent . "%\\t%\\+%f:%l: "
let format .= ",%A" . indent . "%#%\\t%\\+%f:%l: "
" Match the 2nd and later lines of multi-line output. These lines are
" indented the number of spaces for the level of nesting of the test,
@ -197,7 +198,17 @@ function! s:errorformat() abort
" indicate that they're multiple lines of output, but in that case the lines
" get concatenated in the quickfix list, which is not what users typically
" want when writing a newline into their test output.
let format .= ",%G" . indent . "%\\t%\\{2}%m"
let format .= ",%G" . indent . "%#%\\t%\\{2}%m"
" }}}1
" Go 1.11 test output {{{1
" Match test output lines similarly to Go 1.10 test output lines, but they
" use an indent level where the Go 1.10 test output uses tabs, so they'll
" always have at least one level indentation...
let format .= ",%A" . indent . "%\\+%f:%l: %m"
let format .= ",%A" . indent . "%\\+%f:%l: "
let format .= ",%G" . indent . "%\\{2\\,}%m"
" }}}1
" set the format for panics.
@ -261,16 +272,16 @@ function! s:errorformat() abort
let format .= ",%-Cexit status %[0-9]%\\+"
"let format .= ",exit status %[0-9]%\\+"
" Match and ignore exit failure lines whether part of a multi-line message
" Match and ignore failure lines whether part of a multi-line message
" or not, because these lines sometimes come before and sometimes after
" panic stacktraces.
let format .= ",%-CFAIL%\\t%.%#"
"let format .= ",FAIL%\\t%.%#"
" match compiler errors
" These are very smilar to errors from test output, but lack leading tabs
" for the first line of an error, and subsequent lines only have one tab
" instead of two.
" match compiler errors.
" These are very smilar to errors from <=go1.10 test output, but lack
" leading tabs for the first line of an error, and subsequent lines only
" have one tab instead of two.
let format .= ",%A%f:%l:%c: %m"
let format .= ",%A%f:%l: %m"
" It would be nice if this weren't necessary, but panic lines from tests are

View File

@ -74,7 +74,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 only 0 args'},
\ {'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'},
\ ]
call s:test('veterror/veterror.go', expected)
endfunc

View File

@ -76,12 +76,12 @@ function! go#tool#Imports() abort
return imports
endfunction
function! go#tool#Info() abort
function! go#tool#Info(showstatus) abort
let l:mode = go#config#InfoMode()
if l:mode == 'gocode'
call go#complete#Info()
call go#complete#Info(a:showstatus)
elseif l:mode == 'guru'
call go#guru#DescribeInfo()
call go#guru#DescribeInfo(a:showstatus)
else
call go#util#EchoError('go_info_mode value: '. l:mode .' is not valid. Valid values are: [gocode, guru]')
endif

View File

@ -64,6 +64,10 @@ endfunction
" The (optional) first parameter can be added to indicate the 'cwd' or 'env'
" parameters will be used, which wasn't added until a later version.
function! go#util#has_job(...) abort
if has('nvim')
return 1
endif
" cwd and env parameters to job_start was added in this version.
if a:0 > 0 && a:1 is 1
return has('job') && has("patch-8.0.0902")

View File

@ -806,6 +806,11 @@ CTRL-t
Toggles |'g:go_fmt_autosave'|.
*:GoModFmtAutoSaveToggle*
:GoModFmtAutoSaveToggle
Toggles |'g:go_mod_fmt_autosave'|.
*:GoAsmFmtAutoSaveToggle*
:GoAsmFmtAutoSaveToggle
@ -880,6 +885,13 @@ CTRL-t
}
}
<
*:GoModFmt*
:GoModFmt
Filter the current go.mod buffer through "go mod edit -fmt" command. It
tries to preserve cursor position and avoids replacing the buffer with
stderr output.
==============================================================================
MAPPINGS *go-mappings*
@ -1097,6 +1109,10 @@ Calls `:GoImport` for the current package
Generate if err != nil { return ... } automatically which infer the type of
return values and the numbers.
*(go-mod-fmt)*
Calls |:GoModFmt| for the current buffer
==============================================================================
TEXT OBJECTS *go-text-objects*
@ -1287,7 +1303,15 @@ doesn't break. However it's slows (creates/deletes a file for every save) and
it's causing problems on some Vim versions. By default it's disabled. >
let g:go_fmt_experimental = 0
<
*'g:go_mod_fmt_autosave'*
Use this option to auto |:GoModFmt| on save. By default it's enabled >
let g:go_mod_fmt_autosave = 1
<
*'g:go_doc_keywordprg_enabled'*
Use this option to run `godoc` on words under the cursor with |K|; this will
@ -1497,10 +1521,10 @@ that was called. Supported values are "", "quickfix", and "locationlist".
Specifies the type of list to use for command outputs (such as errors from
builds, results from static analysis commands, etc...). When an expected key
is not present in the dictionary, |'g:go_list_type'| will be used instead.
Supported keys are "GoBuild", "GoErrCheck", "GoFmt", "GoInstall", "GoLint",
"GoMetaLinter", "GoMetaLinterAutoSave", "GoModifyTags" (used for both
:GoAddTags and :GoRemoveTags), "GoRename", "GoRun", and "GoTest". Supported
values for each command are "quickfix" and "locationlist".
Supported keys are "GoBuild", "GoErrCheck", "GoFmt", "GoModFmt", "GoInstall",
"GoLint", "GoMetaLinter", "GoMetaLinterAutoSave", "GoModifyTags" (used for
both :GoAddTags and :GoRemoveTags), "GoRename", "GoRun", and "GoTest".
Supported values for each command are "quickfix" and "locationlist".
>
let g:go_list_type_commands = {}
<
@ -1574,14 +1598,6 @@ same.
let g:go_gorename_prefill = 'expand("<cword>") =~# "^[A-Z]"' .
\ '? go#util#pascalcase(expand("<cword>"))' .
\ ': go#util#camelcase(expand("<cword>"))'
<
*'g:go_gocode_autobuild'*
Specifies whether `gocode` should automatically build out-of-date packages
when their source fields are modified, in order to obtain the freshest
autocomplete results for them. By default it is enabled.
>
let g:go_gocode_autobuild = 1
<
*'g:go_gocode_propose_builtins'*
@ -1590,14 +1606,14 @@ to an autocompletion proposals. By default it is enabled.
>
let g:go_gocode_propose_builtins = 1
<
*'g:go_gocode_unimported_packages'*
*'g:go_gocode_propose_source'*
Specifies whether `gocode` should include suggestions from unimported
packages. By default it is disabled.
Specifies whether `gocode` should use source files instead of binary packages
for autocompletion proposals. When disabled, only identifiers from the current
package and packages that have been installed will proposed.
>
let g:go_gocode_unimported_packages = 0
let g:go_gocode_propose_source = 1
<
*'g:go_gocode_socket_type'*
Specifies whether `gocode` should use a different socket type. By default
@ -1882,6 +1898,13 @@ filetype.
The `gohtmltmpl` filetype is automatically set for `*.tmpl` files; the
`gotexttmpl` is never automatically set and needs to be set manually.
==============================================================================
*gomod* *ft-gomod-syntax*
go.mod file syntax~
The `gomod` 'filetype' provides syntax highlighting for Go's module file
`go.mod`
==============================================================================
DEBUGGER *go-debug*
@ -2245,6 +2268,18 @@ By default new terminals are opened in a vertical split. To change it
let g:go_term_mode = "split"
>
How can I customize the highlighting?~
All the highlight groups used by vim-go are prefixed with `go` (e.g.
`goType`) and are defined in the files in the `syntax` directory. To change
the highlighting for any group, add a `highlight` command for the group to
your vimrc. To turn off the highlighting for any group, add `highlight link
group-name NONE` (where `group-name` is the name of the group whose highlight
you'd like to turn off) to your vimrc.
Some people may wish to highlight Go's builtins as keywords. To do so, one
should simply add `highlight link goBuiltins Keyword` to the `vimrc` file.
==============================================================================
DEVELOPMENT *go-development*

View File

@ -31,4 +31,23 @@ au BufReadPost *.s call s:gofiletype_post()
au BufRead,BufNewFile *.tmpl set filetype=gohtmltmpl
" Set the filetype if the first non-comment and non-blank line starts with
" 'module <path>'.
au BufNewFile,BufRead go.mod call s:gomod()
fun! s:gomod()
for l:i in range(1, line('$'))
let l:l = getline(l:i)
if l:l ==# '' || l:l[:1] ==# '//'
continue
endif
if l:l =~# '^module .\+'
set filetype=gomod
endif
break
endfor
endfun
" vim: sw=2 ts=2 et

View File

@ -14,7 +14,7 @@ command! -range=% GoFreevars call go#guru#Freevars(<count>)
command! -range=% GoChannelPeers call go#guru#ChannelPeers(<count>)
command! -range=% GoReferrers call go#guru#Referrers(<count>)
command! -range=0 GoSameIds call go#guru#SameIds()
command! -range=0 GoSameIds call go#guru#SameIds(1)
command! -range=0 GoSameIdsClear call go#guru#ClearSameIds()
command! -range=0 GoSameIdsToggle call go#guru#ToggleSameIds()
command! -range=0 GoSameIdsAutoToggle call go#guru#AutoToogleSameIds()
@ -23,10 +23,13 @@ command! -range=0 GoSameIdsAutoToggle call go#guru#AutoToogleSameIds()
command! -nargs=* -range GoAddTags call go#tags#Add(<line1>, <line2>, <count>, <f-args>)
command! -nargs=* -range GoRemoveTags call go#tags#Remove(<line1>, <line2>, <count>, <f-args>)
" -- mod
command! -nargs=0 -range GoModFmt call go#mod#Format()
" -- tool
command! -nargs=* -complete=customlist,go#tool#ValidFiles GoFiles echo go#tool#Files(<f-args>)
command! -nargs=0 GoDeps echo go#tool#Deps()
command! -nargs=0 GoInfo call go#tool#Info()
command! -nargs=0 GoInfo call go#tool#Info(1)
command! -nargs=0 GoAutoTypeInfoToggle call go#complete#ToggleAutoTypeInfo()
" -- cmd

View File

@ -31,7 +31,7 @@ nnoremap <silent> <Plug>(go-coverage-browser) :<C-u>call go#coverage#Browser(!g:
nnoremap <silent> <Plug>(go-files) :<C-u>call go#tool#Files()<CR>
nnoremap <silent> <Plug>(go-deps) :<C-u>call go#tool#Deps()<CR>
nnoremap <silent> <Plug>(go-info) :<C-u>call go#tool#Info()<CR>
nnoremap <silent> <Plug>(go-info) :<C-u>call go#tool#Info(1)<CR>
nnoremap <silent> <Plug>(go-import) :<C-u>call go#import#SwitchImport(1, '', expand('<cword>'), '')<CR>
nnoremap <silent> <Plug>(go-imports) :<C-u>call go#fmt#Format(1)<CR>
@ -43,13 +43,16 @@ nnoremap <silent> <Plug>(go-callstack) :<C-u>call go#guru#Callstack(-1)<CR>
xnoremap <silent> <Plug>(go-freevars) :<C-u>call go#guru#Freevars(0)<CR>
nnoremap <silent> <Plug>(go-channelpeers) :<C-u>call go#guru#ChannelPeers(-1)<CR>
nnoremap <silent> <Plug>(go-referrers) :<C-u>call go#guru#Referrers(-1)<CR>
nnoremap <silent> <Plug>(go-sameids) :<C-u>call go#guru#SameIds()<CR>
nnoremap <silent> <Plug>(go-sameids) :<C-u>call go#guru#SameIds(1)<CR>
nnoremap <silent> <Plug>(go-pointsto) :<C-u>call go#guru#PointsTo(-1)<CR>
nnoremap <silent> <Plug>(go-whicherrs) :<C-u>call go#guru#Whicherrs(-1)<CR>
nnoremap <silent> <Plug>(go-sameids-toggle) :<C-u>call go#guru#ToggleSameIds()<CR>
nnoremap <silent> <Plug>(go-rename) :<C-u>call go#rename#Rename(!g:go_jump_to_error)<CR>
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>

View File

@ -0,0 +1,15 @@
" gomod.vim: Vim filetype plugin for Go assembler.
if exists("b:did_ftplugin")
finish
endif
let b:did_ftplugin = 1
let b:undo_ftplugin = "setl fo< com< cms<"
setlocal formatoptions-=t
setlocal comments=s1:/*,mb:*,ex:*/,://
setlocal commentstring=//\ %s
" vim: sw=2 ts=2 et

View File

@ -0,0 +1,3 @@
command! -nargs=0 -range GoModFmt call go#mod#Format()
command! -nargs=0 GoModFmtAutoSaveToggle call go#mod#ToggleModFmtAutoSave()

View File

@ -0,0 +1 @@
nnoremap <silent> <Plug>(go-mod-fmt) :<C-u>call go#mod#Format()<CR>

View File

@ -363,6 +363,28 @@ func Test${1:Function}(t *testing.T) {
}
endsnippet
# test table snippet
snippet tt
var tests = []struct {
name string
expected string
given string
}{
{"${1}", "${2}", "${3}",},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T){
actual := ${0:${VISUAL}}(tt.given)
if actual != tt.expected {
t.Errorf("$0(%s): expected %s, actual %s", tt.given, tt.expected, actual)
}
})
}
endsnippet
snippet hf "http.HandlerFunc" !b
func ${1:handler}(w http.ResponseWriter, r *http.Request) {
${0:fmt.Fprintf(w, "hello world")}

View File

@ -0,0 +1,17 @@
var tests = []struct {
name string
expected string
given string
}{
{"", "", "",},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T){
actual := {{++}}(tt.given)
if actual != tt.expected {
t.Errorf("{{+~\~1+}}(%s): expected %s, actual %s", tt.given, tt.expected, actual)
}
})
}

View File

@ -315,6 +315,25 @@ abbr func TestXYZ(t *testing.T) { ... }
func Test${1:Function}(t *testing.T) {
${0}
}
# test table snippet
snippet tt
abbr var test = {...}{...} for {t.Run(){...}}
var tests = []struct {
name string
expected string
given string
}{
{"${2}", "${3}", "${4}",},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T){
actual := ${1:Function}(tt.given)
if actual != tt.expected {
t.Errorf("given(%s): expected %s, actual %s", tt.given, tt.expected, actual)
}
})
}
# test server
snippet tsrv
abbr ts := httptest.NewServer(...)

View File

@ -24,17 +24,6 @@ if exists("*GoIndent")
finish
endif
" use shiftwidth function only if it's available
if exists('*shiftwidth')
func s:sw()
return shiftwidth()
endfunc
else
func s:sw()
return &sw
endfunc
endif
function! GoIndent(lnum)
let prevlnum = prevnonblank(a:lnum-1)
if prevlnum == 0
@ -49,19 +38,23 @@ function! GoIndent(lnum)
let ind = previ
if prevl =~ ' = `[^`]*$'
" previous line started a multi-line raw string
return 0
endif
if prevl =~ '[({]\s*$'
" previous line opened a block
let ind += s:sw()
let ind += shiftwidth()
endif
if prevl =~# '^\s*\(case .*\|default\):$'
" previous line is part of a switch statement
let ind += s:sw()
let ind += shiftwidth()
endif
" TODO: handle if the previous line is a label.
if thisl =~ '^\s*[)}]'
" this line closed a block
let ind -= s:sw()
let ind -= shiftwidth()
endif
" Colons are tricky.
@ -69,7 +62,7 @@ function! GoIndent(lnum)
" We ignore trying to deal with jump labels because (a) they're rare, and
" (b) they're hard to disambiguate from a composite literal key.
if thisl =~# '^\s*\(case .*\|default\):$'
let ind -= s:sw()
let ind -= shiftwidth()
endif
return ind

View File

@ -29,13 +29,13 @@ if
endif
" these packages are used by vim-go and can be automatically installed if
" needed by the user with GoInstallBinaries
" needed by the user with GoInstallBinaries.
let s:packages = {
\ 'asmfmt': ['github.com/klauspost/asmfmt/cmd/asmfmt'],
\ 'dlv': ['github.com/derekparker/delve/cmd/dlv'],
\ 'errcheck': ['github.com/kisielk/errcheck'],
\ 'fillstruct': ['github.com/davidrjenni/reftools/cmd/fillstruct'],
\ 'gocode': ['github.com/nsf/gocode', {'windows': ['-ldflags', '-H=windowsgui']}],
\ 'gocode': ['github.com/mdempsky/gocode', {'windows': ['-ldflags', '-H=windowsgui']}],
\ 'godef': ['github.com/rogpeppe/godef'],
\ 'gogetdoc': ['github.com/zmb3/gogetdoc'],
\ 'goimports': ['golang.org/x/tools/cmd/goimports'],
@ -99,9 +99,9 @@ function! s:GoInstallBinaries(updateBinaries, ...)
set noshellslash
endif
let l:cmd = ['go', 'get', '-v']
let l:dl_cmd = ['go', 'get', '-v', '-d']
if get(g:, "go_get_update", 1) != 0
let l:cmd += ['-u']
let l:dl_cmd += ['-u']
endif
" Filter packages from arguments (if any).
@ -127,16 +127,21 @@ function! s:GoInstallBinaries(updateBinaries, ...)
for [binary, pkg] in items(l:packages)
let l:importPath = pkg[0]
let l:run_cmd = copy(l:cmd)
let l:run_cmd = copy(l:dl_cmd)
if len(l:pkg) > 1 && get(l:pkg[1], l:platform, '') isnot ''
let l:run_cmd += get(l:pkg[1], l:platform, '')
endif
let binname = "go_" . binary . "_bin"
let bin_setting_name = "go_" . binary . "_bin"
let bin = binary
if exists("g:{binname}")
let bin = g:{binname}
if exists("g:{bin_setting_name}")
let bin = g:{bin_setting_name}
else
if go#util#IsWin()
let bin = binary . '.exe'
else
let bin = binary
endif
endif
if !executable(bin) || a:updateBinaries == 1
@ -146,7 +151,15 @@ function! s:GoInstallBinaries(updateBinaries, ...)
echo "vim-go: ". binary ." not found. Installing ". importPath . " to folder " . go_bin_path
endif
" first download the binary
let [l:out, l:err] = go#util#Exec(l:run_cmd + [l:importPath])
if l:err
echom "Error downloading " . l:importPath . ": " . l:out
endif
" and then build and install it
let l:build_cmd = ['go', 'build', '-o', go_bin_path . go#util#PathSep() . bin, l:importPath]
let [l:out, l:err] = go#util#Exec(l:build_cmd + [l:importPath])
if l:err
echom "Error installing " . l:importPath . ": " . l:out
endif
@ -158,6 +171,12 @@ function! s:GoInstallBinaries(updateBinaries, ...)
if resetshellslash
set shellslash
endif
if a:updateBinaries == 1
call go#util#EchoInfo('updating finished!')
else
call go#util#EchoInfo('installing finished!')
endif
endfunction
" CheckBinaries checks if the necessary binaries to install the Go tool
@ -201,14 +220,14 @@ endfunction
function! s:auto_type_info()
" GoInfo automatic update
if get(g:, "go_auto_type_info", 0)
call go#tool#Info()
call go#tool#Info(0)
endif
endfunction
function! s:auto_sameids()
" GoSameId automatic update
if get(g:, "go_auto_sameids", 0)
call go#guru#SameIds()
call go#guru#SameIds(0)
endif
endfunction
@ -226,6 +245,13 @@ function! s:asmfmt_autosave()
endif
endfunction
function! s:modfmt_autosave()
" go.mod code formatting on save
if get(g:, "go_mod_fmt_autosave", 1)
call go#mod#Format()
endif
endfunction
function! s:metalinter_autosave()
" run gometalinter on save
if get(g:, "go_metalinter_autosave", 0)
@ -253,6 +279,7 @@ augroup vim-go
endif
autocmd BufWritePre *.go call s:fmt_autosave()
autocmd BufWritePre *.mod call s:modfmt_autosave()
autocmd BufWritePre *.s call s:asmfmt_autosave()
autocmd BufWritePost *.go call s:metalinter_autosave()
autocmd BufNewFile *.go call s:template_autocreate()

View File

@ -30,7 +30,7 @@ case "$vim" in
"nvim")
# Use latest stable version.
tag="v0.2.0"
tag="v0.3.1"
giturl="https://github.com/neovim/neovim"
;;

View File

@ -47,12 +47,12 @@ hi def link goFloats Type
hi def link goComplexes Type
" Predefined functions and values
syn match goBuiltins /\<\v(append|cap|close|complex|copy|delete|imag|len)\ze\(/
syn match goBuiltins /\<\v(make|new|panic|print|println|real|recover)\ze\(/
syn keyword goBuiltins append cap close complex copy delete imag len
syn keyword goBuiltins make new panic print println real recover
syn keyword goBoolean true false
syn keyword goPredefinedIdentifiers nil iota
hi def link goBuiltins Keyword
hi def link goBuiltins Identifier
hi def link goBoolean Boolean
hi def link goPredefinedIdentifiers goBoolean
@ -148,14 +148,14 @@ endif
" var, const
if go#config#FoldEnable('varconst')
syn region goVar start='var (' end='^\s*)$' transparent fold
\ contains=ALLBUT,goParen,goBlock,goFunction,goTypeName,goReceiverType,goReceiverVar,goArgumentName,goArgumentType,goSimpleArguments
\ contains=ALLBUT,goParen,goBlock,goFunction,goTypeName,goReceiverType,goReceiverVar,goArgumentName,goArgumentType,goSimpleArguments,goPointerOperator
syn region goConst start='const (' end='^\s*)$' transparent fold
\ contains=ALLBUT,goParen,goBlock,goFunction,goTypeName,goReceiverType,goReceiverVar,goArgumentName,goArgumentType,goSimpleArguments
\ contains=ALLBUT,goParen,goBlock,goFunction,goTypeName,goReceiverType,goReceiverVar,goArgumentName,goArgumentType,goSimpleArguments,goPointerOperator
else
syn region goVar start='var (' end='^\s*)$' transparent
\ contains=ALLBUT,goParen,goBlock,goFunction,goTypeName,goReceiverType,goReceiverVar,goArgumentName,goArgumentType,goSimpleArguments
\ contains=ALLBUT,goParen,goBlock,goFunction,goTypeName,goReceiverType,goReceiverVar,goArgumentName,goArgumentType,goSimpleArguments,goPointerOperator
syn region goConst start='const (' end='^\s*)$' transparent
\ contains=ALLBUT,goParen,goBlock,goFunction,goTypeName,goReceiverType,goReceiverVar,goArgumentName,goArgumentType,goSimpleArguments
\ contains=ALLBUT,goParen,goBlock,goFunction,goTypeName,goReceiverType,goReceiverVar,goArgumentName,goArgumentType,goSimpleArguments,goPointerOperator
endif
" Single-line var, const, and import.

View File

@ -0,0 +1,46 @@
" gomod.vim: Vim syntax file for go.mod file
"
" Quit when a (custom) syntax file was already loaded
if exists("b:current_syntax")
finish
endif
syntax case match
" match keywords
syntax keyword gomodModule module
syntax keyword gomodRequire require
syntax keyword gomodExclude exclude
syntax keyword gomodReplace replace
" require, exclude and replace can be also grouped into block
syntax region gomodRequire start='require (' end=')' transparent contains=gomodRequire,gomodVersion
syntax region gomodExclude start='exclude (' end=')' transparent contains=gomodExclude,gomodVersion
syntax region gomodReplace start='replace (' end=')' transparent contains=gomodReplace,gomodVersion
" set highlights
highlight default link gomodModule Keyword
highlight default link gomodRequire Keyword
highlight default link gomodExclude Keyword
highlight default link gomodReplace Keyword
" comments are always in form of // ...
syntax region gomodComment start="//" end="$" contains=@Spell
highlight default link gomodComment Comment
" make sure quoted import paths are higlighted
syntax region gomodString start=+"+ skip=+\\\\\|\\"+ end=+"+
highlight default link gomodString String
" replace operator is in the form of '=>'
syntax match gomodReplaceOperator "\v\=\>"
highlight default link gomodReplaceOperator Operator
" highlight semver, note that this is very simple. But it works for now
syntax match gomodVersion "v\d\+\.\d\+\.\d\+"
syntax match gomodVersion "v\d\+\.\d\+\.\d\+-\S*"
syntax match gomodVersion "v\d\+\.\d\+\.\d\++incompatible"
highlight default link gomodVersion Identifier
let b:current_syntax = "gomod"