]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.1.0817: termdebug: cannot evaluate expr in a popup v9.1.0817
authorPeter Wolf <pwolf2310@gmail.com>
Sun, 27 Oct 2024 20:51:14 +0000 (21:51 +0100)
committerChristian Brabandt <cb@256bit.org>
Sun, 27 Oct 2024 20:51:14 +0000 (21:51 +0100)
Problem:  termdebug: cannot evaluate expr in a popup
Solution: enhance termdebug plugin and allow to evaluate expressions in
          a popup window, add a unit test (Peter Wolf).

fixes: #15877
closes: #15933

Signed-off-by: Peter Wolf <pwolf2310@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
runtime/doc/tags
runtime/doc/terminal.txt
runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
src/testdir/dumps/Test_termdebug_evaluate_in_popup_01.dump [new file with mode: 0644]
src/testdir/dumps/Test_termdebug_evaluate_in_popup_01.vim [new file with mode: 0644]
src/testdir/dumps/Test_termdebug_evaluate_in_popup_02.dump [new file with mode: 0644]
src/testdir/dumps/Test_termdebug_evaluate_in_popup_02.vim [new file with mode: 0644]
src/testdir/test_termdebug.vim
src/version.c

index 0c1b31a663b8d3817c5d59f2f1136d804c7de2b9..75359f26956376c735ba0b04c4ca8c506abbd56b 100644 (file)
@@ -10664,6 +10664,7 @@ termdebug-stepping      terminal.txt    /*termdebug-stepping*
 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*
index 5020ed5b458b253071a70f3bcc5038c1cc1aae26..6b53e0223a7d1531a3d4c095024596cdc0fed134 100644 (file)
@@ -1,4 +1,4 @@
-*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
@@ -1537,6 +1537,7 @@ If there is no g:termdebug_config you can use: >
 <
 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.
@@ -1591,6 +1592,7 @@ If the current window has enough horizontal space, it will be vertically split
 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
@@ -1675,10 +1677,11 @@ If there is no g:termdebug_config you can use: >
 
 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: >
@@ -1716,4 +1719,18 @@ Set the wide value to 1 to use a vertical split without ever changing
 '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:
index 377827e85738bf39a35bb85cb1433d5fe90b6fc5..e7c010d4ce5c4d10ae7dc59e7107a6aeeaf7bca9 100644 (file)
@@ -121,7 +121,9 @@ var breakpoint_locations: dict<any>
 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
@@ -202,7 +204,9 @@ def InitScriptVariables()
   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
@@ -1478,10 +1482,23 @@ def SendEval(expr: string)
   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
@@ -1541,6 +1558,37 @@ def Balloon_show(expr: string)
   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', '')
@@ -1555,13 +1603,12 @@ def HandleEvaluate(msg: string)
     #\ ->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
@@ -1570,8 +1617,12 @@ def HandleEvaluate(msg: string)
     # 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
 
@@ -1588,7 +1639,7 @@ def TermDebugBalloonExpr(): string
     return ''
   endif
   evalFromBalloonExpr = true
-  evalFromBalloonExprResult = ''
+  evalExprResult = ''
   ignoreEvalError = true
   var expr = CleanupExpr(v:beval_text)
   SendEval(expr)
diff --git a/src/testdir/dumps/Test_termdebug_evaluate_in_popup_01.dump b/src/testdir/dumps/Test_termdebug_evaluate_in_popup_01.dump
new file mode 100644 (file)
index 0000000..3dde6cc
--- /dev/null
@@ -0,0 +1,20 @@
+|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| +0&#5fd7ff255@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
diff --git a/src/testdir/dumps/Test_termdebug_evaluate_in_popup_01.vim b/src/testdir/dumps/Test_termdebug_evaluate_in_popup_01.vim
new file mode 100644 (file)
index 0000000..959798a
--- /dev/null
@@ -0,0 +1,9 @@
+" 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
diff --git a/src/testdir/dumps/Test_termdebug_evaluate_in_popup_02.dump b/src/testdir/dumps/Test_termdebug_evaluate_in_popup_02.dump
new file mode 100644 (file)
index 0000000..0e3fa33
--- /dev/null
@@ -0,0 +1,20 @@
+|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| +0&#5fd7ff255@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
diff --git a/src/testdir/dumps/Test_termdebug_evaluate_in_popup_02.vim b/src/testdir/dumps/Test_termdebug_evaluate_in_popup_02.vim
new file mode 100644 (file)
index 0000000..959798a
--- /dev/null
@@ -0,0 +1,9 @@
+" 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
index b5c12aefe190793eacc3c5b36edaf10ac8f26558..30176cb75b61852f7d87cec4f605313124f4a00d 100644 (file)
@@ -1,6 +1,7 @@
 " Test for the termdebug plugin
 
 source shared.vim
+source screendump.vim
 source check.vim
 
 CheckUnix
@@ -243,6 +244,94 @@ func Test_termdebug_tbreak()
   %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())
index 48312818bcfd2ce08625e199ccd8fafb9374ef44..90fc3b3e00c4fcc1d6602d657bf267ddbaf8948f 100644 (file)
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    817,
 /**/
     816,
 /**/