Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Neovim integration #607

Merged
merged 39 commits into from
Dec 8, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
4e07106
jobcontrol: first implementation of jobstart on Neovim
fatih Nov 19, 2015
3863445
jobcontrol: separate setting and showing processes
fatih Nov 19, 2015
f4f8cd7
jobcontrol: working version of build, need testing though
fatih Nov 20, 2015
9a40bbc
jobcontrol: more improvements
fatih Nov 20, 2015
df70767
jobcontrol: jump back again
fatih Nov 20, 2015
7f76a16
cmd: change the way we start jobs
fatih Nov 21, 2015
7696894
job: add comments
fatih Nov 21, 2015
663048d
jobcontrol: refactor error messages
fatih Nov 21, 2015
733d558
jobcontrol: add a statusline function to be used with statusline
fatih Nov 22, 2015
5573e9c
jobcontrol: show the job pased on the file name
fatih Nov 22, 2015
99a3a5f
build: cleanup build for multiple cases
fatih Nov 22, 2015
6c52e5c
term: add initial code, not usable, WIP
fatih Nov 22, 2015
dcb970c
term: add vsplit(), start in insert mode
fatih Nov 22, 2015
71234d0
term: simplify term opening
fatih Nov 22, 2015
6850dc0
term: add g:go_term_mode for term related options
fatih Nov 22, 2015
0d37160
mappings: add new mappings for :GoRun
fatih Nov 23, 2015
f9e29b1
term: add go_term_height and go_term_width settings
fatih Nov 23, 2015
db3331c
cmd: add term feature to :GoTest
fatih Nov 23, 2015
261ffdc
jobcontrol: fix jumping to errors
fatih Nov 24, 2015
b3a9f8b
term: parse errors and display them in qf window
fatih Nov 24, 2015
4a009b4
term: remove prints as the terminal can be anything
fatih Nov 24, 2015
7002b07
term: fix indentation of job var
fatih Nov 24, 2015
44ab21b
term: I don't like the cursorline on the bottom
fatih Nov 25, 2015
b7ae85e
Merge branch 'master' into nvim
fatih Nov 26, 2015
f3b5ffe
jobcontrol: move to new location list
fatih Nov 26, 2015
76195b9
jobcontrol: add async showing of location list
fatih Nov 27, 2015
e644495
jobcontrol: more changes
fatih Nov 29, 2015
a06eb22
Merge branch 'master' into nvim
fatih Nov 29, 2015
89a8c5a
Merge branch 'master' into nvim
fatih Nov 30, 2015
579dd89
cmd: add go_term_enabled for :GoTest .. commands
fatih Nov 30, 2015
cacf197
jobcontrol: improve statusline report
fatih Dec 1, 2015
32924a7
jobcontrol: don't anything for success case
fatih Dec 1, 2015
8ef677a
fmt: do not close location list when it's not due fmt
fatih Dec 1, 2015
7da1d60
jobcontrol: status should be per package instead of per file
fatih Dec 1, 2015
bc2c0ef
jobcontrol: remove nonused key
fatih Dec 1, 2015
9715f28
jobcontrol: fix test and build results
fatih Dec 2, 2015
61c9b49
tool: filter valid filenames, fixes #618
fatih Dec 2, 2015
1751ade
tool: it seems filename is absent too for some cases
fatih Dec 2, 2015
f772a42
jobcontrol: cleanup location list if it's passing
fatih Dec 8, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 56 additions & 41 deletions autoload/go/cmd.vim
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,30 @@ 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, ...)
let default_makeprg = &makeprg
" expand all wildcards(i.e: '%' to the current file name)
let goargs = map(copy(a:000), "expand(v:val)")

let old_gopath = $GOPATH
let $GOPATH = go#path#Detect()
" escape all shell arguments before we pass it to make
let goargs = go#util#Shelllist(goargs, 1)

let l:tmpname = tempname()
" 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 '.')
let args = ["build"] + goargs + [".", "errors"]

if v:shell_error
let &makeprg = "go build . errors"
else
" :make expands '%' and '#' wildcards, so they must also be escaped
let goargs = go#util#Shelljoin(map(copy(a:000), "expand(v:val)"), 1)
let gofiles = go#util#Shelljoin(go#tool#Files(), 1)
let &makeprg = "go build -o " . l:tmpname . ' ' . goargs . ' ' . gofiles
" if we have nvim, call it asynchronously and return early ;)
if has('nvim')
call go#jobcontrol#Spawn("build", args)
return
endif

echon "vim-go: " | echohl Identifier | echon "building ..."| echohl None
let old_gopath = $GOPATH
let $GOPATH = go#path#Detect()
let default_makeprg = &makeprg
let &makeprg = "go " . join(args, ' ')

