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 10860e73f2aSBram Moolenaar call term_sendkeys(s:gdbbuf, 'new-ui mi ' . commpty . "\r") 10960e73f2aSBram Moolenaar 1103e4b84d0SBram Moolenaar " Wait for the response to show up, users may not notice the error and wonder 1113e4b84d0SBram Moolenaar " why the debugger doesn't work. 1123e4b84d0SBram Moolenaar let try_count = 0 1133e4b84d0SBram Moolenaar while 1 1143e4b84d0SBram Moolenaar let response = '' 1153e4b84d0SBram Moolenaar for lnum in range(1,20) 1163e4b84d0SBram Moolenaar if term_getline(s:gdbbuf, lnum) =~ 'new-ui mi ' 1173e4b84d0SBram Moolenaar let response = term_getline(s:gdbbuf, lnum + 1) 1183e4b84d0SBram Moolenaar if response =~ 'Undefined command' 119*f3ba14ffSBram Moolenaar echoerr 'Sorry, your gdb is too old, gdb 7.12 is required' 1203e4b84d0SBram Moolenaar exe 'bwipe! ' . s:ptybuf 1213e4b84d0SBram Moolenaar exe 'bwipe! ' . s:commbuf 1223e4b84d0SBram Moolenaar return 1233e4b84d0SBram Moolenaar endif 1243e4b84d0SBram Moolenaar if response =~ 'New UI allocated' 1253e4b84d0SBram Moolenaar " Success! 1263e4b84d0SBram Moolenaar break 1273e4b84d0SBram Moolenaar endif 1283e4b84d0SBram Moolenaar endif 1293e4b84d0SBram Moolenaar endfor 1303e4b84d0SBram Moolenaar if response =~ 'New UI allocated' 1313e4b84d0SBram Moolenaar break 1323e4b84d0SBram Moolenaar endif 1333e4b84d0SBram Moolenaar let try_count += 1 1343e4b84d0SBram Moolenaar if try_count > 100 1353e4b84d0SBram Moolenaar echoerr 'Cannot check if your gdb works, continuing anyway' 1363e4b84d0SBram Moolenaar break 1373e4b84d0SBram Moolenaar endif 1383e4b84d0SBram Moolenaar sleep 10m 1393e4b84d0SBram Moolenaar endwhile 1403e4b84d0SBram Moolenaar 14160e73f2aSBram Moolenaar " Interpret commands while the target is running. This should usualy only be 14260e73f2aSBram Moolenaar " exec-interrupt, since many commands don't work properly while the target is 14360e73f2aSBram Moolenaar " running. 14460e73f2aSBram Moolenaar call s:SendCommand('-gdb-set mi-async on') 145e09ba7baSBram Moolenaar 146*f3ba14ffSBram Moolenaar " Disable pagination, it causes everything to stop at the gdb 147*f3ba14ffSBram Moolenaar " "Type <return> to continue" prompt. 148*f3ba14ffSBram Moolenaar call s:SendCommand('-gdb-set pagination off') 149*f3ba14ffSBram Moolenaar 15038baa3e6SBram Moolenaar " Sign used to highlight the line where the program has stopped. 15138baa3e6SBram Moolenaar " There can be only one. 15238baa3e6SBram Moolenaar sign define debugPC linehl=debugPC 15338baa3e6SBram Moolenaar 15438baa3e6SBram Moolenaar " Sign used to indicate a breakpoint. 15538baa3e6SBram Moolenaar " Can be used multiple times. 15638baa3e6SBram Moolenaar sign define debugBreakpoint text=>> texthl=debugBreakpoint 15738baa3e6SBram Moolenaar 15845d5f26dSBram Moolenaar " Install debugger commands in the text window. 15945d5f26dSBram Moolenaar call win_gotoid(s:startwin) 160e09ba7baSBram Moolenaar call s:InstallCommands() 16145d5f26dSBram Moolenaar call win_gotoid(s:gdbwin) 162e09ba7baSBram Moolenaar 16351b0f370SBram Moolenaar " Enable showing a balloon with eval info 164246fe03dSBram Moolenaar if has("balloon_eval") || has("balloon_eval_term") 165246fe03dSBram Moolenaar set balloonexpr=TermDebugBalloonExpr() 16651b0f370SBram Moolenaar if has("balloon_eval") 16751b0f370SBram Moolenaar set ballooneval 168246fe03dSBram Moolenaar endif 16951b0f370SBram Moolenaar if has("balloon_eval_term") 17051b0f370SBram Moolenaar set balloonevalterm 17151b0f370SBram Moolenaar endif 17251b0f370SBram Moolenaar endif 17351b0f370SBram Moolenaar 174e09ba7baSBram Moolenaar let s:breakpoints = {} 1751b9645deSBram Moolenaar 1761b9645deSBram Moolenaar augroup TermDebug 1771b9645deSBram Moolenaar au BufRead * call s:BufRead() 1781b9645deSBram Moolenaar au BufUnload * call s:BufUnloaded() 1791b9645deSBram Moolenaar augroup END 180c572da5fSBram Moolenaarendfunc 181c572da5fSBram Moolenaar 182c572da5fSBram Moolenaarfunc s:EndDebug(job, status) 183c572da5fSBram Moolenaar exe 'bwipe! ' . s:ptybuf 184fe386641SBram Moolenaar exe 'bwipe! ' . s:commbuf 185e09ba7baSBram Moolenaar 186e09ba7baSBram Moolenaar let curwinid = win_getid(winnr()) 187e09ba7baSBram Moolenaar 188e09ba7baSBram Moolenaar call win_gotoid(s:startwin) 189e09ba7baSBram Moolenaar let &signcolumn = s:startsigncolumn 190e09ba7baSBram Moolenaar call s:DeleteCommands() 191e09ba7baSBram Moolenaar 192e09ba7baSBram Moolenaar call win_gotoid(curwinid) 19338baa3e6SBram Moolenaar if s:save_columns > 0 19438baa3e6SBram Moolenaar let &columns = s:save_columns 19538baa3e6SBram Moolenaar endif 1961b9645deSBram Moolenaar 197246fe03dSBram Moolenaar if has("balloon_eval") || has("balloon_eval_term") 198246fe03dSBram Moolenaar set balloonexpr= 19951b0f370SBram Moolenaar if has("balloon_eval") 20051b0f370SBram Moolenaar set noballooneval 201246fe03dSBram Moolenaar endif 20251b0f370SBram Moolenaar if has("balloon_eval_term") 20351b0f370SBram Moolenaar set noballoonevalterm 20451b0f370SBram Moolenaar endif 20551b0f370SBram Moolenaar endif 20651b0f370SBram Moolenaar 2071b9645deSBram Moolenaar au! TermDebug 208fe386641SBram Moolenaarendfunc 209fe386641SBram Moolenaar 210fe386641SBram Moolenaar" Handle a message received from gdb on the GDB/MI interface. 211fe386641SBram Moolenaarfunc s:CommOutput(chan, msg) 212fe386641SBram Moolenaar let msgs = split(a:msg, "\r") 213fe386641SBram Moolenaar 214fe386641SBram Moolenaar for msg in msgs 215fe386641SBram Moolenaar " remove prefixed NL 216fe386641SBram Moolenaar if msg[0] == "\n" 217fe386641SBram Moolenaar let msg = msg[1:] 218fe386641SBram Moolenaar endif 219fe386641SBram Moolenaar if msg != '' 2201b9645deSBram Moolenaar if msg =~ '^\(\*stopped\|\*running\|=thread-selected\)' 221e09ba7baSBram Moolenaar call s:HandleCursor(msg) 22245d5f26dSBram Moolenaar elseif msg =~ '^\^done,bkpt=' || msg =~ '^=breakpoint-created,' 223e09ba7baSBram Moolenaar call s:HandleNewBreakpoint(msg) 224e09ba7baSBram Moolenaar elseif msg =~ '^=breakpoint-deleted,' 225e09ba7baSBram Moolenaar call s:HandleBreakpointDelete(msg) 22645d5f26dSBram Moolenaar elseif msg =~ '^\^done,value=' 22745d5f26dSBram Moolenaar call s:HandleEvaluate(msg) 22845d5f26dSBram Moolenaar elseif msg =~ '^\^error,msg=' 22945d5f26dSBram Moolenaar call s:HandleError(msg) 230e09ba7baSBram Moolenaar endif 231e09ba7baSBram Moolenaar endif 232e09ba7baSBram Moolenaar endfor 233e09ba7baSBram Moolenaarendfunc 234e09ba7baSBram Moolenaar 235e09ba7baSBram Moolenaar" Install commands in the current window to control the debugger. 236e09ba7baSBram Moolenaarfunc s:InstallCommands() 237e09ba7baSBram Moolenaar command Break call s:SetBreakpoint() 23871137fedSBram Moolenaar command Clear call s:ClearBreakpoint() 239e09ba7baSBram Moolenaar command Step call s:SendCommand('-exec-step') 24045d5f26dSBram Moolenaar command Over call s:SendCommand('-exec-next') 241e09ba7baSBram Moolenaar command Finish call s:SendCommand('-exec-finish') 24260e73f2aSBram Moolenaar command -nargs=* Run call s:Run(<q-args>) 24360e73f2aSBram Moolenaar command -nargs=* Arguments call s:SendCommand('-exec-arguments ' . <q-args>) 24460e73f2aSBram Moolenaar command Stop call s:SendCommand('-exec-interrupt') 245e09ba7baSBram Moolenaar command Continue call s:SendCommand('-exec-continue') 24645d5f26dSBram Moolenaar command -range -nargs=* Evaluate call s:Evaluate(<range>, <q-args>) 24745d5f26dSBram Moolenaar command Gdb call win_gotoid(s:gdbwin) 24845d5f26dSBram Moolenaar command Program call win_gotoid(s:ptywin) 24971137fedSBram Moolenaar command Winbar call s:InstallWinbar() 25045d5f26dSBram Moolenaar 25145d5f26dSBram Moolenaar " TODO: can the K mapping be restored? 25245d5f26dSBram Moolenaar nnoremap K :Evaluate<CR> 2531b9645deSBram Moolenaar 254f0b03c4eSBram Moolenaar if has('menu') && &mouse != '' 25571137fedSBram Moolenaar call s:InstallWinbar() 25671137fedSBram Moolenaar 25771137fedSBram Moolenaar if !exists('g:termdebug_popup') || g:termdebug_popup != 0 25871137fedSBram Moolenaar let s:saved_mousemodel = &mousemodel 25971137fedSBram Moolenaar let &mousemodel = 'popup_setpos' 26071137fedSBram Moolenaar an 1.200 PopUp.-SEP3- <Nop> 26171137fedSBram Moolenaar an 1.210 PopUp.Set\ breakpoint :Break<CR> 26271137fedSBram Moolenaar an 1.220 PopUp.Clear\ breakpoint :Clear<CR> 26371137fedSBram Moolenaar an 1.230 PopUp.Evaluate :Evaluate<CR> 26471137fedSBram Moolenaar endif 26571137fedSBram Moolenaar endif 26671137fedSBram Moolenaarendfunc 26771137fedSBram Moolenaar 26871137fedSBram Moolenaarlet s:winbar_winids = [] 26971137fedSBram Moolenaar 27071137fedSBram Moolenaar" Install the window toolbar in the current window. 27171137fedSBram Moolenaarfunc s:InstallWinbar() 27224a98a0eSBram Moolenaar nnoremenu WinBar.Step :Step<CR> 27324a98a0eSBram Moolenaar nnoremenu WinBar.Next :Over<CR> 27424a98a0eSBram Moolenaar nnoremenu WinBar.Finish :Finish<CR> 27524a98a0eSBram Moolenaar nnoremenu WinBar.Cont :Continue<CR> 27660e73f2aSBram Moolenaar nnoremenu WinBar.Stop :Stop<CR> 27724a98a0eSBram Moolenaar nnoremenu WinBar.Eval :Evaluate<CR> 27871137fedSBram Moolenaar call add(s:winbar_winids, win_getid(winnr())) 279e09ba7baSBram Moolenaarendfunc 280e09ba7baSBram Moolenaar 281e09ba7baSBram Moolenaar" Delete installed debugger commands in the current window. 282e09ba7baSBram Moolenaarfunc s:DeleteCommands() 283e09ba7baSBram Moolenaar delcommand Break 28471137fedSBram Moolenaar delcommand Clear 285e09ba7baSBram Moolenaar delcommand Step 28645d5f26dSBram Moolenaar delcommand Over 287e09ba7baSBram Moolenaar delcommand Finish 28860e73f2aSBram Moolenaar delcommand Run 28960e73f2aSBram Moolenaar delcommand Arguments 29060e73f2aSBram Moolenaar delcommand Stop 291e09ba7baSBram Moolenaar delcommand Continue 29245d5f26dSBram Moolenaar delcommand Evaluate 29345d5f26dSBram Moolenaar delcommand Gdb 29445d5f26dSBram Moolenaar delcommand Program 29571137fedSBram Moolenaar delcommand Winbar 29645d5f26dSBram Moolenaar 29745d5f26dSBram Moolenaar nunmap K 2981b9645deSBram Moolenaar 2991b9645deSBram Moolenaar if has('menu') 30071137fedSBram Moolenaar " Remove the WinBar entries from all windows where it was added. 30171137fedSBram Moolenaar let curwinid = win_getid(winnr()) 30271137fedSBram Moolenaar for winid in s:winbar_winids 30371137fedSBram Moolenaar if win_gotoid(winid) 3041b9645deSBram Moolenaar aunmenu WinBar.Step 3051b9645deSBram Moolenaar aunmenu WinBar.Next 3061b9645deSBram Moolenaar aunmenu WinBar.Finish 3071b9645deSBram Moolenaar aunmenu WinBar.Cont 30860e73f2aSBram Moolenaar aunmenu WinBar.Stop 3091b9645deSBram Moolenaar aunmenu WinBar.Eval 3101b9645deSBram Moolenaar endif 31171137fedSBram Moolenaar endfor 31271137fedSBram Moolenaar call win_gotoid(curwinid) 31371137fedSBram Moolenaar let s:winbar_winids = [] 31471137fedSBram Moolenaar 31571137fedSBram Moolenaar if exists('s:saved_mousemodel') 31671137fedSBram Moolenaar let &mousemodel = s:saved_mousemodel 31771137fedSBram Moolenaar unlet s:saved_mousemodel 31871137fedSBram Moolenaar aunmenu PopUp.-SEP3- 31971137fedSBram Moolenaar aunmenu PopUp.Set\ breakpoint 32071137fedSBram Moolenaar aunmenu PopUp.Clear\ breakpoint 32171137fedSBram Moolenaar aunmenu PopUp.Evaluate 32271137fedSBram Moolenaar endif 32371137fedSBram Moolenaar endif 3241b9645deSBram Moolenaar 32545d5f26dSBram Moolenaar exe 'sign unplace ' . s:pc_id 32645d5f26dSBram Moolenaar for key in keys(s:breakpoints) 32745d5f26dSBram Moolenaar exe 'sign unplace ' . (s:break_id + key) 32845d5f26dSBram Moolenaar endfor 32938baa3e6SBram Moolenaar sign undefine debugPC 33038baa3e6SBram Moolenaar sign undefine debugBreakpoint 33145d5f26dSBram Moolenaar unlet s:breakpoints 332e09ba7baSBram Moolenaarendfunc 333e09ba7baSBram Moolenaar 334e09ba7baSBram Moolenaar" :Break - Set a breakpoint at the cursor position. 335e09ba7baSBram Moolenaarfunc s:SetBreakpoint() 33660e73f2aSBram Moolenaar " Setting a breakpoint may not work while the program is running. 33760e73f2aSBram Moolenaar " Interrupt to make it work. 33860e73f2aSBram Moolenaar let do_continue = 0 33960e73f2aSBram Moolenaar if !s:stopped 34060e73f2aSBram Moolenaar let do_continue = 1 34160e73f2aSBram Moolenaar call s:SendCommand('-exec-interrupt') 34260e73f2aSBram Moolenaar sleep 10m 34360e73f2aSBram Moolenaar endif 34460e73f2aSBram Moolenaar call s:SendCommand('-break-insert --source ' 34560e73f2aSBram Moolenaar \ . fnameescape(expand('%:p')) . ' --line ' . line('.')) 34660e73f2aSBram Moolenaar if do_continue 34760e73f2aSBram Moolenaar call s:SendCommand('-exec-continue') 34860e73f2aSBram Moolenaar endif 349e09ba7baSBram Moolenaarendfunc 350e09ba7baSBram Moolenaar 35171137fedSBram Moolenaar" :Clear - Delete a breakpoint at the cursor position. 35271137fedSBram Moolenaarfunc s:ClearBreakpoint() 353e09ba7baSBram Moolenaar let fname = fnameescape(expand('%:p')) 354e09ba7baSBram Moolenaar let lnum = line('.') 355e09ba7baSBram Moolenaar for [key, val] in items(s:breakpoints) 356e09ba7baSBram Moolenaar if val['fname'] == fname && val['lnum'] == lnum 357e09ba7baSBram Moolenaar call term_sendkeys(s:commbuf, '-break-delete ' . key . "\r") 358e09ba7baSBram Moolenaar " Assume this always wors, the reply is simply "^done". 359e09ba7baSBram Moolenaar exe 'sign unplace ' . (s:break_id + key) 360e09ba7baSBram Moolenaar unlet s:breakpoints[key] 361e09ba7baSBram Moolenaar break 362e09ba7baSBram Moolenaar endif 363e09ba7baSBram Moolenaar endfor 364e09ba7baSBram Moolenaarendfunc 365e09ba7baSBram Moolenaar 366e09ba7baSBram Moolenaar" :Next, :Continue, etc - send a command to gdb 367e09ba7baSBram Moolenaarfunc s:SendCommand(cmd) 368e09ba7baSBram Moolenaar call term_sendkeys(s:commbuf, a:cmd . "\r") 369e09ba7baSBram Moolenaarendfunc 370e09ba7baSBram Moolenaar 37160e73f2aSBram Moolenaarfunc s:Run(args) 37260e73f2aSBram Moolenaar if a:args != '' 37360e73f2aSBram Moolenaar call s:SendCommand('-exec-arguments ' . a:args) 37460e73f2aSBram Moolenaar endif 37560e73f2aSBram Moolenaar call s:SendCommand('-exec-run') 37660e73f2aSBram Moolenaarendfunc 37760e73f2aSBram Moolenaar 37851b0f370SBram Moolenaarfunc s:SendEval(expr) 37951b0f370SBram Moolenaar call s:SendCommand('-data-evaluate-expression "' . a:expr . '"') 38051b0f370SBram Moolenaar let s:evalexpr = a:expr 38151b0f370SBram Moolenaarendfunc 38251b0f370SBram Moolenaar 38345d5f26dSBram Moolenaar" :Evaluate - evaluate what is under the cursor 38445d5f26dSBram Moolenaarfunc s:Evaluate(range, arg) 38545d5f26dSBram Moolenaar if a:arg != '' 38645d5f26dSBram Moolenaar let expr = a:arg 38745d5f26dSBram Moolenaar elseif a:range == 2 38845d5f26dSBram Moolenaar let pos = getcurpos() 38945d5f26dSBram Moolenaar let reg = getreg('v', 1, 1) 39045d5f26dSBram Moolenaar let regt = getregtype('v') 39145d5f26dSBram Moolenaar normal! gv"vy 39245d5f26dSBram Moolenaar let expr = @v 39345d5f26dSBram Moolenaar call setpos('.', pos) 39445d5f26dSBram Moolenaar call setreg('v', reg, regt) 39545d5f26dSBram Moolenaar else 39645d5f26dSBram Moolenaar let expr = expand('<cexpr>') 39745d5f26dSBram Moolenaar endif 39822f1d0e3SBram Moolenaar let s:ignoreEvalError = 0 39951b0f370SBram Moolenaar call s:SendEval(expr) 40045d5f26dSBram Moolenaarendfunc 40145d5f26dSBram Moolenaar 40222f1d0e3SBram Moolenaarlet s:ignoreEvalError = 0 40351b0f370SBram Moolenaarlet s:evalFromBalloonExpr = 0 40451b0f370SBram Moolenaar 40545d5f26dSBram Moolenaar" Handle the result of data-evaluate-expression 40645d5f26dSBram Moolenaarfunc s:HandleEvaluate(msg) 4071b9645deSBram Moolenaar let value = substitute(a:msg, '.*value="\(.*\)"', '\1', '') 4081b9645deSBram Moolenaar let value = substitute(value, '\\"', '"', 'g') 40951b0f370SBram Moolenaar if s:evalFromBalloonExpr 41051b0f370SBram Moolenaar if s:evalFromBalloonExprResult == '' 41151b0f370SBram Moolenaar let s:evalFromBalloonExprResult = s:evalexpr . ': ' . value 41251b0f370SBram Moolenaar else 41351b0f370SBram Moolenaar let s:evalFromBalloonExprResult .= ' = ' . value 41451b0f370SBram Moolenaar endif 41551b0f370SBram Moolenaar call balloon_show(s:evalFromBalloonExprResult) 41651b0f370SBram Moolenaar else 4171b9645deSBram Moolenaar echomsg '"' . s:evalexpr . '": ' . value 41851b0f370SBram Moolenaar endif 4191b9645deSBram Moolenaar 4207f2e9d7cSBram Moolenaar if s:evalexpr[0] != '*' && value =~ '^0x' && value != '0x0' && value !~ '"$' 4211b9645deSBram Moolenaar " Looks like a pointer, also display what it points to. 42222f1d0e3SBram Moolenaar let s:ignoreEvalError = 1 42351b0f370SBram Moolenaar call s:SendEval('*' . s:evalexpr) 42451b0f370SBram Moolenaar else 42551b0f370SBram Moolenaar let s:evalFromBalloonExpr = 0 4261b9645deSBram Moolenaar endif 42745d5f26dSBram Moolenaarendfunc 42845d5f26dSBram Moolenaar 42951b0f370SBram Moolenaar" Show a balloon with information of the variable under the mouse pointer, 43051b0f370SBram Moolenaar" if there is any. 43151b0f370SBram Moolenaarfunc TermDebugBalloonExpr() 43251b0f370SBram Moolenaar if v:beval_winid != s:startwin 43351b0f370SBram Moolenaar return 43451b0f370SBram Moolenaar endif 43551b0f370SBram Moolenaar let s:evalFromBalloonExpr = 1 43651b0f370SBram Moolenaar let s:evalFromBalloonExprResult = '' 43722f1d0e3SBram Moolenaar let s:ignoreEvalError = 1 43822f1d0e3SBram Moolenaar call s:SendEval(v:beval_text) 43951b0f370SBram Moolenaar return '' 44051b0f370SBram Moolenaarendfunc 44151b0f370SBram Moolenaar 44245d5f26dSBram Moolenaar" Handle an error. 44345d5f26dSBram Moolenaarfunc s:HandleError(msg) 44422f1d0e3SBram Moolenaar if s:ignoreEvalError 44551b0f370SBram Moolenaar " Result of s:SendEval() failed, ignore. 44622f1d0e3SBram Moolenaar let s:ignoreEvalError = 0 44722f1d0e3SBram Moolenaar let s:evalFromBalloonExpr = 0 44851b0f370SBram Moolenaar return 44951b0f370SBram Moolenaar endif 45045d5f26dSBram Moolenaar echoerr substitute(a:msg, '.*msg="\(.*\)"', '\1', '') 45145d5f26dSBram Moolenaarendfunc 45245d5f26dSBram Moolenaar 453e09ba7baSBram Moolenaar" Handle stopping and running message from gdb. 454e09ba7baSBram Moolenaar" Will update the sign that shows the current position. 455e09ba7baSBram Moolenaarfunc s:HandleCursor(msg) 456fe386641SBram Moolenaar let wid = win_getid(winnr()) 457fe386641SBram Moolenaar 45860e73f2aSBram Moolenaar if a:msg =~ '^\*stopped' 45960e73f2aSBram Moolenaar let s:stopped = 1 46060e73f2aSBram Moolenaar elseif a:msg =~ '^\*running' 46160e73f2aSBram Moolenaar let s:stopped = 0 46260e73f2aSBram Moolenaar endif 46360e73f2aSBram Moolenaar 464fe386641SBram Moolenaar if win_gotoid(s:startwin) 465e09ba7baSBram Moolenaar let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '') 4661b9645deSBram Moolenaar if a:msg =~ '^\(\*stopped\|=thread-selected\)' && filereadable(fname) 467e09ba7baSBram Moolenaar let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '') 468fe386641SBram Moolenaar if lnum =~ '^[0-9]*$' 4691b9645deSBram Moolenaar if expand('%:p') != fnamemodify(fname, ':p') 470fe386641SBram Moolenaar if &modified 471fe386641SBram Moolenaar " TODO: find existing window 472fe386641SBram Moolenaar exe 'split ' . fnameescape(fname) 473fe386641SBram Moolenaar let s:startwin = win_getid(winnr()) 474fe386641SBram Moolenaar else 475fe386641SBram Moolenaar exe 'edit ' . fnameescape(fname) 476fe386641SBram Moolenaar endif 477fe386641SBram Moolenaar endif 478fe386641SBram Moolenaar exe lnum 47901164a65SBram Moolenaar exe 'sign unplace ' . s:pc_id 4801b9645deSBram Moolenaar exe 'sign place ' . s:pc_id . ' line=' . lnum . ' name=debugPC file=' . fname 481fe386641SBram Moolenaar setlocal signcolumn=yes 482fe386641SBram Moolenaar endif 483fe386641SBram Moolenaar else 484fe386641SBram Moolenaar exe 'sign unplace ' . s:pc_id 485fe386641SBram Moolenaar endif 486fe386641SBram Moolenaar 487fe386641SBram Moolenaar call win_gotoid(wid) 488fe386641SBram Moolenaar endif 489e09ba7baSBram Moolenaarendfunc 490e09ba7baSBram Moolenaar 491e09ba7baSBram Moolenaar" Handle setting a breakpoint 492e09ba7baSBram Moolenaar" Will update the sign that shows the breakpoint 493e09ba7baSBram Moolenaarfunc s:HandleNewBreakpoint(msg) 494e09ba7baSBram Moolenaar let nr = substitute(a:msg, '.*number="\([0-9]\)*\".*', '\1', '') + 0 495e09ba7baSBram Moolenaar if nr == 0 496e09ba7baSBram Moolenaar return 497fe386641SBram Moolenaar endif 498e09ba7baSBram Moolenaar 499e09ba7baSBram Moolenaar if has_key(s:breakpoints, nr) 500e09ba7baSBram Moolenaar let entry = s:breakpoints[nr] 501e09ba7baSBram Moolenaar else 502e09ba7baSBram Moolenaar let entry = {} 503e09ba7baSBram Moolenaar let s:breakpoints[nr] = entry 504fe386641SBram Moolenaar endif 505e09ba7baSBram Moolenaar 506e09ba7baSBram Moolenaar let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '') 507e09ba7baSBram Moolenaar let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '') 508e09ba7baSBram Moolenaar let entry['fname'] = fname 509e09ba7baSBram Moolenaar let entry['lnum'] = lnum 5101b9645deSBram Moolenaar 5111b9645deSBram Moolenaar if bufloaded(fname) 5121b9645deSBram Moolenaar call s:PlaceSign(nr, entry) 5131b9645deSBram Moolenaar endif 5141b9645deSBram Moolenaarendfunc 5151b9645deSBram Moolenaar 5161b9645deSBram Moolenaarfunc s:PlaceSign(nr, entry) 5171b9645deSBram Moolenaar exe 'sign place ' . (s:break_id + a:nr) . ' line=' . a:entry['lnum'] . ' name=debugBreakpoint file=' . a:entry['fname'] 5181b9645deSBram Moolenaar let a:entry['placed'] = 1 519e09ba7baSBram Moolenaarendfunc 520e09ba7baSBram Moolenaar 521e09ba7baSBram Moolenaar" Handle deleting a breakpoint 522e09ba7baSBram Moolenaar" Will remove the sign that shows the breakpoint 523e09ba7baSBram Moolenaarfunc s:HandleBreakpointDelete(msg) 524e09ba7baSBram Moolenaar let nr = substitute(a:msg, '.*id="\([0-9]*\)\".*', '\1', '') + 0 525e09ba7baSBram Moolenaar if nr == 0 526e09ba7baSBram Moolenaar return 527e09ba7baSBram Moolenaar endif 5281b9645deSBram Moolenaar if has_key(s:breakpoints, nr) 5291b9645deSBram Moolenaar let entry = s:breakpoints[nr] 5301b9645deSBram Moolenaar if has_key(entry, 'placed') 531e09ba7baSBram Moolenaar exe 'sign unplace ' . (s:break_id + nr) 5321b9645deSBram Moolenaar unlet entry['placed'] 5331b9645deSBram Moolenaar endif 534e09ba7baSBram Moolenaar unlet s:breakpoints[nr] 5351b9645deSBram Moolenaar endif 536c572da5fSBram Moolenaarendfunc 5371b9645deSBram Moolenaar 5381b9645deSBram Moolenaar" Handle a BufRead autocommand event: place any signs. 5391b9645deSBram Moolenaarfunc s:BufRead() 5401b9645deSBram Moolenaar let fname = expand('<afile>:p') 5411b9645deSBram Moolenaar for [nr, entry] in items(s:breakpoints) 5421b9645deSBram Moolenaar if entry['fname'] == fname 5431b9645deSBram Moolenaar call s:PlaceSign(nr, entry) 5441b9645deSBram Moolenaar endif 5451b9645deSBram Moolenaar endfor 5461b9645deSBram Moolenaarendfunc 5471b9645deSBram Moolenaar 5481b9645deSBram Moolenaar" Handle a BufUnloaded autocommand event: unplace any signs. 5491b9645deSBram Moolenaarfunc s:BufUnloaded() 5501b9645deSBram Moolenaar let fname = expand('<afile>:p') 5511b9645deSBram Moolenaar for [nr, entry] in items(s:breakpoints) 5521b9645deSBram Moolenaar if entry['fname'] == fname 5531b9645deSBram Moolenaar let entry['placed'] = 0 5541b9645deSBram Moolenaar endif 5551b9645deSBram Moolenaar endfor 5561b9645deSBram Moolenaarendfunc 5571b9645deSBram Moolenaar 558