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 23*60e73f2aSBram Moolenaar" Uncomment this line to write logging in "debuglog". 24*60e73f2aSBram Moolenaar" call ch_logfile('debuglog', 'w') 25*60e73f2aSBram 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 37*60e73f2aSBram 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()) 72fe386641SBram Moolenaar 73fe386641SBram Moolenaar " Create a hidden terminal window to communicate with gdb 74fe386641SBram Moolenaar let s:commbuf = term_start('NONE', { 75fe386641SBram Moolenaar \ 'term_name': 'gdb communication', 76fe386641SBram Moolenaar \ 'out_cb': function('s:CommOutput'), 77fe386641SBram Moolenaar \ 'hidden': 1, 78fe386641SBram Moolenaar \ }) 79fe386641SBram Moolenaar if s:commbuf == 0 80fe386641SBram Moolenaar echoerr 'Failed to open the communication terminal window' 81fe386641SBram Moolenaar exe 'bwipe! ' . s:ptybuf 82fe386641SBram Moolenaar return 83fe386641SBram Moolenaar endif 84fe386641SBram Moolenaar let commpty = job_info(term_getjob(s:commbuf))['tty_out'] 85c572da5fSBram Moolenaar 86c572da5fSBram Moolenaar " Open a terminal window to run the debugger. 87c3632516SBram Moolenaar " Add -quiet to avoid the intro message causing a hit-enter prompt. 88c3632516SBram Moolenaar let cmd = [g:termdebugger, '-quiet', '-tty', pty, a:cmd] 89c572da5fSBram Moolenaar echomsg 'executing "' . join(cmd) . '"' 90*60e73f2aSBram Moolenaar let s:gdbbuf = term_start(cmd, { 91c572da5fSBram Moolenaar \ 'exit_cb': function('s:EndDebug'), 92fe386641SBram Moolenaar \ 'term_finish': 'close', 93c572da5fSBram Moolenaar \ }) 94*60e73f2aSBram Moolenaar if s:gdbbuf == 0 95fe386641SBram Moolenaar echoerr 'Failed to open the gdb terminal window' 96fe386641SBram Moolenaar exe 'bwipe! ' . s:ptybuf 97fe386641SBram Moolenaar exe 'bwipe! ' . s:commbuf 98fe386641SBram Moolenaar return 99fe386641SBram Moolenaar endif 10045d5f26dSBram Moolenaar let s:gdbwin = win_getid(winnr()) 101fe386641SBram Moolenaar 102fe386641SBram Moolenaar " Connect gdb to the communication pty, using the GDB/MI interface 10301164a65SBram Moolenaar " If you get an error "undefined command" your GDB is too old. 104*60e73f2aSBram Moolenaar call term_sendkeys(s:gdbbuf, 'new-ui mi ' . commpty . "\r") 105*60e73f2aSBram Moolenaar 106*60e73f2aSBram Moolenaar " Interpret commands while the target is running. This should usualy only be 107*60e73f2aSBram Moolenaar " exec-interrupt, since many commands don't work properly while the target is 108*60e73f2aSBram Moolenaar " running. 109*60e73f2aSBram Moolenaar call s:SendCommand('-gdb-set mi-async on') 110e09ba7baSBram Moolenaar 11138baa3e6SBram Moolenaar " Sign used to highlight the line where the program has stopped. 11238baa3e6SBram Moolenaar " There can be only one. 11338baa3e6SBram Moolenaar sign define debugPC linehl=debugPC 11438baa3e6SBram Moolenaar 11538baa3e6SBram Moolenaar " Sign used to indicate a breakpoint. 11638baa3e6SBram Moolenaar " Can be used multiple times. 11738baa3e6SBram Moolenaar sign define debugBreakpoint text=>> texthl=debugBreakpoint 11838baa3e6SBram Moolenaar 11945d5f26dSBram Moolenaar " Install debugger commands in the text window. 12045d5f26dSBram Moolenaar call win_gotoid(s:startwin) 121e09ba7baSBram Moolenaar call s:InstallCommands() 12245d5f26dSBram Moolenaar call win_gotoid(s:gdbwin) 123e09ba7baSBram Moolenaar 124e09ba7baSBram Moolenaar let s:breakpoints = {} 1251b9645deSBram Moolenaar 1261b9645deSBram Moolenaar augroup TermDebug 1271b9645deSBram Moolenaar au BufRead * call s:BufRead() 1281b9645deSBram Moolenaar au BufUnload * call s:BufUnloaded() 1291b9645deSBram Moolenaar augroup END 130c572da5fSBram Moolenaarendfunc 131c572da5fSBram Moolenaar 132c572da5fSBram Moolenaarfunc s:EndDebug(job, status) 133c572da5fSBram Moolenaar exe 'bwipe! ' . s:ptybuf 134fe386641SBram Moolenaar exe 'bwipe! ' . s:commbuf 135e09ba7baSBram Moolenaar 136e09ba7baSBram Moolenaar let curwinid = win_getid(winnr()) 137e09ba7baSBram Moolenaar 138e09ba7baSBram Moolenaar call win_gotoid(s:startwin) 139e09ba7baSBram Moolenaar let &signcolumn = s:startsigncolumn 140e09ba7baSBram Moolenaar call s:DeleteCommands() 141e09ba7baSBram Moolenaar 142e09ba7baSBram Moolenaar call win_gotoid(curwinid) 14338baa3e6SBram Moolenaar if s:save_columns > 0 14438baa3e6SBram Moolenaar let &columns = s:save_columns 14538baa3e6SBram Moolenaar endif 1461b9645deSBram Moolenaar 1471b9645deSBram Moolenaar au! TermDebug 148fe386641SBram Moolenaarendfunc 149fe386641SBram Moolenaar 150fe386641SBram Moolenaar" Handle a message received from gdb on the GDB/MI interface. 151fe386641SBram Moolenaarfunc s:CommOutput(chan, msg) 152fe386641SBram Moolenaar let msgs = split(a:msg, "\r") 153fe386641SBram Moolenaar 154fe386641SBram Moolenaar for msg in msgs 155fe386641SBram Moolenaar " remove prefixed NL 156fe386641SBram Moolenaar if msg[0] == "\n" 157fe386641SBram Moolenaar let msg = msg[1:] 158fe386641SBram Moolenaar endif 159fe386641SBram Moolenaar if msg != '' 1601b9645deSBram Moolenaar if msg =~ '^\(\*stopped\|\*running\|=thread-selected\)' 161e09ba7baSBram Moolenaar call s:HandleCursor(msg) 16245d5f26dSBram Moolenaar elseif msg =~ '^\^done,bkpt=' || msg =~ '^=breakpoint-created,' 163e09ba7baSBram Moolenaar call s:HandleNewBreakpoint(msg) 164e09ba7baSBram Moolenaar elseif msg =~ '^=breakpoint-deleted,' 165e09ba7baSBram Moolenaar call s:HandleBreakpointDelete(msg) 16645d5f26dSBram Moolenaar elseif msg =~ '^\^done,value=' 16745d5f26dSBram Moolenaar call s:HandleEvaluate(msg) 16845d5f26dSBram Moolenaar elseif msg =~ '^\^error,msg=' 16945d5f26dSBram Moolenaar call s:HandleError(msg) 170e09ba7baSBram Moolenaar endif 171e09ba7baSBram Moolenaar endif 172e09ba7baSBram Moolenaar endfor 173e09ba7baSBram Moolenaarendfunc 174e09ba7baSBram Moolenaar 175e09ba7baSBram Moolenaar" Install commands in the current window to control the debugger. 176e09ba7baSBram Moolenaarfunc s:InstallCommands() 177e09ba7baSBram Moolenaar command Break call s:SetBreakpoint() 178e09ba7baSBram Moolenaar command Delete call s:DeleteBreakpoint() 179e09ba7baSBram Moolenaar command Step call s:SendCommand('-exec-step') 18045d5f26dSBram Moolenaar command Over call s:SendCommand('-exec-next') 181e09ba7baSBram Moolenaar command Finish call s:SendCommand('-exec-finish') 182*60e73f2aSBram Moolenaar command -nargs=* Run call s:Run(<q-args>) 183*60e73f2aSBram Moolenaar command -nargs=* Arguments call s:SendCommand('-exec-arguments ' . <q-args>) 184*60e73f2aSBram Moolenaar command Stop call s:SendCommand('-exec-interrupt') 185e09ba7baSBram Moolenaar command Continue call s:SendCommand('-exec-continue') 18645d5f26dSBram Moolenaar command -range -nargs=* Evaluate call s:Evaluate(<range>, <q-args>) 18745d5f26dSBram Moolenaar command Gdb call win_gotoid(s:gdbwin) 18845d5f26dSBram Moolenaar command Program call win_gotoid(s:ptywin) 18945d5f26dSBram Moolenaar 19045d5f26dSBram Moolenaar " TODO: can the K mapping be restored? 19145d5f26dSBram Moolenaar nnoremap K :Evaluate<CR> 1921b9645deSBram Moolenaar 1931b9645deSBram Moolenaar if has('menu') 19424a98a0eSBram Moolenaar nnoremenu WinBar.Step :Step<CR> 19524a98a0eSBram Moolenaar nnoremenu WinBar.Next :Over<CR> 19624a98a0eSBram Moolenaar nnoremenu WinBar.Finish :Finish<CR> 19724a98a0eSBram Moolenaar nnoremenu WinBar.Cont :Continue<CR> 198*60e73f2aSBram Moolenaar nnoremenu WinBar.Stop :Stop<CR> 19924a98a0eSBram Moolenaar nnoremenu WinBar.Eval :Evaluate<CR> 2001b9645deSBram Moolenaar endif 201e09ba7baSBram Moolenaarendfunc 202e09ba7baSBram Moolenaar 203e09ba7baSBram Moolenaar" Delete installed debugger commands in the current window. 204e09ba7baSBram Moolenaarfunc s:DeleteCommands() 205e09ba7baSBram Moolenaar delcommand Break 206e09ba7baSBram Moolenaar delcommand Delete 207e09ba7baSBram Moolenaar delcommand Step 20845d5f26dSBram Moolenaar delcommand Over 209e09ba7baSBram Moolenaar delcommand Finish 210*60e73f2aSBram Moolenaar delcommand Run 211*60e73f2aSBram Moolenaar delcommand Arguments 212*60e73f2aSBram Moolenaar delcommand Stop 213e09ba7baSBram Moolenaar delcommand Continue 21445d5f26dSBram Moolenaar delcommand Evaluate 21545d5f26dSBram Moolenaar delcommand Gdb 21645d5f26dSBram Moolenaar delcommand Program 21745d5f26dSBram Moolenaar 21845d5f26dSBram Moolenaar nunmap K 2191b9645deSBram Moolenaar 2201b9645deSBram Moolenaar if has('menu') 2211b9645deSBram Moolenaar aunmenu WinBar.Step 2221b9645deSBram Moolenaar aunmenu WinBar.Next 2231b9645deSBram Moolenaar aunmenu WinBar.Finish 2241b9645deSBram Moolenaar aunmenu WinBar.Cont 225*60e73f2aSBram Moolenaar aunmenu WinBar.Stop 2261b9645deSBram Moolenaar aunmenu WinBar.Eval 2271b9645deSBram Moolenaar endif 2281b9645deSBram Moolenaar 22945d5f26dSBram Moolenaar exe 'sign unplace ' . s:pc_id 23045d5f26dSBram Moolenaar for key in keys(s:breakpoints) 23145d5f26dSBram Moolenaar exe 'sign unplace ' . (s:break_id + key) 23245d5f26dSBram Moolenaar endfor 23338baa3e6SBram Moolenaar sign undefine debugPC 23438baa3e6SBram Moolenaar sign undefine debugBreakpoint 23545d5f26dSBram Moolenaar unlet s:breakpoints 236e09ba7baSBram Moolenaarendfunc 237e09ba7baSBram Moolenaar 238e09ba7baSBram Moolenaar" :Break - Set a breakpoint at the cursor position. 239e09ba7baSBram Moolenaarfunc s:SetBreakpoint() 240*60e73f2aSBram Moolenaar " Setting a breakpoint may not work while the program is running. 241*60e73f2aSBram Moolenaar " Interrupt to make it work. 242*60e73f2aSBram Moolenaar let do_continue = 0 243*60e73f2aSBram Moolenaar if !s:stopped 244*60e73f2aSBram Moolenaar let do_continue = 1 245*60e73f2aSBram Moolenaar call s:SendCommand('-exec-interrupt') 246*60e73f2aSBram Moolenaar sleep 10m 247*60e73f2aSBram Moolenaar endif 248*60e73f2aSBram Moolenaar call s:SendCommand('-break-insert --source ' 249*60e73f2aSBram Moolenaar \ . fnameescape(expand('%:p')) . ' --line ' . line('.')) 250*60e73f2aSBram Moolenaar if do_continue 251*60e73f2aSBram Moolenaar call s:SendCommand('-exec-continue') 252*60e73f2aSBram Moolenaar endif 253e09ba7baSBram Moolenaarendfunc 254e09ba7baSBram Moolenaar 255e09ba7baSBram Moolenaar" :Delete - Delete a breakpoint at the cursor position. 256e09ba7baSBram Moolenaarfunc s:DeleteBreakpoint() 257e09ba7baSBram Moolenaar let fname = fnameescape(expand('%:p')) 258e09ba7baSBram Moolenaar let lnum = line('.') 259e09ba7baSBram Moolenaar for [key, val] in items(s:breakpoints) 260e09ba7baSBram Moolenaar if val['fname'] == fname && val['lnum'] == lnum 261e09ba7baSBram Moolenaar call term_sendkeys(s:commbuf, '-break-delete ' . key . "\r") 262e09ba7baSBram Moolenaar " Assume this always wors, the reply is simply "^done". 263e09ba7baSBram Moolenaar exe 'sign unplace ' . (s:break_id + key) 264e09ba7baSBram Moolenaar unlet s:breakpoints[key] 265e09ba7baSBram Moolenaar break 266e09ba7baSBram Moolenaar endif 267e09ba7baSBram Moolenaar endfor 268e09ba7baSBram Moolenaarendfunc 269e09ba7baSBram Moolenaar 270e09ba7baSBram Moolenaar" :Next, :Continue, etc - send a command to gdb 271e09ba7baSBram Moolenaarfunc s:SendCommand(cmd) 272e09ba7baSBram Moolenaar call term_sendkeys(s:commbuf, a:cmd . "\r") 273e09ba7baSBram Moolenaarendfunc 274e09ba7baSBram Moolenaar 275*60e73f2aSBram Moolenaarfunc s:Run(args) 276*60e73f2aSBram Moolenaar if a:args != '' 277*60e73f2aSBram Moolenaar call s:SendCommand('-exec-arguments ' . a:args) 278*60e73f2aSBram Moolenaar endif 279*60e73f2aSBram Moolenaar call s:SendCommand('-exec-run') 280*60e73f2aSBram Moolenaarendfunc 281*60e73f2aSBram Moolenaar 28245d5f26dSBram Moolenaar" :Evaluate - evaluate what is under the cursor 28345d5f26dSBram Moolenaarfunc s:Evaluate(range, arg) 28445d5f26dSBram Moolenaar if a:arg != '' 28545d5f26dSBram Moolenaar let expr = a:arg 28645d5f26dSBram Moolenaar elseif a:range == 2 28745d5f26dSBram Moolenaar let pos = getcurpos() 28845d5f26dSBram Moolenaar let reg = getreg('v', 1, 1) 28945d5f26dSBram Moolenaar let regt = getregtype('v') 29045d5f26dSBram Moolenaar normal! gv"vy 29145d5f26dSBram Moolenaar let expr = @v 29245d5f26dSBram Moolenaar call setpos('.', pos) 29345d5f26dSBram Moolenaar call setreg('v', reg, regt) 29445d5f26dSBram Moolenaar else 29545d5f26dSBram Moolenaar let expr = expand('<cexpr>') 29645d5f26dSBram Moolenaar endif 297*60e73f2aSBram Moolenaar call s:SendCommand('-data-evaluate-expression "' . expr . '"') 29845d5f26dSBram Moolenaar let s:evalexpr = expr 29945d5f26dSBram Moolenaarendfunc 30045d5f26dSBram Moolenaar 30145d5f26dSBram Moolenaar" Handle the result of data-evaluate-expression 30245d5f26dSBram Moolenaarfunc s:HandleEvaluate(msg) 3031b9645deSBram Moolenaar let value = substitute(a:msg, '.*value="\(.*\)"', '\1', '') 3041b9645deSBram Moolenaar let value = substitute(value, '\\"', '"', 'g') 3051b9645deSBram Moolenaar echomsg '"' . s:evalexpr . '": ' . value 3061b9645deSBram Moolenaar 3077f2e9d7cSBram Moolenaar if s:evalexpr[0] != '*' && value =~ '^0x' && value != '0x0' && value !~ '"$' 3081b9645deSBram Moolenaar " Looks like a pointer, also display what it points to. 3091b9645deSBram Moolenaar let s:evalexpr = '*' . s:evalexpr 3101b9645deSBram Moolenaar call term_sendkeys(s:commbuf, '-data-evaluate-expression "' . s:evalexpr . "\"\r") 3111b9645deSBram Moolenaar endif 31245d5f26dSBram Moolenaarendfunc 31345d5f26dSBram Moolenaar 31445d5f26dSBram Moolenaar" Handle an error. 31545d5f26dSBram Moolenaarfunc s:HandleError(msg) 31645d5f26dSBram Moolenaar echoerr substitute(a:msg, '.*msg="\(.*\)"', '\1', '') 31745d5f26dSBram Moolenaarendfunc 31845d5f26dSBram Moolenaar 319e09ba7baSBram Moolenaar" Handle stopping and running message from gdb. 320e09ba7baSBram Moolenaar" Will update the sign that shows the current position. 321e09ba7baSBram Moolenaarfunc s:HandleCursor(msg) 322fe386641SBram Moolenaar let wid = win_getid(winnr()) 323fe386641SBram Moolenaar 324*60e73f2aSBram Moolenaar if a:msg =~ '^\*stopped' 325*60e73f2aSBram Moolenaar let s:stopped = 1 326*60e73f2aSBram Moolenaar elseif a:msg =~ '^\*running' 327*60e73f2aSBram Moolenaar let s:stopped = 0 328*60e73f2aSBram Moolenaar endif 329*60e73f2aSBram Moolenaar 330fe386641SBram Moolenaar if win_gotoid(s:startwin) 331e09ba7baSBram Moolenaar let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '') 3321b9645deSBram Moolenaar if a:msg =~ '^\(\*stopped\|=thread-selected\)' && filereadable(fname) 333e09ba7baSBram Moolenaar let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '') 334fe386641SBram Moolenaar if lnum =~ '^[0-9]*$' 3351b9645deSBram Moolenaar if expand('%:p') != fnamemodify(fname, ':p') 336fe386641SBram Moolenaar if &modified 337fe386641SBram Moolenaar " TODO: find existing window 338fe386641SBram Moolenaar exe 'split ' . fnameescape(fname) 339fe386641SBram Moolenaar let s:startwin = win_getid(winnr()) 340fe386641SBram Moolenaar else 341fe386641SBram Moolenaar exe 'edit ' . fnameescape(fname) 342fe386641SBram Moolenaar endif 343fe386641SBram Moolenaar endif 344fe386641SBram Moolenaar exe lnum 34501164a65SBram Moolenaar exe 'sign unplace ' . s:pc_id 3461b9645deSBram Moolenaar exe 'sign place ' . s:pc_id . ' line=' . lnum . ' name=debugPC file=' . fname 347fe386641SBram Moolenaar setlocal signcolumn=yes 348fe386641SBram Moolenaar endif 349fe386641SBram Moolenaar else 350fe386641SBram Moolenaar exe 'sign unplace ' . s:pc_id 351fe386641SBram Moolenaar endif 352fe386641SBram Moolenaar 353fe386641SBram Moolenaar call win_gotoid(wid) 354fe386641SBram Moolenaar endif 355e09ba7baSBram Moolenaarendfunc 356e09ba7baSBram Moolenaar 357e09ba7baSBram Moolenaar" Handle setting a breakpoint 358e09ba7baSBram Moolenaar" Will update the sign that shows the breakpoint 359e09ba7baSBram Moolenaarfunc s:HandleNewBreakpoint(msg) 360e09ba7baSBram Moolenaar let nr = substitute(a:msg, '.*number="\([0-9]\)*\".*', '\1', '') + 0 361e09ba7baSBram Moolenaar if nr == 0 362e09ba7baSBram Moolenaar return 363fe386641SBram Moolenaar endif 364e09ba7baSBram Moolenaar 365e09ba7baSBram Moolenaar if has_key(s:breakpoints, nr) 366e09ba7baSBram Moolenaar let entry = s:breakpoints[nr] 367e09ba7baSBram Moolenaar else 368e09ba7baSBram Moolenaar let entry = {} 369e09ba7baSBram Moolenaar let s:breakpoints[nr] = entry 370fe386641SBram Moolenaar endif 371e09ba7baSBram Moolenaar 372e09ba7baSBram Moolenaar let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '') 373e09ba7baSBram Moolenaar let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '') 374e09ba7baSBram Moolenaar let entry['fname'] = fname 375e09ba7baSBram Moolenaar let entry['lnum'] = lnum 3761b9645deSBram Moolenaar 3771b9645deSBram Moolenaar if bufloaded(fname) 3781b9645deSBram Moolenaar call s:PlaceSign(nr, entry) 3791b9645deSBram Moolenaar endif 3801b9645deSBram Moolenaarendfunc 3811b9645deSBram Moolenaar 3821b9645deSBram Moolenaarfunc s:PlaceSign(nr, entry) 3831b9645deSBram Moolenaar exe 'sign place ' . (s:break_id + a:nr) . ' line=' . a:entry['lnum'] . ' name=debugBreakpoint file=' . a:entry['fname'] 3841b9645deSBram Moolenaar let a:entry['placed'] = 1 385e09ba7baSBram Moolenaarendfunc 386e09ba7baSBram Moolenaar 387e09ba7baSBram Moolenaar" Handle deleting a breakpoint 388e09ba7baSBram Moolenaar" Will remove the sign that shows the breakpoint 389e09ba7baSBram Moolenaarfunc s:HandleBreakpointDelete(msg) 390e09ba7baSBram Moolenaar let nr = substitute(a:msg, '.*id="\([0-9]*\)\".*', '\1', '') + 0 391e09ba7baSBram Moolenaar if nr == 0 392e09ba7baSBram Moolenaar return 393e09ba7baSBram Moolenaar endif 3941b9645deSBram Moolenaar if has_key(s:breakpoints, nr) 3951b9645deSBram Moolenaar let entry = s:breakpoints[nr] 3961b9645deSBram Moolenaar if has_key(entry, 'placed') 397e09ba7baSBram Moolenaar exe 'sign unplace ' . (s:break_id + nr) 3981b9645deSBram Moolenaar unlet entry['placed'] 3991b9645deSBram Moolenaar endif 400e09ba7baSBram Moolenaar unlet s:breakpoints[nr] 4011b9645deSBram Moolenaar endif 402c572da5fSBram Moolenaarendfunc 4031b9645deSBram Moolenaar 4041b9645deSBram Moolenaar" Handle a BufRead autocommand event: place any signs. 4051b9645deSBram Moolenaarfunc s:BufRead() 4061b9645deSBram Moolenaar let fname = expand('<afile>:p') 4071b9645deSBram Moolenaar for [nr, entry] in items(s:breakpoints) 4081b9645deSBram Moolenaar if entry['fname'] == fname 4091b9645deSBram Moolenaar call s:PlaceSign(nr, entry) 4101b9645deSBram Moolenaar endif 4111b9645deSBram Moolenaar endfor 4121b9645deSBram Moolenaarendfunc 4131b9645deSBram Moolenaar 4141b9645deSBram Moolenaar" Handle a BufUnloaded autocommand event: unplace any signs. 4151b9645deSBram Moolenaarfunc s:BufUnloaded() 4161b9645deSBram Moolenaar let fname = expand('<afile>:p') 4171b9645deSBram Moolenaar for [nr, entry] in items(s:breakpoints) 4181b9645deSBram Moolenaar if entry['fname'] == fname 4191b9645deSBram Moolenaar let entry['placed'] = 0 4201b9645deSBram Moolenaar endif 4211b9645deSBram Moolenaar endfor 4221b9645deSBram Moolenaarendfunc 4231b9645deSBram Moolenaar 424