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 | 		  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: > | started connected to the terminal emulator. For example, to run a shell: > | ||||||
|      :term bash |      :term bash | ||||||
|  |  | ||||||
| Or to run a debugger: > | Or to run build command: > | ||||||
|      :term gdb vim |      :term make myprogram | ||||||
|  |  | ||||||
| The job runs asynchronously from Vim, the window will be updated to show | 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 ~ | Typing ~ | ||||||
| @ -109,7 +109,8 @@ Syntax ~ | |||||||
|  |  | ||||||
| 			If [range] is given the specified lines are used as | 			If [range] is given the specified lines are used as | ||||||
| 			input for the job.  It will not be possible to type | 			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". | 			Two comma separated numbers are used as "rows,cols". | ||||||
| 			E.g. `:24,80gdb` opens a terminal with 24 rows and 80 | 			E.g. `:24,80gdb` opens a terminal with 24 rows and 80 | ||||||
| @ -133,14 +134,15 @@ Syntax ~ | |||||||
| 					height. | 					height. | ||||||
| 			++cols={width}  Use {width} for the terminal window | 			++cols={width}  Use {width} for the terminal window | ||||||
| 					width. | 					width. | ||||||
| 			++eof={text}	when using [range], text to send after | 			++eof={text}	when using [range]: text to send after | ||||||
| 					the last line was written. The default | 					the last line was written. Cannot | ||||||
| 					is to send CTRL-D.  A CR is appended. | 					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 | 					E.g. for a shell use "++eof=exit" and | ||||||
| 					for Python "++eof=exit()".  Special | 					for Python "++eof=exit()".  Special | ||||||
| 					codes can be used like with `:map`, | 					codes can be used like with `:map`, | ||||||
| 					e.g. "<C-Z>" for CTRL-Z. | 					e.g. "<C-Z>" for CTRL-Z. | ||||||
| 					{only on MS-Windows} |  | ||||||
|  |  | ||||||
| 			If you want to use more options use the |term_start()| | 			If you want to use more options use the |term_start()| | ||||||
| 			function. | 			function. | ||||||
| @ -303,33 +305,90 @@ term_scrape()		inspect terminal screen | |||||||
| 3. Debugging					*terminal-debug* | 3. Debugging					*terminal-debug* | ||||||
|  |  | ||||||
| The Terminal debugging plugin can be used to debug a program with gdb and view | 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: > | Load the plugin with this command: > | ||||||
| 	packadd termdebug | 	packadd termdebug | ||||||
|  | <							*:Termdebug* | ||||||
| To start debugging use `:TermDebug` folowed by the command name, for example: > | To start debugging use `:TermDebug` folowed by the command name, for example: > | ||||||
| 	:TermDebug vim | 	:TermDebug vim | ||||||
|  |  | ||||||
| This opens two windows: | This opens two windows: | ||||||
| - A terminal window in which "gdb vim" is executed.  Here you can directly | - 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 | - 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 |   program I/O will happen in this window, so that it does not interfere with | ||||||
|   controlling gdb. |   controlling gdb.  The buffer name is "gdb program". | ||||||
| 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 | The current window is used to show the source code.  When gdb pauses the | ||||||
| of variables can be inspected, breakpoints set and cleared, etc. | 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. | 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 ~ | 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: |  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>) | command -nargs=* -complete=file Termdebug call s:StartDebug(<q-args>) | ||||||
|  |  | ||||||
| " Name of the gdb command, defaults to "gdb". | " Name of the gdb command, defaults to "gdb". | ||||||
| if !exists('debugger') | if !exists('termdebugger') | ||||||
|   let debugger = 'gdb' |   let termdebugger = 'gdb' | ||||||
| endif | endif | ||||||
|  |  | ||||||
| " Sign used to highlight the line where the program has stopped. | " Sign used to highlight the line where the program has stopped. | ||||||
|  | " There can be only one. | ||||||
| sign define debugPC linehl=debugPC | 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: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) | func s:StartDebug(cmd) | ||||||
|   let s:startwin = win_getid(winnr()) |   let s:startwin = win_getid(winnr()) | ||||||
| @ -61,7 +69,7 @@ func s:StartDebug(cmd) | |||||||
|   let commpty = job_info(term_getjob(s:commbuf))['tty_out'] |   let commpty = job_info(term_getjob(s:commbuf))['tty_out'] | ||||||
|  |  | ||||||
|   " Open a terminal window to run the debugger. |   " 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) . '"' |   echomsg 'executing "' . join(cmd) . '"' | ||||||
|   let gdbbuf = term_start(cmd, { |   let gdbbuf = term_start(cmd, { | ||||||
| 	\ 'exit_cb': function('s:EndDebug'), | 	\ 'exit_cb': function('s:EndDebug'), | ||||||
| @ -76,12 +84,24 @@ func s:StartDebug(cmd) | |||||||
|  |  | ||||||
|   " Connect gdb to the communication pty, using the GDB/MI interface |   " Connect gdb to the communication pty, using the GDB/MI interface | ||||||
|   call term_sendkeys(gdbbuf, 'new-ui mi ' . commpty . "\r") |   call term_sendkeys(gdbbuf, 'new-ui mi ' . commpty . "\r") | ||||||
|  |  | ||||||
|  |   " Install debugger commands. | ||||||
|  |   call s:InstallCommands() | ||||||
|  |  | ||||||
|  |   let s:breakpoints = {} | ||||||
| endfunc | endfunc | ||||||
|  |  | ||||||
| func s:EndDebug(job, status) | func s:EndDebug(job, status) | ||||||
|   exe 'bwipe! ' . s:ptybuf |   exe 'bwipe! ' . s:ptybuf | ||||||
|   exe 'bwipe! ' . s:commbuf |   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 | endfunc | ||||||
|  |  | ||||||
| " Handle a message received from gdb on the GDB/MI interface. | " Handle a message received from gdb on the GDB/MI interface. | ||||||
| @ -95,13 +115,71 @@ func s:CommOutput(chan, msg) | |||||||
|     endif |     endif | ||||||
|     if msg != '' |     if msg != '' | ||||||
|       if msg =~ '^\*\(stopped\|running\)' |       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()) |   let wid = win_getid(winnr()) | ||||||
|  |  | ||||||
|   if win_gotoid(s:startwin) |   if win_gotoid(s:startwin) | ||||||
| 	  if msg =~ '^\*stopped' |     if a:msg =~ '^\*stopped' | ||||||
| 	    " TODO: proper parsing |       let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '') | ||||||
| 	    let fname = substitute(msg, '.*fullname="\([^"]*\)".*', '\1', '') |       let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '') | ||||||
| 	    let lnum = substitute(msg, '.*line="\([^"]*\)".*', '\1', '') |  | ||||||
|       if lnum =~ '^[0-9]*$' |       if lnum =~ '^[0-9]*$' | ||||||
| 	if expand('%:h') != fname | 	if expand('%:h') != fname | ||||||
| 	  if &modified | 	  if &modified | ||||||
| @ -122,7 +200,39 @@ func s:CommOutput(chan, msg) | |||||||
|  |  | ||||||
|     call win_gotoid(wid) |     call win_gotoid(wid) | ||||||
|   endif |   endif | ||||||
|       endif | endfunc | ||||||
|     endif |  | ||||||
|   endfor | " 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 | endfunc | ||||||
|  | |||||||
| @ -769,6 +769,8 @@ static char *(features[]) = | |||||||
|  |  | ||||||
| static int included_patches[] = | static int included_patches[] = | ||||||
| {   /* Add new patch number below this line */ | {   /* Add new patch number below this line */ | ||||||
|  | /**/ | ||||||
|  |     1085, | ||||||
| /**/ | /**/ | ||||||
|     1084, |     1084, | ||||||
| /**/ | /**/ | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user