summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2017-09-09 22:19:47 +0200
committerBram Moolenaar <Bram@vim.org>2017-09-09 22:19:47 +0200
commite09ba7bae5c867f6d3abc184709dd27488318e97 (patch)
tree8a512ae4bf2dd5d5b02feb8a6b3aed8f94e06d79
parent7be9b50fd7e238722c9ba5c0ef1d2a7e7e52b9e3 (diff)
downloadvim-git-e09ba7bae5c867f6d3abc184709dd27488318e97.tar.gz
patch 8.0.1085: terminal debugger can't set breakpointsv8.0.1085
Problem: The terminal debugger can't set breakpoints. Solution: Add :Break and :Delete commands. Also commands for stepping through code.
-rw-r--r--runtime/doc/terminal.txt95
-rw-r--r--runtime/pack/dist/opt/termdebug/plugin/termdebug.vim174
-rw-r--r--src/version.c2
3 files changed, 221 insertions, 50 deletions
diff --git a/runtime/doc/terminal.txt b/runtime/doc/terminal.txt
index 7be6927a0..3489142ce 100644
--- a/runtime/doc/terminal.txt
+++ b/runtime/doc/terminal.txt
@@ -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
+
+NOT WORKING YET: ~
-TODO
+Values of variables can be inspected, etc.
vim:tw=78:ts=8:ft=help:norl:
diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
index f69990b52..1ee887aa5 100644
--- a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
+++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
@@ -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
+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 debugPC term=reverse ctermbg=lightblue guibg=lightblue
+ hi default debugPC term=reverse ctermbg=lightblue guibg=lightblue
else
- hi debugPC term=reverse ctermbg=darkblue guibg=darkblue
+ hi default debugPC term=reverse ctermbg=darkblue guibg=darkblue
endif
-let s:pc_id = 12
+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,34 +115,124 @@ func s:CommOutput(chan, msg)
endif
if msg != ''
if msg =~ '^\*\(stopped\|running\)'
- 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 lnum =~ '^[0-9]*$'
- if expand('%:h') != fname
- if &modified
- " TODO: find existing window
- exe 'split ' . fnameescape(fname)
- let s:startwin = win_getid(winnr())
- else
- exe 'edit ' . fnameescape(fname)
- endif
- endif
- exe lnum
- exe 'sign place ' . s:pc_id . ' line=' . lnum . ' name=debugPC file=' . fnameescape(fname)
- setlocal signcolumn=yes
- endif
+ 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 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
+ " TODO: find existing window
+ exe 'split ' . fnameescape(fname)
+ let s:startwin = win_getid(winnr())
else
- exe 'sign unplace ' . s:pc_id
+ exe 'edit ' . fnameescape(fname)
endif
-
- call win_gotoid(wid)
endif
+ exe lnum
+ exe 'sign place ' . s:pc_id . ' line=' . lnum . ' name=debugPC file=' . fnameescape(fname)
+ setlocal signcolumn=yes
endif
+ else
+ exe 'sign unplace ' . s:pc_id
endif
- endfor
+
+ call win_gotoid(wid)
+ endif
+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
diff --git a/src/version.c b/src/version.c
index acf6e29d8..cb5963424 100644
--- a/src/version.c
+++ b/src/version.c
@@ -770,6 +770,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1085,
+/**/
1084,
/**/
1083,