Mercurial > vim
changeset 32921:0305a7f2b874
Runtime(termdebug): Add support to view local and argument variables
Commit: https://github.com/vim/vim/commit/9f29621415146abc046471440515e9e34f3e57a1
Author: laburnumT <flo.striker@gmail.com>
Date: Sat May 13 16:29:15 2023 +0200
Runtime(termdebug): Add support to view local and argument variables
closes: 12403
Signed-off-by: Christian Brabandt <cb@256bit.org>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sun, 20 Aug 2023 20:15:03 +0200 |
parents | 75f46cfabbff |
children | 397ff3169248 |
files | runtime/doc/terminal.txt runtime/pack/dist/opt/termdebug/plugin/termdebug.vim |
diffstat | 2 files changed, 169 insertions(+), 22 deletions(-) [+] |
line wrap: on
line diff
--- a/runtime/doc/terminal.txt +++ b/runtime/doc/terminal.txt @@ -1384,6 +1384,9 @@ Other commands ~ isn't one *:Asm* jump to the window with the disassembly, create it if there isn't one + *:Var* jump to the window with the local and argument variables, + create it if there isn't one. This window updates whenever the + program is stopped Events ~ *termdebug-events* @@ -1460,6 +1463,15 @@ If there is no g:termdebug_config you ca let g:termdebug_disasm_window = 15 Any value greater than 1 will set the Asm window height to that value. + *termdebug_variables_window* +If you want the Var window shown by default, set the flag to 1. +the "variables_window_height" entry can be used to set the window height: > + let g:termdebug_config['variables_window'] = 1 + let g:termdebug_config['variables_window_height'] = 15 +If there is no g:termdebug_config you can use: > + let g:termdebug_variables_window = 15 +Any value greater than 1 will set the Var window height to that value. + Communication ~ *termdebug-communication* There is another, hidden, buffer, which is used for Vim to communicate with
--- a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim +++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim @@ -69,6 +69,7 @@ let s:pc_id = 12 let s:asm_id = 13 let s:break_id = 14 " breakpoint number is added to this let s:stopped = 1 +let s:running = 0 let s:parsing_disasm_msg = 0 let s:asm_lines = [] @@ -145,6 +146,9 @@ func s:StartDebug_internal(dict) let s:ptywin = 0 let s:pid = 0 let s:asmwin = 0 + let s:asmbuf = 0 + let s:varwin = 0 + let s:varbuf = 0 if exists('#User#TermdebugStartPre') doauto <nomodeline> User TermdebugStartPre @@ -153,7 +157,7 @@ func s:StartDebug_internal(dict) " Uncomment this line to write logging in "debuglog". " call ch_logfile('debuglog', 'w') - let s:sourcewin = win_getid(winnr()) + let s:sourcewin = win_getid() " Remember the old value of 'signcolumn' for each buffer that it's set in, so " that we can restore the value for all buffers. @@ -201,11 +205,17 @@ func s:StartDebug_internal(dict) endif if s:GetDisasmWindow() - let curwinid = win_getid(winnr()) + let curwinid = win_getid() call s:GotoAsmwinOrCreateIt() call win_gotoid(curwinid) endif + if s:GetVariablesWindow() + let curwinid = win_getid() + call s:GotoVariableswinOrCreateIt() + call win_gotoid(curwinid) + endif + if exists('#User#TermdebugStartPost') doauto <nomodeline> User TermdebugStartPost endif @@ -215,6 +225,13 @@ endfunc func s:CloseBuffers() exe 'bwipe! ' . s:ptybuf exe 'bwipe! ' . s:commbuf + if s:asmbuf > 0 + exe 'bwipe! ' . s:asmbuf + endif + if s:varbuf > 0 + exe 'bwipe! ' . s:varbuf + endif + s:running = 0 unlet! s:gdbwin endfunc @@ -239,7 +256,7 @@ func s:StartDebug_term(dict) return endif let pty = job_info(term_getjob(s:ptybuf))['tty_out'] - let s:ptywin = win_getid(winnr()) + let s:ptywin = win_getid() if s:vertical " Assuming the source code window will get a signcolumn, use two more " columns for that, thus one less for the terminal window. @@ -302,7 +319,7 @@ func s:StartDebug_term(dict) call s:CloseBuffers() return endif - let s:gdbwin = win_getid(winnr()) + let s:gdbwin = win_getid() " Wait for the "startupdone" message before sending any commands. let try_count = 0 @@ -390,7 +407,7 @@ func s:StartDebug_prompt(dict) else new endif - let s:gdbwin = win_getid(winnr()) + let s:gdbwin = win_getid() let s:promptbuf = bufnr('') call prompt_setprompt(s:promptbuf, 'gdb> ') set buftype=prompt @@ -451,7 +468,7 @@ func s:StartDebug_prompt(dict) call job_stop(s:gdbjob) return endif - let s:ptywin = win_getid(winnr()) + let s:ptywin = win_getid() let pty = job_info(term_getjob(s:ptybuf))['tty_out'] call s:SendCommand('tty ' . pty) @@ -615,7 +632,7 @@ func s:GdbOutCallback(channel, text) return endif - let curwinid = win_getid(winnr()) + let curwinid = win_getid() call win_gotoid(s:gdbwin) " Add the output above the current prompt. @@ -688,13 +705,20 @@ func s:EndTermDebug(job, status) endif exe 'bwipe! ' . s:commbuf + if s:asmbuf > 0 + exe 'bwipe! ' . s:asmbuf + endif + if s:varbuf > 0 + exe 'bwipe! ' . s:varbuf + endif + let s:running = 0 unlet s:gdbwin call s:EndDebugCommon() endfunc func s:EndDebugCommon() - let curwinid = win_getid(winnr()) + let curwinid = win_getid() if exists('s:ptybuf') && s:ptybuf exe 'bwipe! ' . s:ptybuf @@ -746,7 +770,7 @@ func s:EndPromptDebug(job, status) doauto <nomodeline> User TermdebugStopPre endif - let curwinid = win_getid(winnr()) + let curwinid = win_getid() call win_gotoid(s:gdbwin) set nomodified close @@ -777,9 +801,9 @@ endfunc " - CommOutput: ^error,msg="No function contains specified address." func s:HandleDisasmMsg(msg) if a:msg =~ '^\^done' - let curwinid = win_getid(winnr()) + let curwinid = win_getid() if win_gotoid(s:asmwin) - silent normal! gg0"_dG + silent! %delete _ call setline(1, s:asm_lines) set nomodified set filetype=asm @@ -822,6 +846,49 @@ func s:HandleDisasmMsg(msg) endif endfunc +func s:ParseVarinfo(varinfo) + let dict = {} + let nameIdx = matchstrpos(a:varinfo, '{name="\([^"]*\)"') + let dict['name'] = a:varinfo[nameIdx[1] + 7 : nameIdx[2] - 2] + let typeIdx = matchstrpos(a:varinfo, ',type="\([^"]*\)"') + let dict['type'] = a:varinfo[typeIdx[1] + 7 : typeIdx[2] - 2] + let valueIdx = matchstrpos(a:varinfo, ',value="\(.*\)"}') + if valueIdx[1] == -1 + let dict['value'] = 'Complex value' + else + let dict['value'] = a:varinfo[valueIdx[1] + 8 : valueIdx[2] - 3] + endif + return dict +endfunc + +func s:HandleVariablesMsg(msg) + let curwinid = win_getid() + if win_gotoid(s:varwin) + + silent! %delete _ + let spaceBuffer = 20 + call setline(1, 'Type' . + \ repeat(' ', 16) . + \ 'Name' . + \ repeat(' ', 16) . + \ 'Value') + let cnt = 1 + let capture = '{name=".\{-}",\%(arg=".\{-}",\)\{0,1\}type=".\{-}"\%(,value=".\{-}"\)\{0,1\}}' + let varinfo = matchstr(a:msg, capture, 0, cnt) + while varinfo != '' + let vardict = s:ParseVarinfo(varinfo) + call setline(cnt + 1, vardict['type'] . + \ repeat(' ', max([20 - len(vardict['type']), 1])) . + \ vardict['name'] . + \ repeat(' ', max([20 - len(vardict['name']), 1])) . + \ vardict['value']) + let cnt += 1 + let varinfo = matchstr(a:msg, capture, 0, cnt) + endwhile + endif + call win_gotoid(curwinid) +endfunc + " Handle a message received from gdb on the GDB/MI interface. func s:CommOutput(chan, msg) let msgs = split(a:msg, "\r") @@ -852,6 +919,8 @@ func s:CommOutput(chan, msg) elseif msg =~ '^disassemble' let s:parsing_disasm_msg = 1 let s:asm_lines = [] + elseif msg =~ '^\^done,variables=' + call s:HandleVariablesMsg(msg) endif endif endfor @@ -897,6 +966,7 @@ func s:InstallCommands() command Program call s:GotoProgram() command Source call s:GotoSourcewinOrCreateIt() command Asm call s:GotoAsmwinOrCreateIt() + command Var call s:GotoVariableswinOrCreateIt() command Winbar call s:InstallWinbar(1) let map = 1 @@ -950,7 +1020,7 @@ func s:InstallWinbar(force) nnoremenu WinBar.Cont :Continue<CR> nnoremenu WinBar.Stop :Stop<CR> nnoremenu WinBar.Eval :Evaluate<CR> - call add(s:winbar_winids, win_getid(winnr())) + call add(s:winbar_winids, win_getid()) endif endfunc @@ -971,6 +1041,7 @@ func s:DeleteCommands() delcommand Program delcommand Source delcommand Asm + delcommand Var delcommand Winbar if exists('s:k_map_saved') @@ -984,7 +1055,7 @@ func s:DeleteCommands() if has('menu') " Remove the WinBar entries from all windows where it was added. - let curwinid = win_getid(winnr()) + let curwinid = win_getid() for winid in s:winbar_winids if win_gotoid(winid) aunmenu WinBar.Step @@ -1240,7 +1311,7 @@ endfunc func s:GotoSourcewinOrCreateIt() if !win_gotoid(s:sourcewin) new - let s:sourcewin = win_getid(winnr()) + let s:sourcewin = win_getid() call s:InstallWinbar(0) endif endfunc @@ -1273,19 +1344,21 @@ func s:GotoAsmwinOrCreateIt() exe 'new' endif - let s:asmwin = win_getid(winnr()) + let s:asmwin = win_getid() setlocal nowrap setlocal number setlocal noswapfile setlocal buftype=nofile + setlocal bufhidden=wipe + setlocal signcolumn=no setlocal modifiable - let asmbuf = bufnr('Termdebug-asm-listing') - if asmbuf > 0 - exe 'buffer' . asmbuf + if s:asmbuf > 0 + exe 'buffer' . s:asmbuf else - exe 'file Termdebug-asm-listing' + silent file Termdebug-asm-listing + let s:asmbuf = bufnr('Termdebug-asm-listing') endif if s:GetDisasmWindowHeight() > 0 @@ -1306,17 +1379,75 @@ func s:GotoAsmwinOrCreateIt() endif endfunc +func s:GetVariablesWindow() + if exists('g:termdebug_config') + return get(g:termdebug_config, 'variables_window', 0) + endif + if exists('g:termdebug_disasm_window') + return g:termdebug_variables_window + endif + return 0 +endfunc + +func s:GetVariablesWindowHeight() + if exists('g:termdebug_config') + return get(g:termdebug_config, 'variables_window_height', 0) + endif + if exists('g:termdebug_variables_window') && g:termdebug_variables_window > 1 + return g:termdebug_variables_window + endif + return 0 +endfunc + +func s:GotoVariableswinOrCreateIt() + if !win_gotoid(s:varwin) + if win_gotoid(s:sourcewin) + exe 'rightbelow new' + else + exe 'new' + endif + + let s:varwin = win_getid() + + setlocal nowrap + setlocal noswapfile + setlocal buftype=nofile + setlocal bufhidden=wipe + setlocal signcolumn=no + setlocal modifiable + + if s:varbuf > 0 + exe 'buffer' . s:varbuf + else + silent file Termdebug-variables-listing + let s:varbuf = bufnr('Termdebug-variables-listing') + endif + + if s:GetVariablesWindowHeight() > 0 + exe 'resize ' .. s:GetVariablesWindowHeight() + endif + endif + + if s:running + call s:SendCommand('-stack-list-variables 2') + endif +endfunc + " Handle stopping and running message from gdb. " Will update the sign that shows the current position. func s:HandleCursor(msg) - let wid = win_getid(winnr()) + let wid = win_getid() if a:msg =~ '^\*stopped' call ch_log('program stopped') let s:stopped = 1 + if a:msg =~ '^\*stopped,reason="exited-normally"' + let s:running = 0 + endif elseif a:msg =~ '^\*running' call ch_log('program running') let s:stopped = 0 + let s:running = 1 endif if a:msg =~ 'fullname=' @@ -1330,7 +1461,7 @@ func s:HandleCursor(msg) if asm_addr != '' let s:asm_addr = asm_addr - let curwinid = win_getid(winnr()) + let curwinid = win_getid() if win_gotoid(s:asmwin) let lnum = search('^' . s:asm_addr) if lnum == 0 @@ -1345,6 +1476,10 @@ func s:HandleCursor(msg) endif endif + if s:running && s:stopped && bufwinnr('Termdebug-variables-listing') != -1 + call s:SendCommand('-stack-list-variables 2') + endif + if a:msg =~ '^\(\*stopped\|=thread-selected\)' && filereadable(fname) let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '') if lnum =~ '^[0-9]*$' @@ -1363,7 +1498,7 @@ echomsg 'different fname: "' .. expand(' if &modified " TODO: find existing window exe 'split ' . fnameescape(fname) - let s:sourcewin = win_getid(winnr()) + let s:sourcewin = win_getid() call s:InstallWinbar(0) else exe 'edit ' . fnameescape(fname)