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

Updated plugins, also experimenting with a new font

The font is IBM Plex Mono: https://ibm.github.io/type/
This commit is contained in:
amix
2017-11-24 14:54:40 +01:00
parent 7fc202ec88
commit e9aac9794b
255 changed files with 2898 additions and 3752 deletions

View File

@ -93,10 +93,6 @@ function! ctrlp#decls#enter() abort
return
endif
if exists("l:tmpname")
call delete(l:tmpname)
endif
let result = eval(out)
if type(result) != 4 || !has_key(result, 'decls')
return

View File

@ -9,20 +9,17 @@ endfunction
" default it tries to call simply 'go build', but it first tries to get all
" dependent files for the current folder and passes it to go build.
function! go#cmd#Build(bang, ...) abort
" expand all wildcards(i.e: '%' to the current file name)
let goargs = map(copy(a:000), "expand(v:val)")
" escape all shell arguments before we pass it to make
if !has('nvim')
let goargs = go#util#Shelllist(goargs, 1)
endif
" create our command arguments. go build discards any results when it
" Create our command arguments. go build discards any results when it
" compiles multiple packages. So we pass the `errors` package just as an
" placeholder with the current folder (indicated with '.'). We also pass -i
" that tries to install the dependencies, this has the side effect that it
" caches the build results, so every other build is faster.
let args = ["build"] + goargs + ["-i", ".", "errors"]
let args =
\ ["build"] +
\ map(copy(a:000), "expand(v:val)") +
\ ["-i", ".", "errors"]
" Vim async.
if go#util#has_job()
if get(g:, 'go_echo_command_info', 1)
call go#util#EchoProgress("building dispatched ...")
@ -31,50 +28,52 @@ function! go#cmd#Build(bang, ...) abort
call s:cmd_job({
\ 'cmd': ['go'] + args,
\ 'bang': a:bang,
\ 'for': 'GoBuild',
\})
return
" Nvim async.
elseif has('nvim')
if get(g:, 'go_echo_command_info', 1)
call go#util#EchoProgress("building dispatched ...")
endif
" if we have nvim, call it asynchronously and return early ;)
call go#jobcontrol#Spawn(a:bang, "build", args)
return
endif
call go#jobcontrol#Spawn(a:bang, "build", "GoBuild", args)
let old_gopath = $GOPATH
let $GOPATH = go#path#Detect()
let default_makeprg = &makeprg
let &makeprg = "go " . join(args, ' ')
let l:listtype = go#list#Type("quickfix")
" execute make inside the source folder so we can parse the errors
" correctly
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
let dir = getcwd()
try
execute cd . fnameescape(expand("%:p:h"))
if l:listtype == "locationlist"
silent! exe 'lmake!'
else
silent! exe 'make!'
endif
redraw!
finally
execute cd . fnameescape(dir)
endtry
let errors = go#list#Get(l:listtype)
call go#list#Window(l:listtype, len(errors))
if !empty(errors) && !a:bang
call go#list#JumpToFirst(l:listtype)
" Vim 7.4 without async
else
call go#util#EchoSuccess("[build] SUCCESS")
endif
let old_gopath = $GOPATH
let $GOPATH = go#path#Detect()
let default_makeprg = &makeprg
let &makeprg = "go " . join(go#util#Shelllist(args), ' ')
let &makeprg = default_makeprg
let $GOPATH = old_gopath
let l:listtype = go#list#Type("GoBuild")
" execute make inside the source folder so we can parse the errors
" correctly
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
let dir = getcwd()
try
execute cd . fnameescape(expand("%:p:h"))
if l:listtype == "locationlist"
silent! exe 'lmake!'
else
silent! exe 'make!'
endif
redraw!
finally
execute cd . fnameescape(dir)
endtry
let errors = go#list#Get(l:listtype)
call go#list#Window(l:listtype, len(errors))
if !empty(errors) && !a:bang
call go#list#JumpToFirst(l:listtype)
else
call go#util#EchoSuccess("[build] SUCCESS")
endif
let &makeprg = default_makeprg
let $GOPATH = old_gopath
endif
endfunction
@ -149,7 +148,7 @@ function! go#cmd#Run(bang, ...) abort
let &makeprg = "go run " . go#util#Shelljoin(map(copy(a:000), "expand(v:val)"), 1)
endif
let l:listtype = go#list#Type("quickfix")
let l:listtype = go#list#Type("GoRun")
if l:listtype == "locationlist"
exe 'lmake!'
@ -186,6 +185,7 @@ function! go#cmd#Install(bang, ...) abort
call s:cmd_job({
\ 'cmd': ['go', 'install'] + goargs,
\ 'bang': a:bang,
\ 'for': 'GoInstall',
\})
return
endif
@ -198,7 +198,7 @@ function! go#cmd#Install(bang, ...) abort
let goargs = go#util#Shelljoin(map(copy(a:000), "expand(v:val)"), 1)
let &makeprg = "go install " . goargs
let l:listtype = go#list#Type("quickfix")
let l:listtype = go#list#Type("GoInstall")
" execute make inside the source folder so we can parse the errors
" correctly
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
@ -243,7 +243,7 @@ function! go#cmd#Generate(bang, ...) abort
let &makeprg = "go generate " . goargs . ' ' . gofiles
endif
let l:listtype = go#list#Type("quickfix")
let l:listtype = go#list#Type("GoGenerate")
echon "vim-go: " | echohl Identifier | echon "generating ..."| echohl None
if l:listtype == "locationlist"

View File

@ -53,6 +53,7 @@ function! go#coverage#Buffer(bang, ...) abort
\ 'cmd': ['go', 'test', '-coverprofile', l:tmpname] + a:000,
\ 'custom_cb': function('s:coverage_callback', [l:tmpname]),
\ 'bang': a:bang,
\ 'for': 'GoTest',
\ })
return
endif
@ -94,9 +95,9 @@ function! go#coverage#Clear() abort
if exists("s:toggle") | let s:toggle = 0 | endif
" remove the autocmd we defined
if exists("#BufWinLeave#<buffer>")
autocmd! BufWinLeave <buffer>
endif
augroup vim-go-coverage
autocmd!
augroup end
endfunction
" Browser creates a new cover profile with 'go test -coverprofile' and opens
@ -108,6 +109,7 @@ function! go#coverage#Browser(bang, ...) abort
\ 'cmd': ['go', 'test', '-coverprofile', l:tmpname],
\ 'custom_cb': function('s:coverage_browser_callback', [l:tmpname]),
\ 'bang': a:bang,
\ 'for': 'GoTest',
\ })
return
endif
@ -256,7 +258,10 @@ function! go#coverage#overlay(file) abort
endfor
" clear the matches if we leave the buffer
autocmd BufWinLeave <buffer> call go#coverage#Clear()
augroup vim-go-coverage
autocmd!
autocmd BufWinLeave <buffer> call go#coverage#Clear()
augroup end
for m in matches
call matchaddpos(m.group, m.pos)

View File

@ -168,7 +168,7 @@ function! go#def#jump_to_declaration(out, mode, bin_name) abort
endif
" open the file and jump to line and column
exec cmd fnameescape(filename)
exec cmd fnameescape(fnamemodify(filename, ':.'))
endif
endif
call cursor(line, col)

