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 23fe386641SBram Moolenaar" The command that starts debugging, e.g. ":Termdebug vim". 24fe386641SBram Moolenaar" To end type "quit" in the gdb window. 25c572da5fSBram Moolenaarcommand -nargs=* -complete=file Termdebug call s:StartDebug(<q-args>) 26c572da5fSBram Moolenaar 27fe386641SBram Moolenaar" Name of the gdb command, defaults to "gdb". 28e09ba7baSBram Moolenaarif !exists('termdebugger') 29e09ba7baSBram Moolenaar let termdebugger = 'gdb' 30c572da5fSBram Moolenaarendif 31c572da5fSBram Moolenaar 32fe386641SBram Moolenaarlet s:pc_id = 12 33e09ba7baSBram Moolenaarlet s:break_id = 13 34e09ba7baSBram Moolenaar 35e09ba7baSBram Moolenaarif &background == 'light' 36e09ba7baSBram Moolenaar hi default debugPC term=reverse ctermbg=lightblue guibg=lightblue 37e09ba7baSBram Moolenaarelse 38e09ba7baSBram Moolenaar hi default debugPC term=reverse ctermbg=darkblue guibg=darkblue 39e09ba7baSBram Moolenaarendif 40e09ba7baSBram Moolenaarhi default debugBreakpoint term=reverse ctermbg=red guibg=red 41fe386641SBram Moolenaar 42c572da5fSBram Moolenaarfunc s:StartDebug(cmd) 43fe386641SBram Moolenaar let s:startwin = win_getid(winnr()) 44fe386641SBram Moolenaar let s:startsigncolumn = &signcolumn 45fe386641SBram Moolenaar 4624a98a0eSBram Moolenaar let s:save_columns = 0 4724a98a0eSBram Moolenaar if exists('g:termdebug_wide') 4824a98a0eSBram Moolenaar if &columns < g:termdebug_wide 4938baa3e6SBram Moolenaar let s:save_columns = &columns 5038baa3e6SBram Moolenaar let &columns = g:termdebug_wide 5124a98a0eSBram Moolenaar endif 5238baa3e6SBram Moolenaar let vertical = 1 5338baa3e6SBram Moolenaar else 5438baa3e6SBram Moolenaar let vertical = 0 5538baa3e6SBram Moolenaar endif 5638baa3e6SBram Moolenaar 57c572da5fSBram Moolenaar " Open a terminal window without a job, to run the debugged program 58fe386641SBram Moolenaar let s:ptybuf = term_start('NONE', { 59fe386641SBram Moolenaar \ 'term_name': 'gdb program', 6038baa3e6SBram Moolenaar \ 'vertical': vertical, 61fe386641SBram Moolenaar \ }) 62fe386641SBram Moolenaar if s:ptybuf == 0 63fe386641SBram Moolenaar echoerr 'Failed to open the program terminal window' 64fe386641SBram Moolenaar return 65fe386641SBram Moolenaar endif 66fe386641SBram Moolenaar let pty = job_info(term_getjob(s:ptybuf))['tty_out'] 6745d5f26dSBram Moolenaar let s:ptywin = win_getid(winnr()) 68fe386641SBram Moolenaar 69fe386641SBram Moolenaar " Create a hidden terminal window to communicate with gdb 70fe386641SBram Moolenaar let s:commbuf = term_start('NONE', { 71fe386641SBram Moolenaar \ 'term_name': 'gdb communication', 72fe386641SBram Moolenaar \ 'out_cb': function('s:CommOutput'), 73fe386641SBram Moolenaar \ 'hidden': 1, 74fe386641SBram Moolenaar \ }) 75fe386641SBram Moolenaar if s:commbuf == 0 76fe386641SBram Moolenaar echoerr 'Failed to open the communication terminal window' 77fe386641SBram Moolenaar exe 'bwipe! ' . s:ptybuf 78fe386641SBram Moolenaar return 79fe386641SBram Moolenaar endif 80fe386641SBram Moolenaar let commpty = job_info(term_getjob(s:commbuf))['tty_out'] 81c572da5fSBram Moolenaar 82c572da5fSBram Moolenaar " Open a terminal window to run the debugger. 83c3632516SBram Moolenaar " Add -quiet to avoid the intro message causing a hit-enter prompt. 84c3632516SBram Moolenaar let cmd = [g:termdebugger, '-quiet', '-tty', pty, a:cmd] 85c572da5fSBram Moolenaar echomsg 'executing "' . join(cmd) . '"' 86c572da5fSBram Moolenaar let gdbbuf = term_start(cmd, { 87c572da5fSBram Moolenaar \ 'exit_cb': function('s:EndDebug'), 88fe386641SBram Moolenaar \ 'term_finish': 'close', 89c572da5fSBram Moolenaar \ }) 90fe386641SBram Moolenaar if gdbbuf == 0 91fe386641SBram Moolenaar echoerr 'Failed to open the gdb terminal window' 92fe386641SBram Moolenaar exe 'bwipe! ' . s:ptybuf 93fe386641SBram Moolenaar exe 'bwipe! ' . s:commbuf 94fe386641SBram Moolenaar return 95fe386641SBram Moolenaar endif 9645d5f26dSBram Moolenaar let s:gdbwin = win_getid(winnr()) 97fe386641SBram Moolenaar 98fe386641SBram Moolenaar " Connect gdb to the communication pty, using the GDB/MI interface 9901164a65SBram Moolenaar " If you get an error "undefined command" your GDB is too old. 100fe386641SBram Moolenaar call term_sendkeys(gdbbuf, 'new-ui mi ' . commpty . "\r") 101e09ba7baSBram Moolenaar 10238baa3e6SBram Moolenaar " Sign used to highlight the line where the program has stopped. 10338baa3e6SBram Moolenaar " There can be only one. 10438baa3e6SBram Moolenaar sign define debugPC linehl=debugPC 10538baa3e6SBram Moolenaar 10638baa3e6SBram Moolenaar " Sign used to indicate a breakpoint. 10738baa3e6SBram Moolenaar " Can be used multiple times. 10838baa3e6SBram Moolenaar sign define debugBreakpoint text=>> texthl=debugBreakpoint 10938baa3e6SBram Moolenaar 11045d5f26dSBram Moolenaar " Install debugger commands in the text window. 11145d5f26dSBram Moolenaar call win_gotoid(s:startwin) 112e09ba7baSBram Moolenaar call s:InstallCommands() 11345d5f26dSBram Moolenaar call win_gotoid(s:gdbwin) 114e09ba7baSBram Moolenaar 115e09ba7baSBram Moolenaar let s:breakpoints = {} 1161b9645deSBram Moolenaar 1171b9645deSBram Moolenaar augroup TermDebug 1181b9645deSBram Moolenaar au BufRead * call s:BufRead() 1191b9645deSBram Moolenaar au BufUnload * call s:BufUnloaded() 1201b9645deSBram Moolenaar augroup END 121c572da5fSBram Moolenaarendfunc 122c572da5fSBram Moolenaar 123c572da5fSBram Moolenaarfunc s:EndDebug(job, status) 124c572da5fSBram Moolenaar exe 'bwipe! ' . s:ptybuf 125fe386641SBram Moolenaar exe 'bwipe! ' . s:commbuf 126e09ba7baSBram Moolenaar 127e09ba7baSBram Moolenaar let curwinid = win_getid(winnr()) 128e09ba7baSBram Moolenaar 129e09ba7baSBram Moolenaar call win_gotoid(s:startwin) 130e09ba7baSBram Moolenaar let &signcolumn = s:startsigncolumn 131e09ba7baSBram Moolenaar call s:DeleteCommands() 132e09ba7baSBram Moolenaar 133e09ba7baSBram Moolenaar call win_gotoid(curwinid) 13438baa3e6SBram Moolenaar if s:save_columns > 0 13538baa3e6SBram Moolenaar let &columns = s:save_columns 13638baa3e6SBram Moolenaar endif 1371b9645deSBram Moolenaar 1381b9645deSBram Moolenaar au! TermDebug 139fe386641SBram Moolenaarendfunc 140fe386641SBram Moolenaar 141fe386641SBram Moolenaar" Handle a message received from gdb on the GDB/MI interface. 142fe386641SBram Moolenaarfunc s:CommOutput(chan, msg) 143fe386641SBram Moolenaar let msgs = split(a:msg, "\r") 144fe386641SBram Moolenaar 145fe386641SBram Moolenaar for msg in msgs 146fe386641SBram Moolenaar " remove prefixed NL 147fe386641SBram Moolenaar if msg[0] == "\n" 148fe386641SBram Moolenaar let msg = msg[1:] 149fe386641SBram Moolenaar endif 150fe386641SBram Moolenaar if msg != '' 1511b9645deSBram Moolenaar if msg =~ '^\(\*stopped\|\*running\|=thread-selected\)' 152e09ba7baSBram Moolenaar call s:HandleCursor(msg) 15345d5f26dSBram Moolenaar elseif msg =~ '^\^done,bkpt=' || msg =~ '^=breakpoint-created,' 154e09ba7baSBram Moolenaar call s:HandleNewBreakpoint(msg) 155e09ba7baSBram Moolenaar elseif msg =~ '^=breakpoint-deleted,' 156e09ba7baSBram Moolenaar call s:HandleBreakpointDelete(msg) 15745d5f26dSBram Moolenaar elseif msg =~ '^\^done,value=' 15845d5f26dSBram Moolenaar call s:HandleEvaluate(msg) 15945d5f26dSBram Moolenaar elseif msg =~ '^\^error,msg=' 16045d5f26dSBram Moolenaar call s:HandleError(msg) 161e09ba7baSBram Moolenaar endif 162e09ba7baSBram Moolenaar endif 163e09ba7baSBram Moolenaar endfor 164e09ba7baSBram Moolenaarendfunc 165e09ba7baSBram Moolenaar 166e09ba7baSBram Moolenaar" Install commands in the current window to control the debugger. 167e09ba7baSBram Moolenaarfunc s:InstallCommands() 168e09ba7baSBram Moolenaar command Break call s:SetBreakpoint() 169e09ba7baSBram Moolenaar command Delete call s:DeleteBreakpoint() 170e09ba7baSBram Moolenaar command Step call s:SendCommand('-exec-step') 17145d5f26dSBram Moolenaar command Over call s:SendCommand('-exec-next') 172e09ba7baSBram Moolenaar command Finish call s:SendCommand('-exec-finish') 173e09ba7baSBram Moolenaar command Continue call s:SendCommand('-exec-continue') 17445d5f26dSBram Moolenaar command -range -nargs=* Evaluate call s:Evaluate(<range>, <q-args>) 17545d5f26dSBram Moolenaar command Gdb call win_gotoid(s:gdbwin) 17645d5f26dSBram Moolenaar command Program call win_gotoid(s:ptywin) 17745d5f26dSBram Moolenaar 17845d5f26dSBram Moolenaar " TODO: can the K mapping be restored? 17945d5f26dSBram Moolenaar nnoremap K :Evaluate<CR> 1801b9645deSBram Moolenaar 1811b9645deSBram Moolenaar if has('menu') 18224a98a0eSBram Moolenaar nnoremenu WinBar.Step :Step<CR> 18324a98a0eSBram Moolenaar nnoremenu WinBar.Next :Over<CR> 18424a98a0eSBram Moolenaar nnoremenu WinBar.Finish :Finish<CR> 18524a98a0eSBram Moolenaar nnoremenu WinBar.Cont :Continue<CR> 18624a98a0eSBram Moolenaar nnoremenu WinBar.Eval :Evaluate<CR> 1871b9645deSBram Moolenaar endif 188e09ba7baSBram Moolenaarendfunc 189e09ba7baSBram Moolenaar 190e09ba7baSBram Moolenaar" Delete installed debugger commands in the current window. 191e09ba7baSBram Moolenaarfunc s:DeleteCommands() 192e09ba7baSBram Moolenaar delcommand Break 193e09ba7baSBram Moolenaar delcommand Delete 194e09ba7baSBram Moolenaar delcommand Step 19545d5f26dSBram Moolenaar delcommand Over 196e09ba7baSBram Moolenaar delcommand Finish 197e09ba7baSBram Moolenaar delcommand Continue 19845d5f26dSBram Moolenaar delcommand Evaluate 19945d5f26dSBram Moolenaar delcommand Gdb 20045d5f26dSBram Moolenaar delcommand Program 20145d5f26dSBram Moolenaar 20245d5f26dSBram Moolenaar nunmap K 2031b9645deSBram Moolenaar 2041b9645deSBram Moolenaar if has('menu') 2051b9645deSBram Moolenaar aunmenu WinBar.Step 2061b9645deSBram Moolenaar aunmenu WinBar.Next 2071b9645deSBram Moolenaar aunmenu WinBar.Finish 2081b9645deSBram Moolenaar aunmenu WinBar.Cont 2091b9645deSBram Moolenaar aunmenu WinBar.Eval 2101b9645deSBram Moolenaar endif 2111b9645deSBram Moolenaar 21245d5f26dSBram Moolenaar exe 'sign unplace ' . s:pc_id 21345d5f26dSBram Moolenaar for key in keys(s:breakpoints) 21445d5f26dSBram Moolenaar exe 'sign unplace ' . (s:break_id + key) 21545d5f26dSBram Moolenaar endfor 21638baa3e6SBram Moolenaar sign undefine debugPC 21738baa3e6SBram Moolenaar sign undefine debugBreakpoint 21845d5f26dSBram Moolenaar unlet s:breakpoints 219e09ba7baSBram Moolenaarendfunc 220e09ba7baSBram Moolenaar 221e09ba7baSBram Moolenaar" :Break - Set a breakpoint at the cursor position. 222e09ba7baSBram Moolenaarfunc s:SetBreakpoint() 223e09ba7baSBram Moolenaar call term_sendkeys(s:commbuf, '-break-insert --source ' 224e09ba7baSBram Moolenaar \ . fnameescape(expand('%:p')) . ' --line ' . line('.') . "\r") 225e09ba7baSBram Moolenaarendfunc 226e09ba7baSBram Moolenaar 227e09ba7baSBram Moolenaar" :Delete - Delete a breakpoint at the cursor position. 228e09ba7baSBram Moolenaarfunc s:DeleteBreakpoint() 229e09ba7baSBram Moolenaar let fname = fnameescape(expand('%:p')) 230e09ba7baSBram Moolenaar let lnum = line('.') 231e09ba7baSBram Moolenaar for [key, val] in items(s:breakpoints) 232e09ba7baSBram Moolenaar if val['fname'] == fname && val['lnum'] == lnum 233e09ba7baSBram Moolenaar call term_sendkeys(s:commbuf, '-break-delete ' . key . "\r") 234e09ba7baSBram Moolenaar " Assume this always wors, the reply is simply "^done". 235e09ba7baSBram Moolenaar exe 'sign unplace ' . (s:break_id + key) 236e09ba7baSBram Moolenaar unlet s:breakpoints[key] 237e09ba7baSBram Moolenaar break 238e09ba7baSBram Moolenaar endif 239e09ba7baSBram Moolenaar endfor 240e09ba7baSBram Moolenaarendfunc 241e09ba7baSBram Moolenaar 242e09ba7baSBram Moolenaar" :Next, :Continue, etc - send a command to gdb 243e09ba7baSBram Moolenaarfunc s:SendCommand(cmd) 244e09ba7baSBram Moolenaar call term_sendkeys(s:commbuf, a:cmd . "\r") 245e09ba7baSBram Moolenaarendfunc 246e09ba7baSBram Moolenaar 24745d5f26dSBram Moolenaar" :Evaluate - evaluate what is under the cursor 24845d5f26dSBram Moolenaarfunc s:Evaluate(range, arg) 24945d5f26dSBram Moolenaar if a:arg != '' 25045d5f26dSBram Moolenaar let expr = a:arg 25145d5f26dSBram Moolenaar elseif a:range == 2 25245d5f26dSBram Moolenaar let pos = getcurpos() 25345d5f26dSBram Moolenaar let reg = getreg('v', 1, 1) 25445d5f26dSBram Moolenaar let regt = getregtype('v') 25545d5f26dSBram Moolenaar normal! gv"vy 25645d5f26dSBram Moolenaar let expr = @v 25745d5f26dSBram Moolenaar call setpos('.', pos) 25845d5f26dSBram Moolenaar call setreg('v', reg, regt) 25945d5f26dSBram Moolenaar else 26045d5f26dSBram Moolenaar let expr = expand('<cexpr>') 26145d5f26dSBram Moolenaar endif 26245d5f26dSBram Moolenaar call term_sendkeys(s:commbuf, '-data-evaluate-expression "' . expr . "\"\r") 26345d5f26dSBram Moolenaar let s:evalexpr = expr 26445d5f26dSBram Moolenaarendfunc 26545d5f26dSBram Moolenaar 26645d5f26dSBram Moolenaar" Handle the result of data-evaluate-expression 26745d5f26dSBram Moolenaarfunc s:HandleEvaluate(msg) 2681b9645deSBram Moolenaar let value = substitute(a:msg, '.*value="\(.*\)"', '\1', '') 2691b9645deSBram Moolenaar let value = substitute(value, '\\"', '"', 'g') 2701b9645deSBram Moolenaar echomsg '"' . s:evalexpr . '": ' . value 2711b9645deSBram Moolenaar 272*7f2e9d7cSBram Moolenaar if s:evalexpr[0] != '*' && value =~ '^0x' && value != '0x0' && value !~ '"$' 2731b9645deSBram Moolenaar " Looks like a pointer, also display what it points to. 2741b9645deSBram Moolenaar let s:evalexpr = '*' . s:evalexpr 2751b9645deSBram Moolenaar call term_sendkeys(s:commbuf, '-data-evaluate-expression "' . s:evalexpr . "\"\r") 2761b9645deSBram Moolenaar endif 27745d5f26dSBram Moolenaarendfunc 27845d5f26dSBram Moolenaar 27945d5f26dSBram Moolenaar" Handle an error. 28045d5f26dSBram Moolenaarfunc s:HandleError(msg) 28145d5f26dSBram Moolenaar echoerr substitute(a:msg, '.*msg="\(.*\)"', '\1', '') 28245d5f26dSBram Moolenaarendfunc 28345d5f26dSBram Moolenaar 284e09ba7baSBram Moolenaar" Handle stopping and running message from gdb. 285e09ba7baSBram Moolenaar" Will update the sign that shows the current position. 286e09ba7baSBram Moolenaarfunc s:HandleCursor(msg) 287fe386641SBram Moolenaar let wid = win_getid(winnr()) 288fe386641SBram Moolenaar 289fe386641SBram Moolenaar if win_gotoid(s:startwin) 290e09ba7baSBram Moolenaar let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '') 2911b9645deSBram Moolenaar if a:msg =~ '^\(\*stopped\|=thread-selected\)' && filereadable(fname) 292e09ba7baSBram Moolenaar let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '') 293fe386641SBram Moolenaar if lnum =~ '^[0-9]*$' 2941b9645deSBram Moolenaar if expand('%:p') != fnamemodify(fname, ':p') 295fe386641SBram Moolenaar if &modified 296fe386641SBram Moolenaar " TODO: find existing window 297fe386641SBram Moolenaar exe 'split ' . fnameescape(fname) 298fe386641SBram Moolenaar let s:startwin = win_getid(winnr()) 299fe386641SBram Moolenaar else 300fe386641SBram Moolenaar exe 'edit ' . fnameescape(fname) 301fe386641SBram Moolenaar endif 302fe386641SBram Moolenaar endif 303fe386641SBram Moolenaar exe lnum 30401164a65SBram Moolenaar exe 'sign unplace ' . s:pc_id 3051b9645deSBram Moolenaar exe 'sign place ' . s:pc_id . ' line=' . lnum . ' name=debugPC file=' . fname 306fe386641SBram Moolenaar setlocal signcolumn=yes 307fe386641SBram Moolenaar endif 308fe386641SBram Moolenaar else 309fe386641SBram Moolenaar exe 'sign unplace ' . s:pc_id 310fe386641SBram Moolenaar endif 311fe386641SBram Moolenaar 312fe386641SBram Moolenaar call win_gotoid(wid) 313fe386641SBram Moolenaar endif 314e09ba7baSBram Moolenaarendfunc 315e09ba7baSBram Moolenaar 316e09ba7baSBram Moolenaar" Handle setting a breakpoint 317e09ba7baSBram Moolenaar" Will update the sign that shows the breakpoint 318e09ba7baSBram Moolenaarfunc s:HandleNewBreakpoint(msg) 319e09ba7baSBram Moolenaar let nr = substitute(a:msg, '.*number="\([0-9]\)*\".*', '\1', '') + 0 320e09ba7baSBram Moolenaar if nr == 0 321e09ba7baSBram Moolenaar return 322fe386641SBram Moolenaar endif 323e09ba7baSBram Moolenaar 324e09ba7baSBram Moolenaar if has_key(s:breakpoints, nr) 325e09ba7baSBram Moolenaar let entry = s:breakpoints[nr] 326e09ba7baSBram Moolenaar else 327e09ba7baSBram Moolenaar let entry = {} 328e09ba7baSBram Moolenaar let s:breakpoints[nr] = entry 329fe386641SBram Moolenaar endif 330e09ba7baSBram Moolenaar 331e09ba7baSBram Moolenaar let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '') 332e09ba7baSBram Moolenaar let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '') 333e09ba7baSBram Moolenaar let entry['fname'] = fname 334e09ba7baSBram Moolenaar let entry['lnum'] = lnum 3351b9645deSBram Moolenaar 3361b9645deSBram Moolenaar if bufloaded(fname) 3371b9645deSBram Moolenaar call s:PlaceSign(nr, entry) 3381b9645deSBram Moolenaar endif 3391b9645deSBram Moolenaarendfunc 3401b9645deSBram Moolenaar 3411b9645deSBram Moolenaarfunc s:PlaceSign(nr, entry) 3421b9645deSBram Moolenaar exe 'sign place ' . (s:break_id + a:nr) . ' line=' . a:entry['lnum'] . ' name=debugBreakpoint file=' . a:entry['fname'] 3431b9645deSBram Moolenaar let a:entry['placed'] = 1 344e09ba7baSBram Moolenaarendfunc 345e09ba7baSBram Moolenaar 346e09ba7baSBram Moolenaar" Handle deleting a breakpoint 347e09ba7baSBram Moolenaar" Will remove the sign that shows the breakpoint 348e09ba7baSBram Moolenaarfunc s:HandleBreakpointDelete(msg) 349e09ba7baSBram Moolenaar let nr = substitute(a:msg, '.*id="\([0-9]*\)\".*', '\1', '') + 0 350e09ba7baSBram Moolenaar if nr == 0 351e09ba7baSBram Moolenaar return 352e09ba7baSBram Moolenaar endif 3531b9645deSBram Moolenaar if has_key(s:breakpoints, nr) 3541b9645deSBram Moolenaar let entry = s:breakpoints[nr] 3551b9645deSBram Moolenaar if has_key(entry, 'placed') 356e09ba7baSBram Moolenaar exe 'sign unplace ' . (s:break_id + nr) 3571b9645deSBram Moolenaar unlet entry['placed'] 3581b9645deSBram Moolenaar endif 359e09ba7baSBram Moolenaar unlet s:breakpoints[nr] 3601b9645deSBram Moolenaar endif 361c572da5fSBram Moolenaarendfunc 3621b9645deSBram Moolenaar 3631b9645deSBram Moolenaar" Handle a BufRead autocommand event: place any signs. 3641b9645deSBram Moolenaarfunc s:BufRead() 3651b9645deSBram Moolenaar let fname = expand('<afile>:p') 3661b9645deSBram Moolenaar for [nr, entry] in items(s:breakpoints) 3671b9645deSBram Moolenaar if entry['fname'] == fname 3681b9645deSBram Moolenaar call s:PlaceSign(nr, entry) 3691b9645deSBram Moolenaar endif 3701b9645deSBram Moolenaar endfor 3711b9645deSBram Moolenaarendfunc 3721b9645deSBram Moolenaar 3731b9645deSBram Moolenaar" Handle a BufUnloaded autocommand event: unplace any signs. 3741b9645deSBram Moolenaarfunc s:BufUnloaded() 3751b9645deSBram Moolenaar let fname = expand('<afile>:p') 3761b9645deSBram Moolenaar for [nr, entry] in items(s:breakpoints) 3771b9645deSBram Moolenaar if entry['fname'] == fname 3781b9645deSBram Moolenaar let entry['placed'] = 0 3791b9645deSBram Moolenaar endif 3801b9645deSBram Moolenaar endfor 3811b9645deSBram Moolenaarendfunc 3821b9645deSBram Moolenaar 383