termdebug-timeout terminal.txt /*termdebug-timeout*
termdebug-variables terminal.txt /*termdebug-variables*
termdebug_disasm_window terminal.txt /*termdebug_disasm_window*
+termdebug_evaluate_in_popup terminal.txt /*termdebug_evaluate_in_popup*
termdebug_map_K terminal.txt /*termdebug_map_K*
termdebug_map_minus terminal.txt /*termdebug_map_minus*
termdebug_map_plus terminal.txt /*termdebug_map_plus*
-*terminal.txt* For Vim version 9.1. Last change: 2024 Jul 28
+*terminal.txt* For Vim version 9.1. Last change: 2024 Oct 27
VIM REFERENCE MANUAL by Bram Moolenaar
<
However, the latter form will be deprecated in future releases.
+
Mappings ~
The termdebug plugin enables a few default mappings. All those mappings
are reset to their original values once the termdebug session concludes.
and the Var window will be shown side by side with the source code window (and
the height options won't be used).
+
Communication ~
*termdebug-communication*
There is another, hidden, buffer, which is used for Vim to communicate with
However, the latter form will be deprecated in future releases.
+
Change default signs ~
*termdebug_signs*
Termdebug uses the hex number of the breakpoint ID in the signcolumn to
-represent breakpoints. if it is greater than "0xFF", then it will be displayed
+represent breakpoints. If it is greater than "0xFF", then it will be displayed
as "F+", due to we really only have two screen cells for the sign.
If you want to customize the breakpoint signs: >
'columns'. This is useful when the terminal can't be resized by Vim.
+Evaluate in Popup Window at Cursor ~
+ *termdebug_evaluate_in_popup*
+By default |:Evaluate| will simply echo its output. For larger entities this
+might become difficult to read or even truncated.
+Alternatively, the evaluation result may be output into a popup window at the
+current cursor position: >
+ let g:termdebug_config['evaluate_in_popup'] = v:true
+This can also be used in a "one-shot" manner: >
+ func OnCursorHold()
+ let g:termdebug_config['evaluate_in_popup'] = v:true
+ :Evaluate
+ let g:termdebug_config['evaluate_in_popup'] = v:false
+ endfunc
+<
vim:tw=78:ts=8:noet:ft=help:norl:
var BreakpointSigns: list<string>
var evalFromBalloonExpr: bool
-var evalFromBalloonExprResult: string
+var evalInPopup: bool
+var evalPopupId: number
+var evalExprResult: string
var ignoreEvalError: bool
var evalexpr: string
# Remember the old value of 'signcolumn' for each buffer that it's set in, so
BreakpointSigns = []
evalFromBalloonExpr = false
- evalFromBalloonExprResult = ''
+ evalInPopup = false
+ evalPopupId = -1
+ evalExprResult = ''
ignoreEvalError = false
evalexpr = ''
# Remember the old value of 'signcolumn' for each buffer that it's set in, so
evalexpr = exprLHS
enddef
+# Returns whether to evaluate in a popup or not, defaults to false.
+def EvaluateInPopup(): bool
+ if exists('g:termdebug_config')
+ return get(g:termdebug_config, 'evaluate_in_popup', false)
+ endif
+ return false
+enddef
+
# :Evaluate - evaluate what is specified / under the cursor
def Evaluate(range: number, arg: string)
var expr = GetEvaluationExpression(range, arg)
- echom $"expr: {expr}"
+ if EvaluateInPopup()
+ evalInPopup = true
+ evalExprResult = ''
+ else
+ echomsg $'expr: {expr}'
+ endif
ignoreEvalError = false
SendEval(expr)
enddef
endif
enddef
+def Popup_format(expr: string): list<string>
+ var lines = expr
+ ->substitute('{', '{\n', 'g')
+ ->substitute('}', '\n}', 'g')
+ ->substitute(',', ',\n', 'g')
+ ->split('\n')
+ var indentation = 0
+ var formatted_lines = []
+ for line in lines
+ var stripped = line->substitute('^\s\+', '', '')
+ if stripped =~ '^}'
+ indentation -= 2
+ endif
+ formatted_lines->add(repeat(' ', indentation) .. stripped)
+ if stripped =~ '{$'
+ indentation += 2
+ endif
+ endfor
+ return formatted_lines
+enddef
+
+def Popup_show(expr: string)
+ var formatted = Popup_format(expr)
+ if evalPopupId != -1
+ popup_close(evalPopupId)
+ endif
+ # Specifying the line is necessary, as the winbar seems to cause issues
+ # otherwise. I.e., the popup would be shown one line too high.
+ evalPopupId = popup_atcursor(formatted, {'line': 'cursor-1'})
+enddef
+
def HandleEvaluate(msg: string)
var value = msg
->substitute('.*value="\(.*\)"', '\1', '')
#\ ->substitute('\\0x00', NullRep, 'g')
#\ ->substitute('\\0x\(\x\x\)', {-> eval('"\x' .. submatch(1) .. '"')}, 'g')
->substitute(NullRepl, '\\000', 'g')
- if evalFromBalloonExpr
- if empty(evalFromBalloonExprResult)
- evalFromBalloonExprResult = $'{evalexpr}: {value}'
+ if evalFromBalloonExpr || evalInPopup
+ if empty(evalExprResult)
+ evalExprResult = $'{evalexpr}: {value}'
else
- evalFromBalloonExprResult ..= $' = {value}'
+ evalExprResult ..= $' = {value}'
endif
- Balloon_show(evalFromBalloonExprResult)
else
echomsg $'"{evalexpr}": {value}'
endif
# Looks like a pointer, also display what it points to.
ignoreEvalError = true
SendEval($'*{evalexpr}')
- else
+ elseif evalFromBalloonExpr
+ Balloon_show(evalExprResult)
evalFromBalloonExpr = false
+ elseif evalInPopup
+ Popup_show(evalExprResult)
+ evalInPopup = false
endif
enddef
return ''
endif
evalFromBalloonExpr = true
- evalFromBalloonExprResult = ''
+ evalExprResult = ''
ignoreEvalError = true
var expr = CleanupExpr(v:beval_text)
SendEval(expr)
--- /dev/null
+|U+0&#ffffff0|s|i|n|g| |h|o|s|t| |l|i|b|t|h|r|e|a|d|_|d|b| |l|i|b|r|a|r|y| |"|/+0#00e0003&|l|i|b|/|x|8|6|_|6|4|-|l|i|n|u|x|-|g|n|u|/|l|i|b|t|h|r|e|a|d|_|d|b|.|s|o|.|1|"+0#0000000&|.|
+@75
+|B|r|e|a|k|p|o|i|n|t| |1|,| |m+0#e0e0004&|a|i|n| +0#0000000&|(|a+0#00e0e07&|r|g|c|=+0#0000000&|1|,| |a+0#00e0e07&|r|g|v|=+0#0000000&|0|x|7|f@6|d|e|f|8|)| @26
+@4|a|t| |X+0#00e0003&|T|D|_|e|v|a|l|u|a|t|e|_|i|n|_|p|o|p|u|p|.|c|:+0#0000000&|9| @42
+|9| @8|r+2#0000e05&|e|t|u|r|n| +0#0000000&|0+0#e000e06&|;+0#e000002&| +0#0000000&@55
+@75
+|g+0#ffffff16#00e0003|d|b| |[|r|u|n@1|i|n|g|]| @43|1|,|1| @11|T|o|p
+| +0#0000000#ffffff0@74
+@75
+@75
+@75
+@75
+|d+0#ffffff16#00e0003|e|b|u|p+0#0000001#ffd7ff255|:| |{| @3|g+0#ffffff16#00e0003|r|a|m| |[|a|c|t|i|v|e|]| @31|0|,|0|-|1| @9|A|l@1
+| +0#0000000#e0e0e08| +2#ffffff16#6c6c6c255|S|t| +0#0000001#ffd7ff255@1|x| |=| |1|,|x+2#ffffff16#6c6c6c255|t| | +0#0000000#e0e0e08@1| +2#ffffff16#6c6c6c255|F|i|n|i|s|h| | +0#0000000#e0e0e08@1| +2#ffffff16#6c6c6c255|C|o|n|t| | +0#0000000#e0e0e08@1| +2#ffffff16#6c6c6c255|S|t|o|p| | +0#0000000#e0e0e08@1| +2#ffffff16#6c6c6c255|E|v|a|l| | +0#0000000#e0e0e08@25
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@1| +0#0000001#ffd7ff255@1|y| |=| |2| |o+0#0000000#ffffff0|i|n|t| |p| |=| |{|a|r|g|c|,| |2+0#e000002&|}+0#0000000&|;| @43
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@1|}+0#0000001#ffd7ff255| @6|o+0#0000000#ffffff0|i|n|t|*| |p|_|p|t|r| |=| |&|p|;| @45
+|0+0&#ff404010|1| +0fd7ff255@1>r+0#af5f00255&|e|t|u|r|n| +0#0000000&|0+0#e000002&|;+0#0000000&| @61
+| +0#0000e05#a8a8a8255@1|}+0#0000000#ffffff0| @71
+|X+3&&|T|D|_|e|v|a|l|u|a|t|e|_|i|n|_|p|o|p|u|p|.|c| @33|9|,|3| @11|B|o|t
+|:+0&&|E|v|a|l|u|a|t|e| |p| @63
--- /dev/null
+" replace hex addresses with |0|x|f@12|
+:%s/|0|x|\(\(\w\|@\)\+|\)\+/|0|x|f@12|/g
+
+" Only keep screen lines relevant to the actual popup and evaluation.
+" Especially the top lines are too instable and cause flakiness between
+" different systems and tool versions.
+normal! G
+normal! 8k
+normal! dgg
--- /dev/null
+|U+0&#ffffff0|s|i|n|g| |h|o|s|t| |l|i|b|t|h|r|e|a|d|_|d|b| |l|i|b|r|a|r|y| |"|/+0#00e0003&|l|i|b|/|x|8|6|_|6|4|-|l|i|n|u|x|-|g|n|u|/|l|i|b|t|h|r|e|a|d|_|d|b|.|s|o|.|1|"+0#0000000&|.|
+@75
+|B|r|e|a|k|p|o|i|n|t| |1|,| |m+0#e0e0004&|a|i|n| +0#0000000&|(|a+0#00e0e07&|r|g|c|=+0#0000000&|1|,| |a+0#00e0e07&|r|g|v|=+0#0000000&|0|x|7|f@6|d|e|f|8|)| @26
+@4|a|t| |X+0#00e0003&|T|D|_|e|v|a|l|u|a|t|e|_|i|n|_|p|o|p|u|p|.|c|:+0#0000000&|9| @42
+|9| @8|r+2#0000e05&|e|t|u|r|n| +0#0000000&|0+0#e000e06&|;+0#e000002&| +0#0000000&@55
+@75
+|g+0#ffffff16#00e0003|d|b| |[|r|u|n@1|i|n|g|]| @43|1|,|1| @11|T|o|p
+| +0#0000000#ffffff0@74
+@75
+@75
+@75
+@75
+|d+0#ffffff16#00e0003|e|b|u|p+0#0000001#ffd7ff255|_|p|t|r|:| |0|x|7|f@6|d@1|c|0| |=| |{| +0#ffffff16#00e0003@27|0|,|0|-|1| @9|A|l@1
+| +0#0000000#e0e0e08| +2#ffffff16#6c6c6c255|S|t| +0#0000001#ffd7ff255@1|x| |=| |1|,| @16|o+2#ffffff16#6c6c6c255|n|t| | +0#0000000#e0e0e08@1| +2#ffffff16#6c6c6c255|S|t|o|p| | +0#0000000#e0e0e08@1| +2#ffffff16#6c6c6c255|E|v|a|l| | +0#0000000#e0e0e08@25
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@1| +0#0000001#ffd7ff255@1|y| |=| |2| @17|}+0#0000000#ffffff0|;| @43
+| +0#0000e05#a8a8a8255@1| +0#0000000#ffffff0@1|}+0#0000001#ffd7ff255| @23| +0#0000000#ffffff0@45
+|0+0&#ff404010|1| +0fd7ff255@1>r+0#af5f00255&|e|t|u|r|n| +0#0000000&|0+0#e000002&|;+0#0000000&| @61
+| +0#0000e05#a8a8a8255@1|}+0#0000000#ffffff0| @71
+|X+3&&|T|D|_|e|v|a|l|u|a|t|e|_|i|n|_|p|o|p|u|p|.|c| @33|9|,|3| @11|B|o|t
+|:+0&&|E|v|a|l|u|a|t|e| |p|_|p|t|r| @59
--- /dev/null
+" replace hex addresses with |0|x|f@12|
+:%s/|0|x|\(\(\w\|@\)\+|\)\+/|0|x|f@12|/g
+
+" Only keep screen lines relevant to the actual popup and evaluation.
+" Especially the top lines are too instable and cause flakiness between
+" different systems and tool versions.
+normal! G
+normal! 8k
+normal! dgg
" Test for the termdebug plugin
source shared.vim
+source screendump.vim
source check.vim
CheckUnix
%bw!
endfunc
+func Test_termdebug_evaluate()
+ let bin_name = 'XTD_evaluate'
+ let src_name = bin_name .. '.c'
+ call s:generate_files(bin_name)
+
+ edit XTD_evaluate.c
+ Termdebug ./XTD_evaluate
+ call WaitForAssert({-> assert_true(get(g:, "termdebug_is_running", v:false))})
+ call WaitForAssert({-> assert_equal(3, winnr('$'))})
+ let gdb_buf = winbufnr(1)
+ wincmd b
+
+ " return stmt in main
+ Break 22
+ call term_wait(gdb_buf)
+ Run
+ call term_wait(gdb_buf, 400)
+ redraw!
+
+ " Evaluate an expression
+ Evaluate n
+ call term_wait(gdb_buf)
+ call assert_equal(execute('1messages')->trim(), '"n": 7')
+ Evaluate argc
+ call term_wait(gdb_buf)
+ call assert_equal(execute('1messages')->trim(), '"argc": 1')
+ Evaluate isprime(n)
+ call term_wait(gdb_buf)
+ call assert_equal(execute('1messages')->trim(), '"isprime(n)": 1')
+
+ wincmd t
+ quit!
+ redraw!
+ call s:cleanup_files(bin_name)
+ %bw!
+endfunc
+
+func Test_termdebug_evaluate_in_popup()
+ CheckScreendump
+ let bin_name = 'XTD_evaluate_in_popup'
+ let src_name = bin_name .. '.c'
+ let code =<< trim END
+ struct Point {
+ int x;
+ int y;
+ };
+
+ int main(int argc, char* argv[]) {
+ struct Point p = {argc, 2};
+ struct Point* p_ptr = &p;
+ return 0;
+ }
+ END
+ call writefile(code, src_name, 'D')
+ call system($'{g:GCC} -g -o {bin_name} {src_name}')
+
+ let lines =<< trim END
+ edit XTD_evaluate_in_popup.c
+ packadd termdebug
+ let g:termdebug_config = {}
+ let g:termdebug_config['evaluate_in_popup'] = v:true
+ Termdebug ./XTD_evaluate_in_popup
+ wincmd b
+ Break 9
+ Run
+ END
+
+ call writefile(lines, 'Xscript', 'D')
+ let buf = RunVimInTerminal('-S Xscript', {})
+ call TermWait(buf, 400)
+
+ call term_sendkeys(buf, ":Evaluate p\<CR>")
+ call TermWait(buf, 400)
+ call VerifyScreenDump(buf, 'Test_termdebug_evaluate_in_popup_01', {})
+
+ call term_sendkeys(buf, ":Evaluate p_ptr\<CR>")
+ call TermWait(buf, 400)
+ call VerifyScreenDump(buf, 'Test_termdebug_evaluate_in_popup_02', {})
+
+ " Cleanup
+ call term_sendkeys(buf, ":Gdb")
+ call term_sendkeys(buf, ":quit!\<CR>")
+ call term_sendkeys(buf, ":qa!\<CR>")
+ call StopVimInTerminal(buf)
+ call delete(bin_name)
+ %bw!
+endfunc
+
func Test_termdebug_mapping()
%bw!
call assert_true(maparg('K', 'n', 0, 1)->empty())
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 817,
/**/
816,
/**/