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()) 7251b0f370SBram Moolenaar if vertical 7351b0f370SBram Moolenaar " Assuming the source code window will get a signcolumn, use two more 7451b0f370SBram Moolenaar " columns for that, thus one less for the terminal window. 7551b0f370SBram Moolenaar exe (&columns / 2 - 1) . "wincmd |" 7651b0f370SBram 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 12951b0f370SBram Moolenaar " Enable showing a balloon with eval info 130246fe03dSBram Moolenaar if has("balloon_eval") || has("balloon_eval_term") 131246fe03dSBram Moolenaar set balloonexpr=TermDebugBalloonExpr() 13251b0f370SBram Moolenaar if has("balloon_eval") 13351b0f370SBram Moolenaar set ballooneval 134246fe03dSBram Moolenaar endif 13551b0f370SBram Moolenaar if has("balloon_eval_term") 13651b0f370SBram Moolenaar set balloonevalterm 13751b0f370SBram Moolenaar endif 13851b0f370SBram Moolenaar endif 13951b0f370SBram Moolenaar 140e09ba7baSBram Moolenaar let s:breakpoints = {} 1411b9645deSBram Moolenaar 1421b9645deSBram Moolenaar augroup TermDebug 1431b9645deSBram Moolenaar au BufRead * call s:BufRead() 1441b9645deSBram Moolenaar au BufUnload * call s:BufUnloaded() 1451b9645deSBram Moolenaar augroup END 146c572da5fSBram Moolenaarendfunc 147c572da5fSBram Moolenaar 148c572da5fSBram Moolenaarfunc s:EndDebug(job, status) 149c572da5fSBram Moolenaar exe 'bwipe! ' . s:ptybuf 150fe386641SBram Moolenaar exe 'bwipe! ' . s:commbuf 151e09ba7baSBram Moolenaar 152e09ba7baSBram Moolenaar let curwinid = win_getid(winnr()) 153e09ba7baSBram Moolenaar 154e09ba7baSBram Moolenaar call win_gotoid(s:startwin) 155e09ba7baSBram Moolenaar let &signcolumn = s:startsigncolumn 156e09ba7baSBram Moolenaar call s:DeleteCommands() 157e09ba7baSBram Moolenaar 158e09ba7baSBram Moolenaar call win_gotoid(curwinid) 15938baa3e6SBram Moolenaar if s:save_columns > 0 16038baa3e6SBram Moolenaar let &columns = s:save_columns 16138baa3e6SBram Moolenaar endif 1621b9645deSBram Moolenaar 163246fe03dSBram Moolenaar if has("balloon_eval") || has("balloon_eval_term") 164246fe03dSBram Moolenaar set balloonexpr= 16551b0f370SBram Moolenaar if has("balloon_eval") 16651b0f370SBram Moolenaar set noballooneval 167246fe03dSBram Moolenaar endif 16851b0f370SBram Moolenaar if has("balloon_eval_term") 16951b0f370SBram Moolenaar set noballoonevalterm 17051b0f370SBram Moolenaar endif 17151b0f370SBram Moolenaar endif 17251b0f370SBram Moolenaar 1731b9645deSBram Moolenaar au! TermDebug 174fe386641SBram Moolenaarendfunc 175fe386641SBram Moolenaar 176fe386641SBram Moolenaar" Handle a message received from gdb on the GDB/MI interface. 177fe386641SBram Moolenaarfunc s:CommOutput(chan, msg) 178fe386641SBram Moolenaar let msgs = split(a:msg, "\r") 179fe386641SBram Moolenaar 180fe386641SBram Moolenaar for msg in msgs 181fe386641SBram Moolenaar " remove prefixed NL 182fe386641SBram Moolenaar if msg[0] == "\n" 183fe386641SBram Moolenaar let msg = msg[1:] 184fe386641SBram Moolenaar endif 185fe386641SBram Moolenaar if msg != '' 1861b9645deSBram Moolenaar if msg =~ '^\(\*stopped\|\*running\|=thread-selected\)' 187e09ba7baSBram Moolenaar call s:HandleCursor(msg) 18845d5f26dSBram Moolenaar elseif msg =~ '^\^done,bkpt=' || msg =~ '^=breakpoint-created,' 189e09ba7baSBram Moolenaar call s:HandleNewBreakpoint(msg) 190e09ba7baSBram Moolenaar elseif msg =~ '^=breakpoint-deleted,' 191e09ba7baSBram Moolenaar call s:HandleBreakpointDelete(msg) 19245d5f26dSBram Moolenaar elseif msg =~ '^\^done,value=' 19345d5f26dSBram Moolenaar call s:HandleEvaluate(msg) 19445d5f26dSBram Moolenaar elseif msg =~ '^\^error,msg=' 19545d5f26dSBram Moolenaar call s:HandleError(msg) 196e09ba7baSBram Moolenaar endif 197e09ba7baSBram Moolenaar endif 198e09ba7baSBram Moolenaar endfor 199e09ba7baSBram Moolenaarendfunc 200e09ba7baSBram Moolenaar 201e09ba7baSBram Moolenaar" Install commands in the current window to control the debugger. 202e09ba7baSBram Moolenaarfunc s:InstallCommands() 203e09ba7baSBram Moolenaar command Break call s:SetBreakpoint() 204*71137fedSBram Moolenaar command Clear call s:ClearBreakpoint() 205e09ba7baSBram Moolenaar command Step call s:SendCommand('-exec-step') 20645d5f26dSBram Moolenaar command Over call s:SendCommand('-exec-next') 207e09ba7baSBram Moolenaar command Finish call s:SendCommand('-exec-finish') 20860e73f2aSBram Moolenaar command -nargs=* Run call s:Run(<q-args>) 20960e73f2aSBram Moolenaar command -nargs=* Arguments call s:SendCommand('-exec-arguments ' . <q-args>) 21060e73f2aSBram Moolenaar command Stop call s:SendCommand('-exec-interrupt') 211e09ba7baSBram Moolenaar command Continue call s:SendCommand('-exec-continue') 21245d5f26dSBram Moolenaar command -range -nargs=* Evaluate call s:Evaluate(<range>, <q-args>) 21345d5f26dSBram Moolenaar command Gdb call win_gotoid(s:gdbwin) 21445d5f26dSBram Moolenaar command Program call win_gotoid(s:ptywin) 215*71137fedSBram Moolenaar command Winbar call s:InstallWinbar() 21645d5f26dSBram Moolenaar 21745d5f26dSBram Moolenaar " TODO: can the K mapping be restored? 21845d5f26dSBram Moolenaar nnoremap K :Evaluate<CR> 2191b9645deSBram Moolenaar 220f0b03c4eSBram Moolenaar if has('menu') && &mouse != '' 221*71137fedSBram Moolenaar call s:InstallWinbar() 222*71137fedSBram Moolenaar 223*71137fedSBram Moolenaar if !exists('g:termdebug_popup') || g:termdebug_popup != 0 224*71137fedSBram Moolenaar let s:saved_mousemodel = &mousemodel 225*71137fedSBram Moolenaar let &mousemodel = 'popup_setpos' 226*71137fedSBram Moolenaar an 1.200 PopUp.-SEP3- <Nop> 227*71137fedSBram Moolenaar an 1.210 PopUp.Set\ breakpoint :Break<CR> 228*71137fedSBram Moolenaar an 1.220 PopUp.Clear\ breakpoint :Clear<CR> 229*71137fedSBram Moolenaar an 1.230 PopUp.Evaluate :Evaluate<CR> 230*71137fedSBram Moolenaar endif 231*71137fedSBram Moolenaar endif 232*71137fedSBram Moolenaarendfunc 233*71137fedSBram Moolenaar 234*71137fedSBram Moolenaarlet s:winbar_winids = [] 235*71137fedSBram Moolenaar 236*71137fedSBram Moolenaar" Install the window toolbar in the current window. 237*71137fedSBram Moolenaarfunc s:InstallWinbar() 23824a98a0eSBram Moolenaar nnoremenu WinBar.Step :Step<CR> 23924a98a0eSBram Moolenaar nnoremenu WinBar.Next :Over<CR> 24024a98a0eSBram Moolenaar nnoremenu WinBar.Finish :Finish<CR> 24124a98a0eSBram Moolenaar nnoremenu WinBar.Cont :Continue<CR> 24260e73f2aSBram Moolenaar nnoremenu WinBar.Stop :Stop<CR> 24324a98a0eSBram Moolenaar nnoremenu WinBar.Eval :Evaluate<CR> 244*71137fedSBram Moolenaar call add(s:winbar_winids, win_getid(winnr())) 245e09ba7baSBram Moolenaarendfunc 246e09ba7baSBram Moolenaar 247e09ba7baSBram Moolenaar" Delete installed debugger commands in the current window. 248e09ba7baSBram Moolenaarfunc s:DeleteCommands() 249e09ba7baSBram Moolenaar delcommand Break 250*71137fedSBram Moolenaar delcommand Clear 251e09ba7baSBram Moolenaar delcommand Step 25245d5f26dSBram Moolenaar delcommand Over 253e09ba7baSBram Moolenaar delcommand Finish 25460e73f2aSBram Moolenaar delcommand Run 25560e73f2aSBram Moolenaar delcommand Arguments 25660e73f2aSBram Moolenaar delcommand Stop 257e09ba7baSBram Moolenaar delcommand Continue 25845d5f26dSBram Moolenaar delcommand Evaluate 25945d5f26dSBram Moolenaar delcommand Gdb 26045d5f26dSBram Moolenaar delcommand Program 261*71137fedSBram Moolenaar delcommand Winbar 26245d5f26dSBram Moolenaar 26345d5f26dSBram Moolenaar nunmap K 2641b9645deSBram Moolenaar 2651b9645deSBram Moolenaar if has('menu') 266*71137fedSBram Moolenaar " Remove the WinBar entries from all windows where it was added. 267*71137fedSBram Moolenaar let curwinid = win_getid(winnr()) 268*71137fedSBram Moolenaar for winid in s:winbar_winids 269*71137fedSBram Moolenaar if win_gotoid(winid) 2701b9645deSBram Moolenaar aunmenu WinBar.Step 2711b9645deSBram Moolenaar aunmenu WinBar.Next 2721b9645deSBram Moolenaar aunmenu WinBar.Finish 2731b9645deSBram Moolenaar aunmenu WinBar.Cont 27460e73f2aSBram Moolenaar aunmenu WinBar.Stop 2751b9645deSBram Moolenaar aunmenu WinBar.Eval 2761b9645deSBram Moolenaar endif 277*71137fedSBram Moolenaar endfor 278*71137fedSBram Moolenaar call win_gotoid(curwinid) 279*71137fedSBram Moolenaar let s:winbar_winids = [] 280*71137fedSBram Moolenaar 281*71137fedSBram Moolenaar if exists('s:saved_mousemodel') 282*71137fedSBram Moolenaar let &mousemodel = s:saved_mousemodel 283*71137fedSBram Moolenaar unlet s:saved_mousemodel 284*71137fedSBram Moolenaar aunmenu PopUp.-SEP3- 285*71137fedSBram Moolenaar aunmenu PopUp.Set\ breakpoint 286*71137fedSBram Moolenaar aunmenu PopUp.Clear\ breakpoint 287*71137fedSBram Moolenaar aunmenu PopUp.Evaluate 288*71137fedSBram Moolenaar endif 289*71137fedSBram Moolenaar endif 2901b9645deSBram Moolenaar 29145d5f26dSBram Moolenaar exe 'sign unplace ' . s:pc_id 29245d5f26dSBram Moolenaar for key in keys(s:breakpoints) 29345d5f26dSBram Moolenaar exe 'sign unplace ' . (s:break_id + key) 29445d5f26dSBram Moolenaar endfor 29538baa3e6SBram Moolenaar sign undefine debugPC 29638baa3e6SBram Moolenaar sign undefine debugBreakpoint 29745d5f26dSBram Moolenaar unlet s:breakpoints 298e09ba7baSBram Moolenaarendfunc 299e09ba7baSBram Moolenaar 300e09ba7baSBram Moolenaar" :Break - Set a breakpoint at the cursor position. 301e09ba7baSBram Moolenaarfunc s:SetBreakpoint() 30260e73f2aSBram Moolenaar " Setting a breakpoint may not work while the program is running. 30360e73f2aSBram Moolenaar " Interrupt to make it work. 30460e73f2aSBram Moolenaar let do_continue = 0 30560e73f2aSBram Moolenaar if !s:stopped 30660e73f2aSBram Moolenaar let do_continue = 1 30760e73f2aSBram Moolenaar call s:SendCommand('-exec-interrupt') 30860e73f2aSBram Moolenaar sleep 10m 30960e73f2aSBram Moolenaar endif 31060e73f2aSBram Moolenaar call s:SendCommand('-break-insert --source ' 31160e73f2aSBram Moolenaar \ . fnameescape(expand('%:p')) . ' --line ' . line('.')) 31260e73f2aSBram Moolenaar if do_continue 31360e73f2aSBram Moolenaar call s:SendCommand('-exec-continue') 31460e73f2aSBram Moolenaar endif 315e09ba7baSBram Moolenaarendfunc 316e09ba7baSBram Moolenaar 317*71137fedSBram Moolenaar" :Clear - Delete a breakpoint at the cursor position. 318*71137fedSBram Moolenaarfunc s:ClearBreakpoint() 319e09ba7baSBram Moolenaar let fname = fnameescape(expand('%:p')) 320e09ba7baSBram Moolenaar let lnum = line('.') 321e09ba7baSBram Moolenaar for [key, val] in items(s:breakpoints) 322e09ba7baSBram Moolenaar if val['fname'] == fname && val['lnum'] == lnum 323e09ba7baSBram Moolenaar call term_sendkeys(s:commbuf, '-break-delete ' . key . "\r") 324e09ba7baSBram Moolenaar " Assume this always wors, the reply is simply "^done". 325e09ba7baSBram Moolenaar exe 'sign unplace ' . (s:break_id + key) 326e09ba7baSBram Moolenaar unlet s:breakpoints[key] 327e09ba7baSBram Moolenaar break 328e09ba7baSBram Moolenaar endif 329e09ba7baSBram Moolenaar endfor 330e09ba7baSBram Moolenaarendfunc 331e09ba7baSBram Moolenaar 332e09ba7baSBram Moolenaar" :Next, :Continue, etc - send a command to gdb 333e09ba7baSBram Moolenaarfunc s:SendCommand(cmd) 334e09ba7baSBram Moolenaar call term_sendkeys(s:commbuf, a:cmd . "\r") 335e09ba7baSBram Moolenaarendfunc 336e09ba7baSBram Moolenaar 33760e73f2aSBram Moolenaarfunc s:Run(args) 33860e73f2aSBram Moolenaar if a:args != '' 33960e73f2aSBram Moolenaar call s:SendCommand('-exec-arguments ' . a:args) 34060e73f2aSBram Moolenaar endif 34160e73f2aSBram Moolenaar call s:SendCommand('-exec-run') 34260e73f2aSBram Moolenaarendfunc 34360e73f2aSBram Moolenaar 34451b0f370SBram Moolenaarfunc s:SendEval(expr) 34551b0f370SBram Moolenaar call s:SendCommand('-data-evaluate-expression "' . a:expr . '"') 34651b0f370SBram Moolenaar let s:evalexpr = a:expr 34751b0f370SBram Moolenaarendfunc 34851b0f370SBram Moolenaar 34945d5f26dSBram Moolenaar" :Evaluate - evaluate what is under the cursor 35045d5f26dSBram Moolenaarfunc s:Evaluate(range, arg) 35145d5f26dSBram Moolenaar if a:arg != '' 35245d5f26dSBram Moolenaar let expr = a:arg 35345d5f26dSBram Moolenaar elseif a:range == 2 35445d5f26dSBram Moolenaar let pos = getcurpos() 35545d5f26dSBram Moolenaar let reg = getreg('v', 1, 1) 35645d5f26dSBram Moolenaar let regt = getregtype('v') 35745d5f26dSBram Moolenaar normal! gv"vy 35845d5f26dSBram Moolenaar let expr = @v 35945d5f26dSBram Moolenaar call setpos('.', pos) 36045d5f26dSBram Moolenaar call setreg('v', reg, regt) 36145d5f26dSBram Moolenaar else 36245d5f26dSBram Moolenaar let expr = expand('<cexpr>') 36345d5f26dSBram Moolenaar endif 36422f1d0e3SBram Moolenaar let s:ignoreEvalError = 0 36551b0f370SBram Moolenaar call s:SendEval(expr) 36645d5f26dSBram Moolenaarendfunc 36745d5f26dSBram Moolenaar 36822f1d0e3SBram Moolenaarlet s:ignoreEvalError = 0 36951b0f370SBram Moolenaarlet s:evalFromBalloonExpr = 0 37051b0f370SBram Moolenaar 37145d5f26dSBram Moolenaar" Handle the result of data-evaluate-expression 37245d5f26dSBram Moolenaarfunc s:HandleEvaluate(msg) 3731b9645deSBram Moolenaar let value = substitute(a:msg, '.*value="\(.*\)"', '\1', '') 3741b9645deSBram Moolenaar let value = substitute(value, '\\"', '"', 'g') 37551b0f370SBram Moolenaar if s:evalFromBalloonExpr 37651b0f370SBram Moolenaar if s:evalFromBalloonExprResult == '' 37751b0f370SBram Moolenaar let s:evalFromBalloonExprResult = s:evalexpr . ': ' . value 37851b0f370SBram Moolenaar else 37951b0f370SBram Moolenaar let s:evalFromBalloonExprResult .= ' = ' . value 38051b0f370SBram Moolenaar endif 38151b0f370SBram Moolenaar call balloon_show(s:evalFromBalloonExprResult) 38251b0f370SBram Moolenaar else 3831b9645deSBram Moolenaar echomsg '"' . s:evalexpr . '": ' . value 38451b0f370SBram Moolenaar endif 3851b9645deSBram Moolenaar 3867f2e9d7cSBram Moolenaar if s:evalexpr[0] != '*' && value =~ '^0x' && value != '0x0' && value !~ '"$' 3871b9645deSBram Moolenaar " Looks like a pointer, also display what it points to. 38822f1d0e3SBram Moolenaar let s:ignoreEvalError = 1 38951b0f370SBram Moolenaar call s:SendEval('*' . s:evalexpr) 39051b0f370SBram Moolenaar else 39151b0f370SBram Moolenaar let s:evalFromBalloonExpr = 0 3921b9645deSBram Moolenaar endif 39345d5f26dSBram Moolenaarendfunc 39445d5f26dSBram Moolenaar 39551b0f370SBram Moolenaar" Show a balloon with information of the variable under the mouse pointer, 39651b0f370SBram Moolenaar" if there is any. 39751b0f370SBram Moolenaarfunc TermDebugBalloonExpr() 39851b0f370SBram Moolenaar if v:beval_winid != s:startwin 39951b0f370SBram Moolenaar return 40051b0f370SBram Moolenaar endif 40151b0f370SBram Moolenaar let s:evalFromBalloonExpr = 1 40251b0f370SBram Moolenaar let s:evalFromBalloonExprResult = '' 40322f1d0e3SBram Moolenaar let s:ignoreEvalError = 1 40422f1d0e3SBram Moolenaar call s:SendEval(v:beval_text) 40551b0f370SBram Moolenaar return '' 40651b0f370SBram Moolenaarendfunc 40751b0f370SBram Moolenaar 40845d5f26dSBram Moolenaar" Handle an error. 40945d5f26dSBram Moolenaarfunc s:HandleError(msg) 41022f1d0e3SBram Moolenaar if s:ignoreEvalError 41151b0f370SBram Moolenaar " Result of s:SendEval() failed, ignore. 41222f1d0e3SBram Moolenaar let s:ignoreEvalError = 0 41322f1d0e3SBram Moolenaar let s:evalFromBalloonExpr = 0 41451b0f370SBram Moolenaar return 41551b0f370SBram Moolenaar endif 41645d5f26dSBram Moolenaar echoerr substitute(a:msg, '.*msg="\(.*\)"', '\1', '') 41745d5f26dSBram Moolenaarendfunc 41845d5f26dSBram Moolenaar 419e09ba7baSBram Moolenaar" Handle stopping and running message from gdb. 420e09ba7baSBram Moolenaar" Will update the sign that shows the current position. 421e09ba7baSBram Moolenaarfunc s:HandleCursor(msg) 422fe386641SBram Moolenaar let wid = win_getid(winnr()) 423fe386641SBram Moolenaar 42460e73f2aSBram Moolenaar if a:msg =~ '^\*stopped' 42560e73f2aSBram Moolenaar let s:stopped = 1 42660e73f2aSBram Moolenaar elseif a:msg =~ '^\*running' 42760e73f2aSBram Moolenaar let s:stopped = 0 42860e73f2aSBram Moolenaar endif 42960e73f2aSBram Moolenaar 430fe386641SBram Moolenaar if win_gotoid(s:startwin) 431e09ba7baSBram Moolenaar let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '') 4321b9645deSBram Moolenaar if a:msg =~ '^\(\*stopped\|=thread-selected\)' && filereadable(fname) 433e09ba7baSBram Moolenaar let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '') 434fe386641SBram Moolenaar if lnum =~ '^[0-9]*$' 4351b9645deSBram Moolenaar if expand('%:p') != fnamemodify(fname, ':p') 436fe386641SBram Moolenaar if &modified 437fe386641SBram Moolenaar " TODO: find existing window 438fe386641SBram Moolenaar exe 'split ' . fnameescape(fname) 439fe386641SBram Moolenaar let s:startwin = win_getid(winnr()) 440fe386641SBram Moolenaar else 441fe386641SBram Moolenaar exe 'edit ' . fnameescape(fname) 442fe386641SBram Moolenaar endif 443fe386641SBram Moolenaar endif 444fe386641SBram Moolenaar exe lnum 44501164a65SBram Moolenaar exe 'sign unplace ' . s:pc_id 4461b9645deSBram Moolenaar exe 'sign place ' . s:pc_id . ' line=' . lnum . ' name=debugPC file=' . fname 447fe386641SBram Moolenaar setlocal signcolumn=yes 448fe386641SBram Moolenaar endif 449fe386641SBram Moolenaar else 450fe386641SBram Moolenaar exe 'sign unplace ' . s:pc_id 451fe386641SBram Moolenaar endif 452fe386641SBram Moolenaar 453fe386641SBram Moolenaar call win_gotoid(wid) 454fe386641SBram Moolenaar endif 455e09ba7baSBram Moolenaarendfunc 456e09ba7baSBram Moolenaar 457e09ba7baSBram Moolenaar" Handle setting a breakpoint 458e09ba7baSBram Moolenaar" Will update the sign that shows the breakpoint 459e09ba7baSBram Moolenaarfunc s:HandleNewBreakpoint(msg) 460e09ba7baSBram Moolenaar let nr = substitute(a:msg, '.*number="\([0-9]\)*\".*', '\1', '') + 0 461e09ba7baSBram Moolenaar if nr == 0 462e09ba7baSBram Moolenaar return 463fe386641SBram Moolenaar endif 464e09ba7baSBram Moolenaar 465e09ba7baSBram Moolenaar if has_key(s:breakpoints, nr) 466e09ba7baSBram Moolenaar let entry = s:breakpoints[nr] 467e09ba7baSBram Moolenaar else 468e09ba7baSBram Moolenaar let entry = {} 469e09ba7baSBram Moolenaar let s:breakpoints[nr] = entry 470fe386641SBram Moolenaar endif 471e09ba7baSBram Moolenaar 472e09ba7baSBram Moolenaar let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '') 473e09ba7baSBram Moolenaar let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '') 474e09ba7baSBram Moolenaar let entry['fname'] = fname 475e09ba7baSBram Moolenaar let entry['lnum'] = lnum 4761b9645deSBram Moolenaar 4771b9645deSBram Moolenaar if bufloaded(fname) 4781b9645deSBram Moolenaar call s:PlaceSign(nr, entry) 4791b9645deSBram Moolenaar endif 4801b9645deSBram Moolenaarendfunc 4811b9645deSBram Moolenaar 4821b9645deSBram Moolenaarfunc s:PlaceSign(nr, entry) 4831b9645deSBram Moolenaar exe 'sign place ' . (s:break_id + a:nr) . ' line=' . a:entry['lnum'] . ' name=debugBreakpoint file=' . a:entry['fname'] 4841b9645deSBram Moolenaar let a:entry['placed'] = 1 485e09ba7baSBram Moolenaarendfunc 486e09ba7baSBram Moolenaar 487e09ba7baSBram Moolenaar" Handle deleting a breakpoint 488e09ba7baSBram Moolenaar" Will remove the sign that shows the breakpoint 489e09ba7baSBram Moolenaarfunc s:HandleBreakpointDelete(msg) 490e09ba7baSBram Moolenaar let nr = substitute(a:msg, '.*id="\([0-9]*\)\".*', '\1', '') + 0 491e09ba7baSBram Moolenaar if nr == 0 492e09ba7baSBram Moolenaar return 493e09ba7baSBram Moolenaar endif 4941b9645deSBram Moolenaar if has_key(s:breakpoints, nr) 4951b9645deSBram Moolenaar let entry = s:breakpoints[nr] 4961b9645deSBram Moolenaar if has_key(entry, 'placed') 497e09ba7baSBram Moolenaar exe 'sign unplace ' . (s:break_id + nr) 4981b9645deSBram Moolenaar unlet entry['placed'] 4991b9645deSBram Moolenaar endif 500e09ba7baSBram Moolenaar unlet s:breakpoints[nr] 5011b9645deSBram Moolenaar endif 502c572da5fSBram Moolenaarendfunc 5031b9645deSBram Moolenaar 5041b9645deSBram Moolenaar" Handle a BufRead autocommand event: place any signs. 5051b9645deSBram Moolenaarfunc s:BufRead() 5061b9645deSBram Moolenaar let fname = expand('<afile>:p') 5071b9645deSBram Moolenaar for [nr, entry] in items(s:breakpoints) 5081b9645deSBram Moolenaar if entry['fname'] == fname 5091b9645deSBram Moolenaar call s:PlaceSign(nr, entry) 5101b9645deSBram Moolenaar endif 5111b9645deSBram Moolenaar endfor 5121b9645deSBram Moolenaarendfunc 5131b9645deSBram Moolenaar 5141b9645deSBram Moolenaar" Handle a BufUnloaded autocommand event: unplace any signs. 5151b9645deSBram Moolenaarfunc s:BufUnloaded() 5161b9645deSBram Moolenaar let fname = expand('<afile>:p') 5171b9645deSBram Moolenaar for [nr, entry] in items(s:breakpoints) 5181b9645deSBram Moolenaar if entry['fname'] == fname 5191b9645deSBram Moolenaar let entry['placed'] = 0 5201b9645deSBram Moolenaar endif 5211b9645deSBram Moolenaar endfor 5221b9645deSBram Moolenaarendfunc 5231b9645deSBram Moolenaar 524