forked from aniani/vim
patch 8.0.1085: terminal debugger can't set breakpoints
Problem: The terminal debugger can't set breakpoints. Solution: Add :Break and :Delete commands. Also commands for stepping through code.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
*terminal.txt* For Vim version 8.0. Last change: 2017 Aug 29
|
||||
*terminal.txt* For Vim version 8.0. Last change: 2017 Sep 09
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -30,11 +30,11 @@ This feature is for running a terminal emulator in a Vim window. A job can be
|
||||
started connected to the terminal emulator. For example, to run a shell: >
|
||||
:term bash
|
||||
|
||||
Or to run a debugger: >
|
||||
:term gdb vim
|
||||
Or to run build command: >
|
||||
:term make myprogram
|
||||
|
||||
The job runs asynchronously from Vim, the window will be updated to show
|
||||
output from the job, also while editing in any other window.
|
||||
output from the job, also while editing in another window.
|
||||
|
||||
|
||||
Typing ~
|
||||
@@ -109,7 +109,8 @@ Syntax ~
|
||||
|
||||
If [range] is given the specified lines are used as
|
||||
input for the job. It will not be possible to type
|
||||
keys in the terminal window.
|
||||
keys in the terminal window. For MS-Windows see the
|
||||
++eof argument below.
|
||||
|
||||
Two comma separated numbers are used as "rows,cols".
|
||||
E.g. `:24,80gdb` opens a terminal with 24 rows and 80
|
||||
@@ -133,14 +134,15 @@ Syntax ~
|
||||
height.
|
||||
++cols={width} Use {width} for the terminal window
|
||||
width.
|
||||
++eof={text} when using [range], text to send after
|
||||
the last line was written. The default
|
||||
is to send CTRL-D. A CR is appended.
|
||||
++eof={text} when using [range]: text to send after
|
||||
the last line was written. Cannot
|
||||
contain white space. A CR is
|
||||
appended. For MS-Windows the default
|
||||
is to send CTRL-D.
|
||||
E.g. for a shell use "++eof=exit" and
|
||||
for Python "++eof=exit()". Special
|
||||
codes can be used like with `:map`,
|
||||
e.g. "<C-Z>" for CTRL-Z.
|
||||
{only on MS-Windows}
|
||||
|
||||
If you want to use more options use the |term_start()|
|
||||
function.
|
||||
@@ -303,33 +305,90 @@ term_scrape() inspect terminal screen
|
||||
3. Debugging *terminal-debug*
|
||||
|
||||
The Terminal debugging plugin can be used to debug a program with gdb and view
|
||||
the source code in a Vim window.
|
||||
the source code in a Vim window. Since this is completely contained inside
|
||||
Vim this also works remotely over an ssh connection.
|
||||
|
||||
|
||||
Starting ~
|
||||
|
||||
Load the plugin with this command: >
|
||||
packadd termdebug
|
||||
|
||||
< *:Termdebug*
|
||||
To start debugging use `:TermDebug` folowed by the command name, for example: >
|
||||
:TermDebug vim
|
||||
|
||||
This opens two windows:
|
||||
- A terminal window in which "gdb vim" is executed. Here you can directly
|
||||
interact with gdb.
|
||||
interact with gdb. The buffer name is "!gdb".
|
||||
- A terminal window for the executed program. When "run" is used in gdb the
|
||||
program I/O will happen in this window, so that it does not interfere with
|
||||
controlling gdb.
|
||||
The current window is used to show the source code. When gdb jumps to a
|
||||
source file location this window will display the code, if possible. Values
|
||||
of variables can be inspected, breakpoints set and cleared, etc.
|
||||
controlling gdb. The buffer name is "gdb program".
|
||||
|
||||
The current window is used to show the source code. When gdb pauses the
|
||||
source file location will be displayed, if possible. A sign is used to
|
||||
highlight the current position (using highlight group debugPC).
|
||||
|
||||
If the buffer in the current window is modified, another window will be opened
|
||||
to display the current gdb position.
|
||||
|
||||
Focus the terminal of the executed program to interact with it. This works
|
||||
the same as any command running in a terminal window.
|
||||
|
||||
When the debugger ends the two opened windows are closed.
|
||||
|
||||
|
||||
Stepping through code ~
|
||||
|
||||
Put focus on the gdb window to type commands there. Some common ones are:
|
||||
- CTRL-C interrupt the program
|
||||
- next execute the current line and stop at the next line
|
||||
- step execute the current line and stop at the next statement, entering
|
||||
functions
|
||||
- finish execute until leaving the current function
|
||||
- where show the stack
|
||||
- frame N go to the Nth stack frame
|
||||
- continue continue execution
|
||||
|
||||
In the window showing the source code some commands can passed to gdb:
|
||||
- Break set a breakpoint at the current line; a sign will be displayed
|
||||
- Delete delete a breakpoint at the current line
|
||||
- Step execute the gdb "step" command
|
||||
- NNext execute the gdb "next" command (:Next is a Vim command)
|
||||
- Finish execute the gdb "finish" command
|
||||
- Continue execute the gdb "continue" command
|
||||
|
||||
|
||||
Communication ~
|
||||
|
||||
There is another, hidden, buffer, which is used for Vim to communicate with
|
||||
gdb. The buffer name is "gdb communication". Do not delete this buffer, it
|
||||
will break the debugger.
|
||||
|
||||
|
||||
Customizing ~
|
||||
|
||||
g:debugger The debugger command. Default "gdb".
|
||||
To change the name of the gdb command, set the "termdebugger" variable before
|
||||
invoking `:Termdebug`: >
|
||||
let termdebugger = "mygdb"
|
||||
Only debuggers fully compatible with gdb will work. Vim uses the GDB/MI
|
||||
interface.
|
||||
|
||||
The color of the signs can be adjusted with these highlight groups:
|
||||
- debugPC the current position
|
||||
- debugBreakpoint a breakpoint
|
||||
|
||||
The defaults are, when 'background' is "light":
|
||||
hi debugPC term=reverse ctermbg=lightblue guibg=lightblue
|
||||
hi debugBreakpoint term=reverse ctermbg=red guibg=red
|
||||
|
||||
When 'background' is "dark":
|
||||
hi debugPC term=reverse ctermbg=darkblue guibg=darkblue
|
||||
hi debugBreakpoint term=reverse ctermbg=red guibg=red
|
||||
|
||||
|
||||
TODO
|
||||
NOT WORKING YET: ~
|
||||
|
||||
Values of variables can be inspected, etc.
|
||||
|
||||
|
||||
vim:tw=78:ts=8:ft=help:norl:
|
||||
|
142
runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
vendored
142
runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
vendored
@@ -20,18 +20,26 @@
|
||||
command -nargs=* -complete=file Termdebug call s:StartDebug(<q-args>)
|
||||
|
||||
" Name of the gdb command, defaults to "gdb".
|
||||
if !exists('debugger')
|
||||
let debugger = 'gdb'
|
||||
if !exists('termdebugger')
|
||||
let termdebugger = 'gdb'
|
||||
endif
|
||||
|
||||
" Sign used to highlight the line where the program has stopped.
|
||||
" There can be only one.
|
||||
sign define debugPC linehl=debugPC
|
||||
if &background == 'light'
|
||||
hi debugPC term=reverse ctermbg=lightblue guibg=lightblue
|
||||
else
|
||||
hi debugPC term=reverse ctermbg=darkblue guibg=darkblue
|
||||
endif
|
||||
let s:pc_id = 12
|
||||
let s:break_id = 13
|
||||
|
||||
" Sign used to indicate a breakpoint.
|
||||
" Can be used multiple times.
|
||||
sign define debugBreakpoint text=>> texthl=debugBreakpoint
|
||||
|
||||
if &background == 'light'
|
||||
hi default debugPC term=reverse ctermbg=lightblue guibg=lightblue
|
||||
else
|
||||
hi default debugPC term=reverse ctermbg=darkblue guibg=darkblue
|
||||
endif
|
||||
hi default debugBreakpoint term=reverse ctermbg=red guibg=red
|
||||
|
||||
func s:StartDebug(cmd)
|
||||
let s:startwin = win_getid(winnr())
|
||||
@@ -61,7 +69,7 @@ func s:StartDebug(cmd)
|
||||
let commpty = job_info(term_getjob(s:commbuf))['tty_out']
|
||||
|
||||
" Open a terminal window to run the debugger.
|
||||
let cmd = [g:debugger, '-tty', pty, a:cmd]
|
||||
let cmd = [g:termdebugger, '-tty', pty, a:cmd]
|
||||
echomsg 'executing "' . join(cmd) . '"'
|
||||
let gdbbuf = term_start(cmd, {
|
||||
\ 'exit_cb': function('s:EndDebug'),
|
||||
@@ -76,12 +84,24 @@ func s:StartDebug(cmd)
|
||||
|
||||
" Connect gdb to the communication pty, using the GDB/MI interface
|
||||
call term_sendkeys(gdbbuf, 'new-ui mi ' . commpty . "\r")
|
||||
|
||||
" Install debugger commands.
|
||||
call s:InstallCommands()
|
||||
|
||||
let s:breakpoints = {}
|
||||
endfunc
|
||||
|
||||
func s:EndDebug(job, status)
|
||||
exe 'bwipe! ' . s:ptybuf
|
||||
exe 'bwipe! ' . s:commbuf
|
||||
call setwinvar(s:startwin, '&signcolumn', s:startsigncolumn)
|
||||
|
||||
let curwinid = win_getid(winnr())
|
||||
|
||||
call win_gotoid(s:startwin)
|
||||
let &signcolumn = s:startsigncolumn
|
||||
call s:DeleteCommands()
|
||||
|
||||
call win_gotoid(curwinid)
|
||||
endfunc
|
||||
|
||||
" Handle a message received from gdb on the GDB/MI interface.
|
||||
@@ -95,13 +115,71 @@ func s:CommOutput(chan, msg)
|
||||
endif
|
||||
if msg != ''
|
||||
if msg =~ '^\*\(stopped\|running\)'
|
||||
call s:HandleCursor(msg)
|
||||
elseif msg =~ '^\^done,bkpt='
|
||||
call s:HandleNewBreakpoint(msg)
|
||||
elseif msg =~ '^=breakpoint-deleted,'
|
||||
call s:HandleBreakpointDelete(msg)
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
endfunc
|
||||
|
||||
" Install commands in the current window to control the debugger.
|
||||
func s:InstallCommands()
|
||||
command Break call s:SetBreakpoint()
|
||||
command Delete call s:DeleteBreakpoint()
|
||||
command Step call s:SendCommand('-exec-step')
|
||||
command NNext call s:SendCommand('-exec-next')
|
||||
command Finish call s:SendCommand('-exec-finish')
|
||||
command Continue call s:SendCommand('-exec-continue')
|
||||
endfunc
|
||||
|
||||
" Delete installed debugger commands in the current window.
|
||||
func s:DeleteCommands()
|
||||
delcommand Break
|
||||
delcommand Delete
|
||||
delcommand Step
|
||||
delcommand NNext
|
||||
delcommand Finish
|
||||
delcommand Continue
|
||||
endfunc
|
||||
|
||||
" :Break - Set a breakpoint at the cursor position.
|
||||
func s:SetBreakpoint()
|
||||
call term_sendkeys(s:commbuf, '-break-insert --source '
|
||||
\ . fnameescape(expand('%:p')) . ' --line ' . line('.') . "\r")
|
||||
endfunc
|
||||
|
||||
" :Delete - Delete a breakpoint at the cursor position.
|
||||
func s:DeleteBreakpoint()
|
||||
let fname = fnameescape(expand('%:p'))
|
||||
let lnum = line('.')
|
||||
for [key, val] in items(s:breakpoints)
|
||||
if val['fname'] == fname && val['lnum'] == lnum
|
||||
call term_sendkeys(s:commbuf, '-break-delete ' . key . "\r")
|
||||
" Assume this always wors, the reply is simply "^done".
|
||||
exe 'sign unplace ' . (s:break_id + key)
|
||||
unlet s:breakpoints[key]
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
endfunc
|
||||
|
||||
" :Next, :Continue, etc - send a command to gdb
|
||||
func s:SendCommand(cmd)
|
||||
call term_sendkeys(s:commbuf, a:cmd . "\r")
|
||||
endfunc
|
||||
|
||||
" Handle stopping and running message from gdb.
|
||||
" Will update the sign that shows the current position.
|
||||
func s:HandleCursor(msg)
|
||||
let wid = win_getid(winnr())
|
||||
|
||||
if win_gotoid(s:startwin)
|
||||
if msg =~ '^\*stopped'
|
||||
" TODO: proper parsing
|
||||
let fname = substitute(msg, '.*fullname="\([^"]*\)".*', '\1', '')
|
||||
let lnum = substitute(msg, '.*line="\([^"]*\)".*', '\1', '')
|
||||
if a:msg =~ '^\*stopped'
|
||||
let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '')
|
||||
let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '')
|
||||
if lnum =~ '^[0-9]*$'
|
||||
if expand('%:h') != fname
|
||||
if &modified
|
||||
@@ -122,7 +200,39 @@ func s:CommOutput(chan, msg)
|
||||
|
||||
call win_gotoid(wid)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
endfunc
|
||||
|
||||
" Handle setting a breakpoint
|
||||
" Will update the sign that shows the breakpoint
|
||||
func s:HandleNewBreakpoint(msg)
|
||||
let nr = substitute(a:msg, '.*number="\([0-9]\)*\".*', '\1', '') + 0
|
||||
if nr == 0
|
||||
return
|
||||
endif
|
||||
|
||||
if has_key(s:breakpoints, nr)
|
||||
let entry = s:breakpoints[nr]
|
||||
else
|
||||
let entry = {}
|
||||
let s:breakpoints[nr] = entry
|
||||
endif
|
||||
|
||||
let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '')
|
||||
let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '')
|
||||
|
||||
exe 'sign place ' . (s:break_id + nr) . ' line=' . lnum . ' name=debugBreakpoint file=' . fnameescape(fname)
|
||||
|
||||
let entry['fname'] = fname
|
||||
let entry['lnum'] = lnum
|
||||
endfunc
|
||||
|
||||
" Handle deleting a breakpoint
|
||||
" Will remove the sign that shows the breakpoint
|
||||
func s:HandleBreakpointDelete(msg)
|
||||
let nr = substitute(a:msg, '.*id="\([0-9]*\)\".*', '\1', '') + 0
|
||||
if nr == 0
|
||||
return
|
||||
endif
|
||||
exe 'sign unplace ' . (s:break_id + nr)
|
||||
unlet s:breakpoints[nr]
|
||||
endfunc
|
||||
|
@@ -769,6 +769,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1085,
|
||||
/**/
|
||||
1084,
|
||||
/**/
|
||||
|
Reference in New Issue
Block a user