Skip to content

Commit

Permalink
Merge pull request #3179 from bhcleek/debug/connect
Browse files Browse the repository at this point in the history
debug: add :GoDebugConnect
  • Loading branch information
bhcleek authored Mar 20, 2021
2 parents 696613b + 458f9ef commit baaede2
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 85 deletions.
165 changes: 92 additions & 73 deletions autoload/go/debug.vim
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ function! go#debug#Stop() abort
endfor
command! -nargs=* -complete=customlist,go#package#Complete GoDebugStart call go#debug#Start('debug', <f-args>)
command! -nargs=* -complete=customlist,go#package#Complete GoDebugTest call go#debug#Start('test', <f-args>)
command! -nargs=? GoDebugConnect call go#debug#Start('connect', <f-args>)
command! -nargs=* GoDebugTestFunc call go#debug#TestFunc(<f-args>)
command! -nargs=1 GoDebugAttach call go#debug#Start('attach', <f-args>)
command! -nargs=? GoDebugBreakpoint call go#debug#Breakpoint(<f-args>)
Expand Down Expand Up @@ -507,7 +508,9 @@ function! s:start_cb() abort

silent! delcommand GoDebugStart
silent! delcommand GoDebugTest
silent! delcommand GoDebugTestFunc
silent! delcommand GoDebugAttach
silent! delcommand GoDebugConnect

command! -nargs=0 GoDebugContinue call go#debug#Stack('continue')
command! -nargs=0 GoDebugStop call go#debug#Stop()
Expand Down Expand Up @@ -575,44 +578,52 @@ function! s:out_cb(ch, msg) abort
let s:state['message'] += [a:msg]

