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
18fe386641SBram Moolenaar" The command that starts debugging, e.g. ":Termdebug vim".
19fe386641SBram Moolenaar" To end type "quit" in the gdb window.
20c572da5fSBram Moolenaarcommand -nargs=* -complete=file Termdebug call s:StartDebug(<q-args>)
21c572da5fSBram Moolenaar
22fe386641SBram Moolenaar" Name of the gdb command, defaults to "gdb".
23e09ba7baSBram Moolenaarif !exists('termdebugger')
24e09ba7baSBram Moolenaar  let termdebugger = 'gdb'
25c572da5fSBram Moolenaarendif
26c572da5fSBram Moolenaar
27fe386641SBram Moolenaarlet s:pc_id = 12
28e09ba7baSBram Moolenaarlet s:break_id = 13
29e09ba7baSBram Moolenaar
30e09ba7baSBram Moolenaarif &background == 'light'
31e09ba7baSBram Moolenaar  hi default debugPC term=reverse ctermbg=lightblue guibg=lightblue
32e09ba7baSBram Moolenaarelse
33e09ba7baSBram Moolenaar  hi default debugPC term=reverse ctermbg=darkblue guibg=darkblue
34e09ba7baSBram Moolenaarendif
35e09ba7baSBram Moolenaarhi default debugBreakpoint term=reverse ctermbg=red guibg=red
36fe386641SBram Moolenaar
37c572da5fSBram Moolenaarfunc s:StartDebug(cmd)
38fe386641SBram Moolenaar  let s:startwin = win_getid(winnr())
39fe386641SBram Moolenaar  let s:startsigncolumn = &signcolumn
40fe386641SBram Moolenaar
4138baa3e6SBram Moolenaar  if exists('g:termdebug_wide') && &columns < g:termdebug_wide
4238baa3e6SBram Moolenaar    let s:save_columns = &columns
4338baa3e6SBram Moolenaar    let &columns = g:termdebug_wide
4438baa3e6SBram Moolenaar    let vertical = 1
4538baa3e6SBram Moolenaar  else
4638baa3e6SBram Moolenaar    let s:save_columns = 0
4738baa3e6SBram Moolenaar    let vertical = 0
4838baa3e6SBram Moolenaar  endif
4938baa3e6SBram Moolenaar
50c572da5fSBram Moolenaar  " Open a terminal window without a job, to run the debugged program
51fe386641SBram Moolenaar  let s:ptybuf = term_start('NONE', {
52fe386641SBram Moolenaar	\ 'term_name': 'gdb program',
5338baa3e6SBram Moolenaar	\ 'vertical': vertical,
54fe386641SBram Moolenaar	\ })
55fe386641SBram Moolenaar  if s:ptybuf == 0
56fe386641SBram Moolenaar    echoerr 'Failed to open the program terminal window'
57fe386641SBram Moolenaar    return
58fe386641SBram Moolenaar  endif
59fe386641SBram Moolenaar  let pty = job_info(term_getjob(s:ptybuf))['tty_out']
6045d5f26dSBram Moolenaar  let s:ptywin = win_getid(winnr())
61fe386641SBram Moolenaar
62fe386641SBram Moolenaar  " Create a hidden terminal window to communicate with gdb
63fe386641SBram Moolenaar  let s:commbuf = term_start('NONE', {
64fe386641SBram Moolenaar	\ 'term_name': 'gdb communication',
65fe386641SBram Moolenaar	\ 'out_cb': function('s:CommOutput'),
66fe386641SBram Moolenaar	\ 'hidden': 1,
67fe386641SBram Moolenaar	\ })
68fe386641SBram Moolenaar  if s:commbuf == 0
69fe386641SBram Moolenaar    echoerr 'Failed to open the communication terminal window'
70fe386641SBram Moolenaar    exe 'bwipe! ' . s:ptybuf
71fe386641SBram Moolenaar    return
72fe386641SBram Moolenaar  endif
73fe386641SBram Moolenaar  let commpty = job_info(term_getjob(s:commbuf))['tty_out']
74c572da5fSBram Moolenaar
75c572da5fSBram Moolenaar  " Open a terminal window to run the debugger.
76e09ba7baSBram Moolenaar  let cmd = [g:termdebugger, '-tty', pty, a:cmd]
77c572da5fSBram Moolenaar  echomsg 'executing "' . join(cmd) . '"'
78c572da5fSBram Moolenaar  let gdbbuf = term_start(cmd, {
79c572da5fSBram Moolenaar	\ 'exit_cb': function('s:EndDebug'),
80fe386641SBram Moolenaar	\ 'term_finish': 'close',
81c572da5fSBram Moolenaar	\ })
82fe386641SBram Moolenaar  if gdbbuf == 0
83fe386641SBram Moolenaar    echoerr 'Failed to open the gdb terminal window'
84fe386641SBram Moolenaar    exe 'bwipe! ' . s:ptybuf
85fe386641SBram Moolenaar    exe 'bwipe! ' . s:commbuf
86fe386641SBram Moolenaar    return
87fe386641SBram Moolenaar  endif
8845d5f26dSBram Moolenaar  let s:gdbwin = win_getid(winnr())
89fe386641SBram Moolenaar
90fe386641SBram Moolenaar  " Connect gdb to the communication pty, using the GDB/MI interface
91fe386641SBram Moolenaar  call term_sendkeys(gdbbuf, 'new-ui mi ' . commpty . "\r")
92e09ba7baSBram Moolenaar
9338baa3e6SBram Moolenaar  " Sign used to highlight the line where the program has stopped.
9438baa3e6SBram Moolenaar  " There can be only one.
9538baa3e6SBram Moolenaar  sign define debugPC linehl=debugPC
9638baa3e6SBram Moolenaar
9738baa3e6SBram Moolenaar  " Sign used to indicate a breakpoint.
9838baa3e6SBram Moolenaar  " Can be used multiple times.
9938baa3e6SBram Moolenaar  sign define debugBreakpoint text=>> texthl=debugBreakpoint
10038baa3e6SBram Moolenaar
10145d5f26dSBram Moolenaar  " Install debugger commands in the text window.
10245d5f26dSBram Moolenaar  call win_gotoid(s:startwin)
103e09ba7baSBram Moolenaar  call s:InstallCommands()
10445d5f26dSBram Moolenaar  call win_gotoid(s:gdbwin)
105e09ba7baSBram Moolenaar
106e09ba7baSBram Moolenaar  let s:breakpoints = {}
107*1b9645deSBram Moolenaar
108*1b9645deSBram Moolenaar  augroup TermDebug
109*1b9645deSBram Moolenaar    au BufRead * call s:BufRead()
110*1b9645deSBram Moolenaar    au BufUnload * call s:BufUnloaded()
111*1b9645deSBram Moolenaar  augroup END
112c572da5fSBram Moolenaarendfunc
113c572da5fSBram Moolenaar
114c572da5fSBram Moolenaarfunc s:EndDebug(job, status)
115c572da5fSBram Moolenaar  exe 'bwipe! ' . s:ptybuf
116fe386641SBram Moolenaar  exe 'bwipe! ' . s:commbuf
117e09ba7baSBram Moolenaar
118e09ba7baSBram Moolenaar  let curwinid = win_getid(winnr())
119e09ba7baSBram Moolenaar
120e09ba7baSBram Moolenaar  call win_gotoid(s:startwin)
121e09ba7baSBram Moolenaar  let &signcolumn = s:startsigncolumn
122e09ba7baSBram Moolenaar  call s:DeleteCommands()
123e09ba7baSBram Moolenaar
124e09ba7baSBram Moolenaar  call win_gotoid(curwinid)
12538baa3e6SBram Moolenaar  if s:save_columns > 0
12638baa3e6SBram Moolenaar    let &columns = s:save_columns
12738baa3e6SBram Moolenaar  endif
128*1b9645deSBram Moolenaar
129*1b9645deSBram Moolenaar  au! TermDebug
130fe386641SBram Moolenaarendfunc
131fe386641SBram Moolenaar
132fe386641SBram Moolenaar" Handle a message received from gdb on the GDB/MI interface.
133fe386641SBram Moolenaarfunc s:CommOutput(chan, msg)
134fe386641SBram Moolenaar  let msgs = split(a:msg, "\r")
135fe386641SBram Moolenaar
136fe386641SBram Moolenaar  for msg in msgs
137fe386641SBram Moolenaar    " remove prefixed NL
138fe386641SBram Moolenaar    if msg[0] == "\n"
139fe386641SBram Moolenaar      let msg = msg[1:]
140fe386641SBram Moolenaar    endif
141fe386641SBram Moolenaar    if msg != ''
142*1b9645deSBram Moolenaar      if msg =~ '^\(\*stopped\|\*running\|=thread-selected\)'
143e09ba7baSBram Moolenaar	call s:HandleCursor(msg)
14445d5f26dSBram Moolenaar      elseif msg =~ '^\^done,bkpt=' || msg =~ '^=breakpoint-created,'
145e09ba7baSBram Moolenaar	call s:HandleNewBreakpoint(msg)
146e09ba7baSBram Moolenaar      elseif msg =~ '^=breakpoint-deleted,'
147e09ba7baSBram Moolenaar	call s:HandleBreakpointDelete(msg)
14845d5f26dSBram Moolenaar      elseif msg =~ '^\^done,value='
14945d5f26dSBram Moolenaar	call s:HandleEvaluate(msg)
15045d5f26dSBram Moolenaar      elseif msg =~ '^\^error,msg='
15145d5f26dSBram Moolenaar	call s:HandleError(msg)
152e09ba7baSBram Moolenaar      endif
153e09ba7baSBram Moolenaar    endif
154e09ba7baSBram Moolenaar  endfor
155e09ba7baSBram Moolenaarendfunc
156e09ba7baSBram Moolenaar
157e09ba7baSBram Moolenaar" Install commands in the current window to control the debugger.
158e09ba7baSBram Moolenaarfunc s:InstallCommands()
159e09ba7baSBram Moolenaar  command Break call s:SetBreakpoint()
160e09ba7baSBram Moolenaar  command Delete call s:DeleteBreakpoint()
161e09ba7baSBram Moolenaar  command Step call s:SendCommand('-exec-step')
16245d5f26dSBram Moolenaar  command Over call s:SendCommand('-exec-next')
163e09ba7baSBram Moolenaar  command Finish call s:SendCommand('-exec-finish')
164e09ba7baSBram Moolenaar  command Continue call s:SendCommand('-exec-continue')
16545d5f26dSBram Moolenaar  command -range -nargs=* Evaluate call s:Evaluate(<range>, <q-args>)
16645d5f26dSBram Moolenaar  command Gdb call win_gotoid(s:gdbwin)
16745d5f26dSBram Moolenaar  command Program call win_gotoid(s:ptywin)
16845d5f26dSBram Moolenaar
16945d5f26dSBram Moolenaar  " TODO: can the K mapping be restored?
17045d5f26dSBram Moolenaar  nnoremap K :Evaluate<CR>
171*1b9645deSBram Moolenaar
172*1b9645deSBram Moolenaar  if has('menu')
173*1b9645deSBram Moolenaar    amenu WinBar.Step :Step<CR>
174*1b9645deSBram Moolenaar    amenu WinBar.Next :Over<CR>
175*1b9645deSBram Moolenaar    amenu WinBar.Finish :Finish<CR>
176*1b9645deSBram Moolenaar    amenu WinBar.Cont :Continue<CR>
177*1b9645deSBram Moolenaar    amenu WinBar.Eval :Evaluate<CR>
178*1b9645deSBram Moolenaar  endif
179e09ba7baSBram Moolenaarendfunc
180e09ba7baSBram Moolenaar
181e09ba7baSBram Moolenaar" Delete installed debugger commands in the current window.
182e09ba7baSBram Moolenaarfunc s:DeleteCommands()
183e09ba7baSBram Moolenaar  delcommand Break
184e09ba7baSBram Moolenaar  delcommand Delete
185e09ba7baSBram Moolenaar  delcommand Step
18645d5f26dSBram Moolenaar  delcommand Over
187e09ba7baSBram Moolenaar  delcommand Finish
188e09ba7baSBram Moolenaar  delcommand Continue
18945d5f26dSBram Moolenaar  delcommand Evaluate
19045d5f26dSBram Moolenaar  delcommand Gdb
19145d5f26dSBram Moolenaar  delcommand Program
19245d5f26dSBram Moolenaar
19345d5f26dSBram Moolenaar  nunmap K
194*1b9645deSBram Moolenaar
195*1b9645deSBram Moolenaar  if has('menu')
196*1b9645deSBram Moolenaar    aunmenu WinBar.Step
197*1b9645deSBram Moolenaar    aunmenu WinBar.Next
198*1b9645deSBram Moolenaar    aunmenu WinBar.Finish
199*1b9645deSBram Moolenaar    aunmenu WinBar.Cont
200*1b9645deSBram Moolenaar    aunmenu WinBar.Eval
201*1b9645deSBram Moolenaar  endif
202*1b9645deSBram Moolenaar
20345d5f26dSBram Moolenaar  exe 'sign unplace ' . s:pc_id
20445d5f26dSBram Moolenaar  for key in keys(s:breakpoints)
20545d5f26dSBram Moolenaar    exe 'sign unplace ' . (s:break_id + key)
20645d5f26dSBram Moolenaar  endfor
20738baa3e6SBram Moolenaar  sign undefine debugPC
20838baa3e6SBram Moolenaar  sign undefine debugBreakpoint
20945d5f26dSBram Moolenaar  unlet s:breakpoints
210e09ba7baSBram Moolenaarendfunc
211e09ba7baSBram Moolenaar
212e09ba7baSBram Moolenaar" :Break - Set a breakpoint at the cursor position.
213e09ba7baSBram Moolenaarfunc s:SetBreakpoint()
214e09ba7baSBram Moolenaar  call term_sendkeys(s:commbuf, '-break-insert --source '
215e09ba7baSBram Moolenaar	\ . fnameescape(expand('%:p')) . ' --line ' . line('.') . "\r")
216e09ba7baSBram Moolenaarendfunc
217e09ba7baSBram Moolenaar
218e09ba7baSBram Moolenaar" :Delete - Delete a breakpoint at the cursor position.
219e09ba7baSBram Moolenaarfunc s:DeleteBreakpoint()
220e09ba7baSBram Moolenaar  let fname = fnameescape(expand('%:p'))
221e09ba7baSBram Moolenaar  let lnum = line('.')
222e09ba7baSBram Moolenaar  for [key, val] in items(s:breakpoints)
223e09ba7baSBram Moolenaar    if val['fname'] == fname && val['lnum'] == lnum
224e09ba7baSBram Moolenaar      call term_sendkeys(s:commbuf, '-break-delete ' . key . "\r")
225e09ba7baSBram Moolenaar      " Assume this always wors, the reply is simply "^done".
226e09ba7baSBram Moolenaar      exe 'sign unplace ' . (s:break_id + key)
227e09ba7baSBram Moolenaar      unlet s:breakpoints[key]
228e09ba7baSBram Moolenaar      break
229e09ba7baSBram Moolenaar    endif
230e09ba7baSBram Moolenaar  endfor
231e09ba7baSBram Moolenaarendfunc
232e09ba7baSBram Moolenaar
233e09ba7baSBram Moolenaar" :Next, :Continue, etc - send a command to gdb
234e09ba7baSBram Moolenaarfunc s:SendCommand(cmd)
235e09ba7baSBram Moolenaar  call term_sendkeys(s:commbuf, a:cmd . "\r")
236e09ba7baSBram Moolenaarendfunc
237e09ba7baSBram Moolenaar
23845d5f26dSBram Moolenaar" :Evaluate - evaluate what is under the cursor
23945d5f26dSBram Moolenaarfunc s:Evaluate(range, arg)
24045d5f26dSBram Moolenaar  if a:arg != ''
24145d5f26dSBram Moolenaar    let expr = a:arg
24245d5f26dSBram Moolenaar  elseif a:range == 2
24345d5f26dSBram Moolenaar    let pos = getcurpos()
24445d5f26dSBram Moolenaar    let reg = getreg('v', 1, 1)
24545d5f26dSBram Moolenaar    let regt = getregtype('v')
24645d5f26dSBram Moolenaar    normal! gv"vy
24745d5f26dSBram Moolenaar    let expr = @v
24845d5f26dSBram Moolenaar    call setpos('.', pos)
24945d5f26dSBram Moolenaar    call setreg('v', reg, regt)
25045d5f26dSBram Moolenaar  else
25145d5f26dSBram Moolenaar    let expr = expand('<cexpr>')
25245d5f26dSBram Moolenaar  endif
25345d5f26dSBram Moolenaar  call term_sendkeys(s:commbuf, '-data-evaluate-expression "' . expr . "\"\r")
25445d5f26dSBram Moolenaar  let s:evalexpr = expr
25545d5f26dSBram Moolenaarendfunc
25645d5f26dSBram Moolenaar
25745d5f26dSBram Moolenaar" Handle the result of data-evaluate-expression
25845d5f26dSBram Moolenaarfunc s:HandleEvaluate(msg)
259*1b9645deSBram Moolenaar  let value = substitute(a:msg, '.*value="\(.*\)"', '\1', '')
260*1b9645deSBram Moolenaar  let value = substitute(value, '\\"', '"', 'g')
261*1b9645deSBram Moolenaar  echomsg '"' . s:evalexpr . '": ' . value
262*1b9645deSBram Moolenaar
263*1b9645deSBram Moolenaar  if s:evalexpr[0] != '*' && value =~ '^0x' && value !~ '"$'
264*1b9645deSBram Moolenaar    " Looks like a pointer, also display what it points to.
265*1b9645deSBram Moolenaar    let s:evalexpr = '*' . s:evalexpr
266*1b9645deSBram Moolenaar    call term_sendkeys(s:commbuf, '-data-evaluate-expression "' . s:evalexpr . "\"\r")
267*1b9645deSBram Moolenaar  endif
26845d5f26dSBram Moolenaarendfunc
26945d5f26dSBram Moolenaar
27045d5f26dSBram Moolenaar" Handle an error.
27145d5f26dSBram Moolenaarfunc s:HandleError(msg)
27245d5f26dSBram Moolenaar  echoerr substitute(a:msg, '.*msg="\(.*\)"', '\1', '')
27345d5f26dSBram Moolenaarendfunc
27445d5f26dSBram Moolenaar
275e09ba7baSBram Moolenaar" Handle stopping and running message from gdb.
276e09ba7baSBram Moolenaar" Will update the sign that shows the current position.
277e09ba7baSBram Moolenaarfunc s:HandleCursor(msg)
278fe386641SBram Moolenaar  let wid = win_getid(winnr())
279fe386641SBram Moolenaar
280fe386641SBram Moolenaar  if win_gotoid(s:startwin)
281e09ba7baSBram Moolenaar    let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '')
282*1b9645deSBram Moolenaar    if a:msg =~ '^\(\*stopped\|=thread-selected\)' && filereadable(fname)
283e09ba7baSBram Moolenaar      let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '')
284fe386641SBram Moolenaar      if lnum =~ '^[0-9]*$'
285*1b9645deSBram Moolenaar	if expand('%:p') != fnamemodify(fname, ':p')
286fe386641SBram Moolenaar	  if &modified
287fe386641SBram Moolenaar	    " TODO: find existing window
288fe386641SBram Moolenaar	    exe 'split ' . fnameescape(fname)
289fe386641SBram Moolenaar	    let s:startwin = win_getid(winnr())
290fe386641SBram Moolenaar	  else
291fe386641SBram Moolenaar	    exe 'edit ' . fnameescape(fname)
292fe386641SBram Moolenaar	  endif
293fe386641SBram Moolenaar	endif
294fe386641SBram Moolenaar	exe lnum
295*1b9645deSBram Moolenaar	exe 'sign place ' . s:pc_id . ' line=' . lnum . ' name=debugPC file=' . fname
296fe386641SBram Moolenaar	setlocal signcolumn=yes
297fe386641SBram Moolenaar      endif
298fe386641SBram Moolenaar    else
299fe386641SBram Moolenaar      exe 'sign unplace ' . s:pc_id
300fe386641SBram Moolenaar    endif
301fe386641SBram Moolenaar
302fe386641SBram Moolenaar    call win_gotoid(wid)
303fe386641SBram Moolenaar  endif
304e09ba7baSBram Moolenaarendfunc
305e09ba7baSBram Moolenaar
306e09ba7baSBram Moolenaar" Handle setting a breakpoint
307e09ba7baSBram Moolenaar" Will update the sign that shows the breakpoint
308e09ba7baSBram Moolenaarfunc s:HandleNewBreakpoint(msg)
309e09ba7baSBram Moolenaar  let nr = substitute(a:msg, '.*number="\([0-9]\)*\".*', '\1', '') + 0
310e09ba7baSBram Moolenaar  if nr == 0
311e09ba7baSBram Moolenaar    return
312fe386641SBram Moolenaar  endif
313e09ba7baSBram Moolenaar
314e09ba7baSBram Moolenaar  if has_key(s:breakpoints, nr)
315e09ba7baSBram Moolenaar    let entry = s:breakpoints[nr]
316e09ba7baSBram Moolenaar  else
317e09ba7baSBram Moolenaar    let entry = {}
318e09ba7baSBram Moolenaar    let s:breakpoints[nr] = entry
319fe386641SBram Moolenaar  endif
320e09ba7baSBram Moolenaar
321e09ba7baSBram Moolenaar  let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '')
322e09ba7baSBram Moolenaar  let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '')
323e09ba7baSBram Moolenaar  let entry['fname'] = fname
324e09ba7baSBram Moolenaar  let entry['lnum'] = lnum
325*1b9645deSBram Moolenaar
326*1b9645deSBram Moolenaar  if bufloaded(fname)
327*1b9645deSBram Moolenaar    call s:PlaceSign(nr, entry)
328*1b9645deSBram Moolenaar  endif
329*1b9645deSBram Moolenaarendfunc
330*1b9645deSBram Moolenaar
331*1b9645deSBram Moolenaarfunc s:PlaceSign(nr, entry)
332*1b9645deSBram Moolenaar  exe 'sign place ' . (s:break_id + a:nr) . ' line=' . a:entry['lnum'] . ' name=debugBreakpoint file=' . a:entry['fname']
333*1b9645deSBram Moolenaar  let a:entry['placed'] = 1
334e09ba7baSBram Moolenaarendfunc
335e09ba7baSBram Moolenaar
336e09ba7baSBram Moolenaar" Handle deleting a breakpoint
337e09ba7baSBram Moolenaar" Will remove the sign that shows the breakpoint
338e09ba7baSBram Moolenaarfunc s:HandleBreakpointDelete(msg)
339e09ba7baSBram Moolenaar  let nr = substitute(a:msg, '.*id="\([0-9]*\)\".*', '\1', '') + 0
340e09ba7baSBram Moolenaar  if nr == 0
341e09ba7baSBram Moolenaar    return
342e09ba7baSBram Moolenaar  endif
343*1b9645deSBram Moolenaar  if has_key(s:breakpoints, nr)
344*1b9645deSBram Moolenaar    let entry = s:breakpoints[nr]
345*1b9645deSBram Moolenaar    if has_key(entry, 'placed')
346e09ba7baSBram Moolenaar      exe 'sign unplace ' . (s:break_id + nr)
347*1b9645deSBram Moolenaar      unlet entry['placed']
348*1b9645deSBram Moolenaar    endif
349e09ba7baSBram Moolenaar    unlet s:breakpoints[nr]
350*1b9645deSBram Moolenaar  endif
351c572da5fSBram Moolenaarendfunc
352*1b9645deSBram Moolenaar
353*1b9645deSBram Moolenaar" Handle a BufRead autocommand event: place any signs.
354*1b9645deSBram Moolenaarfunc s:BufRead()
355*1b9645deSBram Moolenaar  let fname = expand('<afile>:p')
356*1b9645deSBram Moolenaar  for [nr, entry] in items(s:breakpoints)
357*1b9645deSBram Moolenaar    if entry['fname'] == fname
358*1b9645deSBram Moolenaar      call s:PlaceSign(nr, entry)
359*1b9645deSBram Moolenaar    endif
360*1b9645deSBram Moolenaar  endfor
361*1b9645deSBram Moolenaarendfunc
362*1b9645deSBram Moolenaar
363*1b9645deSBram Moolenaar" Handle a BufUnloaded autocommand event: unplace any signs.
364*1b9645deSBram Moolenaarfunc s:BufUnloaded()
365*1b9645deSBram Moolenaar  let fname = expand('<afile>:p')
366*1b9645deSBram Moolenaar  for [nr, entry] in items(s:breakpoints)
367*1b9645deSBram Moolenaar    if entry['fname'] == fname
368*1b9645deSBram Moolenaar      let entry['placed'] = 0
369*1b9645deSBram Moolenaar    endif
370*1b9645deSBram Moolenaar  endfor
371*1b9645deSBram Moolenaarendfunc
372*1b9645deSBram Moolenaar
373