1*fe386641SBram Moolenaar" Debugger plugin using gdb.
2c572da5fSBram Moolenaar"
3c572da5fSBram Moolenaar" WORK IN PROGRESS - much doesn't work yet
4c572da5fSBram Moolenaar"
5*fe386641SBram Moolenaar" Open two visible terminal windows:
6c572da5fSBram Moolenaar" 1. run a pty, as with ":term NONE"
7c572da5fSBram Moolenaar" 2. run gdb, passing the pty
8*fe386641SBram Moolenaar" The current window is used to view source code and follows gdb.
9*fe386641SBram Moolenaar"
10*fe386641SBram Moolenaar" A third terminal window is hidden, it is used for communication with gdb.
11*fe386641SBram Moolenaar"
12*fe386641SBram Moolenaar" The communication with gdb uses GDB/MI.  See:
13*fe386641SBram Moolenaar" https://sourceware.org/gdb/current/onlinedocs/gdb/GDB_002fMI.html
14c572da5fSBram Moolenaar"
15c572da5fSBram Moolenaar" Author: Bram Moolenaar
16*fe386641SBram Moolenaar" Copyright: Vim license applies, see ":help license"
17c572da5fSBram Moolenaar
18*fe386641SBram Moolenaar" The command that starts debugging, e.g. ":Termdebug vim".
19*fe386641SBram Moolenaar" To end type "quit" in the gdb window.
20c572da5fSBram Moolenaarcommand -nargs=* -complete=file Termdebug call s:StartDebug(<q-args>)
21c572da5fSBram Moolenaar
22*fe386641SBram Moolenaar" Name of the gdb command, defaults to "gdb".
23c572da5fSBram Moolenaarif !exists('debugger')
24c572da5fSBram Moolenaar  let debugger = 'gdb'
25c572da5fSBram Moolenaarendif
26c572da5fSBram Moolenaar
27*fe386641SBram Moolenaar" Sign used to highlight the line where the program has stopped.
28*fe386641SBram Moolenaarsign define debugPC linehl=debugPC
29*fe386641SBram Moolenaarif &background == 'light'
30*fe386641SBram Moolenaar  hi debugPC term=reverse ctermbg=lightblue guibg=lightblue
31*fe386641SBram Moolenaarelse
32*fe386641SBram Moolenaar  hi debugPC term=reverse ctermbg=darkblue guibg=darkblue
33*fe386641SBram Moolenaarendif
34*fe386641SBram Moolenaarlet s:pc_id = 12
35*fe386641SBram Moolenaar
36c572da5fSBram Moolenaarfunc s:StartDebug(cmd)
37*fe386641SBram Moolenaar  let s:startwin = win_getid(winnr())
38*fe386641SBram Moolenaar  let s:startsigncolumn = &signcolumn
39*fe386641SBram Moolenaar
40c572da5fSBram Moolenaar  " Open a terminal window without a job, to run the debugged program
41*fe386641SBram Moolenaar  let s:ptybuf = term_start('NONE', {
42*fe386641SBram Moolenaar	\ 'term_name': 'gdb program',
43*fe386641SBram Moolenaar	\ })
44*fe386641SBram Moolenaar  if s:ptybuf == 0
45*fe386641SBram Moolenaar    echoerr 'Failed to open the program terminal window'
46*fe386641SBram Moolenaar    return
47*fe386641SBram Moolenaar  endif
48*fe386641SBram Moolenaar  let pty = job_info(term_getjob(s:ptybuf))['tty_out']
49*fe386641SBram Moolenaar
50*fe386641SBram Moolenaar  " Create a hidden terminal window to communicate with gdb
51*fe386641SBram Moolenaar  let s:commbuf = term_start('NONE', {
52*fe386641SBram Moolenaar	\ 'term_name': 'gdb communication',
53*fe386641SBram Moolenaar	\ 'out_cb': function('s:CommOutput'),
54*fe386641SBram Moolenaar	\ 'hidden': 1,
55*fe386641SBram Moolenaar	\ })
56*fe386641SBram Moolenaar  if s:commbuf == 0
57*fe386641SBram Moolenaar    echoerr 'Failed to open the communication terminal window'
58*fe386641SBram Moolenaar    exe 'bwipe! ' . s:ptybuf
59*fe386641SBram Moolenaar    return
60*fe386641SBram Moolenaar  endif
61*fe386641SBram Moolenaar  let commpty = job_info(term_getjob(s:commbuf))['tty_out']
62c572da5fSBram Moolenaar
63c572da5fSBram Moolenaar  " Open a terminal window to run the debugger.
64c572da5fSBram Moolenaar  let cmd = [g:debugger, '-tty', pty, a:cmd]
65c572da5fSBram Moolenaar  echomsg 'executing "' . join(cmd) . '"'
66c572da5fSBram Moolenaar  let gdbbuf = term_start(cmd, {
67c572da5fSBram Moolenaar	\ 'exit_cb': function('s:EndDebug'),
68*fe386641SBram Moolenaar	\ 'term_finish': 'close',
69c572da5fSBram Moolenaar	\ })
70*fe386641SBram Moolenaar  if gdbbuf == 0
71*fe386641SBram Moolenaar    echoerr 'Failed to open the gdb terminal window'
72*fe386641SBram Moolenaar    exe 'bwipe! ' . s:ptybuf
73*fe386641SBram Moolenaar    exe 'bwipe! ' . s:commbuf
74*fe386641SBram Moolenaar    return
75*fe386641SBram Moolenaar  endif
76*fe386641SBram Moolenaar
77*fe386641SBram Moolenaar  " Connect gdb to the communication pty, using the GDB/MI interface
78*fe386641SBram Moolenaar  call term_sendkeys(gdbbuf, 'new-ui mi ' . commpty . "\r")
79c572da5fSBram Moolenaarendfunc
80c572da5fSBram Moolenaar
81c572da5fSBram Moolenaarfunc s:EndDebug(job, status)
82c572da5fSBram Moolenaar  exe 'bwipe! ' . s:ptybuf
83*fe386641SBram Moolenaar  exe 'bwipe! ' . s:commbuf
84*fe386641SBram Moolenaar  call setwinvar(s:startwin, '&signcolumn', s:startsigncolumn)
85*fe386641SBram Moolenaarendfunc
86*fe386641SBram Moolenaar
87*fe386641SBram Moolenaar" Handle a message received from gdb on the GDB/MI interface.
88*fe386641SBram Moolenaarfunc s:CommOutput(chan, msg)
89*fe386641SBram Moolenaar  let msgs = split(a:msg, "\r")
90*fe386641SBram Moolenaar
91*fe386641SBram Moolenaar  for msg in msgs
92*fe386641SBram Moolenaar    " remove prefixed NL
93*fe386641SBram Moolenaar    if msg[0] == "\n"
94*fe386641SBram Moolenaar      let msg = msg[1:]
95*fe386641SBram Moolenaar    endif
96*fe386641SBram Moolenaar    if msg != ''
97*fe386641SBram Moolenaar      if msg =~ '^\*\(stopped\|running\)'
98*fe386641SBram Moolenaar	let wid = win_getid(winnr())
99*fe386641SBram Moolenaar
100*fe386641SBram Moolenaar	if win_gotoid(s:startwin)
101*fe386641SBram Moolenaar	  if msg =~ '^\*stopped'
102*fe386641SBram Moolenaar	    " TODO: proper parsing
103*fe386641SBram Moolenaar	    let fname = substitute(msg, '.*fullname="\([^"]*\)".*', '\1', '')
104*fe386641SBram Moolenaar	    let lnum = substitute(msg, '.*line="\([^"]*\)".*', '\1', '')
105*fe386641SBram Moolenaar	    if lnum =~ '^[0-9]*$'
106*fe386641SBram Moolenaar	      if expand('%:h') != fname
107*fe386641SBram Moolenaar		if &modified
108*fe386641SBram Moolenaar		  " TODO: find existing window
109*fe386641SBram Moolenaar		  exe 'split ' . fnameescape(fname)
110*fe386641SBram Moolenaar		  let s:startwin = win_getid(winnr())
111*fe386641SBram Moolenaar		else
112*fe386641SBram Moolenaar		  exe 'edit ' . fnameescape(fname)
113*fe386641SBram Moolenaar		endif
114*fe386641SBram Moolenaar	      endif
115*fe386641SBram Moolenaar	      exe lnum
116*fe386641SBram Moolenaar	      exe 'sign place ' . s:pc_id . ' line=' . lnum . ' name=debugPC file=' . fnameescape(fname)
117*fe386641SBram Moolenaar	      setlocal signcolumn=yes
118*fe386641SBram Moolenaar	    endif
119*fe386641SBram Moolenaar	  else
120*fe386641SBram Moolenaar	    exe 'sign unplace ' . s:pc_id
121*fe386641SBram Moolenaar	  endif
122*fe386641SBram Moolenaar
123*fe386641SBram Moolenaar	  call win_gotoid(wid)
124*fe386641SBram Moolenaar	endif
125*fe386641SBram Moolenaar      endif
126*fe386641SBram Moolenaar    endif
127*fe386641SBram Moolenaar  endfor
128c572da5fSBram Moolenaarendfunc
129