Skip to content

Commit

Permalink
Merge pull request #2007 from bhcleek/debug-async
Browse files Browse the repository at this point in the history
add debugger support to Neovim
  • Loading branch information
bhcleek authored Oct 10, 2018
2 parents d5e08f0 + 8af4ee9 commit 79215e5
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 33 deletions.
104 changes: 75 additions & 29 deletions autoload/go/debug.vim
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ function! s:complete(job, exit_status, data) abort
if has_key(s:state, 'job')
call remove(s:state, 'job')
endif

if has_key(s:state, 'ready')
call remove(s:state, 'ready')
endif

call s:clearState()
if a:exit_status > 0
call go#util#EchoError(s:state['message'])
Expand Down Expand Up @@ -66,7 +71,6 @@ function! s:call_jsonrpc(method, ...) abort
let Cb = a:000[0]
let args = a:000[1:]
else
let Cb = v:none
let args = a:000
endif
let s:state['rpcid'] += 1
Expand All @@ -78,9 +82,26 @@ function! s:call_jsonrpc(method, ...) abort

try
" Use callback
if type(Cb) == v:t_func
let s:ch = ch_open('127.0.0.1:8181', {'mode': 'nl', 'callback': Cb})
call ch_sendraw(s:ch, req_json)
if exists('l:Cb')
if has('nvim')
let state = {'callback': Cb}
function! state.on_data(ch, msg, event) abort
call self.state.callback(a:ch, a:msg)
endfunction
let l:ch = sockconnect('tcp', go#config#DebugAddress(), {'on_data': state.on_data, 'state': state})
call chansend(l:ch, req_json)

if go#util#HasDebug('debugger-commands')
let g:go_debug_commands = add(g:go_debug_commands, {
\ 'request': req_json,
\ 'response': Cb,
\ })
endif
return
endif

let l:ch = ch_open(go#config#DebugAddress(), {'mode': 'nl', 'callback': Cb})
call ch_sendraw(l:ch, req_json)

if go#util#HasDebug('debugger-commands')
let g:go_debug_commands = add(g:go_debug_commands, {
Expand All @@ -91,9 +112,23 @@ function! s:call_jsonrpc(method, ...) abort
return
endif

let ch = ch_open('127.0.0.1:8181', {'mode': 'nl', 'timeout': 20000})
call ch_sendraw(ch, req_json)
let resp_json = ch_readraw(ch)
if has('nvim')
let state = {'done': 0}
function! state.on_data(ch, msg, event) abort
let self.resp = a:msg
let self.done = 1
endfunction
let l:ch = sockconnect('tcp', go#config#DebugAddress(), {'on_data': state.on_data, 'state': state})
call chansend(l:ch, req_json)
while state.done == 0
sleep 50m
endwhile
let resp_json = state.resp
else
let ch = ch_open(go#config#DebugAddress(), {'mode': 'raw', 'timeout': 20000})
call ch_sendraw(ch, req_json)
let resp_json = ch_readraw(ch)
endif

if go#util#HasDebug('debugger-commands')
let g:go_debug_commands = add(g:go_debug_commands, {
Expand Down Expand Up @@ -218,9 +253,14 @@ endfunction
function! s:stop() abort
call s:clearState()
if has_key(s:state, 'job')
call job_stop(s:state['job'])
" TODO(bc): call Detach
call go#job#Stop(s:state['job'])
call remove(s:state, 'job')
endif

if has_key(s:state, 'ready')
call remove(s:state, 'ready')
endif
endfunction

function! go#debug#Stop() abort
Expand Down Expand Up @@ -257,8 +297,10 @@ function! go#debug#Stop() abort
silent! exe bufwinnr(bufnr('__GODEBUG_VARIABLES__')) 'wincmd c'
silent! exe bufwinnr(bufnr('__GODEBUG_OUTPUT__')) 'wincmd c'

set noballooneval
set balloonexpr=
if !has('balloon_eval')
set noballooneval
set balloonexpr=
endif

augroup vim-go-debug
autocmd!
Expand Down Expand Up @@ -453,8 +495,10 @@ function! s:start_cb(ch, json) abort
nnoremap <silent> <Plug>(go-debug-stop) :<C-u>call go#debug#Stop()<CR>
nnoremap <silent> <Plug>(go-debug-print) :<C-u>call go#debug#Print(expand('<cword>'))<CR>
set balloonexpr=go#debug#BalloonExpr()
set ballooneval
if has('balloon_eval')
set balloonexpr=go#debug#BalloonExpr()
set ballooneval
endif

exe bufwinnr(oldbuf) 'wincmd w'

Expand All @@ -470,20 +514,29 @@ function! s:start_cb(ch, json) abort
endfunction

function! s:err_cb(ch, msg) abort
if get(s:state, 'ready', 0) != 0
call call('s:logger', ['ERR: ', a:ch, a:msg])
return
endif

call go#util#EchoError(a:msg)
let s:state['message'] += [a:msg]
endfunction

function! s:out_cb(ch, msg) abort
if get(s:state, 'ready', 0) != 0
call call('s:logger', ['OUT: ', a:ch, a:msg])
return
endif

call go#util#EchoProgress(a:msg)
let s:state['message'] += [a:msg]

" TODO: why do this in this callback?
if stridx(a:msg, go#config#DebugAddress()) != -1
call ch_setoptions(a:ch, {
\ 'out_cb': function('s:logger', ['OUT: ']),
\ 'err_cb': function('s:logger', ['ERR: ']),
\})
" After this block executes, Delve will be running with all the
" breakpoints setup, so this callback doesn't have to run again; just log
" future messages.
let s:state['ready'] = 1

" Tell dlv about the breakpoints that the user added before delve started.
let l:breaks = copy(s:state.breakpoint)
Expand All @@ -501,17 +554,13 @@ endfunction
function! go#debug#Start(is_test, ...) abort
call go#cmd#autowrite()

if has('nvim')
call go#util#EchoError('This feature only works in Vim for now; Neovim is not (yet) supported. Sorry :-(')
return
endif
if !go#util#has_job()
call go#util#EchoError('This feature requires Vim 8.0.0087 or newer with +job.')
call go#util#EchoError('This feature requires either Vim 8.0.0087 or newer with +job or Neovim.')
return
endif

" It's already running.
if has_key(s:state, 'job') && job_status(s:state['job']) == 'run'
if has_key(s:state, 'job')
return
endif

Expand Down Expand Up @@ -807,10 +856,7 @@ function! go#debug#Restart() abort
call go#cmd#autowrite()

try
call job_stop(s:state['job'])
while has_key(s:state, 'job') && job_status(s:state['job']) is# 'run'
sleep 50m
endwhile
call go#job#Stop(s:state['job'])

let l:breaks = s:state['breakpoint']
let s:state = {
Expand Down Expand Up @@ -857,7 +903,7 @@ function! go#debug#Breakpoint(...) abort

try
" Check if we already have a breakpoint for this line.
let found = v:none
let found = {}
for k in keys(s:state.breakpoint)
let bt = s:state.breakpoint[k]
if bt.file == l:filename && bt.line == linenr
Expand All @@ -867,7 +913,7 @@ function! go#debug#Breakpoint(...) abort
endfor

" Remove breakpoint.
if type(found) == v:t_dict
if type(found) == v:t_dict && !empty(found)
call remove(s:state['breakpoint'], bt.id)
exe 'sign unplace '. found.id .' file=' . found.file
if s:isActive()
Expand Down
23 changes: 23 additions & 0 deletions autoload/go/job.vim
Original file line number Diff line number Diff line change
Expand Up @@ -505,4 +505,27 @@ function! s:neooptions(options)
return l:options
endfunction

function! go#job#Stop(job) abort
if has('nvim')
call jobstop(a:job)
return
endif

call job_stop(a:job)
call go#job#Wait(a:job)
return
endfunction

function! go#job#Wait(job) abort
if has('nvim')
call jobwait(a:job)
return
endif

while job_status(a:job) is# 'run'
sleep 50m
endwhile

endfunction

" vim: sw=2 ts=2 et
8 changes: 4 additions & 4 deletions doc/vim-go.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1924,10 +1924,10 @@ features:
* Toggle breakpoint.
* Stack operation continue/next/step out.

This feature requires Vim 8.0.0087 or newer with the |+job| feature. Neovim
does _not_ work (yet).
This requires Delve 1.0.0 or newer, and it is recommended to use Go 1.10 or
newer, as its new caching will speed up recompiles.
This feature requires either Vim 8.0.0087 or newer with the |+job| feature or
Neovim. This features also requires Delve 1.0.0 or newer, and it is
recommended to use Go 1.10 or newer, as its new caching will speed up
recompiles.

*go-debug-intro*
GETTING STARTED WITH THE DEBUGGER~
Expand Down

0 comments on commit 79215e5

Please sign in to comment.