1fe386641SBram Moolenaar" Debugger plugin using gdb. 2c572da5fSBram Moolenaar" 3*b3307b5eSBram Moolenaar" Author: Bram Moolenaar 4*b3307b5eSBram Moolenaar" Copyright: Vim license applies, see ":help license" 5*b3307b5eSBram Moolenaar" Last Update: 2018 Jun 3 6c572da5fSBram Moolenaar" 7*b3307b5eSBram Moolenaar" WORK IN PROGRESS - Only the basics work 8*b3307b5eSBram Moolenaar" Note: On MS-Windows you need a recent version of gdb. The one included with 9*b3307b5eSBram Moolenaar" MingW is too old (7.6.1). 10*b3307b5eSBram Moolenaar" I used version 7.12 from http://www.equation.com/servlet/equation.cmd?fa=gdb 11fe386641SBram Moolenaar" 12*b3307b5eSBram Moolenaar" There are two ways to run gdb: 13*b3307b5eSBram Moolenaar" - In a terminal window; used if possible, does not work on MS-Windows 14*b3307b5eSBram Moolenaar" Not used when g:termdebug_use_prompt is set to 1. 15*b3307b5eSBram Moolenaar" - Using a "prompt" buffer; may use a terminal window for the program 16*b3307b5eSBram Moolenaar" 17*b3307b5eSBram Moolenaar" For both the current window is used to view source code and shows the 18*b3307b5eSBram Moolenaar" current statement from gdb. 19*b3307b5eSBram Moolenaar" 20*b3307b5eSBram Moolenaar" USING A TERMINAL WINDOW 21*b3307b5eSBram Moolenaar" 22*b3307b5eSBram Moolenaar" Opens two visible terminal windows: 23*b3307b5eSBram Moolenaar" 1. runs a pty for the debugged program, as with ":term NONE" 24*b3307b5eSBram Moolenaar" 2. runs gdb, passing the pty of the debugged program 25fe386641SBram Moolenaar" A third terminal window is hidden, it is used for communication with gdb. 26fe386641SBram Moolenaar" 27*b3307b5eSBram Moolenaar" USING A PROMPT BUFFER 28*b3307b5eSBram Moolenaar" 29*b3307b5eSBram Moolenaar" Opens a window with a prompt buffer to communicate with gdb. 30*b3307b5eSBram Moolenaar" Gdb is run as a job with callbacks for I/O. 31*b3307b5eSBram Moolenaar" On Unix another terminal window is opened to run the debugged program 32*b3307b5eSBram Moolenaar" On MS-Windows a separate console is opened to run the debugged program 33*b3307b5eSBram Moolenaar" 34fe386641SBram Moolenaar" The communication with gdb uses GDB/MI. See: 35fe386641SBram Moolenaar" https://sourceware.org/gdb/current/onlinedocs/gdb/GDB_002fMI.html 36c572da5fSBram Moolenaar 37*b3307b5eSBram Moolenaar" In case this gets sourced twice. 3837c64c78SBram Moolenaarif exists(':Termdebug') 3937c64c78SBram Moolenaar finish 4037c64c78SBram Moolenaarendif 4137c64c78SBram Moolenaar 42*b3307b5eSBram Moolenaar" Need either the +terminal feature or +channel and the prompt buffer. 43*b3307b5eSBram Moolenaar" The terminal feature does not work with gdb on win32. 44*b3307b5eSBram Moolenaarif has('terminal') && !has('win32') 45*b3307b5eSBram Moolenaar let s:way = 'terminal' 46*b3307b5eSBram Moolenaarelseif has('channel') && exists('*prompt_setprompt') 47*b3307b5eSBram Moolenaar let s:way = 'prompt' 48*b3307b5eSBram Moolenaarelse 49*b3307b5eSBram Moolenaar if has('terminal') 50*b3307b5eSBram Moolenaar let s:err = 'Cannot debug, missing prompt buffer support' 51*b3307b5eSBram Moolenaar else 52*b3307b5eSBram Moolenaar let s:err = 'Cannot debug, +channel feature is not supported' 53*b3307b5eSBram Moolenaar endif 54*b3307b5eSBram Moolenaar command -nargs=* -complete=file -bang Termdebug echoerr s:err 55*b3307b5eSBram Moolenaar command -nargs=+ -complete=file -bang TermdebugCommand echoerr s:err 56*b3307b5eSBram Moolenaar finish 57*b3307b5eSBram Moolenaarendif 5860e73f2aSBram Moolenaar 59fe386641SBram Moolenaar" The command that starts debugging, e.g. ":Termdebug vim". 60fe386641SBram Moolenaar" To end type "quit" in the gdb window. 6132c67ba7SBram Moolenaarcommand -nargs=* -complete=file -bang Termdebug call s:StartDebug(<bang>0, <f-args>) 6232c67ba7SBram Moolenaarcommand -nargs=+ -complete=file -bang TermdebugCommand call s:StartDebugCommand(<bang>0, <f-args>) 63c572da5fSBram Moolenaar 64fe386641SBram Moolenaar" Name of the gdb command, defaults to "gdb". 65e09ba7baSBram Moolenaarif !exists('termdebugger') 66e09ba7baSBram Moolenaar let termdebugger = 'gdb' 67c572da5fSBram Moolenaarendif 68c572da5fSBram Moolenaar 69fe386641SBram Moolenaarlet s:pc_id = 12 70e09ba7baSBram Moolenaarlet s:break_id = 13 7160e73f2aSBram Moolenaarlet s:stopped = 1 72e09ba7baSBram Moolenaar 73e09ba7baSBram Moolenaarif &background == 'light' 74e09ba7baSBram Moolenaar hi default debugPC term=reverse ctermbg=lightblue guibg=lightblue 75e09ba7baSBram Moolenaarelse 76e09ba7baSBram Moolenaar hi default debugPC term=reverse ctermbg=darkblue guibg=darkblue 77e09ba7baSBram Moolenaarendif 78e09ba7baSBram Moolenaarhi default debugBreakpoint term=reverse ctermbg=red guibg=red 79fe386641SBram Moolenaar 8032c67ba7SBram Moolenaarfunc s:StartDebug(bang, ...) 8132c67ba7SBram Moolenaar " First argument is the command to debug, second core file or process ID. 8232c67ba7SBram Moolenaar call s:StartDebug_internal({'gdb_args': a:000, 'bang': a:bang}) 8332c67ba7SBram Moolenaarendfunc 8432c67ba7SBram Moolenaar 8532c67ba7SBram Moolenaarfunc s:StartDebugCommand(bang, ...) 8632c67ba7SBram Moolenaar " First argument is the command to debug, rest are run arguments. 8732c67ba7SBram Moolenaar call s:StartDebug_internal({'gdb_args': [a:1], 'proc_args': a:000[1:], 'bang': a:bang}) 8832c67ba7SBram Moolenaarendfunc 8932c67ba7SBram Moolenaar 9032c67ba7SBram Moolenaarfunc s:StartDebug_internal(dict) 91b3623a38SBram Moolenaar if exists('s:gdbwin') 92b3623a38SBram Moolenaar echoerr 'Terminal debugger already running' 93b3623a38SBram Moolenaar return 94b3623a38SBram Moolenaar endif 95*b3307b5eSBram Moolenaar let s:ptywin = 0 96b3623a38SBram Moolenaar 97*b3307b5eSBram Moolenaar " Uncomment this line to write logging in "debuglog". 98*b3307b5eSBram Moolenaar " call ch_logfile('debuglog', 'w') 99*b3307b5eSBram Moolenaar 100*b3307b5eSBram Moolenaar let s:sourcewin = win_getid(winnr()) 101fe386641SBram Moolenaar let s:startsigncolumn = &signcolumn 102fe386641SBram Moolenaar 10324a98a0eSBram Moolenaar let s:save_columns = 0 10424a98a0eSBram Moolenaar if exists('g:termdebug_wide') 10524a98a0eSBram Moolenaar if &columns < g:termdebug_wide 10638baa3e6SBram Moolenaar let s:save_columns = &columns 10738baa3e6SBram Moolenaar let &columns = g:termdebug_wide 10824a98a0eSBram Moolenaar endif 109*b3307b5eSBram Moolenaar let s:vertical = 1 11038baa3e6SBram Moolenaar else 111*b3307b5eSBram Moolenaar let s:vertical = 0 11238baa3e6SBram Moolenaar endif 11338baa3e6SBram Moolenaar 114*b3307b5eSBram Moolenaar " Override using a terminal window by setting g:termdebug_use_prompt to 1. 115*b3307b5eSBram Moolenaar let use_prompt = exists('g:termdebug_use_prompt') && g:termdebug_use_prompt 116*b3307b5eSBram Moolenaar if has('terminal') && !has('win32') && !use_prompt 117*b3307b5eSBram Moolenaar let s:way = 'terminal' 118*b3307b5eSBram Moolenaar else 119*b3307b5eSBram Moolenaar let s:way = 'prompt' 120*b3307b5eSBram Moolenaar endif 121*b3307b5eSBram Moolenaar 122*b3307b5eSBram Moolenaar if s:way == 'prompt' 123*b3307b5eSBram Moolenaar call s:StartDebug_prompt(a:dict) 124*b3307b5eSBram Moolenaar else 125*b3307b5eSBram Moolenaar call s:StartDebug_term(a:dict) 126*b3307b5eSBram Moolenaar endif 127*b3307b5eSBram Moolenaarendfunc 128*b3307b5eSBram Moolenaar 129*b3307b5eSBram Moolenaarfunc s:StartDebug_term(dict) 130*b3307b5eSBram Moolenaar " Open a terminal window without a job, to run the debugged program in. 131fe386641SBram Moolenaar let s:ptybuf = term_start('NONE', { 132*b3307b5eSBram Moolenaar \ 'term_name': 'debugged program', 133*b3307b5eSBram Moolenaar \ 'vertical': s:vertical, 134fe386641SBram Moolenaar \ }) 135fe386641SBram Moolenaar if s:ptybuf == 0 136fe386641SBram Moolenaar echoerr 'Failed to open the program terminal window' 137fe386641SBram Moolenaar return 138fe386641SBram Moolenaar endif 139fe386641SBram Moolenaar let pty = job_info(term_getjob(s:ptybuf))['tty_out'] 14045d5f26dSBram Moolenaar let s:ptywin = win_getid(winnr()) 141*b3307b5eSBram Moolenaar if s:vertical 14251b0f370SBram Moolenaar " Assuming the source code window will get a signcolumn, use two more 14351b0f370SBram Moolenaar " columns for that, thus one less for the terminal window. 14451b0f370SBram Moolenaar exe (&columns / 2 - 1) . "wincmd |" 14551b0f370SBram Moolenaar endif 146fe386641SBram Moolenaar 147fe386641SBram Moolenaar " Create a hidden terminal window to communicate with gdb 148fe386641SBram Moolenaar let s:commbuf = term_start('NONE', { 149fe386641SBram Moolenaar \ 'term_name': 'gdb communication', 150fe386641SBram Moolenaar \ 'out_cb': function('s:CommOutput'), 151fe386641SBram Moolenaar \ 'hidden': 1, 152fe386641SBram Moolenaar \ }) 153fe386641SBram Moolenaar if s:commbuf == 0 154fe386641SBram Moolenaar echoerr 'Failed to open the communication terminal window' 155fe386641SBram Moolenaar exe 'bwipe! ' . s:ptybuf 156fe386641SBram Moolenaar return 157fe386641SBram Moolenaar endif 158fe386641SBram Moolenaar let commpty = job_info(term_getjob(s:commbuf))['tty_out'] 159c572da5fSBram Moolenaar 160c572da5fSBram Moolenaar " Open a terminal window to run the debugger. 161c3632516SBram Moolenaar " Add -quiet to avoid the intro message causing a hit-enter prompt. 16232c67ba7SBram Moolenaar let gdb_args = get(a:dict, 'gdb_args', []) 16332c67ba7SBram Moolenaar let proc_args = get(a:dict, 'proc_args', []) 16432c67ba7SBram Moolenaar 16532c67ba7SBram Moolenaar let cmd = [g:termdebugger, '-quiet', '-tty', pty] + gdb_args 166*b3307b5eSBram Moolenaar call ch_log('executing "' . join(cmd) . '"') 16760e73f2aSBram Moolenaar let s:gdbbuf = term_start(cmd, { 168*b3307b5eSBram Moolenaar \ 'exit_cb': function('s:EndTermDebug'), 169fe386641SBram Moolenaar \ 'term_finish': 'close', 170c572da5fSBram Moolenaar \ }) 17160e73f2aSBram Moolenaar if s:gdbbuf == 0 172fe386641SBram Moolenaar echoerr 'Failed to open the gdb terminal window' 173fe386641SBram Moolenaar exe 'bwipe! ' . s:ptybuf 174fe386641SBram Moolenaar exe 'bwipe! ' . s:commbuf 175fe386641SBram Moolenaar return 176fe386641SBram Moolenaar endif 17745d5f26dSBram Moolenaar let s:gdbwin = win_getid(winnr()) 178fe386641SBram Moolenaar 17932c67ba7SBram Moolenaar " Set arguments to be run 18032c67ba7SBram Moolenaar if len(proc_args) 18132c67ba7SBram Moolenaar call term_sendkeys(s:gdbbuf, 'set args ' . join(proc_args) . "\r") 18232c67ba7SBram Moolenaar endif 18332c67ba7SBram Moolenaar 184fe386641SBram Moolenaar " Connect gdb to the communication pty, using the GDB/MI interface 18560e73f2aSBram Moolenaar call term_sendkeys(s:gdbbuf, 'new-ui mi ' . commpty . "\r") 18660e73f2aSBram Moolenaar 1873e4b84d0SBram Moolenaar " Wait for the response to show up, users may not notice the error and wonder 1883e4b84d0SBram Moolenaar " why the debugger doesn't work. 1893e4b84d0SBram Moolenaar let try_count = 0 1903e4b84d0SBram Moolenaar while 1 1913e4b84d0SBram Moolenaar let response = '' 192b3623a38SBram Moolenaar for lnum in range(1,200) 1933e4b84d0SBram Moolenaar if term_getline(s:gdbbuf, lnum) =~ 'new-ui mi ' 1943e4b84d0SBram Moolenaar let response = term_getline(s:gdbbuf, lnum + 1) 1953e4b84d0SBram Moolenaar if response =~ 'Undefined command' 196f3ba14ffSBram Moolenaar echoerr 'Sorry, your gdb is too old, gdb 7.12 is required' 1973e4b84d0SBram Moolenaar exe 'bwipe! ' . s:ptybuf 1983e4b84d0SBram Moolenaar exe 'bwipe! ' . s:commbuf 1993e4b84d0SBram Moolenaar return 2003e4b84d0SBram Moolenaar endif 2013e4b84d0SBram Moolenaar if response =~ 'New UI allocated' 2023e4b84d0SBram Moolenaar " Success! 2033e4b84d0SBram Moolenaar break 2043e4b84d0SBram Moolenaar endif 2053e4b84d0SBram Moolenaar endif 2063e4b84d0SBram Moolenaar endfor 2073e4b84d0SBram Moolenaar if response =~ 'New UI allocated' 2083e4b84d0SBram Moolenaar break 2093e4b84d0SBram Moolenaar endif 2103e4b84d0SBram Moolenaar let try_count += 1 2113e4b84d0SBram Moolenaar if try_count > 100 2123e4b84d0SBram Moolenaar echoerr 'Cannot check if your gdb works, continuing anyway' 2133e4b84d0SBram Moolenaar break 2143e4b84d0SBram Moolenaar endif 2153e4b84d0SBram Moolenaar sleep 10m 2163e4b84d0SBram Moolenaar endwhile 2173e4b84d0SBram Moolenaar 21860e73f2aSBram Moolenaar " Interpret commands while the target is running. This should usualy only be 21960e73f2aSBram Moolenaar " exec-interrupt, since many commands don't work properly while the target is 22060e73f2aSBram Moolenaar " running. 22160e73f2aSBram Moolenaar call s:SendCommand('-gdb-set mi-async on') 222*b3307b5eSBram Moolenaar " Older gdb uses a different command. 223*b3307b5eSBram Moolenaar call s:SendCommand('-gdb-set target-async on') 224e09ba7baSBram Moolenaar 225f3ba14ffSBram Moolenaar " Disable pagination, it causes everything to stop at the gdb 226f3ba14ffSBram Moolenaar " "Type <return> to continue" prompt. 227*b3307b5eSBram Moolenaar call s:SendCommand('set pagination off') 228f3ba14ffSBram Moolenaar 229*b3307b5eSBram Moolenaar call s:StartDebugCommon(a:dict) 230*b3307b5eSBram Moolenaarendfunc 231*b3307b5eSBram Moolenaar 232*b3307b5eSBram Moolenaarfunc s:StartDebug_prompt(dict) 233*b3307b5eSBram Moolenaar " Open a window with a prompt buffer to run gdb in. 234*b3307b5eSBram Moolenaar if s:vertical 235*b3307b5eSBram Moolenaar vertical new 236*b3307b5eSBram Moolenaar else 237*b3307b5eSBram Moolenaar new 238*b3307b5eSBram Moolenaar endif 239*b3307b5eSBram Moolenaar let s:gdbwin = win_getid(winnr()) 240*b3307b5eSBram Moolenaar let s:promptbuf = bufnr('') 241*b3307b5eSBram Moolenaar call prompt_setprompt(s:promptbuf, 'gdb> ') 242*b3307b5eSBram Moolenaar set buftype=prompt 243*b3307b5eSBram Moolenaar file gdb 244*b3307b5eSBram Moolenaar call prompt_setcallback(s:promptbuf, function('s:PromptCallback')) 245*b3307b5eSBram Moolenaar call prompt_setinterrupt(s:promptbuf, function('s:PromptInterrupt')) 246*b3307b5eSBram Moolenaar 247*b3307b5eSBram Moolenaar if s:vertical 248*b3307b5eSBram Moolenaar " Assuming the source code window will get a signcolumn, use two more 249*b3307b5eSBram Moolenaar " columns for that, thus one less for the terminal window. 250*b3307b5eSBram Moolenaar exe (&columns / 2 - 1) . "wincmd |" 251*b3307b5eSBram Moolenaar endif 252*b3307b5eSBram Moolenaar 253*b3307b5eSBram Moolenaar " Add -quiet to avoid the intro message causing a hit-enter prompt. 254*b3307b5eSBram Moolenaar let gdb_args = get(a:dict, 'gdb_args', []) 255*b3307b5eSBram Moolenaar let proc_args = get(a:dict, 'proc_args', []) 256*b3307b5eSBram Moolenaar 257*b3307b5eSBram Moolenaar let cmd = [g:termdebugger, '-quiet', '--interpreter=mi2'] + gdb_args 258*b3307b5eSBram Moolenaar call ch_log('executing "' . join(cmd) . '"') 259*b3307b5eSBram Moolenaar 260*b3307b5eSBram Moolenaar let s:gdbjob = job_start(cmd, { 261*b3307b5eSBram Moolenaar \ 'exit_cb': function('s:EndPromptDebug'), 262*b3307b5eSBram Moolenaar \ 'out_cb': function('s:GdbOutCallback'), 263*b3307b5eSBram Moolenaar \ }) 264*b3307b5eSBram Moolenaar if job_status(s:gdbjob) != "run" 265*b3307b5eSBram Moolenaar echoerr 'Failed to start gdb' 266*b3307b5eSBram Moolenaar exe 'bwipe! ' . s:promptbuf 267*b3307b5eSBram Moolenaar return 268*b3307b5eSBram Moolenaar endif 269*b3307b5eSBram Moolenaar let s:gdb_channel = job_getchannel(s:gdbjob) 270*b3307b5eSBram Moolenaar 271*b3307b5eSBram Moolenaar " Interpret commands while the target is running. This should usualy only 272*b3307b5eSBram Moolenaar " be exec-interrupt, since many commands don't work properly while the 273*b3307b5eSBram Moolenaar " target is running. 274*b3307b5eSBram Moolenaar call s:SendCommand('-gdb-set mi-async on') 275*b3307b5eSBram Moolenaar " Older gdb uses a different command. 276*b3307b5eSBram Moolenaar call s:SendCommand('-gdb-set target-async on') 277*b3307b5eSBram Moolenaar 278*b3307b5eSBram Moolenaar let s:ptybuf = 0 279*b3307b5eSBram Moolenaar if has('win32') 280*b3307b5eSBram Moolenaar " MS-Windows: run in a new console window for maximum compatibility 281*b3307b5eSBram Moolenaar call s:SendCommand('set new-console on') 282*b3307b5eSBram Moolenaar elseif has('terminal') 283*b3307b5eSBram Moolenaar " Unix: Run the debugged program in a terminal window. Open it below the 284*b3307b5eSBram Moolenaar " gdb window. 285*b3307b5eSBram Moolenaar belowright let s:ptybuf = term_start('NONE', { 286*b3307b5eSBram Moolenaar \ 'term_name': 'debugged program', 287*b3307b5eSBram Moolenaar \ }) 288*b3307b5eSBram Moolenaar if s:ptybuf == 0 289*b3307b5eSBram Moolenaar echoerr 'Failed to open the program terminal window' 290*b3307b5eSBram Moolenaar call job_stop(s:gdbjob) 291*b3307b5eSBram Moolenaar return 292*b3307b5eSBram Moolenaar endif 293*b3307b5eSBram Moolenaar let s:ptywin = win_getid(winnr()) 294*b3307b5eSBram Moolenaar let pty = job_info(term_getjob(s:ptybuf))['tty_out'] 295*b3307b5eSBram Moolenaar call s:SendCommand('tty ' . pty) 296*b3307b5eSBram Moolenaar 297*b3307b5eSBram Moolenaar " Since GDB runs in a prompt window, the environment has not been set to 298*b3307b5eSBram Moolenaar " match a terminal window, need to do that now. 299*b3307b5eSBram Moolenaar call s:SendCommand('set env TERM = xterm-color') 300*b3307b5eSBram Moolenaar call s:SendCommand('set env ROWS = ' . winheight(s:ptywin)) 301*b3307b5eSBram Moolenaar call s:SendCommand('set env LINES = ' . winheight(s:ptywin)) 302*b3307b5eSBram Moolenaar call s:SendCommand('set env COLUMNS = ' . winwidth(s:ptywin)) 303*b3307b5eSBram Moolenaar call s:SendCommand('set env COLORS = ' . &t_Co) 304*b3307b5eSBram Moolenaar call s:SendCommand('set env VIM_TERMINAL = ' . v:version) 305*b3307b5eSBram Moolenaar else 306*b3307b5eSBram Moolenaar " TODO: open a new terminal get get the tty name, pass on to gdb 307*b3307b5eSBram Moolenaar call s:SendCommand('show inferior-tty') 308*b3307b5eSBram Moolenaar endif 309*b3307b5eSBram Moolenaar call s:SendCommand('set print pretty on') 310*b3307b5eSBram Moolenaar call s:SendCommand('set breakpoint pending on') 311*b3307b5eSBram Moolenaar " Disable pagination, it causes everything to stop at the gdb 312*b3307b5eSBram Moolenaar call s:SendCommand('set pagination off') 313*b3307b5eSBram Moolenaar 314*b3307b5eSBram Moolenaar " Set arguments to be run 315*b3307b5eSBram Moolenaar if len(proc_args) 316*b3307b5eSBram Moolenaar call s:SendCommand('set args ' . join(proc_args)) 317*b3307b5eSBram Moolenaar endif 318*b3307b5eSBram Moolenaar 319*b3307b5eSBram Moolenaar call s:StartDebugCommon(a:dict) 320*b3307b5eSBram Moolenaar startinsert 321*b3307b5eSBram Moolenaarendfunc 322*b3307b5eSBram Moolenaar 323*b3307b5eSBram Moolenaarfunc s:StartDebugCommon(dict) 32438baa3e6SBram Moolenaar " Sign used to highlight the line where the program has stopped. 32538baa3e6SBram Moolenaar " There can be only one. 32638baa3e6SBram Moolenaar sign define debugPC linehl=debugPC 32738baa3e6SBram Moolenaar 32838baa3e6SBram Moolenaar " Sign used to indicate a breakpoint. 32938baa3e6SBram Moolenaar " Can be used multiple times. 33038baa3e6SBram Moolenaar sign define debugBreakpoint text=>> texthl=debugBreakpoint 33138baa3e6SBram Moolenaar 33245d5f26dSBram Moolenaar " Install debugger commands in the text window. 333*b3307b5eSBram Moolenaar call win_gotoid(s:sourcewin) 334e09ba7baSBram Moolenaar call s:InstallCommands() 33545d5f26dSBram Moolenaar call win_gotoid(s:gdbwin) 336e09ba7baSBram Moolenaar 33751b0f370SBram Moolenaar " Enable showing a balloon with eval info 338246fe03dSBram Moolenaar if has("balloon_eval") || has("balloon_eval_term") 339246fe03dSBram Moolenaar set balloonexpr=TermDebugBalloonExpr() 34051b0f370SBram Moolenaar if has("balloon_eval") 34151b0f370SBram Moolenaar set ballooneval 342246fe03dSBram Moolenaar endif 34351b0f370SBram Moolenaar if has("balloon_eval_term") 34451b0f370SBram Moolenaar set balloonevalterm 34551b0f370SBram Moolenaar endif 34651b0f370SBram Moolenaar endif 34751b0f370SBram Moolenaar 348e09ba7baSBram Moolenaar let s:breakpoints = {} 3491b9645deSBram Moolenaar 3501b9645deSBram Moolenaar augroup TermDebug 3511b9645deSBram Moolenaar au BufRead * call s:BufRead() 3521b9645deSBram Moolenaar au BufUnload * call s:BufUnloaded() 3531b9645deSBram Moolenaar augroup END 35432c67ba7SBram Moolenaar 355*b3307b5eSBram Moolenaar " Run the command if the bang attribute was given and got to the debug 356*b3307b5eSBram Moolenaar " window. 35732c67ba7SBram Moolenaar if get(a:dict, 'bang', 0) 35832c67ba7SBram Moolenaar call s:SendCommand('-exec-run') 35932c67ba7SBram Moolenaar call win_gotoid(s:ptywin) 36032c67ba7SBram Moolenaar endif 361c572da5fSBram Moolenaarendfunc 362c572da5fSBram Moolenaar 363*b3307b5eSBram Moolenaar" Send a command to gdb. "cmd" is the string without line terminator. 364*b3307b5eSBram Moolenaarfunc s:SendCommand(cmd) 365*b3307b5eSBram Moolenaar call ch_log('sending to gdb: ' . a:cmd) 366*b3307b5eSBram Moolenaar if s:way == 'prompt' 367*b3307b5eSBram Moolenaar call ch_sendraw(s:gdb_channel, a:cmd . "\n") 368*b3307b5eSBram Moolenaar else 369*b3307b5eSBram Moolenaar call term_sendkeys(s:commbuf, a:cmd . "\r") 370*b3307b5eSBram Moolenaar endif 371*b3307b5eSBram Moolenaarendfunc 372*b3307b5eSBram Moolenaar 373*b3307b5eSBram Moolenaar" This is global so that a user can create their mappings with this. 374*b3307b5eSBram Moolenaarfunc TermDebugSendCommand(cmd) 375*b3307b5eSBram Moolenaar if s:way == 'prompt' 376*b3307b5eSBram Moolenaar call ch_sendraw(s:gdb_channel, a:cmd . "\n") 377*b3307b5eSBram Moolenaar else 378*b3307b5eSBram Moolenaar let do_continue = 0 379*b3307b5eSBram Moolenaar if !s:stopped 380*b3307b5eSBram Moolenaar let do_continue = 1 381*b3307b5eSBram Moolenaar call s:SendCommand('-exec-interrupt') 382*b3307b5eSBram Moolenaar sleep 10m 383*b3307b5eSBram Moolenaar endif 384*b3307b5eSBram Moolenaar call term_sendkeys(s:gdbbuf, a:cmd . "\r") 385*b3307b5eSBram Moolenaar if do_continue 386*b3307b5eSBram Moolenaar Continue 387*b3307b5eSBram Moolenaar endif 388*b3307b5eSBram Moolenaar endif 389*b3307b5eSBram Moolenaarendfunc 390*b3307b5eSBram Moolenaar 391*b3307b5eSBram Moolenaar" Function called when entering a line in the prompt buffer. 392*b3307b5eSBram Moolenaarfunc s:PromptCallback(text) 393*b3307b5eSBram Moolenaar call s:SendCommand(a:text) 394*b3307b5eSBram Moolenaarendfunc 395*b3307b5eSBram Moolenaar 396*b3307b5eSBram Moolenaar" Function called when pressing CTRL-C in the prompt buffer. 397*b3307b5eSBram Moolenaarfunc s:PromptInterrupt() 398*b3307b5eSBram Moolenaar call ch_log('Interrupting gdb') 399*b3307b5eSBram Moolenaar call job_stop(s:gdbjob, 'int') 400*b3307b5eSBram Moolenaarendfunc 401*b3307b5eSBram Moolenaar 402*b3307b5eSBram Moolenaar" Function called when gdb outputs text. 403*b3307b5eSBram Moolenaarfunc s:GdbOutCallback(channel, text) 404*b3307b5eSBram Moolenaar call ch_log('received from gdb: ' . a:text) 405*b3307b5eSBram Moolenaar 406*b3307b5eSBram Moolenaar " Drop the gdb prompt, we have our own. 407*b3307b5eSBram Moolenaar " Drop status and echo'd commands. 408*b3307b5eSBram Moolenaar if a:text == '(gdb) ' || a:text == '^done' || a:text[0] == '&' || a:text[0] == '=' 409*b3307b5eSBram Moolenaar return 410*b3307b5eSBram Moolenaar endif 411*b3307b5eSBram Moolenaar if a:text =~ '^^error,msg=' 412*b3307b5eSBram Moolenaar let text = s:DecodeMessage(a:text[11:]) 413*b3307b5eSBram Moolenaar if exists('s:evalexpr') && text =~ 'A syntax error in expression, near\|No symbol .* in current context' 414*b3307b5eSBram Moolenaar " Silently drop evaluation errors. 415*b3307b5eSBram Moolenaar unlet s:evalexpr 416*b3307b5eSBram Moolenaar return 417*b3307b5eSBram Moolenaar endif 418*b3307b5eSBram Moolenaar elseif a:text[0] == '~' 419*b3307b5eSBram Moolenaar let text = s:DecodeMessage(a:text[1:]) 420*b3307b5eSBram Moolenaar else 421*b3307b5eSBram Moolenaar call s:CommOutput(a:channel, a:text) 422*b3307b5eSBram Moolenaar return 423*b3307b5eSBram Moolenaar endif 424*b3307b5eSBram Moolenaar 425*b3307b5eSBram Moolenaar let curwinid = win_getid(winnr()) 426*b3307b5eSBram Moolenaar call win_gotoid(s:gdbwin) 427*b3307b5eSBram Moolenaar 428*b3307b5eSBram Moolenaar " Add the output above the current prompt. 429*b3307b5eSBram Moolenaar call append(line('$') - 1, text) 430*b3307b5eSBram Moolenaar set nomodified 431*b3307b5eSBram Moolenaar 432*b3307b5eSBram Moolenaar call win_gotoid(curwinid) 433*b3307b5eSBram Moolenaarendfunc 434*b3307b5eSBram Moolenaar 435*b3307b5eSBram Moolenaar" Decode a message from gdb. quotedText starts with a ", return the text up 436*b3307b5eSBram Moolenaar" to the next ", unescaping characters. 437*b3307b5eSBram Moolenaarfunc s:DecodeMessage(quotedText) 438*b3307b5eSBram Moolenaar if a:quotedText[0] != '"' 439*b3307b5eSBram Moolenaar echoerr 'DecodeMessage(): missing quote' 440*b3307b5eSBram Moolenaar return 441*b3307b5eSBram Moolenaar endif 442*b3307b5eSBram Moolenaar let result = '' 443*b3307b5eSBram Moolenaar let i = 1 444*b3307b5eSBram Moolenaar while a:quotedText[i] != '"' && i < len(a:quotedText) 445*b3307b5eSBram Moolenaar if a:quotedText[i] == '\' 446*b3307b5eSBram Moolenaar let i += 1 447*b3307b5eSBram Moolenaar if a:quotedText[i] == 'n' 448*b3307b5eSBram Moolenaar " drop \n 449*b3307b5eSBram Moolenaar let i += 1 450*b3307b5eSBram Moolenaar continue 451*b3307b5eSBram Moolenaar endif 452*b3307b5eSBram Moolenaar endif 453*b3307b5eSBram Moolenaar let result .= a:quotedText[i] 454*b3307b5eSBram Moolenaar let i += 1 455*b3307b5eSBram Moolenaar endwhile 456*b3307b5eSBram Moolenaar return result 457*b3307b5eSBram Moolenaarendfunc 458*b3307b5eSBram Moolenaar 459*b3307b5eSBram Moolenaarfunc s:EndTermDebug(job, status) 460fe386641SBram Moolenaar exe 'bwipe! ' . s:commbuf 461b3623a38SBram Moolenaar unlet s:gdbwin 462e09ba7baSBram Moolenaar 463*b3307b5eSBram Moolenaar call s:EndDebugCommon() 464*b3307b5eSBram Moolenaarendfunc 465*b3307b5eSBram Moolenaar 466*b3307b5eSBram Moolenaarfunc s:EndDebugCommon() 467e09ba7baSBram Moolenaar let curwinid = win_getid(winnr()) 468e09ba7baSBram Moolenaar 469*b3307b5eSBram Moolenaar if exists('s:ptybuf') && s:ptybuf 470*b3307b5eSBram Moolenaar exe 'bwipe! ' . s:ptybuf 471*b3307b5eSBram Moolenaar endif 472*b3307b5eSBram Moolenaar 473*b3307b5eSBram Moolenaar call win_gotoid(s:sourcewin) 474e09ba7baSBram Moolenaar let &signcolumn = s:startsigncolumn 475e09ba7baSBram Moolenaar call s:DeleteCommands() 476e09ba7baSBram Moolenaar 477e09ba7baSBram Moolenaar call win_gotoid(curwinid) 478*b3307b5eSBram Moolenaar 47938baa3e6SBram Moolenaar if s:save_columns > 0 48038baa3e6SBram Moolenaar let &columns = s:save_columns 48138baa3e6SBram Moolenaar endif 4821b9645deSBram Moolenaar 483246fe03dSBram Moolenaar if has("balloon_eval") || has("balloon_eval_term") 484246fe03dSBram Moolenaar set balloonexpr= 48551b0f370SBram Moolenaar if has("balloon_eval") 48651b0f370SBram Moolenaar set noballooneval 487246fe03dSBram Moolenaar endif 48851b0f370SBram Moolenaar if has("balloon_eval_term") 48951b0f370SBram Moolenaar set noballoonevalterm 49051b0f370SBram Moolenaar endif 49151b0f370SBram Moolenaar endif 49251b0f370SBram Moolenaar 4931b9645deSBram Moolenaar au! TermDebug 494fe386641SBram Moolenaarendfunc 495fe386641SBram Moolenaar 496*b3307b5eSBram Moolenaarfunc s:EndPromptDebug(job, status) 497*b3307b5eSBram Moolenaar let curwinid = win_getid(winnr()) 498*b3307b5eSBram Moolenaar call win_gotoid(s:gdbwin) 499*b3307b5eSBram Moolenaar close 500*b3307b5eSBram Moolenaar if curwinid != s:gdbwin 501*b3307b5eSBram Moolenaar call win_gotoid(curwinid) 502*b3307b5eSBram Moolenaar endif 503*b3307b5eSBram Moolenaar 504*b3307b5eSBram Moolenaar call s:EndDebugCommon() 505*b3307b5eSBram Moolenaar unlet s:gdbwin 506*b3307b5eSBram Moolenaar call ch_log("Returning from EndPromptDebug()") 507*b3307b5eSBram Moolenaarendfunc 508*b3307b5eSBram Moolenaar 509fe386641SBram Moolenaar" Handle a message received from gdb on the GDB/MI interface. 510fe386641SBram Moolenaarfunc s:CommOutput(chan, msg) 511fe386641SBram Moolenaar let msgs = split(a:msg, "\r") 512fe386641SBram Moolenaar 513fe386641SBram Moolenaar for msg in msgs 514fe386641SBram Moolenaar " remove prefixed NL 515fe386641SBram Moolenaar if msg[0] == "\n" 516fe386641SBram Moolenaar let msg = msg[1:] 517fe386641SBram Moolenaar endif 518fe386641SBram Moolenaar if msg != '' 5191b9645deSBram Moolenaar if msg =~ '^\(\*stopped\|\*running\|=thread-selected\)' 520e09ba7baSBram Moolenaar call s:HandleCursor(msg) 52145d5f26dSBram Moolenaar elseif msg =~ '^\^done,bkpt=' || msg =~ '^=breakpoint-created,' 522e09ba7baSBram Moolenaar call s:HandleNewBreakpoint(msg) 523e09ba7baSBram Moolenaar elseif msg =~ '^=breakpoint-deleted,' 524e09ba7baSBram Moolenaar call s:HandleBreakpointDelete(msg) 52545d5f26dSBram Moolenaar elseif msg =~ '^\^done,value=' 52645d5f26dSBram Moolenaar call s:HandleEvaluate(msg) 52745d5f26dSBram Moolenaar elseif msg =~ '^\^error,msg=' 52845d5f26dSBram Moolenaar call s:HandleError(msg) 529e09ba7baSBram Moolenaar endif 530e09ba7baSBram Moolenaar endif 531e09ba7baSBram Moolenaar endfor 532e09ba7baSBram Moolenaarendfunc 533e09ba7baSBram Moolenaar 534e09ba7baSBram Moolenaar" Install commands in the current window to control the debugger. 535e09ba7baSBram Moolenaarfunc s:InstallCommands() 536e09ba7baSBram Moolenaar command Break call s:SetBreakpoint() 53771137fedSBram Moolenaar command Clear call s:ClearBreakpoint() 538e09ba7baSBram Moolenaar command Step call s:SendCommand('-exec-step') 53945d5f26dSBram Moolenaar command Over call s:SendCommand('-exec-next') 540e09ba7baSBram Moolenaar command Finish call s:SendCommand('-exec-finish') 54160e73f2aSBram Moolenaar command -nargs=* Run call s:Run(<q-args>) 54260e73f2aSBram Moolenaar command -nargs=* Arguments call s:SendCommand('-exec-arguments ' . <q-args>) 54360e73f2aSBram Moolenaar command Stop call s:SendCommand('-exec-interrupt') 544*b3307b5eSBram Moolenaar 545*b3307b5eSBram Moolenaar " using -exec-continue results in CTRL-C in gdb window not working 546*b3307b5eSBram Moolenaar if s:way == 'prompt' 547*b3307b5eSBram Moolenaar command Continue call s:SendCommand('continue') 548*b3307b5eSBram Moolenaar else 549*b3307b5eSBram Moolenaar command Continue call term_sendkeys(s:gdbbuf, "continue\r") 550*b3307b5eSBram Moolenaar endif 551*b3307b5eSBram Moolenaar 55245d5f26dSBram Moolenaar command -range -nargs=* Evaluate call s:Evaluate(<range>, <q-args>) 55345d5f26dSBram Moolenaar command Gdb call win_gotoid(s:gdbwin) 55445d5f26dSBram Moolenaar command Program call win_gotoid(s:ptywin) 555*b3307b5eSBram Moolenaar command Source call s:GotoSourcewinOrCreateIt() 55671137fedSBram Moolenaar command Winbar call s:InstallWinbar() 55745d5f26dSBram Moolenaar 55845d5f26dSBram Moolenaar " TODO: can the K mapping be restored? 55945d5f26dSBram Moolenaar nnoremap K :Evaluate<CR> 5601b9645deSBram Moolenaar 561f0b03c4eSBram Moolenaar if has('menu') && &mouse != '' 56271137fedSBram Moolenaar call s:InstallWinbar() 56371137fedSBram Moolenaar 56471137fedSBram Moolenaar if !exists('g:termdebug_popup') || g:termdebug_popup != 0 56571137fedSBram Moolenaar let s:saved_mousemodel = &mousemodel 56671137fedSBram Moolenaar let &mousemodel = 'popup_setpos' 56771137fedSBram Moolenaar an 1.200 PopUp.-SEP3- <Nop> 56871137fedSBram Moolenaar an 1.210 PopUp.Set\ breakpoint :Break<CR> 56971137fedSBram Moolenaar an 1.220 PopUp.Clear\ breakpoint :Clear<CR> 57071137fedSBram Moolenaar an 1.230 PopUp.Evaluate :Evaluate<CR> 57171137fedSBram Moolenaar endif 57271137fedSBram Moolenaar endif 57371137fedSBram Moolenaarendfunc 57471137fedSBram Moolenaar 57571137fedSBram Moolenaarlet s:winbar_winids = [] 57671137fedSBram Moolenaar 57771137fedSBram Moolenaar" Install the window toolbar in the current window. 57871137fedSBram Moolenaarfunc s:InstallWinbar() 579c4b533e1SBram Moolenaar if has('menu') && &mouse != '' 58024a98a0eSBram Moolenaar nnoremenu WinBar.Step :Step<CR> 58124a98a0eSBram Moolenaar nnoremenu WinBar.Next :Over<CR> 58224a98a0eSBram Moolenaar nnoremenu WinBar.Finish :Finish<CR> 58324a98a0eSBram Moolenaar nnoremenu WinBar.Cont :Continue<CR> 58460e73f2aSBram Moolenaar nnoremenu WinBar.Stop :Stop<CR> 58524a98a0eSBram Moolenaar nnoremenu WinBar.Eval :Evaluate<CR> 58671137fedSBram Moolenaar call add(s:winbar_winids, win_getid(winnr())) 587c4b533e1SBram Moolenaar endif 588e09ba7baSBram Moolenaarendfunc 589e09ba7baSBram Moolenaar 590e09ba7baSBram Moolenaar" Delete installed debugger commands in the current window. 591e09ba7baSBram Moolenaarfunc s:DeleteCommands() 592e09ba7baSBram Moolenaar delcommand Break 59371137fedSBram Moolenaar delcommand Clear 594e09ba7baSBram Moolenaar delcommand Step 59545d5f26dSBram Moolenaar delcommand Over 596e09ba7baSBram Moolenaar delcommand Finish 59760e73f2aSBram Moolenaar delcommand Run 59860e73f2aSBram Moolenaar delcommand Arguments 59960e73f2aSBram Moolenaar delcommand Stop 600e09ba7baSBram Moolenaar delcommand Continue 60145d5f26dSBram Moolenaar delcommand Evaluate 60245d5f26dSBram Moolenaar delcommand Gdb 60345d5f26dSBram Moolenaar delcommand Program 604b3623a38SBram Moolenaar delcommand Source 60571137fedSBram Moolenaar delcommand Winbar 60645d5f26dSBram Moolenaar 60745d5f26dSBram Moolenaar nunmap K 6081b9645deSBram Moolenaar 6091b9645deSBram Moolenaar if has('menu') 61071137fedSBram Moolenaar " Remove the WinBar entries from all windows where it was added. 61171137fedSBram Moolenaar let curwinid = win_getid(winnr()) 61271137fedSBram Moolenaar for winid in s:winbar_winids 61371137fedSBram Moolenaar if win_gotoid(winid) 6141b9645deSBram Moolenaar aunmenu WinBar.Step 6151b9645deSBram Moolenaar aunmenu WinBar.Next 6161b9645deSBram Moolenaar aunmenu WinBar.Finish 6171b9645deSBram Moolenaar aunmenu WinBar.Cont 61860e73f2aSBram Moolenaar aunmenu WinBar.Stop 6191b9645deSBram Moolenaar aunmenu WinBar.Eval 6201b9645deSBram Moolenaar endif 62171137fedSBram Moolenaar endfor 62271137fedSBram Moolenaar call win_gotoid(curwinid) 62371137fedSBram Moolenaar let s:winbar_winids = [] 62471137fedSBram Moolenaar 62571137fedSBram Moolenaar if exists('s:saved_mousemodel') 62671137fedSBram Moolenaar let &mousemodel = s:saved_mousemodel 62771137fedSBram Moolenaar unlet s:saved_mousemodel 62871137fedSBram Moolenaar aunmenu PopUp.-SEP3- 62971137fedSBram Moolenaar aunmenu PopUp.Set\ breakpoint 63071137fedSBram Moolenaar aunmenu PopUp.Clear\ breakpoint 63171137fedSBram Moolenaar aunmenu PopUp.Evaluate 63271137fedSBram Moolenaar endif 63371137fedSBram Moolenaar endif 6341b9645deSBram Moolenaar 63545d5f26dSBram Moolenaar exe 'sign unplace ' . s:pc_id 63645d5f26dSBram Moolenaar for key in keys(s:breakpoints) 63745d5f26dSBram Moolenaar exe 'sign unplace ' . (s:break_id + key) 63845d5f26dSBram Moolenaar endfor 63938baa3e6SBram Moolenaar sign undefine debugPC 64038baa3e6SBram Moolenaar sign undefine debugBreakpoint 64145d5f26dSBram Moolenaar unlet s:breakpoints 642e09ba7baSBram Moolenaarendfunc 643e09ba7baSBram Moolenaar 644e09ba7baSBram Moolenaar" :Break - Set a breakpoint at the cursor position. 645e09ba7baSBram Moolenaarfunc s:SetBreakpoint() 64660e73f2aSBram Moolenaar " Setting a breakpoint may not work while the program is running. 64760e73f2aSBram Moolenaar " Interrupt to make it work. 64860e73f2aSBram Moolenaar let do_continue = 0 64960e73f2aSBram Moolenaar if !s:stopped 65060e73f2aSBram Moolenaar let do_continue = 1 651*b3307b5eSBram Moolenaar if s:way == 'prompt' 652*b3307b5eSBram Moolenaar " Need to send a signal to get the UI to listen. Strangely this is only 653*b3307b5eSBram Moolenaar " needed once. 654*b3307b5eSBram Moolenaar call job_stop(s:gdbjob, 'int') 655*b3307b5eSBram Moolenaar else 65660e73f2aSBram Moolenaar call s:SendCommand('-exec-interrupt') 657*b3307b5eSBram Moolenaar endif 65860e73f2aSBram Moolenaar sleep 10m 65960e73f2aSBram Moolenaar endif 66060e73f2aSBram Moolenaar call s:SendCommand('-break-insert --source ' 66160e73f2aSBram Moolenaar \ . fnameescape(expand('%:p')) . ' --line ' . line('.')) 66260e73f2aSBram Moolenaar if do_continue 66360e73f2aSBram Moolenaar call s:SendCommand('-exec-continue') 66460e73f2aSBram Moolenaar endif 665e09ba7baSBram Moolenaarendfunc 666e09ba7baSBram Moolenaar 66771137fedSBram Moolenaar" :Clear - Delete a breakpoint at the cursor position. 66871137fedSBram Moolenaarfunc s:ClearBreakpoint() 669e09ba7baSBram Moolenaar let fname = fnameescape(expand('%:p')) 670e09ba7baSBram Moolenaar let lnum = line('.') 671e09ba7baSBram Moolenaar for [key, val] in items(s:breakpoints) 672e09ba7baSBram Moolenaar if val['fname'] == fname && val['lnum'] == lnum 673*b3307b5eSBram Moolenaar call s:SendCommand('-break-delete ' . key) 674e09ba7baSBram Moolenaar " Assume this always wors, the reply is simply "^done". 675e09ba7baSBram Moolenaar exe 'sign unplace ' . (s:break_id + key) 676e09ba7baSBram Moolenaar unlet s:breakpoints[key] 677e09ba7baSBram Moolenaar break 678e09ba7baSBram Moolenaar endif 679e09ba7baSBram Moolenaar endfor 680e09ba7baSBram Moolenaarendfunc 681e09ba7baSBram Moolenaar 68260e73f2aSBram Moolenaarfunc s:Run(args) 68360e73f2aSBram Moolenaar if a:args != '' 68460e73f2aSBram Moolenaar call s:SendCommand('-exec-arguments ' . a:args) 68560e73f2aSBram Moolenaar endif 68660e73f2aSBram Moolenaar call s:SendCommand('-exec-run') 68760e73f2aSBram Moolenaarendfunc 68860e73f2aSBram Moolenaar 68951b0f370SBram Moolenaarfunc s:SendEval(expr) 69051b0f370SBram Moolenaar call s:SendCommand('-data-evaluate-expression "' . a:expr . '"') 69151b0f370SBram Moolenaar let s:evalexpr = a:expr 69251b0f370SBram Moolenaarendfunc 69351b0f370SBram Moolenaar 69445d5f26dSBram Moolenaar" :Evaluate - evaluate what is under the cursor 69545d5f26dSBram Moolenaarfunc s:Evaluate(range, arg) 69645d5f26dSBram Moolenaar if a:arg != '' 69745d5f26dSBram Moolenaar let expr = a:arg 69845d5f26dSBram Moolenaar elseif a:range == 2 69945d5f26dSBram Moolenaar let pos = getcurpos() 70045d5f26dSBram Moolenaar let reg = getreg('v', 1, 1) 70145d5f26dSBram Moolenaar let regt = getregtype('v') 70245d5f26dSBram Moolenaar normal! gv"vy 70345d5f26dSBram Moolenaar let expr = @v 70445d5f26dSBram Moolenaar call setpos('.', pos) 70545d5f26dSBram Moolenaar call setreg('v', reg, regt) 70645d5f26dSBram Moolenaar else 70745d5f26dSBram Moolenaar let expr = expand('<cexpr>') 70845d5f26dSBram Moolenaar endif 70922f1d0e3SBram Moolenaar let s:ignoreEvalError = 0 71051b0f370SBram Moolenaar call s:SendEval(expr) 71145d5f26dSBram Moolenaarendfunc 71245d5f26dSBram Moolenaar 71322f1d0e3SBram Moolenaarlet s:ignoreEvalError = 0 71451b0f370SBram Moolenaarlet s:evalFromBalloonExpr = 0 71551b0f370SBram Moolenaar 71645d5f26dSBram Moolenaar" Handle the result of data-evaluate-expression 71745d5f26dSBram Moolenaarfunc s:HandleEvaluate(msg) 7181b9645deSBram Moolenaar let value = substitute(a:msg, '.*value="\(.*\)"', '\1', '') 7191b9645deSBram Moolenaar let value = substitute(value, '\\"', '"', 'g') 72051b0f370SBram Moolenaar if s:evalFromBalloonExpr 72151b0f370SBram Moolenaar if s:evalFromBalloonExprResult == '' 72251b0f370SBram Moolenaar let s:evalFromBalloonExprResult = s:evalexpr . ': ' . value 72351b0f370SBram Moolenaar else 72451b0f370SBram Moolenaar let s:evalFromBalloonExprResult .= ' = ' . value 72551b0f370SBram Moolenaar endif 72651b0f370SBram Moolenaar call balloon_show(s:evalFromBalloonExprResult) 72751b0f370SBram Moolenaar else 7281b9645deSBram Moolenaar echomsg '"' . s:evalexpr . '": ' . value 72951b0f370SBram Moolenaar endif 7301b9645deSBram Moolenaar 7317f2e9d7cSBram Moolenaar if s:evalexpr[0] != '*' && value =~ '^0x' && value != '0x0' && value !~ '"$' 7321b9645deSBram Moolenaar " Looks like a pointer, also display what it points to. 73322f1d0e3SBram Moolenaar let s:ignoreEvalError = 1 73451b0f370SBram Moolenaar call s:SendEval('*' . s:evalexpr) 73551b0f370SBram Moolenaar else 73651b0f370SBram Moolenaar let s:evalFromBalloonExpr = 0 7371b9645deSBram Moolenaar endif 73845d5f26dSBram Moolenaarendfunc 73945d5f26dSBram Moolenaar 74051b0f370SBram Moolenaar" Show a balloon with information of the variable under the mouse pointer, 74151b0f370SBram Moolenaar" if there is any. 74251b0f370SBram Moolenaarfunc TermDebugBalloonExpr() 743*b3307b5eSBram Moolenaar if v:beval_winid != s:sourcewin 744*b3307b5eSBram Moolenaar return 745*b3307b5eSBram Moolenaar endif 746*b3307b5eSBram Moolenaar if !s:stopped 747*b3307b5eSBram Moolenaar " Only evaluate when stopped, otherwise setting a breakpoint using the 748*b3307b5eSBram Moolenaar " mouse triggers a balloon. 74951b0f370SBram Moolenaar return 75051b0f370SBram Moolenaar endif 75151b0f370SBram Moolenaar let s:evalFromBalloonExpr = 1 75251b0f370SBram Moolenaar let s:evalFromBalloonExprResult = '' 75322f1d0e3SBram Moolenaar let s:ignoreEvalError = 1 75422f1d0e3SBram Moolenaar call s:SendEval(v:beval_text) 75551b0f370SBram Moolenaar return '' 75651b0f370SBram Moolenaarendfunc 75751b0f370SBram Moolenaar 75845d5f26dSBram Moolenaar" Handle an error. 75945d5f26dSBram Moolenaarfunc s:HandleError(msg) 76022f1d0e3SBram Moolenaar if s:ignoreEvalError 76151b0f370SBram Moolenaar " Result of s:SendEval() failed, ignore. 76222f1d0e3SBram Moolenaar let s:ignoreEvalError = 0 76322f1d0e3SBram Moolenaar let s:evalFromBalloonExpr = 0 76451b0f370SBram Moolenaar return 76551b0f370SBram Moolenaar endif 76645d5f26dSBram Moolenaar echoerr substitute(a:msg, '.*msg="\(.*\)"', '\1', '') 76745d5f26dSBram Moolenaarendfunc 76845d5f26dSBram Moolenaar 769*b3307b5eSBram Moolenaarfunc s:GotoSourcewinOrCreateIt() 770*b3307b5eSBram Moolenaar if !win_gotoid(s:sourcewin) 771c4b533e1SBram Moolenaar new 772*b3307b5eSBram Moolenaar let s:sourcewin = win_getid(winnr()) 773c4b533e1SBram Moolenaar call s:InstallWinbar() 774c4b533e1SBram Moolenaar endif 775c4b533e1SBram Moolenaarendfunc 776c4b533e1SBram Moolenaar 777e09ba7baSBram Moolenaar" Handle stopping and running message from gdb. 778e09ba7baSBram Moolenaar" Will update the sign that shows the current position. 779e09ba7baSBram Moolenaarfunc s:HandleCursor(msg) 780fe386641SBram Moolenaar let wid = win_getid(winnr()) 781fe386641SBram Moolenaar 78260e73f2aSBram Moolenaar if a:msg =~ '^\*stopped' 78360e73f2aSBram Moolenaar let s:stopped = 1 78460e73f2aSBram Moolenaar elseif a:msg =~ '^\*running' 78560e73f2aSBram Moolenaar let s:stopped = 0 78660e73f2aSBram Moolenaar endif 78760e73f2aSBram Moolenaar 788*b3307b5eSBram Moolenaar call s:GotoSourcewinOrCreateIt() 789c4b533e1SBram Moolenaar 790e09ba7baSBram Moolenaar let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '') 7911b9645deSBram Moolenaar if a:msg =~ '^\(\*stopped\|=thread-selected\)' && filereadable(fname) 792e09ba7baSBram Moolenaar let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '') 793fe386641SBram Moolenaar if lnum =~ '^[0-9]*$' 7941b9645deSBram Moolenaar if expand('%:p') != fnamemodify(fname, ':p') 795fe386641SBram Moolenaar if &modified 796fe386641SBram Moolenaar " TODO: find existing window 797fe386641SBram Moolenaar exe 'split ' . fnameescape(fname) 798*b3307b5eSBram Moolenaar let s:sourcewin = win_getid(winnr()) 799c4b533e1SBram Moolenaar call s:InstallWinbar() 800fe386641SBram Moolenaar else 801fe386641SBram Moolenaar exe 'edit ' . fnameescape(fname) 802fe386641SBram Moolenaar endif 803fe386641SBram Moolenaar endif 804fe386641SBram Moolenaar exe lnum 80501164a65SBram Moolenaar exe 'sign unplace ' . s:pc_id 8061b9645deSBram Moolenaar exe 'sign place ' . s:pc_id . ' line=' . lnum . ' name=debugPC file=' . fname 807fe386641SBram Moolenaar setlocal signcolumn=yes 808fe386641SBram Moolenaar endif 809fe386641SBram Moolenaar else 810fe386641SBram Moolenaar exe 'sign unplace ' . s:pc_id 811fe386641SBram Moolenaar endif 812fe386641SBram Moolenaar 813fe386641SBram Moolenaar call win_gotoid(wid) 814e09ba7baSBram Moolenaarendfunc 815e09ba7baSBram Moolenaar 816e09ba7baSBram Moolenaar" Handle setting a breakpoint 817e09ba7baSBram Moolenaar" Will update the sign that shows the breakpoint 818e09ba7baSBram Moolenaarfunc s:HandleNewBreakpoint(msg) 819e09ba7baSBram Moolenaar let nr = substitute(a:msg, '.*number="\([0-9]\)*\".*', '\1', '') + 0 820e09ba7baSBram Moolenaar if nr == 0 821e09ba7baSBram Moolenaar return 822fe386641SBram Moolenaar endif 823e09ba7baSBram Moolenaar 824e09ba7baSBram Moolenaar if has_key(s:breakpoints, nr) 825e09ba7baSBram Moolenaar let entry = s:breakpoints[nr] 826e09ba7baSBram Moolenaar else 827e09ba7baSBram Moolenaar let entry = {} 828e09ba7baSBram Moolenaar let s:breakpoints[nr] = entry 829fe386641SBram Moolenaar endif 830e09ba7baSBram Moolenaar 831e09ba7baSBram Moolenaar let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '') 832e09ba7baSBram Moolenaar let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '') 833e09ba7baSBram Moolenaar let entry['fname'] = fname 834e09ba7baSBram Moolenaar let entry['lnum'] = lnum 8351b9645deSBram Moolenaar 8361b9645deSBram Moolenaar if bufloaded(fname) 8371b9645deSBram Moolenaar call s:PlaceSign(nr, entry) 8381b9645deSBram Moolenaar endif 8391b9645deSBram Moolenaarendfunc 8401b9645deSBram Moolenaar 8411b9645deSBram Moolenaarfunc s:PlaceSign(nr, entry) 8421b9645deSBram Moolenaar exe 'sign place ' . (s:break_id + a:nr) . ' line=' . a:entry['lnum'] . ' name=debugBreakpoint file=' . a:entry['fname'] 8431b9645deSBram Moolenaar let a:entry['placed'] = 1 844e09ba7baSBram Moolenaarendfunc 845e09ba7baSBram Moolenaar 846e09ba7baSBram Moolenaar" Handle deleting a breakpoint 847e09ba7baSBram Moolenaar" Will remove the sign that shows the breakpoint 848e09ba7baSBram Moolenaarfunc s:HandleBreakpointDelete(msg) 849e09ba7baSBram Moolenaar let nr = substitute(a:msg, '.*id="\([0-9]*\)\".*', '\1', '') + 0 850e09ba7baSBram Moolenaar if nr == 0 851e09ba7baSBram Moolenaar return 852e09ba7baSBram Moolenaar endif 8531b9645deSBram Moolenaar if has_key(s:breakpoints, nr) 8541b9645deSBram Moolenaar let entry = s:breakpoints[nr] 8551b9645deSBram Moolenaar if has_key(entry, 'placed') 856e09ba7baSBram Moolenaar exe 'sign unplace ' . (s:break_id + nr) 8571b9645deSBram Moolenaar unlet entry['placed'] 8581b9645deSBram Moolenaar endif 859e09ba7baSBram Moolenaar unlet s:breakpoints[nr] 8601b9645deSBram Moolenaar endif 861c572da5fSBram Moolenaarendfunc 8621b9645deSBram Moolenaar 8631b9645deSBram Moolenaar" Handle a BufRead autocommand event: place any signs. 8641b9645deSBram Moolenaarfunc s:BufRead() 8651b9645deSBram Moolenaar let fname = expand('<afile>:p') 8661b9645deSBram Moolenaar for [nr, entry] in items(s:breakpoints) 8671b9645deSBram Moolenaar if entry['fname'] == fname 8681b9645deSBram Moolenaar call s:PlaceSign(nr, entry) 8691b9645deSBram Moolenaar endif 8701b9645deSBram Moolenaar endfor 8711b9645deSBram Moolenaarendfunc 8721b9645deSBram Moolenaar 8731b9645deSBram Moolenaar" Handle a BufUnloaded autocommand event: unplace any signs. 8741b9645deSBram Moolenaarfunc s:BufUnloaded() 8751b9645deSBram Moolenaar let fname = expand('<afile>:p') 8761b9645deSBram Moolenaar for [nr, entry] in items(s:breakpoints) 8771b9645deSBram Moolenaar if entry['fname'] == fname 8781b9645deSBram Moolenaar let entry['placed'] = 0 8791b9645deSBram Moolenaar endif 8801b9645deSBram Moolenaar endfor 8811b9645deSBram Moolenaarendfunc 8821b9645deSBram Moolenaar 883