if stridx(a:msg, go#config#DebugAddress()) != -1
let s:state['data'] = []
let l:state = {'databuf': ''}
call s:connect(go#config#DebugAddress())
endif
endfunction

" explicitly bind callback to state so that within it, self will
" always refer to state. See :help Partial for more information.
let l:state.on_data = function('s:on_data', [], l:state)
function! s:connect(addr) abort
let s:state['data'] = []
let l:state = {'databuf': ''}

if has('nvim')
let l:ch = sockconnect('tcp', go#config#DebugAddress(), {'on_data': l:state.on_data, 'state': l:state})
if l:ch == 0
call go#util#EchoError("could not connect to debugger")
" explicitly bind callback to state so that within it, self will
" always refer to state. See :help Partial for more information.
let l:state.on_data = function('s:on_data', [], l:state)

if has('nvim')
let l:ch = sockconnect('tcp', a:addr, {'on_data': l:state.on_data, 'state': l:state})
if l:ch == 0
call go#util#EchoError("could not connect to debugger")
if has_key(s:state, 'job')
call go#job#Stop(s:state['job'])
return
endif
else
let l:ch = ch_open(go#config#DebugAddress(), {'mode': 'raw', 'timeout': 20000, 'callback': l:state.on_data})
if ch_status(l:ch) !=# 'open'
call go#util#EchoError("could not connect to debugger")
return
endif
else
let l:ch = ch_open(a:addr, {'mode': 'raw', 'timeout': 20000, 'callback': l:state.on_data})
if ch_status(l:ch) !=# 'open'
call go#util#EchoError("could not connect to debugger")
if has_key(s:state, 'job')
call go#job#Stop(s:state['job'])
return
endif
return
endif
endif

let s:state['ch'] = l:ch
let s:state['ch'] = l:ch

" 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
" 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

" replace all the breakpoints set before delve started so that the ids won't overlap.
for l:bt in s:list_breakpoints()
call s:sign_unplace(l:bt.id, l:bt.file)
call go#debug#Breakpoint(l:bt.line, l:bt.file)
endfor
" replace all the breakpoints set before delve started so that the ids won't overlap.
for l:bt in s:list_breakpoints()
call s:sign_unplace(l:bt.id, l:bt.file)
call go#debug#Breakpoint(l:bt.line, l:bt.file)
endfor

call s:start_cb()
endif
call s:start_cb()
endfunction

" s:on_data's third optional argument is provided, but not used, so that the
Expand Down Expand Up @@ -750,56 +761,64 @@ function! go#debug#Start(mode, ...) abort
endif

try

let l:cmd = [dlv, a:mode]

let s:state['kill_on_detach'] = v:true
if a:mode is 'debug' || a:mode is 'test'
let l:cmd = extend(l:cmd, s:package(a:000))
let l:cmd = extend(l:cmd, ['--output', tempname()])
elseif a:mode is 'attach'
let l:cmd = add(l:cmd, a:1)
if a:mode is 'connect'
let l:addr = go#config#DebugAddress()
if len(a:0) > 0
let l:addr = a:1
endif
let s:state['kill_on_detach'] = v:false

call s:connect(l:addr)
else
call go#util#EchoError('Unknown dlv command')
endif
let l:cmd = [dlv, a:mode]

let s:state['kill_on_detach'] = v:true
if a:mode is 'debug' || a:mode is 'test'
let l:cmd = extend(l:cmd, s:package(a:000))
let l:cmd = extend(l:cmd, ['--output', tempname()])
elseif a:mode is 'attach'
let l:cmd = add(l:cmd, a:1)
let s:state['kill_on_detach'] = v:false
else
call go#util#EchoError('Unknown dlv command')
endif

let l:cmd += [
\ '--headless',
\ '--api-version', '2',
\ '--listen', go#config#DebugAddress(),
\]
let l:debugLogOutput = go#config#DebugLogOutput()
if l:debugLogOutput != ''
let cmd += ['--log', '--log-output', l:debugLogOutput]
endif
let l:cmd += [
\ '--headless',
\ '--api-version', '2',
\ '--listen', go#config#DebugAddress(),
\]
let l:debugLogOutput = go#config#DebugLogOutput()
if l:debugLogOutput != ''
let cmd += ['--log', '--log-output', l:debugLogOutput]
endif

let l:buildtags = go#config#BuildTags()
if buildtags isnot ''
let l:cmd += ['--build-flags', '--tags=' . buildtags]
endif
let l:buildtags = go#config#BuildTags()
if buildtags isnot ''
let l:cmd += ['--build-flags', '--tags=' . buildtags]
endif

if len(a:000) > 1
let l:cmd += ['--'] + a:000[1:]
endif
if len(a:000) > 1
let l:cmd += ['--'] + a:000[1:]
endif

let s:state['message'] = []
let l:opts = {
\ 'for': 'GoDebug',
\ '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)
let s:state['message'] = []
let l:opts = {
\ 'for': 'GoDebug',
\ '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)
return s:state['job']
endif
catch
call go#util#EchoError(printf('could not start debugger: %s', v:exception))
endtry

return s:state['job']
endfunction

" s:package returns the import path of package name of a :GoDebug(Start|Test)
Expand Down Expand Up @@ -1292,9 +1311,9 @@ function! go#debug#Restart() abort
endtry
endfunction

" Report if debugger mode is active.
function! s:isActive()
return len(s:state['message']) > 0
" Report if debugger mode is ready.
function! s:isReady()
return get(s:state, 'ready', 0) != 0
endfunction

" Change Goroutine
Expand Down Expand Up @@ -1346,13 +1365,13 @@ function! go#debug#Breakpoint(...) abort
" Remove breakpoint.
if type(l:found) == v:t_dict && !empty(l:found)
call s:sign_unplace(l:found.id, l:found.file)
if s:isActive()
if s:isReady()
let l:promise = go#promise#New(function('s:rpc_response'), 20000, {})
call s:call_jsonrpc(l:promise.wrapper, 'RPCServer.ClearBreakpoint', {'id': l:found.id})
let res = l:promise.await()
endif
else " Add breakpoint
if s:isActive()
if s:isReady()
let l:promise = go#promise#New(function('s:rpc_response'), 20000, {})
call s:call_jsonrpc(l:promise.wrapper, 'RPCServer.CreateBreakpoint', {'Breakpoint': {'file': l:filename, 'line': l:linenr}})
let l:res = l:promise.await()
Expand Down
35 changes: 23 additions & 12 deletions doc/vim-go.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2324,12 +2324,24 @@ the `dlv` process, or |:GoDebugRestart| to recompile the code.
*go-debug-commands*
DEBUGGER COMMANDS~

Only |:GoDebugAttach|, |:GoDebugStart|, |:GoDebugTest|, and
|:GoDebugBreakpoint| are available by default. |:GoDebugContinue| becomes
available after running |:GoDebugAttach|, |:GoDebugStart| or |:GoDebugTest|.
The rest of the commands and mappings become available after executing
Only the commands to start the client or toggle breakpoints are available by
default. |:GoDebugContinue| becomes available after starting the client. The
rest of the commands and mappings become available after executing
|:GoDebugContinue|.

*:GoDebugStart*
:GoDebugStart [pkg] [program-args]

Start the debug mode for [pkg]; this does several things:

* Setup the debug windows according to |'g:go_debug_windows'|.
* Make the `:GoDebug*` commands and `(go-debug-*)` mappings available.

The directory of the current buffer is used if [pkg] is empty. Any other
arguments will be passed to the program.

Use |:GoDebugStop| to stop `dlv` and exit debugging mode.

*:GoDebugAttach*
:GoDebugAttach pid

Expand All @@ -2340,18 +2352,17 @@ The rest of the commands and mappings become available after executing

Use |:GoDebugStop| to stop `dlv` and exit debugging mode.

*:GoDebugStart*
:GoDebugStart [pkg] [program-args]
*:GoDebugConnect*
:GoDebugConnect [addr]

Start the debug mode for [pkg]; this does several things:
Connect to a running instance of delve. If addr is not supplied, then
|'g:go_debug_address'| will be used.

* Setup the debug windows according to |'g:go_debug_windows'|.
* Make the `:GoDebug*` commands and `(go-debug-*)` mappings available.
The debug windows will be setup according to |'g:go_debug_windows'|, and the
`:GoDebug*` commands and `(go-debug-*)` mappings will be available.

The directory of the current buffer is used if [pkg] is empty. Any other
arguments will be passed to the program.
Use |:GoDebugStop| to exit debugging mode.

Use |:GoDebugStop| to stop `dlv` and exit debugging mode.

*:GoDebugTest*
:GoDebugTest [pkg] [program-args]
Expand Down
1 change: 1 addition & 0 deletions ftplugin/go/commands.vim
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ if !exists(':GoDebugStart')
command! -nargs=* -complete=customlist,go#package#Complete GoDebugTest call go#debug#Start('test', <f-args>)
command! -nargs=* GoDebugTestFunc call go#debug#TestFunc(<f-args>)
command! -nargs=1 GoDebugAttach call go#debug#Start('attach', <f-args>)
command! -nargs=? GoDebugConnect call go#debug#Start('connect', <f-args>)
command! -nargs=? GoDebugBreakpoint call go#debug#Breakpoint(<f-args>)
endif

Expand Down

0 comments on commit baaede2

Please sign in to comment.