View File

@ -1,32 +1,37 @@
func Test_jump_to_declaration_guru()
let file_name = "test-fixtures/def/jump.go"
let lnum = 5
let col = 6
func! Test_jump_to_declaration_guru() abort
try
let l:filename = 'def/jump.go'
let lnum = 5
let col = 6
let l:tmp = gotest#load_fixture(l:filename)
let out = printf("%s:%d:%d: defined here as func main", file_name, lnum, col)
let bin_name = "guru"
let guru_out = printf("%s:%d:%d: defined here as func main", filename, lnum, col)
call go#def#jump_to_declaration(guru_out, "", 'guru')
call go#def#jump_to_declaration(out, "", bin_name)
call assert_equal(file_name, bufname("%"))
call assert_equal(lnum, getcurpos()[1])
call assert_equal(col, getcurpos()[2])
call assert_equal(filename, bufname("%"))
call assert_equal(lnum, getcurpos()[1])
call assert_equal(col, getcurpos()[2])
finally
call delete(l:tmp, 'rf')
endtry
endfunc
func Test_jump_to_declaration_godef()
let file_name = "test-fixtures/def/jump.go"
let lnum = 5
let col = 6
func! Test_jump_to_declaration_godef() abort
try
let filename = 'def/jump.go'
let lnum = 5
let col = 6
let l:tmp = gotest#load_fixture(l:filename)
" note that the output of godef has two lines
let out = printf("%s:%d:%d\ndefined here as func main", file_name, lnum, col)
let bin_name = "godef"
let godef_out = printf("%s:%d:%d\ndefined here as func main", filename, lnum, col)
call go#def#jump_to_declaration(godef_out, "", 'godef')
call go#def#jump_to_declaration(out, "", bin_name)
call assert_equal(file_name, bufname("%"))
call assert_equal(lnum, getcurpos()[1])
call assert_equal(col, getcurpos()[2])
call assert_equal(filename, bufname("%"))
call assert_equal(lnum, getcurpos()[1])
call assert_equal(col, getcurpos()[2])
finally
call delete(l:tmp, 'rf')
endtry
endfunc
" vim: sw=2 ts=2 et

View File

