view runtime/pack/dist/opt/termdebug/plugin/termdebug.vim @ 12395:39e1087e7094 v8.0.1077

patch 8.0.1077: no debugger making use of the terminal window commit https://github.com/vim/vim/commit/fe386641b0c56c5de2bca8e1f4cd5e2a1f1aea7e Author: Bram Moolenaar <Bram@vim.org> Date: Fri Sep 8 21:10:04 2017 +0200 patch 8.0.1077: no debugger making use of the terminal window Problem: No debugger making use of the terminal window. Solution: Add the term debugger plugin. So far only displays the current line when stopped.
author Christian Brabandt <cb@256bit.org>
date Fri, 08 Sep 2017 21:15:05 +0200
parents 8d76a56861ec
children 5d4d744151c2
line wrap: on
line source

" Debugger plugin using gdb.
"
" WORK IN PROGRESS - much doesn't work yet
"
" Open two visible terminal windows:
" 1. run a pty, as with ":term NONE"
" 2. run gdb, passing the pty
" The current window is used to view source code and follows gdb.
"
" A third terminal window is hidden, it is used for communication with gdb.
"
" The communication with gdb uses GDB/MI.  See:
" https://sourceware.org/gdb/current/onlinedocs/gdb/GDB_002fMI.html
"
" Author: Bram Moolenaar
" Copyright: Vim license applies, see ":help license"

" The command that starts debugging, e.g. ":Termdebug vim".
" To end type "quit" in the gdb window.
command -nargs=* -complete=file Termdebug call s:StartDebug(<q-args>)

" Name of the gdb command, defaults to "gdb".
if !exists('debugger')
  let debugger = 'gdb'
endif

" Sign used to highlight the line where the program has stopped.
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

func s:StartDebug(cmd)
  let s:startwin = win_getid(winnr())
  let s:startsigncolumn = &signcolumn

  " Open a terminal window without a job, to run the debugged program
  let s:ptybuf = term_start('NONE', {
	\ 'term_name': 'gdb program',
	\ })
  if s:ptybuf == 0
    echoerr 'Failed to open the program terminal window'
    return
  endif
  let pty = job_info(term_getjob(s:ptybuf))['tty_out']

  " Create a hidden terminal window to communicate with gdb
  let s:commbuf = term_start('NONE', {
	\ 'term_name': 'gdb communication',
	\ 'out_cb': function('s:CommOutput'),
	\ 'hidden': 1,
	\ })
  if s:commbuf == 0
    echoerr 'Failed to open the communication terminal window'
    exe 'bwipe! ' . s:ptybuf
    return
  endif
  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]
  echomsg 'executing "' . join(cmd) . '"'
  let gdbbuf = term_start(cmd, {
	\ 'exit_cb': function('s:EndDebug'),
	\ 'term_finish': 'close',
	\ })
  if gdbbuf == 0
    echoerr 'Failed to open the gdb terminal window'
    exe 'bwipe! ' . s:ptybuf
    exe 'bwipe! ' . s:commbuf
    return
  endif

  " Connect gdb to the communication pty, using the GDB/MI interface
  call term_sendkeys(gdbbuf, 'new-ui mi ' . commpty . "\r")
endfunc

func s:EndDebug(job, status)
  exe 'bwipe! ' . s:ptybuf
  exe 'bwipe! ' . s:commbuf
  call setwinvar(s:startwin, '&signcolumn', s:startsigncolumn)
endfunc

" Handle a message received from gdb on the GDB/MI interface.
func s:CommOutput(chan, msg)
  let msgs = split(a:msg, "\r")

  for msg in msgs
    " remove prefixed NL
    if msg[0] == "\n"
      let msg = msg[1:]
    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
      endif
    endif
  endfor
endfunc