if g:go_dispatch_enabled && exists(':Make') == 2
call go#util#EchoProgress("building dispatched ...")
silent! exe 'Make'
else
silent! exe 'lmake!'
Expand All @@ -42,25 +48,35 @@ function! go#cmd#Build(bang, ...)
let errors = go#list#Get()
call go#list#Window(len(errors))

if !empty(errors)
if !empty(errors)
if !a:bang
call go#list#JumpToFirst()
endif
else
redraws! | echon "vim-go: " | echohl Function | echon "[build] SUCCESS"| echohl None
call go#util#EchoSuccess("[build] SUCCESS")
endif


call delete(l:tmpname)
let &makeprg = default_makeprg
let $GOPATH = old_gopath
endfunction


" Run runs the current file (and their dependencies if any) in a new terminal.
function! go#cmd#RunTerm(mode)
let cmd = "go run ". go#util#Shelljoin(go#tool#Files())
call go#term#newmode(cmd, a:mode)
endfunction

" Run runs the current file (and their dependencies if any) and outputs it.
" This is intented to test small programs and play with them. It's not
" suitable for long running apps, because vim is blocking by default and
" calling long running apps will block the whole UI.
function! go#cmd#Run(bang, ...)
if has('nvim')
call go#cmd#RunTerm('')
return
endif

let old_gopath = $GOPATH
let $GOPATH = go#path#Detect()

Expand Down Expand Up @@ -90,27 +106,8 @@ function! go#cmd#Run(bang, ...)
exe 'lmake!'
endif

" Remove any nonvalid filename from the location list to avoid opening an
" empty buffer. See https://github.com/fatih/vim-go/issues/287 for
" details.
let items = go#list#Get()
let errors = []
let is_readable = {}

for item in items
let filename = bufname(item.bufnr)
if !has_key(is_readable, filename)
let is_readable[filename] = filereadable(filename)
endif
if is_readable[filename]
call add(errors, item)
endif
endfor

for k in keys(filter(is_readable, '!v:val'))
echo "vim-go: " | echohl Identifier | echon "[run] Dropped " | echohl Constant | echon '"' . k . '"'
echohl Identifier | echon " from location list (nonvalid filename)" | echohl None
endfor
let errors = go#tool#FilterValids(items)

call go#list#Populate(errors)
call go#list#Window(len(errors))
Expand Down Expand Up @@ -149,33 +146,51 @@ endfunction
" compile the tests instead of running them (useful to catch errors in the
" test files). Any other argument is appendend to the final `go test` command
function! go#cmd#Test(bang, compile, ...)
let command = "go test "
let args = ["test"]

" don't run the test, only compile it. Useful to capture and fix errors or
" to create a test binary.
if a:compile
let command .= "-c "
call add(args, "-c")
endif