@ -5,11 +5,7 @@
let s:buf_nr = -1
if !exists("g:go_doc_command")
let g:go_doc_command = "godoc"
endif
if !exists("g:go_doc_options")
let g:go_doc_options = ""
let g:go_doc_command = ["godoc"]
endif
function! go#doc#OpenBrowser(...) abort
@ -60,12 +56,11 @@ endfunction
function! go#doc#Open(newmode, mode, ...) abort
" With argument: run "godoc [arg]".
if len(a:000)
let bin_path = go#path#CheckBinPath('godoc')
if empty(bin_path)
if empty(go#path#CheckBinPath(g:go_doc_command[0]))
return
endif
let command = printf("%s %s", go#util#Shellescape(bin_path), join(a:000, ' '))
let command = printf("%s %s", go#util#Shelljoin(g:go_doc_command), join(a:000, ' '))
let out = go#util#System(command)
" Without argument: run gogetdoc on cursor position.
else
@ -85,6 +80,7 @@ endfunction
function! s:GodocView(newposition, position, content) abort
" reuse existing buffer window if it exists otherwise create a new one
let is_visible = bufexists(s:buf_nr) && bufwinnr(s:buf_nr) != -1
if !bufexists(s:buf_nr)
execute a:newposition
sil file `="[Godoc]"`
@ -96,20 +92,23 @@ function! s:GodocView(newposition, position, content) abort
execute bufwinnr(s:buf_nr) . 'wincmd w'
endif
if a:position == "split"
" cap window height to 20, but resize it for smaller contents
let max_height = get(g:, "go_doc_max_height", 20)
let content_height = len(split(a:content, "\n"))
if content_height > max_height
exe 'resize ' . max_height
" if window was not visible then resize it
if !is_visible
if a:position == "split"
" cap window height to 20, but resize it for smaller contents
let max_height = get(g:, "go_doc_max_height", 20)
let content_height = len(split(a:content, "\n"))
if content_height > max_height
exe 'resize ' . max_height
else
exe 'resize ' . content_height
endif
else
exe 'resize ' . content_height
" set a sane maximum width for vertical splits. In this case the minimum
" that fits the godoc for package http without extra linebreaks and line
" numbers on
exe 'vertical resize 84'
endif
else
" set a sane maximum width for vertical splits. In this case the minimum
" that fits the godoc for package http without extra linebreaks and line
" numbers on
exe 'vertical resize 84'
endif
setlocal filetype=godoc
@ -155,18 +154,8 @@ function! s:gogetdoc(json) abort
let command = join(cmd, " ")
if &modified
" gogetdoc supports the same archive format as guru for dealing with
" modified buffers.
" use the -modified flag
" write each archive entry on stdin as:
" filename followed by newline
" file size followed by newline
" file contents
let in = ""
let content = join(go#util#GetLines(), "\n")
let in = fname . "\n" . strlen(content) . "\n" . content
let command .= " -modified"
let out = go#util#System(command, in)
let out = go#util#System(command, go#util#archive())
else
let out = go#util#System(command)
endif

View File

@ -127,17 +127,23 @@ function! go#fmt#update_file(source, target)
let &fileformat = old_fileformat
let &syntax = &syntax
let l:listtype = go#list#Type("GoFmt")
" the title information was introduced with 7.4-2200
" https://github.com/vim/vim/commit/d823fa910cca43fec3c31c030ee908a14c272640
if !has('patch-7.4-2200')
return
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
" clean up previous location list
let l:list_title = getqflist({'title': 1})
if has_key(l:list_title, "title") && l:list_title['title'] == "Format"
let l:listtype = go#list#Type("quickfix")
call go#list#Clean(l:listtype)
call go#list#Window(l:listtype)
endif
@ -245,7 +251,7 @@ 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("quickfix")
let l:listtype = go#list#Type("GoFmt")
if !empty(a:errors)
call go#list#Populate(l:listtype, a:errors, 'Format')
echohl Error | echomsg "Gofmt returned error" | echohl None

View File

@ -1,4 +1,4 @@
func Test_run_fmt()
func! Test_run_fmt() abort
let actual_file = tempname()
call writefile(readfile("test-fixtures/fmt/hello.go"), actual_file)
@ -13,7 +13,7 @@ func Test_run_fmt()
call assert_equal(expected, actual)
endfunc
func Test_update_file()
func! Test_update_file() abort
let expected = join(readfile("test-fixtures/fmt/hello_golden.go"), "\n")
let source_file = tempname()
call writefile(readfile("test-fixtures/fmt/hello_golden.go"), source_file)
@ -30,7 +30,7 @@ func Test_update_file()
call assert_equal(expected, actual)
endfunc
func Test_goimports()
func! Test_goimports() abort
let $GOPATH = 'test-fixtures/fmt/'
let actual_file = tempname()
call writefile(readfile("test-fixtures/fmt/src/imports/goimports.go"), actual_file)
@ -45,3 +45,5 @@ func Test_goimports()
call assert_equal(expected, actual)
endfunc
" vim: sw=2 ts=2 et

View File

@ -34,8 +34,7 @@ function! s:guru_cmd(args) range abort
let filename = fnamemodify(expand("%"), ':p:gs?\\?/?')
if &modified
let content = join(go#util#GetLines(), "\n")
let result.stdin_content = filename . "\n" . strlen(content) . "\n" . content
let result.stdin_content = go#util#archive()
call add(cmd, "-modified")
endif
@ -112,7 +111,8 @@ function! s:sync_guru(args) abort
if !has_key(a:args, 'disable_progress')
if a:args.needs_scope
call go#util#EchoProgress("analysing with scope ". result.scope . " ...")
call go#util#EchoProgress("analysing with scope ". result.scope .
\ " (see ':help go-guru-scope' if this doesn't work)...")
elseif a:args.mode !=# 'what'
" the query might take time, let us give some feedback
call go#util#EchoProgress("analysing ...")
@ -150,7 +150,8 @@ function! s:async_guru(args) abort
if !has_key(a:args, 'disable_progress')
if a:args.needs_scope
call go#util#EchoProgress("analysing with scope ". result.scope . " ...")
call go#util#EchoProgress("analysing with scope " . result.scope .
\ " (see ':help go-guru-scope' if this doesn't work)...")
endif
endif
@ -159,9 +160,10 @@ function! s:async_guru(args) abort
call add(messages, a:msg)
endfunction
function! s:exit_cb(job, exitval) closure
let out = join(messages, "\n")
let status = {}
let exitval = 0
function! s:exit_cb(job, exitval) closure
let status = {
\ 'desc': 'last status',
\ 'type': statusline_type,
@ -169,21 +171,27 @@ function! s:async_guru(args) abort
\ }
if a:exitval
let exitval = a:exitval
let status.state = "failed"
endif
call go#statusline#Update(status_dir, status)
endfunction
function! s:close_cb(ch) closure
let out = join(messages, "\n")
if has_key(a:args, 'custom_parse')
call a:args.custom_parse(a:exitval, out)
call a:args.custom_parse(exitval, out)
else
call s:parse_guru_output(a:exitval, out, a:args.mode)
call s:parse_guru_output(exitval, out, a:args.mode)
endif
endfunction
let start_options = {
\ 'callback': funcref("s:callback"),
\ 'exit_cb': funcref("s:exit_cb"),
\ 'close_cb': funcref("s:close_cb"),
\ }
if has_key(result, 'stdin_content')
@ -521,28 +529,40 @@ function! s:same_ids_highlight(exit_val, output) abort
if get(g:, "go_auto_sameids", 0)
" re-apply SameIds at the current cursor position at the time the buffer
" is redisplayed: e.g. :edit, :GoRename, etc.
autocmd BufWinEnter <buffer> nested call go#guru#SameIds()
augroup vim-go-sameids
autocmd!
autocmd BufWinEnter <buffer> nested call go#guru#SameIds()
augroup end
endif
endfunction
" ClearSameIds returns 0 when it removes goSameId groups and non-zero if no
" goSameId groups are found.
function! go#guru#ClearSameIds() abort
let l:cleared = 0
let m = getmatches()
for item in m
if item['group'] == 'goSameId'
call matchdelete(item['id'])
let l:cleared = 1
endif
endfor
" remove the autocmds we defined
if exists("#BufWinEnter#<buffer>")
autocmd! BufWinEnter <buffer>
if !l:cleared
return 1
endif
" remove the autocmds we defined
augroup vim-go-sameids
autocmd!
augroup end
return 0
endfunction
function! go#guru#ToggleSameIds() abort
if len(getmatches()) != 0
call go#guru#ClearSameIds()
else
if go#guru#ClearSameIds() != 0
call go#guru#SameIds()
endif
endfunction
@ -583,11 +603,12 @@ function! s:parse_guru_output(exit_val, output, title) abort
let old_errorformat = &errorformat
let errformat = "%f:%l.%c-%[%^:]%#:\ %m,%f:%l:%c:\ %m"
call go#list#ParseFormat("locationlist", errformat, a:output, a:title)
let l:listtype = go#list#Type("_guru")
call go#list#ParseFormat(l:listtype, errformat, a:output, a:title)
let &errorformat = old_errorformat
let errors = go#list#Get("locationlist")
call go#list#Window("locationlist", len(errors))
let errors = go#list#Get(l:listtype)
call go#list#Window(l:listtype, len(errors))
endfun
function! go#guru#Scope(...) abort

View File

@ -6,11 +6,13 @@ function! go#impl#Impl(...) abort
let recv = ""
let iface = ""
let interactive = 0
let pos = getpos('.')
if a:0 == 0
" user didn't passed anything, just called ':GoImpl'
let receiveType = expand("<cword>")
let recv = printf("%s *%s", tolower(receiveType)[0], receiveType)
" Interactive mode if user didn't pass any arguments.
let recv = s:getReceiver()
let iface = input("vim-go: generating method stubs for interface: ")
redraw!
if empty(iface)
@ -20,8 +22,7 @@ function! go#impl#Impl(...) abort
elseif a:0 == 1
" we assume the user only passed the interface type,
" i.e: ':GoImpl io.Writer'
let receiveType = expand("<cword>")
let recv = printf("%s *%s", tolower(receiveType)[0], receiveType)
let recv = s:getReceiver()
let iface = a:1
elseif a:0 > 2
" user passed receiver and interface type both,
@ -33,20 +34,41 @@ function! go#impl#Impl(...) abort
return
endif
let result = go#util#System(join(go#util#Shelllist([binpath, recv, iface], ' ')))
if go#util#ShellError() != 0
call go#util#EchoError(result)
return
" Make sure we put the generated code *after* the struct.
if getline(".") =~ "struct "
normal! $%
endif
if result ==# ''
return
end
try
let dirname = fnameescape(expand('%:p:h'))
let result = go#util#System(join(go#util#Shelllist([binpath, '-dir', dirname, recv, iface], ' ')))
let result = substitute(result, "\n*$", "", "")
if go#util#ShellError() != 0
call go#util#EchoError(result)
return
endif
let pos = getpos('.')
put =''
put =result
call setpos('.', pos)
if result ==# ''
return
end
put =''
put =result
finally
call setpos('.', pos)
endtry
endfunction
function! s:getReceiver()
let receiveType = expand("<cword>")
if receiveType == "type"
normal! w
let receiveType = expand("<cword>")
elseif receiveType == "struct"
normal! ge
let receiveType = expand("<cword>")
endif
return printf("%s *%s", tolower(receiveType)[0], receiveType)
endfunction
if exists('*uniq')

View File

@ -10,12 +10,17 @@ function go#job#Spawn(args)
\ 'messages': [],
\ 'args': a:args.cmd,
\ 'bang': 0,
\ 'for': "_job",
\ }
if has_key(a:args, 'bang')
let cbs.bang = a:args.bang
endif
if has_key(a:args, 'for')
let cbs.for = a:args.for
endif
" add final callback to be called if async job is finished
" The signature should be in form: func(job, exit_status, messages)
if has_key(a:args, 'custom_cb')
@ -47,7 +52,7 @@ function go#job#Spawn(args)
call self.custom_cb(a:job, a:exitval, self.messages)
endif
let l:listtype = go#list#Type("quickfix")
let l:listtype = go#list#Type(self.for)
if a:exitval == 0
call go#list#Clean(l:listtype)
call go#list#Window(l:listtype)
@ -69,8 +74,7 @@ function go#job#Spawn(args)
if !len(errors)
" failed to parse errors, output the original content
call go#util#EchoError(join(self.messages, " "))
call go#util#EchoError(self.dir)
call go#util#EchoError(self.messages + [self.dir])
return
endif

View File

@ -9,11 +9,11 @@ let s:handlers = {}
" Spawn is a wrapper around s:spawn. It can be executed by other files and
" scripts if needed. Desc defines the description for printing the status
" during the job execution (useful for statusline integration).
function! go#jobcontrol#Spawn(bang, desc, args) abort
function! go#jobcontrol#Spawn(bang, desc, for, args) abort
" autowrite is not enabled for jobs
call go#cmd#autowrite()
let job = s:spawn(a:bang, a:desc, a:args)
let job = s:spawn(a:bang, a:desc, a:for, a:args)
return job.id
endfunction
@ -37,7 +37,7 @@ endfunction
" a job is started a reference will be stored inside s:jobs. spawn changes the
" GOPATH when g:go_autodetect_gopath is enabled. The job is started inside the
" current files folder.
function! s:spawn(bang, desc, args) abort
function! s:spawn(bang, desc, for, args) abort
let status_type = a:args[0]
let status_dir = expand('%:p:h')
let started_at = reltime()
@ -62,6 +62,7 @@ function! s:spawn(bang, desc, args) abort
\ 'status_type' : status_type,
\ 'status_dir' : status_dir,
\ 'started_at' : started_at,
\ 'for' : a:for,
\ }
" modify GOPATH if needed
@ -129,7 +130,7 @@ function! s:on_exit(job_id, exit_status, event) dict abort
call s:callback_handlers_on_exit(s:jobs[a:job_id], a:exit_status, std_combined)
let l:listtype = go#list#Type("quickfix")
let l:listtype = go#list#Type(self.for)
if a:exit_status == 0
call go#list#Clean(l:listtype)
call go#list#Window(l:listtype)

View File

@ -57,3 +57,5 @@ endfunction
function! s:chomp(string)
return substitute(a:string, '\n\+$', '', '')
endfunction
" vim: sw=2 ts=2 et

View File

@ -48,6 +48,13 @@ function! go#lint#Gometa(autosave, ...) abort
let cmd += ["--exclude=".exclude]
endfor
" 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"]
" path
let cmd += [expand('%:p:h')]
else
@ -60,7 +67,7 @@ function! go#lint#Gometa(autosave, ...) abort
" For async mode (s:lint_job), we want to override the default deadline only
" if we have a deadline configured.
"
" For sync mode (go#tool#ExecuteInDir), always explicitly pass the 5 seconds
" For sync mode (go#util#System), always explicitly pass the 5 seconds
" deadline if there is no other deadline configured. If a deadline is
" configured, then use it.
@ -87,9 +94,9 @@ function! go#lint#Gometa(autosave, ...) abort
let meta_command = join(cmd, " ")
let out = go#tool#ExecuteInDir(meta_command)
let out = go#util#System(meta_command)
let l:listtype = "quickfix"
let l:listtype = go#list#Type("GoMetaLinter")
if go#util#ShellError() == 0
redraw | echo
call go#list#Clean(l:listtype)
@ -134,7 +141,7 @@ function! go#lint#Golint(...) abort
return
endif
let l:listtype = "quickfix"
let l:listtype = go#list#Type("GoLint")
call go#list#Parse(l:listtype, out)
let errors = go#list#Get(l:listtype)
call go#list#Window(l:listtype, len(errors))
@ -152,7 +159,7 @@ function! go#lint#Vet(bang, ...) abort
let out = go#util#System('go tool vet ' . go#util#Shelljoin(a:000))
endif
let l:listtype = "quickfix"
let l:listtype = go#list#Type("GoVet")
if go#util#ShellError() != 0
let errors = go#tool#ParseErrors(split(out, '\n'))
call go#list#Populate(l:listtype, errors, 'Vet')
@ -192,7 +199,7 @@ function! go#lint#Errcheck(...) abort
let command = go#util#Shellescape(bin_path) . ' -abspath ' . import_path
let out = go#tool#ExecuteInDir(command)
let l:listtype = "quickfix"
let l:listtype = go#list#Type("GoErrCheck")
if go#util#ShellError() != 0
let errformat = "%f:%l:%c:\ %m, %f:%l:%c\ %#%m"
@ -246,7 +253,7 @@ function s:lint_job(args)
" autowrite is not enabled for jobs
call go#cmd#autowrite()
let l:listtype = go#list#Type("quickfix")
let l:listtype = go#list#Type("GoMetaLinter")
let l:errformat = '%f:%l:%c:%t%*[^:]:\ %m,%f:%l::%t%*[^:]:\ %m'
function! s:callback(chan, msg) closure

