1fe386641SBram Moolenaar" Debugger plugin using gdb.
2c572da5fSBram Moolenaar"
3c572da5fSBram Moolenaar" WORK IN PROGRESS - much doesn't work yet
4c572da5fSBram Moolenaar"
5fe386641SBram Moolenaar" Open two visible terminal windows:
6c572da5fSBram Moolenaar" 1. run a pty, as with ":term NONE"
7c572da5fSBram Moolenaar" 2. run gdb, passing the pty
8fe386641SBram Moolenaar" The current window is used to view source code and follows gdb.
9fe386641SBram Moolenaar"
10fe386641SBram Moolenaar" A third terminal window is hidden, it is used for communication with gdb.
11fe386641SBram Moolenaar"
12fe386641SBram Moolenaar" The communication with gdb uses GDB/MI.  See:
13fe386641SBram Moolenaar" https://sourceware.org/gdb/current/onlinedocs/gdb/GDB_002fMI.html
14c572da5fSBram Moolenaar"
15c572da5fSBram Moolenaar" Author: Bram Moolenaar
16fe386641SBram Moolenaar" Copyright: Vim license applies, see ":help license"
17c572da5fSBram Moolenaar
1837c64c78SBram Moolenaar" In case this gets loaded twice.
1937c64c78SBram Moolenaarif exists(':Termdebug')
2037c64c78SBram Moolenaar  finish
2137c64c78SBram Moolenaarendif
2237c64c78SBram Moolenaar
2360e73f2aSBram Moolenaar" Uncomment this line to write logging in "debuglog".
2460e73f2aSBram Moolenaar" call ch_logfile('debuglog', 'w')
2560e73f2aSBram Moolenaar
26fe386641SBram Moolenaar" The command that starts debugging, e.g. ":Termdebug vim".
27fe386641SBram Moolenaar" To end type "quit" in the gdb window.
28c572da5fSBram Moolenaarcommand -nargs=* -complete=file Termdebug call s:StartDebug(<q-args>)
29c572da5fSBram Moolenaar
30fe386641SBram Moolenaar" Name of the gdb command, defaults to "gdb".
31e09ba7baSBram Moolenaarif !exists('termdebugger')
32e09ba7baSBram Moolenaar  let termdebugger = 'gdb'
33c572da5fSBram Moolenaarendif
34c572da5fSBram Moolenaar
35fe386641SBram Moolenaarlet s:pc_id = 12
36e09ba7baSBram Moolenaarlet s:break_id = 13
3760e73f2aSBram Moolenaarlet s:stopped = 1
38e09ba7baSBram Moolenaar
39e09ba7baSBram Moolenaarif &background == 'light'
40e09ba7baSBram Moolenaar  hi default debugPC term=reverse ctermbg=lightblue guibg=lightblue
41e09ba7baSBram Moolenaarelse
42e09ba7baSBram Moolenaar  hi default debugPC term=reverse ctermbg=darkblue guibg=darkblue
43e09ba7baSBram Moolenaarendif
44e09ba7baSBram Moolenaarhi default debugBreakpoint term=reverse ctermbg=red guibg=red
45fe386641SBram Moolenaar
46c572da5fSBram Moolenaarfunc s:StartDebug(cmd)
47fe386641SBram Moolenaar  let s:startwin = win_getid(winnr())
48fe386641SBram Moolenaar  let s:startsigncolumn = &signcolumn
49fe386641SBram Moolenaar
5024a98a0eSBram Moolenaar  let s:save_columns = 0
5124a98a0eSBram Moolenaar  if exists('g:termdebug_wide')
5224a98a0eSBram Moolenaar    if &columns < g:termdebug_wide
5338baa3e6SBram Moolenaar      let s:save_columns = &columns
5438baa3e6SBram Moolenaar      let &columns = g:termdebug_wide
5524a98a0eSBram Moolenaar    endif
5638baa3e6SBram Moolenaar    let vertical = 1
5738baa3e6SBram Moolenaar  else
5838baa3e6SBram Moolenaar    let vertical = 0
5938baa3e6SBram Moolenaar  endif
6038baa3e6SBram Moolenaar
61c572da5fSBram Moolenaar  " Open a terminal window without a job, to run the debugged program
62fe386641SBram Moolenaar  let s:ptybuf = term_start('NONE', {
63fe386641SBram Moolenaar	\ 'term_name': 'gdb program',
6438baa3e6SBram Moolenaar	\ 'vertical': vertical,
65fe386641SBram Moolenaar	\ })
66fe386641SBram Moolenaar  if s:ptybuf == 0
67fe386641SBram Moolenaar    echoerr 'Failed to open the program terminal window'
68fe386641SBram Moolenaar    return
69fe386641SBram Moolenaar  endif
70fe386641SBram Moolenaar  let pty = job_info(term_getjob(s:ptybuf))['tty_out']
7145d5f26dSBram Moolenaar  let s:ptywin = win_getid(winnr())
72*51b0f370SBram Moolenaar  if vertical
73*51b0f370SBram Moolenaar    " Assuming the source code window will get a signcolumn, use two more
74*51b0f370SBram Moolenaar    " columns for that, thus one less for the terminal window.
75*51b0f370SBram Moolenaar    exe (&columns / 2 - 1) . "wincmd |"
76*51b0f370SBram Moolenaar  endif
77fe386641SBram Moolenaar
78fe386641SBram Moolenaar  " Create a hidden terminal window to communicate with gdb
79fe386641SBram Moolenaar  let s:commbuf = term_start('NONE', {
80fe386641SBram Moolenaar	\ 'term_name': 'gdb communication',
81fe386641SBram Moolenaar	\ 'out_cb': function('s:CommOutput'),
82fe386641SBram Moolenaar	\ 'hidden': 1,
83fe386641SBram Moolenaar	\ })
84fe386641SBram Moolenaar  if s:commbuf == 0
85fe386641SBram Moolenaar    echoerr 'Failed to open the communication terminal window'
86fe386641SBram Moolenaar    exe 'bwipe! ' . s:ptybuf
87fe386641SBram Moolenaar    return
88fe386641SBram Moolenaar  endif
89fe386641SBram Moolenaar  let commpty = job_info(term_getjob(s:commbuf))['tty_out']
90c572da5fSBram Moolenaar
91c572da5fSBram Moolenaar  " Open a terminal window to run the debugger.
92c3632516SBram Moolenaar  " Add -quiet to avoid the intro message causing a hit-enter prompt.
93c3632516SBram Moolenaar  let cmd = [g:termdebugger, '-quiet', '-tty', pty, a:cmd]
94c572da5fSBram Moolenaar  echomsg 'executing "' . join(cmd) . '"'
9560e73f2aSBram Moolenaar  let s:gdbbuf = term_start(cmd, {
96c572da5fSBram Moolenaar	\ 'exit_cb': function('s:EndDebug'),
97fe386641SBram Moolenaar	\ 'term_finish': 'close',
98c572da5fSBram Moolenaar	\ })
9960e73f2aSBram Moolenaar  if s:gdbbuf == 0
100fe386641SBram Moolenaar    echoerr 'Failed to open the gdb terminal window'
101fe386641SBram Moolenaar    exe 'bwipe! ' . s:ptybuf
102fe386641SBram Moolenaar    exe 'bwipe! ' . s:commbuf
103fe386641SBram Moolenaar    return
104fe386641SBram Moolenaar  endif
10545d5f26dSBram Moolenaar  let s:gdbwin = win_getid(winnr())
106fe386641SBram Moolenaar
107fe386641SBram Moolenaar  " Connect gdb to the communication pty, using the GDB/MI interface
10801164a65SBram Moolenaar  " If you get an error "undefined command" your GDB is too old.
10960e73f2aSBram Moolenaar  call term_sendkeys(s:gdbbuf, 'new-ui mi ' . commpty . "\r")
11060e73f2aSBram Moolenaar
11160e73f2aSBram Moolenaar  " Interpret commands while the target is running.  This should usualy only be
11260e73f2aSBram Moolenaar  " exec-interrupt, since many commands don't work properly while the target is
11360e73f2aSBram Moolenaar  " running.
11460e73f2aSBram Moolenaar  call s:SendCommand('-gdb-set mi-async on')
115e09ba7baSBram Moolenaar
11638baa3e6SBram Moolenaar  " Sign used to highlight the line where the program has stopped.
11738baa3e6SBram Moolenaar  " There can be only one.
11838baa3e6SBram Moolenaar  sign define debugPC linehl=debugPC
11938baa3e6SBram Moolenaar
12038baa3e6SBram Moolenaar  " Sign used to indicate a breakpoint.
12138baa3e6SBram Moolenaar  " Can be used multiple times.
12238baa3e6SBram Moolenaar  sign define debugBreakpoint text=>> texthl=debugBreakpoint
12338baa3e6SBram Moolenaar
12445d5f26dSBram Moolenaar  " Install debugger commands in the text window.
12545d5f26dSBram Moolenaar  call win_gotoid(s:startwin)
126e09ba7baSBram Moolenaar  call s:InstallCommands()
12745d5f26dSBram Moolenaar  call win_gotoid(s:gdbwin)
128e09ba7baSBram Moolenaar
129*51b0f370SBram Moolenaar  " Enable showing a balloon with eval info
130*51b0f370SBram Moolenaar  if has("balloon_eval")
131*51b0f370SBram Moolenaar    set ballooneval
132*51b0f370SBram Moolenaar    set balloonexpr=TermDebugBalloonExpr()
133*51b0f370SBram Moolenaar    if has("balloon_eval_term")
134*51b0f370SBram Moolenaar      set balloonevalterm
135*51b0f370SBram Moolenaar    endif
136*51b0f370SBram Moolenaar  endif
137*51b0f370SBram Moolenaar
138e09ba7baSBram Moolenaar  let s:breakpoints = {}
1391b9645deSBram Moolenaar
1401b9645deSBram Moolenaar  augroup TermDebug
1411b9645deSBram Moolenaar    au BufRead * call s:BufRead()
1421b9645deSBram Moolenaar    au BufUnload * call s:BufUnloaded()
1431b9645deSBram Moolenaar  augroup END
144c572da5fSBram Moolenaarendfunc
145c572da5fSBram Moolenaar
146c572da5fSBram Moolenaarfunc s:EndDebug(job, status)
147c572da5fSBram Moolenaar  exe 'bwipe! ' . s:ptybuf
148fe386641SBram Moolenaar  exe 'bwipe! ' . s:commbuf
149e09ba7baSBram Moolenaar
150e09ba7baSBram Moolenaar  let curwinid = win_getid(winnr())
151e09ba7baSBram Moolenaar
152e09ba7baSBram Moolenaar  call win_gotoid(s:startwin)
153e09ba7baSBram Moolenaar  let &signcolumn = s:startsigncolumn
154e09ba7baSBram Moolenaar  call s:DeleteCommands()
155e09ba7baSBram Moolenaar
156e09ba7baSBram Moolenaar  call win_gotoid(curwinid)
15738baa3e6SBram Moolenaar  if s:save_columns > 0
15838baa3e6SBram Moolenaar    let &columns = s:save_columns
15938baa3e6SBram Moolenaar  endif
1601b9645deSBram Moolenaar
161*51b0f370SBram Moolenaar  if has("balloon_eval")
162*51b0f370SBram Moolenaar    set noballooneval
163*51b0f370SBram Moolenaar    set balloonexpr=
164*51b0f370SBram Moolenaar    if has("balloon_eval_term")
165*51b0f370SBram Moolenaar      set noballoonevalterm
166*51b0f370SBram Moolenaar    endif
167*51b0f370SBram Moolenaar  endif
168*51b0f370SBram Moolenaar
1691b9645deSBram Moolenaar  au! TermDebug
170fe386641SBram Moolenaarendfunc
171fe386641SBram Moolenaar
172fe386641SBram Moolenaar" Handle a message received from gdb on the GDB/MI interface.
173fe386641SBram Moolenaarfunc s:CommOutput(chan, msg)
174fe386641SBram Moolenaar  let msgs = split(a:msg, "\r")
175fe386641SBram Moolenaar
176fe386641SBram Moolenaar  for msg in msgs
177fe386641SBram Moolenaar    " remove prefixed NL
178fe386641SBram Moolenaar    if msg[0] == "\n"
179fe386641SBram Moolenaar      let msg = msg[1:]
180fe386641SBram Moolenaar    endif
181fe386641SBram Moolenaar    if msg != ''
1821b9645deSBram Moolenaar      if msg =~ '^\(\*stopped\|\*running\|=thread-selected\)'
183e09ba7baSBram Moolenaar	call s:HandleCursor(msg)
18445d5f26dSBram Moolenaar      elseif msg =~ '^\^done,bkpt=' || msg =~ '^=breakpoint-created,'
185e09ba7baSBram Moolenaar	call s:HandleNewBreakpoint(msg)
186e09ba7baSBram Moolenaar      elseif msg =~ '^=breakpoint-deleted,'
187e09ba7baSBram Moolenaar	call s:HandleBreakpointDelete(msg)
18845d5f26dSBram Moolenaar      elseif msg =~ '^\^done,value='
18945d5f26dSBram Moolenaar	call s:HandleEvaluate(msg)
19045d5f26dSBram Moolenaar      elseif msg =~ '^\^error,msg='
19145d5f26dSBram Moolenaar	call s:HandleError(msg)
192e09ba7baSBram Moolenaar      endif
193e09ba7baSBram Moolenaar    endif
194e09ba7baSBram Moolenaar  endfor
195e09ba7baSBram Moolenaarendfunc
196e09ba7baSBram Moolenaar
197e09ba7baSBram Moolenaar" Install commands in the current window to control the debugger.
198e09ba7baSBram Moolenaarfunc s:InstallCommands()
199e09ba7baSBram Moolenaar  command Break call s:SetBreakpoint()
200e09ba7baSBram Moolenaar  command Delete call s:DeleteBreakpoint()
201e09ba7baSBram Moolenaar  command Step call s:SendCommand('-exec-step')
20245d5f26dSBram Moolenaar  command Over call s:SendCommand('-exec-next')
203e09ba7baSBram Moolenaar  command Finish call s:SendCommand('-exec-finish')
20460e73f2aSBram Moolenaar  command -nargs=* Run call s:Run(<q-args>)
20560e73f2aSBram Moolenaar  command -nargs=* Arguments call s:SendCommand('-exec-arguments ' . <q-args>)
20660e73f2aSBram Moolenaar  command Stop call s:SendCommand('-exec-interrupt')
207e09ba7baSBram Moolenaar  command Continue call s:SendCommand('-exec-continue')
20845d5f26dSBram Moolenaar  command -range -nargs=* Evaluate call s:Evaluate(<range>, <q-args>)
20945d5f26dSBram Moolenaar  command Gdb call win_gotoid(s:gdbwin)
21045d5f26dSBram Moolenaar  command Program call win_gotoid(s:ptywin)
21145d5f26dSBram Moolenaar
21245d5f26dSBram Moolenaar  " TODO: can the K mapping be restored?
21345d5f26dSBram Moolenaar  nnoremap K :Evaluate<CR>
2141b9645deSBram Moolenaar
2151b9645deSBram Moolenaar  if has('menu')
21624a98a0eSBram Moolenaar    nnoremenu WinBar.Step :Step<CR>
21724a98a0eSBram Moolenaar    nnoremenu WinBar.Next :Over<CR>
21824a98a0eSBram Moolenaar    nnoremenu WinBar.Finish :Finish<CR>
21924a98a0eSBram Moolenaar    nnoremenu WinBar.Cont :Continue<CR>
22060e73f2aSBram Moolenaar    nnoremenu WinBar.Stop :Stop<CR>
22124a98a0eSBram Moolenaar    nnoremenu WinBar.Eval :Evaluate<CR>
2221b9645deSBram Moolenaar  endif
223e09ba7baSBram Moolenaarendfunc
224e09ba7baSBram Moolenaar
225e09ba7baSBram Moolenaar" Delete installed debugger commands in the current window.
226e09ba7baSBram Moolenaarfunc s:DeleteCommands()
227e09ba7baSBram Moolenaar  delcommand Break
228e09ba7baSBram Moolenaar  delcommand Delete
229e09ba7baSBram Moolenaar  delcommand Step
23045d5f26dSBram Moolenaar  delcommand Over
231e09ba7baSBram Moolenaar  delcommand Finish
23260e73f2aSBram Moolenaar  delcommand Run
23360e73f2aSBram Moolenaar  delcommand Arguments
23460e73f2aSBram Moolenaar  delcommand Stop
235e09ba7baSBram Moolenaar  delcommand Continue
23645d5f26dSBram Moolenaar  delcommand Evaluate
23745d5f26dSBram Moolenaar  delcommand Gdb
23845d5f26dSBram Moolenaar  delcommand Program
23945d5f26dSBram Moolenaar
24045d5f26dSBram Moolenaar  nunmap K
2411b9645deSBram Moolenaar
2421b9645deSBram Moolenaar  if has('menu')
2431b9645deSBram Moolenaar    aunmenu WinBar.Step
2441b9645deSBram Moolenaar    aunmenu WinBar.Next
2451b9645deSBram Moolenaar    aunmenu WinBar.Finish
2461b9645deSBram Moolenaar    aunmenu WinBar.Cont
24760e73f2aSBram Moolenaar    aunmenu WinBar.Stop
2481b9645deSBram Moolenaar    aunmenu WinBar.Eval
2491b9645deSBram Moolenaar  endif
2501b9645deSBram Moolenaar
25145d5f26dSBram Moolenaar  exe 'sign unplace ' . s:pc_id
25245d5f26dSBram Moolenaar  for key in keys(s:breakpoints)
25345d5f26dSBram Moolenaar    exe 'sign unplace ' . (s:break_id + key)
25445d5f26dSBram Moolenaar  endfor
25538baa3e6SBram Moolenaar  sign undefine debugPC
25638baa3e6SBram Moolenaar  sign undefine debugBreakpoint
25745d5f26dSBram Moolenaar  unlet s:breakpoints
258e09ba7baSBram Moolenaarendfunc
259e09ba7baSBram Moolenaar
260e09ba7baSBram Moolenaar" :Break - Set a breakpoint at the cursor position.
261e09ba7baSBram Moolenaarfunc s:SetBreakpoint()
26260e73f2aSBram Moolenaar  " Setting a breakpoint may not work while the program is running.
26360e73f2aSBram Moolenaar  " Interrupt to make it work.
26460e73f2aSBram Moolenaar  let do_continue = 0
26560e73f2aSBram Moolenaar  if !s:stopped
26660e73f2aSBram Moolenaar    let do_continue = 1
26760e73f2aSBram Moolenaar    call s:SendCommand('-exec-interrupt')
26860e73f2aSBram Moolenaar    sleep 10m
26960e73f2aSBram Moolenaar  endif
27060e73f2aSBram Moolenaar  call s:SendCommand('-break-insert --source '
27160e73f2aSBram Moolenaar	\ . fnameescape(expand('%:p')) . ' --line ' . line('.'))
27260e73f2aSBram Moolenaar  if do_continue
27360e73f2aSBram Moolenaar    call s:SendCommand('-exec-continue')
27460e73f2aSBram Moolenaar  endif
275e09ba7baSBram Moolenaarendfunc
276e09ba7baSBram Moolenaar
277e09ba7baSBram Moolenaar" :Delete - Delete a breakpoint at the cursor position.
278e09ba7baSBram Moolenaarfunc s:DeleteBreakpoint()
279e09ba7baSBram Moolenaar  let fname = fnameescape(expand('%:p'))
280e09ba7baSBram Moolenaar  let lnum = line('.')
281e09ba7baSBram Moolenaar  for [key, val] in items(s:breakpoints)
282e09ba7baSBram Moolenaar    if val['fname'] == fname && val['lnum'] == lnum
283e09ba7baSBram Moolenaar      call term_sendkeys(s:commbuf, '-break-delete ' . key . "\r")
284e09ba7baSBram Moolenaar      " Assume this always wors, the reply is simply "^done".
285e09ba7baSBram Moolenaar      exe 'sign unplace ' . (s:break_id + key)
286e09ba7baSBram Moolenaar      unlet s:breakpoints[key]
287e09ba7baSBram Moolenaar      break
288e09ba7baSBram Moolenaar    endif
289e09ba7baSBram Moolenaar  endfor
290e09ba7baSBram Moolenaarendfunc
291e09ba7baSBram Moolenaar
292e09ba7baSBram Moolenaar" :Next, :Continue, etc - send a command to gdb
293e09ba7baSBram Moolenaarfunc s:SendCommand(cmd)
294e09ba7baSBram Moolenaar  call term_sendkeys(s:commbuf, a:cmd . "\r")
295e09ba7baSBram Moolenaarendfunc
296e09ba7baSBram Moolenaar
29760e73f2aSBram Moolenaarfunc s:Run(args)
29860e73f2aSBram Moolenaar  if a:args != ''
29960e73f2aSBram Moolenaar    call s:SendCommand('-exec-arguments ' . a:args)
30060e73f2aSBram Moolenaar  endif
30160e73f2aSBram Moolenaar  call s:SendCommand('-exec-run')
30260e73f2aSBram Moolenaarendfunc
30360e73f2aSBram Moolenaar
304*51b0f370SBram Moolenaarfunc s:SendEval(expr)
305*51b0f370SBram Moolenaar  call s:SendCommand('-data-evaluate-expression "' . a:expr . '"')
306*51b0f370SBram Moolenaar  let s:evalexpr = a:expr
307*51b0f370SBram Moolenaarendfunc
308*51b0f370SBram Moolenaar
30945d5f26dSBram Moolenaar" :Evaluate - evaluate what is under the cursor
31045d5f26dSBram Moolenaarfunc s:Evaluate(range, arg)
31145d5f26dSBram Moolenaar  if a:arg != ''
31245d5f26dSBram Moolenaar    let expr = a:arg
31345d5f26dSBram Moolenaar  elseif a:range == 2
31445d5f26dSBram Moolenaar    let pos = getcurpos()
31545d5f26dSBram Moolenaar    let reg = getreg('v', 1, 1)
31645d5f26dSBram Moolenaar    let regt = getregtype('v')
31745d5f26dSBram Moolenaar    normal! gv"vy
31845d5f26dSBram Moolenaar    let expr = @v
31945d5f26dSBram Moolenaar    call setpos('.', pos)
32045d5f26dSBram Moolenaar    call setreg('v', reg, regt)
32145d5f26dSBram Moolenaar  else
32245d5f26dSBram Moolenaar    let expr = expand('<cexpr>')
32345d5f26dSBram Moolenaar  endif
324*51b0f370SBram Moolenaar  call s:SendEval(expr)
32545d5f26dSBram Moolenaarendfunc
32645d5f26dSBram Moolenaar
327*51b0f370SBram Moolenaarlet s:evalFromBalloonExpr = 0
328*51b0f370SBram Moolenaar
32945d5f26dSBram Moolenaar" Handle the result of data-evaluate-expression
33045d5f26dSBram Moolenaarfunc s:HandleEvaluate(msg)
3311b9645deSBram Moolenaar  let value = substitute(a:msg, '.*value="\(.*\)"', '\1', '')
3321b9645deSBram Moolenaar  let value = substitute(value, '\\"', '"', 'g')
333*51b0f370SBram Moolenaar  if s:evalFromBalloonExpr
334*51b0f370SBram Moolenaar    if s:evalFromBalloonExprResult == ''
335*51b0f370SBram Moolenaar      let s:evalFromBalloonExprResult = s:evalexpr . ': ' . value
336*51b0f370SBram Moolenaar    else
337*51b0f370SBram Moolenaar      let s:evalFromBalloonExprResult .= ' = ' . value
338*51b0f370SBram Moolenaar    endif
339*51b0f370SBram Moolenaar    call balloon_show(s:evalFromBalloonExprResult)
340*51b0f370SBram Moolenaar  else
3411b9645deSBram Moolenaar    echomsg '"' . s:evalexpr . '": ' . value
342*51b0f370SBram Moolenaar  endif
3431b9645deSBram Moolenaar
3447f2e9d7cSBram Moolenaar  if s:evalexpr[0] != '*' && value =~ '^0x' && value != '0x0' && value !~ '"$'
3451b9645deSBram Moolenaar    " Looks like a pointer, also display what it points to.
346*51b0f370SBram Moolenaar    call s:SendEval('*' . s:evalexpr)
347*51b0f370SBram Moolenaar  else
348*51b0f370SBram Moolenaar    let s:evalFromBalloonExpr = 0
3491b9645deSBram Moolenaar  endif
35045d5f26dSBram Moolenaarendfunc
35145d5f26dSBram Moolenaar
352*51b0f370SBram Moolenaar" Show a balloon with information of the variable under the mouse pointer,
353*51b0f370SBram Moolenaar" if there is any.
354*51b0f370SBram Moolenaarfunc TermDebugBalloonExpr()
355*51b0f370SBram Moolenaar  if v:beval_winid != s:startwin
356*51b0f370SBram Moolenaar    return
357*51b0f370SBram Moolenaar  endif
358*51b0f370SBram Moolenaar  call s:SendEval(v:beval_text)
359*51b0f370SBram Moolenaar  let s:evalFromBalloonExpr = 1
360*51b0f370SBram Moolenaar  let s:evalFromBalloonExprResult = ''
361*51b0f370SBram Moolenaar  return ''
362*51b0f370SBram Moolenaarendfunc
363*51b0f370SBram Moolenaar
36445d5f26dSBram Moolenaar" Handle an error.
36545d5f26dSBram Moolenaarfunc s:HandleError(msg)
366*51b0f370SBram Moolenaar  if a:msg =~ 'No symbol .* in current context'
367*51b0f370SBram Moolenaar	\ || a:msg =~ 'Cannot access memory at address '
368*51b0f370SBram Moolenaar	\ || a:msg =~ 'Attempt to use a type name as an expression'
369*51b0f370SBram Moolenaar    " Result of s:SendEval() failed, ignore.
370*51b0f370SBram Moolenaar    return
371*51b0f370SBram Moolenaar  endif
37245d5f26dSBram Moolenaar  echoerr substitute(a:msg, '.*msg="\(.*\)"', '\1', '')
37345d5f26dSBram Moolenaarendfunc
37445d5f26dSBram Moolenaar
375e09ba7baSBram Moolenaar" Handle stopping and running message from gdb.
376e09ba7baSBram Moolenaar" Will update the sign that shows the current position.
377e09ba7baSBram Moolenaarfunc s:HandleCursor(msg)
378fe386641SBram Moolenaar  let wid = win_getid(winnr())
379fe386641SBram Moolenaar
38060e73f2aSBram Moolenaar  if a:msg =~ '^\*stopped'
38160e73f2aSBram Moolenaar    let s:stopped = 1
38260e73f2aSBram Moolenaar  elseif a:msg =~ '^\*running'
38360e73f2aSBram Moolenaar    let s:stopped = 0
38460e73f2aSBram Moolenaar  endif
38560e73f2aSBram Moolenaar
386fe386641SBram Moolenaar  if win_gotoid(s:startwin)
387e09ba7baSBram Moolenaar    let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '')
3881b9645deSBram Moolenaar    if a:msg =~ '^\(\*stopped\|=thread-selected\)' && filereadable(fname)
389e09ba7baSBram Moolenaar      let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '')
390fe386641SBram Moolenaar      if lnum =~ '^[0-9]*$'
3911b9645deSBram Moolenaar	if expand('%:p') != fnamemodify(fname, ':p')
392fe386641SBram Moolenaar	  if &modified
393fe386641SBram Moolenaar	    " TODO: find existing window
394fe386641SBram Moolenaar	    exe 'split ' . fnameescape(fname)
395fe386641SBram Moolenaar	    let s:startwin = win_getid(winnr())
396fe386641SBram Moolenaar	  else
397fe386641SBram Moolenaar	    exe 'edit ' . fnameescape(fname)
398fe386641SBram Moolenaar	  endif
399fe386641SBram Moolenaar	endif
400fe386641SBram Moolenaar	exe lnum
40101164a65SBram Moolenaar	exe 'sign unplace ' . s:pc_id
4021b9645deSBram Moolenaar	exe 'sign place ' . s:pc_id . ' line=' . lnum . ' name=debugPC file=' . fname
403fe386641SBram Moolenaar	setlocal signcolumn=yes
404fe386641SBram Moolenaar      endif
405fe386641SBram Moolenaar    else
406fe386641SBram Moolenaar      exe 'sign unplace ' . s:pc_id
407fe386641SBram Moolenaar    endif
408fe386641SBram Moolenaar
409fe386641SBram Moolenaar    call win_gotoid(wid)
410fe386641SBram Moolenaar  endif
411e09ba7baSBram Moolenaarendfunc
412e09ba7baSBram Moolenaar
413e09ba7baSBram Moolenaar" Handle setting a breakpoint
414e09ba7baSBram Moolenaar" Will update the sign that shows the breakpoint
415e09ba7baSBram Moolenaarfunc s:HandleNewBreakpoint(msg)
416e09ba7baSBram Moolenaar  let nr = substitute(a:msg, '.*number="\([0-9]\)*\".*', '\1', '') + 0
417e09ba7baSBram Moolenaar  if nr == 0
418e09ba7baSBram Moolenaar    return
419fe386641SBram Moolenaar  endif
420e09ba7baSBram Moolenaar
421e09ba7baSBram Moolenaar  if has_key(s:breakpoints, nr)
422e09ba7baSBram Moolenaar    let entry = s:breakpoints[nr]
423e09ba7baSBram Moolenaar  else
424e09ba7baSBram Moolenaar    let entry = {}
425e09ba7baSBram Moolenaar    let s:breakpoints[nr] = entry
426fe386641SBram Moolenaar  endif
427e09ba7baSBram Moolenaar
428e09ba7baSBram Moolenaar  let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '')
429e09ba7baSBram Moolenaar  let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '')
430e09ba7baSBram Moolenaar  let entry['fname'] = fname
431e09ba7baSBram Moolenaar  let entry['lnum'] = lnum
4321b9645deSBram Moolenaar
4331b9645deSBram Moolenaar  if bufloaded(fname)
4341b9645deSBram Moolenaar    call s:PlaceSign(nr, entry)
4351b9645deSBram Moolenaar  endif
4361b9645deSBram Moolenaarendfunc
4371b9645deSBram Moolenaar
4381b9645deSBram Moolenaarfunc s:PlaceSign(nr, entry)
4391b9645deSBram Moolenaar  exe 'sign place ' . (s:break_id + a:nr) . ' line=' . a:entry['lnum'] . ' name=debugBreakpoint file=' . a:entry['fname']
4401b9645deSBram Moolenaar  let a:entry['placed'] = 1
441e09ba7baSBram Moolenaarendfunc
442e09ba7baSBram Moolenaar
443e09ba7baSBram Moolenaar" Handle deleting a breakpoint
444e09ba7baSBram Moolenaar" Will remove the sign that shows the breakpoint
445e09ba7baSBram Moolenaarfunc s:HandleBreakpointDelete(msg)
446e09ba7baSBram Moolenaar  let nr = substitute(a:msg, '.*id="\([0-9]*\)\".*', '\1', '') + 0
447e09ba7baSBram Moolenaar  if nr == 0
448e09ba7baSBram Moolenaar    return
449e09ba7baSBram Moolenaar  endif
4501b9645deSBram Moolenaar  if has_key(s:breakpoints, nr)
4511b9645deSBram Moolenaar    let entry = s:breakpoints[nr]
4521b9645deSBram Moolenaar    if has_key(entry, 'placed')
453e09ba7baSBram Moolenaar      exe 'sign unplace ' . (s:break_id + nr)
4541b9645deSBram Moolenaar      unlet entry['placed']
4551b9645deSBram Moolenaar    endif
456e09ba7baSBram Moolenaar    unlet s:breakpoints[nr]
4571b9645deSBram Moolenaar  endif
458c572da5fSBram Moolenaarendfunc
4591b9645deSBram Moolenaar
4601b9645deSBram Moolenaar" Handle a BufRead autocommand event: place any signs.
4611b9645deSBram Moolenaarfunc s:BufRead()
4621b9645deSBram Moolenaar  let fname = expand('<afile>:p')
4631b9645deSBram Moolenaar  for [nr, entry] in items(s:breakpoints)
4641b9645deSBram Moolenaar    if entry['fname'] == fname
4651b9645deSBram Moolenaar      call s:PlaceSign(nr, entry)
4661b9645deSBram Moolenaar    endif
4671b9645deSBram Moolenaar  endfor
4681b9645deSBram Moolenaarendfunc
4691b9645deSBram Moolenaar
4701b9645deSBram Moolenaar" Handle a BufUnloaded autocommand event: unplace any signs.
4711b9645deSBram Moolenaarfunc s:BufUnloaded()
4721b9645deSBram Moolenaar  let fname = expand('<afile>:p')
4731b9645deSBram Moolenaar  for [nr, entry] in items(s:breakpoints)
4741b9645deSBram Moolenaar    if entry['fname'] == fname
4751b9645deSBram Moolenaar      let entry['placed'] = 0
4761b9645deSBram Moolenaar    endif
4771b9645deSBram Moolenaar  endfor
4781b9645deSBram Moolenaarendfunc
4791b9645deSBram Moolenaar
480