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

debug: add :GoDebugConnect #3179

Merged
merged 2 commits into from
Mar 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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