diff runtime/pack/dist/opt/termdebug/plugin/termdebug.vim @ 12411:5d4d744151c2 v8.0.1085

patch 8.0.1085: terminal debugger can't set breakpoints commit https://github.com/vim/vim/commit/e09ba7bae5c867f6d3abc184709dd27488318e97 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Sep 9 22:19:47 2017 +0200 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.
author Christian Brabandt <cb@256bit.org>
date Sat, 09 Sep 2017 22:30:04 +0200
parents 39e1087e7094
children 29d21591ad6b
line wrap: on
line diff
--- 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
-	  else
-	    exe 'sign unplace ' . s:pc_id
-	  endif
-
-	  call win_gotoid(wid)
-	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 'edit ' . fnameescape(fname)
+	  endif
+	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
+
+    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