169 lines
4.2 KiB
VimL
169 lines
4.2 KiB
VimL
|
" 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
|