1
0
forked from aniani/vim

Runtime(termdebug): Add support to view local and argument variables

closes: 12403

Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
laburnumT
2023-05-13 16:29:15 +02:00
committed by Christian Brabandt
parent 72904d5fda
commit 9f29621415
2 changed files with 169 additions and 22 deletions

View File

@@ -1384,6 +1384,9 @@ Other commands ~
isn't one isn't one
*:Asm* jump to the window with the disassembly, create it if there *:Asm* jump to the window with the disassembly, create it if there
isn't one 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 ~ Events ~
*termdebug-events* *termdebug-events*
@@ -1460,6 +1463,15 @@ If there is no g:termdebug_config you can use: >
let g:termdebug_disasm_window = 15 let g:termdebug_disasm_window = 15
Any value greater than 1 will set the Asm window height to that value. 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 ~ Communication ~
*termdebug-communication* *termdebug-communication*
There is another, hidden, buffer, which is used for Vim to communicate with There is another, hidden, buffer, which is used for Vim to communicate with

View File

@@ -69,6 +69,7 @@ let s:pc_id = 12
let s:asm_id = 13 let s:asm_id = 13
let s:break_id = 14 " breakpoint number is added to this let s:break_id = 14 " breakpoint number is added to this
let s:stopped = 1 let s:stopped = 1
let s:running = 0
let s:parsing_disasm_msg = 0 let s:parsing_disasm_msg = 0
let s:asm_lines = [] let s:asm_lines = []
@@ -145,6 +146,9 @@ func s:StartDebug_internal(dict)
let s:ptywin = 0 let s:ptywin = 0
let s:pid = 0 let s:pid = 0
let s:asmwin = 0 let s:asmwin = 0
let s:asmbuf = 0
let s:varwin = 0
let s:varbuf = 0
if exists('#User#TermdebugStartPre') if exists('#User#TermdebugStartPre')
doauto <nomodeline> User TermdebugStartPre doauto <nomodeline> User TermdebugStartPre
@@ -153,7 +157,7 @@ func s:StartDebug_internal(dict)
" Uncomment this line to write logging in "debuglog". " Uncomment this line to write logging in "debuglog".
" call ch_logfile('debuglog', 'w') " 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 " Remember the old value of 'signcolumn' for each buffer that it's set in, so
" that we can restore the value for all buffers. " that we can restore the value for all buffers.
@@ -201,11 +205,17 @@ func s:StartDebug_internal(dict)
endif endif
if s:GetDisasmWindow() if s:GetDisasmWindow()
let curwinid = win_getid(winnr()) let curwinid = win_getid()
call s:GotoAsmwinOrCreateIt() call s:GotoAsmwinOrCreateIt()
call win_gotoid(curwinid) call win_gotoid(curwinid)
endif endif
if s:GetVariablesWindow()
let curwinid = win_getid()
call s:GotoVariableswinOrCreateIt()
call win_gotoid(curwinid)
endif
if exists('#User#TermdebugStartPost') if exists('#User#TermdebugStartPost')
doauto <nomodeline> User TermdebugStartPost doauto <nomodeline> User TermdebugStartPost
endif endif
@@ -215,6 +225,13 @@ endfunc
func s:CloseBuffers() func s:CloseBuffers()
exe 'bwipe! ' . s:ptybuf exe 'bwipe! ' . s:ptybuf
exe 'bwipe! ' . s:commbuf 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 unlet! s:gdbwin
endfunc endfunc
@@ -239,7 +256,7 @@ func s:StartDebug_term(dict)
return return
endif endif
let pty = job_info(term_getjob(s:ptybuf))['tty_out'] let pty = job_info(term_getjob(s:ptybuf))['tty_out']
let s:ptywin = win_getid(winnr()) let s:ptywin = win_getid()
if s:vertical if s:vertical
" Assuming the source code window will get a signcolumn, use two more " Assuming the source code window will get a signcolumn, use two more
" columns for that, thus one less for the terminal window. " columns for that, thus one less for the terminal window.
@@ -302,7 +319,7 @@ func s:StartDebug_term(dict)
call s:CloseBuffers() call s:CloseBuffers()
return return
endif endif
let s:gdbwin = win_getid(winnr()) let s:gdbwin = win_getid()
" Wait for the "startupdone" message before sending any commands. " Wait for the "startupdone" message before sending any commands.
let try_count = 0 let try_count = 0
@@ -390,7 +407,7 @@ func s:StartDebug_prompt(dict)
else else
new new
endif endif
let s:gdbwin = win_getid(winnr()) let s:gdbwin = win_getid()
let s:promptbuf = bufnr('') let s:promptbuf = bufnr('')
call prompt_setprompt(s:promptbuf, 'gdb> ') call prompt_setprompt(s:promptbuf, 'gdb> ')
set buftype=prompt set buftype=prompt
@@ -451,7 +468,7 @@ func s:StartDebug_prompt(dict)
call job_stop(s:gdbjob) call job_stop(s:gdbjob)
return return
endif endif
let s:ptywin = win_getid(winnr()) let s:ptywin = win_getid()
let pty = job_info(term_getjob(s:ptybuf))['tty_out'] let pty = job_info(term_getjob(s:ptybuf))['tty_out']
call s:SendCommand('tty ' . pty) call s:SendCommand('tty ' . pty)
@@ -615,7 +632,7 @@ func s:GdbOutCallback(channel, text)
return return
endif endif
let curwinid = win_getid(winnr()) let curwinid = win_getid()
call win_gotoid(s:gdbwin) call win_gotoid(s:gdbwin)
" Add the output above the current prompt. " Add the output above the current prompt.
@@ -688,13 +705,20 @@ func s:EndTermDebug(job, status)
endif endif
exe 'bwipe! ' . s:commbuf 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 unlet s:gdbwin
call s:EndDebugCommon() call s:EndDebugCommon()
endfunc endfunc
func s:EndDebugCommon() func s:EndDebugCommon()
let curwinid = win_getid(winnr()) let curwinid = win_getid()
if exists('s:ptybuf') && s:ptybuf if exists('s:ptybuf') && s:ptybuf
exe 'bwipe! ' . s:ptybuf exe 'bwipe! ' . s:ptybuf
@@ -746,7 +770,7 @@ func s:EndPromptDebug(job, status)
doauto <nomodeline> User TermdebugStopPre doauto <nomodeline> User TermdebugStopPre
endif endif
let curwinid = win_getid(winnr()) let curwinid = win_getid()
call win_gotoid(s:gdbwin) call win_gotoid(s:gdbwin)
set nomodified set nomodified
close close
@@ -777,9 +801,9 @@ endfunc
" - CommOutput: ^error,msg="No function contains specified address." " - CommOutput: ^error,msg="No function contains specified address."
func s:HandleDisasmMsg(msg) func s:HandleDisasmMsg(msg)
if a:msg =~ '^\^done' if a:msg =~ '^\^done'
let curwinid = win_getid(winnr()) let curwinid = win_getid()
if win_gotoid(s:asmwin) if win_gotoid(s:asmwin)
silent normal! gg0"_dG silent! %delete _
call setline(1, s:asm_lines) call setline(1, s:asm_lines)
set nomodified set nomodified
set filetype=asm set filetype=asm
@@ -822,6 +846,49 @@ func s:HandleDisasmMsg(msg)
endif endif
endfunc 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. " Handle a message received from gdb on the GDB/MI interface.
func s:CommOutput(chan, msg) func s:CommOutput(chan, msg)
let msgs = split(a:msg, "\r") let msgs = split(a:msg, "\r")
@@ -852,6 +919,8 @@ func s:CommOutput(chan, msg)
elseif msg =~ '^disassemble' elseif msg =~ '^disassemble'
let s:parsing_disasm_msg = 1 let s:parsing_disasm_msg = 1
let s:asm_lines = [] let s:asm_lines = []
elseif msg =~ '^\^done,variables='
call s:HandleVariablesMsg(msg)
endif endif
endif endif
endfor endfor
@@ -897,6 +966,7 @@ func s:InstallCommands()
command Program call s:GotoProgram() command Program call s:GotoProgram()
command Source call s:GotoSourcewinOrCreateIt() command Source call s:GotoSourcewinOrCreateIt()
command Asm call s:GotoAsmwinOrCreateIt() command Asm call s:GotoAsmwinOrCreateIt()
command Var call s:GotoVariableswinOrCreateIt()
command Winbar call s:InstallWinbar(1) command Winbar call s:InstallWinbar(1)
let map = 1 let map = 1
@@ -950,7 +1020,7 @@ func s:InstallWinbar(force)
nnoremenu WinBar.Cont :Continue<CR> nnoremenu WinBar.Cont :Continue<CR>
nnoremenu WinBar.Stop :Stop<CR> nnoremenu WinBar.Stop :Stop<CR>
nnoremenu WinBar.Eval :Evaluate<CR> nnoremenu WinBar.Eval :Evaluate<CR>
call add(s:winbar_winids, win_getid(winnr())) call add(s:winbar_winids, win_getid())
endif endif
endfunc endfunc
@@ -971,6 +1041,7 @@ func s:DeleteCommands()
delcommand Program delcommand Program
delcommand Source delcommand Source
delcommand Asm delcommand Asm
delcommand Var
delcommand Winbar delcommand Winbar
if exists('s:k_map_saved') if exists('s:k_map_saved')
@@ -984,7 +1055,7 @@ func s:DeleteCommands()
if has('menu') if has('menu')
" Remove the WinBar entries from all windows where it was added. " 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 for winid in s:winbar_winids
if win_gotoid(winid) if win_gotoid(winid)
aunmenu WinBar.Step aunmenu WinBar.Step
@@ -1240,7 +1311,7 @@ endfunc
func s:GotoSourcewinOrCreateIt() func s:GotoSourcewinOrCreateIt()
if !win_gotoid(s:sourcewin) if !win_gotoid(s:sourcewin)
new new
let s:sourcewin = win_getid(winnr()) let s:sourcewin = win_getid()
call s:InstallWinbar(0) call s:InstallWinbar(0)
endif endif
endfunc endfunc
@@ -1273,19 +1344,21 @@ func s:GotoAsmwinOrCreateIt()
exe 'new' exe 'new'
endif endif
let s:asmwin = win_getid(winnr()) let s:asmwin = win_getid()
setlocal nowrap setlocal nowrap
setlocal number setlocal number
setlocal noswapfile setlocal noswapfile
setlocal buftype=nofile setlocal buftype=nofile
setlocal bufhidden=wipe
setlocal signcolumn=no
setlocal modifiable setlocal modifiable
let asmbuf = bufnr('Termdebug-asm-listing') if s:asmbuf > 0
if asmbuf > 0 exe 'buffer' . s:asmbuf
exe 'buffer' . asmbuf
else else
exe 'file Termdebug-asm-listing' silent file Termdebug-asm-listing
let s:asmbuf = bufnr('Termdebug-asm-listing')
endif endif
if s:GetDisasmWindowHeight() > 0 if s:GetDisasmWindowHeight() > 0
@@ -1306,17 +1379,75 @@ func s:GotoAsmwinOrCreateIt()
endif endif
endfunc 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. " Handle stopping and running message from gdb.
" Will update the sign that shows the current position. " Will update the sign that shows the current position.
func s:HandleCursor(msg) func s:HandleCursor(msg)
let wid = win_getid(winnr()) let wid = win_getid()
if a:msg =~ '^\*stopped' if a:msg =~ '^\*stopped'
call ch_log('program stopped') call ch_log('program stopped')
let s:stopped = 1 let s:stopped = 1
if a:msg =~ '^\*stopped,reason="exited-normally"'
let s:running = 0
endif
elseif a:msg =~ '^\*running' elseif a:msg =~ '^\*running'
call ch_log('program running') call ch_log('program running')
let s:stopped = 0 let s:stopped = 0
let s:running = 1
endif endif
if a:msg =~ 'fullname=' if a:msg =~ 'fullname='
@@ -1330,7 +1461,7 @@ func s:HandleCursor(msg)
if asm_addr != '' if asm_addr != ''
let s:asm_addr = asm_addr let s:asm_addr = asm_addr
let curwinid = win_getid(winnr()) let curwinid = win_getid()
if win_gotoid(s:asmwin) if win_gotoid(s:asmwin)
let lnum = search('^' . s:asm_addr) let lnum = search('^' . s:asm_addr)
if lnum == 0 if lnum == 0
@@ -1345,6 +1476,10 @@ func s:HandleCursor(msg)
endif endif
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) if a:msg =~ '^\(\*stopped\|=thread-selected\)' && filereadable(fname)
let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '') let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '')
if lnum =~ '^[0-9]*$' if lnum =~ '^[0-9]*$'
@@ -1363,7 +1498,7 @@ echomsg 'different fname: "' .. expand('%:p') .. '" vs "' .. fnamemodify(fname,
if &modified if &modified
" TODO: find existing window " TODO: find existing window
exe 'split ' . fnameescape(fname) exe 'split ' . fnameescape(fname)
let s:sourcewin = win_getid(winnr()) let s:sourcewin = win_getid()
call s:InstallWinbar(0) call s:InstallWinbar(0)
else else
exe 'edit ' . fnameescape(fname) exe 'edit ' . fnameescape(fname)