View File

@ -2,13 +2,16 @@ if !exists("g:go_list_type")
let g:go_list_type = ""
endif
if !exists("g:go_list_type_commands")
let g:go_list_type_commands = {}
endif
" Window opens the list with the given height up to 10 lines maximum.
" Otherwise g:go_loclist_height is used.
" Otherwise g:go_loclist_height is used.
"
" If no or zero height is given it closes the window by default.
" If no or zero height is given it closes the window by default.
" To prevent this, set g:go_list_autoclose = 0
function! go#list#Window(listtype, ...) abort
let l:listtype = go#list#Type(a:listtype)
" we don't use lwindow to close the location list as we need also the
" ability to resize the window. So, we are going to use lopen and lclose
" for a better user experience. If the number of errors in a current
@ -17,7 +20,7 @@ function! go#list#Window(listtype, ...) abort
if !a:0 || a:1 == 0
let autoclose_window = get(g:, 'go_list_autoclose', 1)
if autoclose_window
if l:listtype == "locationlist"
if a:listtype == "locationlist"
lclose
else
cclose
@ -36,7 +39,7 @@ function! go#list#Window(listtype, ...) abort
endif
endif
if l:listtype == "locationlist"
if a:listtype == "locationlist"
exe 'lopen ' . height
else
exe 'copen ' . height
@ -44,20 +47,18 @@ function! go#list#Window(listtype, ...) abort
endfunction
" Get returns the current list of items from the location list
" Get returns the current items from the list
function! go#list#Get(listtype) abort
let l:listtype = go#list#Type(a:listtype)
if l:listtype == "locationlist"
if a:listtype == "locationlist"
return getloclist(0)
else
return getqflist()
endif
endfunction
" Populate populate the location list with the given items
" Populate populate the list with the given items
function! go#list#Populate(listtype, items, title) abort
let l:listtype = go#list#Type(a:listtype)
if l:listtype == "locationlist"
if a:listtype == "locationlist"
call setloclist(0, a:items, 'r')
" The last argument ({what}) is introduced with 7.4.2200:
@ -69,20 +70,15 @@ function! go#list#Populate(listtype, items, title) abort
endif
endfunction
function! go#list#PopulateWin(winnr, items) abort
call setloclist(a:winnr, a:items, 'r')
endfunction
" Parse parses the given items based on the specified errorformat and
" populates the location list.
" populates the list.
function! go#list#ParseFormat(listtype, errformat, items, title) abort
let l:listtype = go#list#Type(a:listtype)
" backup users errorformat, will be restored once we are finished
let old_errorformat = &errorformat
" parse and populate the location list
let &errorformat = a:errformat
if l:listtype == "locationlist"
if a:listtype == "locationlist"
lgetexpr a:items
if has("patch-7.4.2200") | call setloclist(0, [], 'a', {'title': a:title}) | endif
else
@ -95,10 +91,9 @@ function! go#list#ParseFormat(listtype, errformat, items, title) abort
endfunction
" Parse parses the given items based on the global errorformat and
" populates the location list.
" populates the list.
function! go#list#Parse(listtype, items) abort
let l:listtype = go#list#Type(a:listtype)
if l:listtype == "locationlist"
if a:listtype == "locationlist"
lgetexpr a:items
else
cgetexpr a:items
@ -107,8 +102,7 @@ endfunction
" JumpToFirst jumps to the first item in the location list
function! go#list#JumpToFirst(listtype) abort
let l:listtype = go#list#Type(a:listtype)
if l:listtype == "locationlist"
if a:listtype == "locationlist"
ll 1
else
cc 1
@ -117,22 +111,57 @@ endfunction
" Clean cleans the location list
function! go#list#Clean(listtype) abort
let l:listtype = go#list#Type(a:listtype)
if l:listtype == "locationlist"
if a:listtype == "locationlist"
lex []
else
cex []
endif
endfunction
function! go#list#Type(listtype) abort
function! s:listtype(listtype) abort
if g:go_list_type == "locationlist"
return "locationlist"
elseif g:go_list_type == "quickfix"
return "quickfix"
else
return a:listtype
endif
return a:listtype
endfunction
" s:default_list_type_commands is the defaults that will be used for each of
" the supported commands (see documentation for g:go_list_type_commands). When
" defining a default, quickfix should be used if the command operates on
" multiple files, while locationlist should be used if the command operates on a
" single file or buffer. Keys that begin with an underscore are not supported
" in g:go_list_type_commands.
let s:default_list_type_commands = {
\ "GoBuild": "quickfix",
\ "GoErrCheck": "quickfix",
\ "GoFmt": "locationlist",
\ "GoGenerate": "quickfix",
\ "GoInstall": "quickfix",
\ "GoLint": "quickfix",
\ "GoMetaLinter": "quickfix",
\ "GoModifyTags": "locationlist",
\ "GoRename": "quickfix",
\ "GoRun": "quickfix",
\ "GoTest": "quickfix",
\ "GoVet": "quickfix",
\ "_guru": "locationlist",
\ "_term": "locationlist",
\ "_job": "locationlist",
\ }
function! go#list#Type(for) abort
let l:listtype = s:listtype(get(s:default_list_type_commands, a:for))
if l:listtype == "0"
call go#util#EchoError(printf(
\ "unknown list type command value found ('%s'). Please open a bug report in the vim-go repo.",
\ a:for))
let l:listtype = "quickfix"
endif
return get(g:go_list_type_commands, a:for, l:listtype)
endfunction
" vim: sw=2 ts=2 et