if a:0
let command .= go#util#Shelljoin(map(copy(a:000), "expand(v:val)"))
" 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 test
call extend(args, go#util#Shelllist(goargs, 1))
else
" only add this if no custom flags are passed
let timeout = get(g:, 'go_test_timeout', '10s')
let command .= "-timeout=" . timeout . " "
call add(args, printf("-timeout=%s", timeout))
endif

if has('nvim')
if get(g:, 'go_term_enabled', 0)
call go#term#new(["go"] + args)
else
call go#jobcontrol#Spawn("test", args)
endif
return
endif

call go#cmd#autowrite()
if a:compile
echon "vim-go: " | echohl Identifier | echon "compiling tests ..." | echohl None
else
echon "vim-go: " | echohl Identifier | echon "testing ..." | echohl None
endif

call go#cmd#autowrite()
redraw

let command = "go " . join(args, ' ')

let out = go#tool#ExecuteInDir(command)
if v:shell_error
let errors = go#tool#ParseErrors(split(out, '\n'))
let errors = go#tool#FilterValids(errors)

call go#list#Populate(errors)
call go#list#Window(len(errors))
if !empty(errors) && !a:bang
Expand Down
12 changes: 9 additions & 3 deletions autoload/go/fmt.vim
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ if !exists("g:go_fmt_experimental")
let g:go_fmt_experimental = 0
endif

let s:got_fmt_error = 0

" we have those problems :
" http://stackoverflow.com/questions/12741977/prevent-vim-from-updating-its-undo-tree
" http://stackoverflow.com/questions/18532692/golang-formatter-and-vim-how-to-destroy-history-record?rq=1
Expand Down Expand Up @@ -117,9 +119,12 @@ function! go#fmt#Format(withGoimport)
let &fileformat = old_fileformat
let &syntax = &syntax

" clean up previous location list
call go#list#Clean()
call go#list#Window()
" clean up previous location list, but only if it's due fmt
if s:got_fmt_error
let s:got_fmt_error = 0
call go#list#Clean()
call go#list#Window()
endif
elseif g:go_fmt_fail_silently == 0
let splitted = split(out, '\n')
"otherwise get the errors and put them to location list
Expand All @@ -141,6 +146,7 @@ function! go#fmt#Format(withGoimport)
echohl Error | echomsg "Gofmt returned error" | echohl None
endif

let s:got_fmt_error = 1
call go#list#Window(len(errors))

" We didn't use the temp file, so clean up
Expand Down
168 changes: 168 additions & 0 deletions autoload/go/jobcontrol.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
" s:jobs is a global reference to all jobs started with Spawn() or with the
" internal function s:spawn
let s:jobs = {}

" 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(desc, args)
" autowrite is not enabled for jobs
call go#cmd#autowrite()

let job = s:spawn(a:desc, a:args)
return job.id
endfunction

" Statusline returns the current status of the job
function! go#jobcontrol#Statusline() abort
if empty(s:jobs)
return ''
endif

let import_path = go#package#ImportPath(expand('%:p:h'))

for job in values(s:jobs)
if job.importpath != import_path
continue
endif

if job.state == "SUCCESS"
return ''
endif

return printf("%s ... [%s]", job.desc, job.state)
endfor

return ''
endfunction

" spawn spawns a go subcommand with the name and arguments with jobstart. Once
" 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(desc, args)
let job = {
\ 'desc': a:desc,
\ 'winnr': winnr(),
\ 'importpath': go#package#ImportPath(expand('%:p:h')),
\ 'state': "RUNNING",
\ 'stderr' : [],
\ 'stdout' : [],
\ 'on_stdout': function('s:on_stdout'),
\ 'on_stderr': function('s:on_stderr'),
\ 'on_exit' : function('s:on_exit'),
\ }

" modify GOPATH if needed
let old_gopath = $GOPATH
let $GOPATH = go#path#Detect()

" execute go build in the files directory
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '

" cleanup previous jobs for this file
for jb in values(s:jobs)
if jb.importpath == job.importpath
unlet s:jobs[jb.id]
endif
endfor

let dir = getcwd()

execute cd . fnameescape(expand("%:p:h"))

" append the subcommand, such as 'build'
let argv = ['go'] + a:args

" run, forrest, run!
let id = jobstart(argv, job)
let job.id = id
let s:jobs[id] = job

execute cd . fnameescape(dir)

" restore back GOPATH
let $GOPATH = old_gopath

return job
endfunction

" on_exit is the exit handler for jobstart(). It handles cleaning up the job
" references and also displaying errors in the quickfix window collected by
" on_stderr handler. If there are no errors and a quickfix window is open,
" it'll be closed.
function! s:on_exit(job_id, data)
let std_combined = self.stderr + self.stdout
if empty(std_combined)
call go#list#Clean()
call go#list#Window()

let self.state = "SUCCESS"
return
endif

let errors = go#tool#ParseErrors(std_combined)
let errors = go#tool#FilterValids(errors)

if !len(errors)
" no errors could be past, just return
call go#list#Clean()
call go#list#Window()

let self.state = "SUCCESS"
return
endif

let self.state = "FAILED"

" if we are still in the same windows show the list
if self.winnr == winnr()
call go#list#Populate(errors)
call go#list#Window(len(errors))
call go#list#JumpToFirst()
endif
endfunction

" on_stdout is the stdout handler for jobstart(). It collects the output of
" stderr and stores them to the jobs internal stdout list.
function! s:on_stdout(job_id, data)
call extend(self.stdout, a:data)
endfunction

" on_stderr is the stderr handler for jobstart(). It collects the output of
" stderr and stores them to the jobs internal stderr list.
function! s:on_stderr(job_id, data)
call extend(self.stderr, a:data)
endfunction

" abort_all aborts all current jobs created with s:spawn()
function! s:abort_all()
if empty(s:jobs)
return
endif

for id in keys(s:jobs)
if id > 0
silent! call jobstop(id)
endif
endfor

let s:jobs = {}
endfunction

" abort aborts the job with the given name, where name is the first argument
" passed to s:spawn()
function! s:abort(path)
if empty(s:jobs)
return
endif

for job in values(s:jobs)
if job.importpath == path && job.id > 0
silent! call jobstop(job.id)
unlet s:jobs['job.id']
endif
endfor
endfunction

" vim:ts=2:sw=2:et
4 changes: 4 additions & 0 deletions autoload/go/list.vim
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ function! go#list#Populate(items)
call setloclist(0, a:items, 'r')
endfunction

function! go#list#PopulateWin(winnr, items)
call setloclist(a:winnr, a:items, 'r')
endfunction

" Parse parses the given items based on the specified errorformat nad
" populates the location list.
function! go#list#ParseFormat(errformat, items)
Expand Down
Loading