View File

@ -80,6 +80,7 @@ function! go#package#FromPath(arg) abort
for dir in dirs
if len(dir) && match(path, dir) == 0
let workspace = dir
break
endif
endfor
@ -87,10 +88,12 @@ function! go#package#FromPath(arg) abort
return -1
endif
let path = substitute(path, '/*$', '', '')
let workspace = substitute(workspace . '/src/', '/+', '', '')
if isdirectory(path)
return substitute(path, workspace . 'src/', '', '')
return substitute(path, workspace, '', '')
else
return substitute(substitute(path, workspace . 'src/', '', ''),
return substitute(substitute(path, workspace, '', ''),
\ '/' . fnamemodify(path, ':t'), '', '')
endif
endfunction

View File

@ -73,7 +73,7 @@ function! go#path#Detect() abort
let gopath = go#path#Default()
" don't lookup for godeps if autodetect is disabled.
if !get(g:, "go_autodetect_gopath", 1)
if !get(g:, "go_autodetect_gopath", 0)
return gopath
endif
@ -179,7 +179,6 @@ function! go#path#CheckBinPath(binpath) abort
" just get the basename
let basename = fnamemodify(binpath, ":t")
if !executable(basename)
call go#util#EchoError(printf("could not find '%s'. Run :GoInstallBinaries to fix it", basename))
" restore back!

View File

@ -70,24 +70,4 @@ function! s:get_visual_selection() abort
return join(lines, "\n")
endfunction
" following two functions are from: https://github.com/mattn/gist-vim
" thanks @mattn
function! s:get_browser_command() abort
let go_play_browser_command = get(g:, 'go_play_browser_command', '')
if go_play_browser_command == ''
if has('win32') || has('win64')
let go_play_browser_command = '!start rundll32 url.dll,FileProtocolHandler %URL%'
elseif has('mac') || has('macunix') || has('gui_macvim') || go#util#System('uname') =~? '^darwin'
let go_play_browser_command = 'open %URL%'
elseif executable('xdg-open')
let go_play_browser_command = 'xdg-open %URL%'
elseif executable('firefox')
let go_play_browser_command = 'firefox %URL% &'
else
let go_play_browser_command = ''
endif
endif
return go_play_browser_command
endfunction
" vim: sw=2 ts=2 et

View File

@ -2,17 +2,25 @@ if !exists("g:go_gorename_bin")
let g:go_gorename_bin = "gorename"
endif
if !exists("g:go_gorename_prefill")
let g:go_gorename_prefill = 1
endif
" Set the default value. A value of "1" is a shortcut for this, for
" compatibility reasons.
function! s:default() abort
if !exists("g:go_gorename_prefill") || g:go_gorename_prefill == 1
let g:go_gorename_prefill = 'expand("<cword>") =~# "^[A-Z]"' .
\ '? go#util#pascalcase(expand("<cword>"))' .
\ ': go#util#camelcase(expand("<cword>"))'
endif
endfunction
call s:default()
function! go#rename#Rename(bang, ...) abort
call s:default()
let to_identifier = ""
if a:0 == 0
let from = expand("<cword>")
let ask = printf("vim-go: rename '%s' to: ", from)
if g:go_gorename_prefill
let to_identifier = input(ask, from)
let ask = printf("vim-go: rename '%s' to: ", expand("<cword>"))
if g:go_gorename_prefill != ''
let to_identifier = input(ask, eval(g:go_gorename_prefill))
else
let to_identifier = input(ask)
endif
@ -24,7 +32,7 @@ function! go#rename#Rename(bang, ...) abort
let to_identifier = a:1
endif
"return with a warning if the bin doesn't exist
" return with a warning if the bin doesn't exist
let bin_path = go#path#CheckBinPath(g:go_gorename_bin)
if empty(bin_path)
return
@ -117,7 +125,7 @@ function s:parse_errors(exit_val, bang, out)
silent! checktime
let &autoread = current_autoread
let l:listtype = "quickfix"
let l:listtype = go#list#Type("GoRename")
if a:exit_val != 0
call go#util#EchoError("FAILED")
let errors = go#tool#ParseErrors(a:out)
@ -127,7 +135,7 @@ function s:parse_errors(exit_val, bang, out)
call go#list#JumpToFirst(l:listtype)
elseif empty(errors)
" failed to parse errors, output the original content
call go#util#EchoError(join(a:out, ""))
call go#util#EchoError(a:out)
endif
return
@ -146,4 +154,13 @@ function s:parse_errors(exit_val, bang, out)
silent execute ":e"
endfunction
" Commandline completion: original, unexported camelCase, and exported
" CamelCase.
function! go#rename#Complete(lead, cmdline, cursor)
let l:word = expand('<cword>')
return filter(uniq(sort(
\ [l:word, go#util#camelcase(l:word), go#util#pascalcase(l:word)])),
\ 'strpart(v:val, 0, len(a:lead)) == a:lead')
endfunction
" vim: sw=2 ts=2 et

View File

@ -95,12 +95,12 @@ func s:write_out(out) abort
if has_key(result, 'errors')
let l:winnr = winnr()
let l:listtype = go#list#Type("quickfix")
let l:listtype = go#list#Type("GoModifyTags")
call go#list#ParseFormat(l:listtype, "%f:%l:%c:%m", result['errors'], "gomodifytags")
call go#list#Window(l:listtype, len(result['errors']))
"prevent jumping to quickfix list
exe l:winnr . "wincmd w"
exe l:winnr . "wincmd w"
endif
endfunc
@ -210,3 +210,5 @@ func s:create_cmd(args) abort
return {'cmd': cmd}
endfunc
" vim: sw=2 ts=2 et

View File

@ -1,28 +1,22 @@
func Test_add_tags()
let input_file = tempname()
call writefile(readfile("test-fixtures/tags/add_all_input.go"), input_file)
let expected = join(readfile("test-fixtures/tags/add_all_golden.go"), "\n")
" run for offset 40, which is inside the struct
call go#tags#run(0, 0, 40, "add", input_file, 1)
let actual = join(readfile(input_file), "\n")
call assert_equal(expected, actual)
func! Test_add_tags() abort
try
let l:tmp = gotest#load_fixture('tags/add_all_input.go')
silent call go#tags#run(0, 0, 40, "add", bufname(''), 1)
call gotest#assert_fixture('tags/add_all_golden.go')
finally
call delete(l:tmp, 'rf')
endtry
endfunc
func Test_remove_tags()
let input_file = tempname()
call writefile(readfile("test-fixtures/tags/remove_all_input.go"), input_file)
let expected = join(readfile("test-fixtures/tags/remove_all_golden.go"), "\n")
" run for offset 40, which is inside the struct
call go#tags#run(0, 0, 40, "remove", input_file, 1)
let actual = join(readfile(input_file), "\n")
call assert_equal(expected, actual)
func! Test_remove_tags() abort
try
let l:tmp = gotest#load_fixture('tags/remove_all_input.go')
silent call go#tags#run(0, 0, 40, "remove", bufname(''), 1)
call gotest#assert_fixture('tags/remove_all_golden.go')
finally
call delete(l:tmp, 'rf')
endtry
endfunc
" vim:ts=2:sts=2:sw=2:et

View File

@ -77,6 +77,7 @@ function! go#term#newmode(bang, cmd, mode) abort
call jobresize(id, width, height)
let s:jobs[id] = job
stopinsert
return id
endfunction
@ -104,7 +105,7 @@ function! s:on_exit(job_id, exit_status, event) dict abort
endif
let job = s:jobs[a:job_id]
let l:listtype = "locationlist"
let l:listtype = go#list#Type("_term")
" usually there is always output so never branch into this clause
if empty(job.stdout)

View File

@ -6,9 +6,13 @@ function! go#test#Test(bang, compile, ...) abort
" don't run the test, only compile it. Useful to capture and fix errors.
if a:compile
" we're going to tell to run a test function that doesn't exist. This
" triggers a build of the test file itself but no tests will run.
call extend(args, ["-run", "499EE4A2-5C85-4D35-98FC-7377CD87F263"])
let testfile = tempname() . ".vim-go.test"
call extend(args, ["-c", "-o", testfile])
endif
if exists('g:go_build_tags')
let tags = get(g:, 'go_build_tags')
call extend(args, ["-tags", tags])
endif
if a:0
@ -33,9 +37,9 @@ function! go#test#Test(bang, compile, ...) abort
if get(g:, 'go_echo_command_info', 1)
if a:compile
echon "vim-go: " | echohl Identifier | echon "compiling tests ..." | echohl None
call go#util#EchoProgress("compiling tests ...")
else
echon "vim-go: " | echohl Identifier | echon "testing ..." | echohl None
call go#util#EchoProgress("testing...")
endif
endif
@ -57,7 +61,7 @@ function! go#test#Test(bang, compile, ...) abort
if get(g:, 'go_term_enabled', 0)
let id = go#term#new(a:bang, ["go"] + args)
else
let id = go#jobcontrol#Spawn(a:bang, "test", args)
let id = go#jobcontrol#Spawn(a:bang, "test", "GoTest", args)
endif
return id
@ -69,7 +73,7 @@ function! go#test#Test(bang, compile, ...) abort
let command = "go " . join(args, ' ')
let out = go#tool#ExecuteInDir(command)
let l:listtype = "quickfix"
let l:listtype = go#list#Type("GoTest")
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
let dir = getcwd()
@ -87,15 +91,15 @@ function! go#test#Test(bang, compile, ...) abort
" failed to parse errors, output the original content
call go#util#EchoError(out)
endif
echon "vim-go: " | echohl ErrorMsg | echon "[test] FAIL" | echohl None
call go#util#EchoError("[test] FAIL")
else
call go#list#Clean(l:listtype)
call go#list#Window(l:listtype)
if a:compile
echon "vim-go: " | echohl Function | echon "[test] SUCCESS" | echohl None
call go#util#EchoSuccess("[test] SUCCESS")
else
echon "vim-go: " | echohl Function | echon "[test] PASS" | echohl None
call go#util#EchoSuccess("[test] PASS")
endif
endif
execute cd . fnameescape(dir)
@ -172,12 +176,12 @@ function s:test_job(args) abort
if get(g:, 'go_echo_command_info', 1)
if a:exitval == 0
if a:args.compile_test
call go#util#EchoSuccess("SUCCESS")
call go#util#EchoSuccess("[test] SUCCESS")
else
call go#util#EchoSuccess("PASS")
call go#util#EchoSuccess("[test] PASS")
endif
else
call go#util#EchoError("FAILED")
call go#util#EchoError("[test] FAIL")
endif
endif
@ -188,7 +192,7 @@ function s:test_job(args) abort
call go#statusline#Update(status_dir, status)
let l:listtype = go#list#Type("quickfix")
let l:listtype = go#list#Type("GoTest")
if a:exitval == 0
call go#list#Clean(l:listtype)
call go#list#Window(l:listtype)
@ -222,9 +226,9 @@ endfunction
" show_errors parses the given list of lines of a 'go test' output and returns
" a quickfix compatible list of errors. It's intended to be used only for go
" test output.
" test output.
function! s:show_errors(args, exit_val, messages) abort
let l:listtype = go#list#Type("quickfix")
let l:listtype = go#list#Type("GoTest")
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
try
@ -237,7 +241,7 @@ function! s:show_errors(args, exit_val, messages) abort
if !len(errors)
" failed to parse errors, output the original content
call go#util#EchoError(join(a:messages, " "))
call go#util#EchoError(a:messages)
call go#util#EchoError(a:args.dir)
return
endif
@ -253,28 +257,85 @@ endfunction
function! s:parse_errors(lines) abort
let errors = []
let paniced = 0 " signals whether all remaining lines should be included in errors.
let test = ''
" NOTE(arslan): once we get JSON output everything will be easier :)
" https://github.com/golang/go/issues/2981
for line in a:lines
let fatalerrors = matchlist(line, '^\(fatal error:.*\)$')
let tokens = matchlist(line, '^\s*\(.\{-}\.go\):\(\d\+\):\s*\(.*\)')
let fatalerrors = matchlist(line, '^\(\(fatal error\|panic\):.*\)$')
if !empty(fatalerrors)
call add(errors, {"text": fatalerrors[1]})
elseif !empty(tokens)
let paniced = 1
call add(errors, {"text": line})
continue
endif
if !paniced
" Matches failure lines. These lines always have zero or more leading spaces followed by '-- FAIL: ', following by the test name followed by a space the duration of the test in parentheses
" e.g.:
" '--- FAIL: TestSomething (0.00s)'
let failure = matchlist(line, '^ *--- FAIL: \(.*\) (.*)$')
if get(g:, 'go_test_prepend_name', 0)
if !empty(failure)
let test = failure[1] . ': '
continue
endif
endif
endif
let tokens = []
if paniced
" Matches lines in stacktraces produced by panic. The lines always have
" one or more leading tabs, followed by the path to the file. The file
" path is followed by a colon and then the line number within the file
" where the panic occurred. After that there's a space and hexadecimal
" number.
"
" e.g.:
" '\t/usr/local/go/src/time.go:1313 +0x5d'
let tokens = matchlist(line, '^\t\+\(.\{-}\.go\):\(\d\+\) \(+0x.*\)')
else
" matches lines produced by `go test`. All lines produced by `go test`
" that we're interested in start with zero or more spaces (increasing
" depth of subtests is represented by a similar increase in the number
" of spaces at the start of output lines. Top level tests start with
" zero leading spaces). Lines that indicate test status (e.g. RUN, FAIL,
" PASS) start after the spaces. Lines that indicate test failure
" location or test log message location (e.g. "testing.T".Log) begin
" with the appropriate number of spaces for the current test level,
" followed by a tab, a filename , a colon, the line number, another
" colon, a space, and the failure or log message.
"
" e.g.:
" '\ttime_test.go:30: Likely problem: the time zone files have not been installed.'
let tokens = matchlist(line, '^ *\t\+\(.\{-}\.go\):\(\d\+\):\s*\(.*\)')
endif
if !empty(tokens) " Check whether the line may refer to a file.
" strip endlines of form ^M
let out = substitute(tokens[3], '\r$', '', '')
let file = fnamemodify(tokens[1], ':p')
" Preserve the line when the filename is not readable. This is an
" unusual case, but possible; any test that produces lines that match
" the pattern used in the matchlist assigned to tokens is a potential
" source of this condition. For instance, github.com/golang/mock/gomock
" will sometimes produce lines that satisfy this condition.
if !filereadable(file)
call add(errors, {"text": test . line})
continue
endif
call add(errors, {
\ "filename" : fnamemodify(tokens[1], ':p'),
\ "filename" : file,
\ "lnum" : tokens[2],
\ "text" : out,
\ "text" : test . out,
\ })
elseif paniced
call add(errors, {"text": line})
elseif !empty(errors)
" Preserve indented lines.
" This comes up especially with multi-line test output.
if match(line, '^\s') >= 0
" Preserve indented lines. This comes up especially with multi-line test output.
if match(line, '^ *\t\+') >= 0
call add(errors, {"text": line})
endif
endif
@ -284,4 +345,3 @@ function! s:parse_errors(lines) abort
endfunction
" vim: sw=2 ts=2 et
"

View File

@ -162,6 +162,18 @@ function! go#tool#FilterValids(items) abort
endfunction
function! go#tool#ExecuteInDir(cmd) abort
" Verify that the directory actually exists. If the directory does not
" exist, then assume that the a:cmd should not be executed. Callers expect
" to check v:shell_error (via go#util#ShellError()), so execute a command
" that will return an error as if a:cmd was run and exited with an error.
" This helps avoid errors when working with plugins that use virtual files
" that don't actually exist on the file system (e.g. vim-fugitive's
" GitDiff).
if !isdirectory(expand("%:p:h"))
let [out, err] = go#util#Exec(["false"])
return ''
endif
let old_gopath = $GOPATH
let old_goroot = $GOROOT
let $GOPATH = go#path#Detect()
@ -194,7 +206,6 @@ function! go#tool#Exists(importpath) abort
return 0
endfunction
" following two functions are from: https://github.com/mattn/gist-vim
" thanks @mattn
function! s:get_browser_command() abort
@ -202,12 +213,14 @@ function! s:get_browser_command() abort
if go_play_browser_command == ''
if go#util#IsWin()
let go_play_browser_command = '!start rundll32 url.dll,FileProtocolHandler %URL%'
elseif has('mac') || has('macunix') || has('gui_macvim') || go#util#System('uname') =~? '^darwin'
elseif go#util#IsMac()
let go_play_browser_command = 'open %URL%'
elseif executable('xdg-open')
let go_play_browser_command = 'xdg-open %URL%'
elseif executable('firefox')
let go_play_browser_command = 'firefox %URL% &'
elseif executable('chromium')
let go_play_browser_command = 'chromium %URL% &'
else
let go_play_browser_command = ''
endif

View File

@ -43,6 +43,14 @@ function! go#util#IsWin() abort
return 0
endfunction
" IsMac returns 1 if current OS is macOS or 0 otherwise.
function! go#util#IsMac() abort
return has('mac') ||
\ has('macunix') ||
\ has('gui_macvim') ||
\ go#util#System('uname') =~? '^darwin'
endfunction
" Checks if using:
" 1) Windows system,
" 2) And has cygpath executable,
@ -110,25 +118,22 @@ function! go#util#osarch() abort
return go#util#env("goos") . '_' . go#util#env("goarch")
endfunction
" System runs a shell command. If possible, it will temporary set
" the shell to /bin/sh for Unix-like systems providing a Bourne
" POSIX like environment.
function! go#util#System(str, ...) abort
" Run a shell command.
"
" It will temporary set the shell to /bin/sh for Unix-like systems if possible,
" so that we always use a standard POSIX-compatible Bourne shell (and not e.g.
" csh, fish, etc.) See #988 and #1276.
function! s:system(cmd, ...) abort
" Preserve original shell and shellredir values
let l:shell = &shell
let l:shellredir = &shellredir
" Use a Bourne POSIX like shell. Some parts of vim-go expect
" commands to be executed using bourne semantics #988 and #1276.
" Alter shellredir to match bourne. Especially important if login shell
" is set to any of the csh or zsh family #1276.
if !go#util#IsWin() && executable('/bin/sh')
set shell=/bin/sh shellredir=>%s\ 2>&1
endif
try
let l:output = call('system', [a:str] + a:000)
return l:output
return call('system', [a:cmd] + a:000)
finally
" Restore original values
let &shell = l:shell
@ -136,6 +141,31 @@ function! go#util#System(str, ...) abort
endtry
endfunction
" System runs a shell command "str". Every arguments after "str" is passed to
" stdin.
function! go#util#System(str, ...) abort
return call('s:system', [a:str] + a:000)
endfunction
" Exec runs a shell command "cmd", which must be a list, one argument per item.
" Every list entry will be automatically shell-escaped
" Every other argument is passed to stdin.
function! go#util#Exec(cmd, ...) abort
if len(a:cmd) == 0
call go#util#EchoError("go#util#Exec() called with empty a:cmd")
return
endif
" CheckBinPath will show a warning for us.
let l:bin = go#path#CheckBinPath(a:cmd[0])
if empty(l:bin)
return ["", 1]
endif
let l:out = call('s:system', [go#util#Shelljoin([l:bin] + a:cmd[1:])] + a:000)
return [l:out, go#util#ShellError()]
endfunction
function! go#util#ShellError() abort
return v:shell_error
endfunction
@ -242,50 +272,71 @@ endfunction
" snakecase converts a string to snake case. i.e: FooBar -> foo_bar
" Copied from tpope/vim-abolish
function! go#util#snakecase(word) abort
let word = substitute(a:word,'::','/','g')
let word = substitute(word,'\(\u\+\)\(\u\l\)','\1_\2','g')
let word = substitute(word,'\(\l\|\d\)\(\u\)','\1_\2','g')
let word = substitute(word,'[.-]','_','g')
let word = substitute(a:word, '::', '/', 'g')
let word = substitute(word, '\(\u\+\)\(\u\l\)', '\1_\2', 'g')
let word = substitute(word, '\(\l\|\d\)\(\u\)', '\1_\2', 'g')
let word = substitute(word, '[.-]', '_', 'g')
let word = tolower(word)
return word
endfunction
" camelcase converts a string to camel case. i.e: FooBar -> fooBar
" Copied from tpope/vim-abolish
" camelcase converts a string to camel case. e.g. FooBar or foo_bar will become
" fooBar.
" Copied from tpope/vim-abolish.
function! go#util#camelcase(word) abort
let word = substitute(a:word, '-', '_', 'g')
if word !~# '_' && word =~# '\l'
return substitute(word,'^.','\l&','')
return substitute(word, '^.', '\l&', '')
else
return substitute(word,'\C\(_\)\=\(.\)','\=submatch(1)==""?tolower(submatch(2)) : toupper(submatch(2))','g')
return substitute(word, '\C\(_\)\=\(.\)', '\=submatch(1)==""?tolower(submatch(2)) : toupper(submatch(2))','g')
endif
endfunction
" TODO(arslan): I couldn't parameterize the highlight types. Check if we can
" simplify the following functions
" pascalcase converts a string to 'PascalCase'. e.g. fooBar or foo_bar will
" become FooBar.
function! go#util#pascalcase(word) abort
let word = go#util#camelcase(a:word)
return toupper(word[0]) . word[1:]
endfunction
" Echo a message to the screen and highlight it with the group in a:hi.
"
" NOTE(arslan): echon doesn't work well with redraw, thus echo doesn't print
" even though we order it. However echom seems to be work fine.
" The message can be a list or string; every line with be :echomsg'd separately.
function! s:echo(msg, hi)
let l:msg = []
if type(a:msg) != type([])
let l:msg = split(a:msg, "\n")
else
let l:msg = a:msg
endif
" Tabs display as ^I or <09>, so manually expand them.
let l:msg = map(l:msg, 'substitute(v:val, "\t", " ", "")')
exe 'echohl ' . a:hi
for line in l:msg
echom "vim-go: " . line
endfor
echohl None
endfunction
function! go#util#EchoSuccess(msg)
redraw | echohl Function | echom "vim-go: " . a:msg | echohl None
call s:echo(a:msg, 'Function')
endfunction
function! go#util#EchoError(msg)
redraw | echohl ErrorMsg | echom "vim-go: " . a:msg | echohl None
call s:echo(a:msg, 'ErrorMsg')
endfunction
function! go#util#EchoWarning(msg)
redraw | echohl WarningMsg | echom "vim-go: " . a:msg | echohl None
call s:echo(a:msg, 'WarningMsg')
endfunction
function! go#util#EchoProgress(msg)
redraw | echohl Identifier | echom "vim-go: " . a:msg | echohl None
call s:echo(a:msg, 'Identifier')
endfunction
function! go#util#EchoInfo(msg)
redraw | echohl Debug | echom "vim-go: " . a:msg | echohl None
call s:echo(a:msg, 'Debug')
endfunction
" Get all lines in the buffer as a a list.
function! go#util#GetLines()
let buf = getline(1, '$')
if &encoding != 'utf-8'
@ -299,4 +350,49 @@ function! go#util#GetLines()
return buf
endfunction
" Convert the current buffer to the "archive" format of
" golang.org/x/tools/go/buildutil:
" https://godoc.org/golang.org/x/tools/go/buildutil#ParseOverlayArchive
"
" > The archive consists of a series of files. Each file consists of a name, a
" > decimal file size and the file contents, separated by newlinews. No newline
" > follows after the file contents.
function! go#util#archive()
let l:buffer = join(go#util#GetLines(), "\n")
return expand("%:p:gs!\\!/!") . "\n" . strlen(l:buffer) . "\n" . l:buffer
endfunction
" Make a named temporary directory which starts with "prefix".
"
" Unfortunately Vim's tempname() is not portable enough across various systems;
" see: https://github.com/mattn/vim-go/pull/3#discussion_r138084911
function! go#util#tempdir(prefix) abort
" See :help tempfile
if go#util#IsWin()
let l:dirs = [$TMP, $TEMP, 'c:\tmp', 'c:\temp']
else
let l:dirs = [$TMPDIR, '/tmp', './', $HOME]
endif
let l:dir = ''
for l:d in dirs
if !empty(l:d) && filewritable(l:d) == 2
let l:dir = l:d
break
endif
endfor
if l:dir == ''
echoerr 'Unable to find directory to store temporary directory in'
return
endif
" Not great randomness, but "good enough" for our purpose here.
let l:rnd = sha256(printf('%s%s', localtime(), fnamemodify(bufname(''), ":p")))
let l:tmp = printf("%s/%s%s", l:dir, a:prefix, l:rnd)
call mkdir(l:tmp, 'p', 0700)
return l:tmp
endfunction
" vim: sw=2 ts=2 et