diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index 75ed961..9ac7ff1 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -523,43 +523,15 @@ function! vimspector#OnBufferCreated( file_name ) abort py3 _vimspector_session.RefreshSigns( vim.eval( 'a:file_name' ) ) endfunction -function! vimspector#ShowTooltipForSelection() range abort - let [start, end] = [[line("'<"), col("'<") - 1], [line("'>"), col("'>")]] - " restor cursor position, since command mode puts it to the begining of the - " current line when invoked from visual mode - call cursor(end) - - " retrive the lines selected in visual mode - let lines = getbufline(bufnr('%'), start[0], end[0]) - - if(len(lines) < 1) - return - endif - - " make sure the leave only the parts we care about if multiple lines are - " selected - let lines[0] = strcharpart(lines[0], start[1]) - let lines_len = len(lines) - 1 - - if len( lines ) == 1 - let lines[lines_len] = strcharpart(lines[lines_len], 0, end[1] - start[1]) +function! vimspector#ShowEvalBalloon( is_visual ) abort + if a:is_visual + let expr = py3eval( '__import__( "vimspector", fromlist = [ "utils" ] ).utils.GetVisualSelection( int( vim.eval( "winbufnr( winnr() )" ) ) )' ) + let expr = join(expr) else - let lines[lines_len] = strcharpart(lines[lines_len], 0, end[1]) + let expr = expand('') endif - let str = join(lines) - - call vimspector#ShowTooltip(str) -endfunction - -function! vimspector#ShowTooltip(...) abort - let str = '' - - if a:0 > 0 - let str = a:1 - endif - - return py3eval('_vimspector_session.ShowTooltip(int( vim.eval( "winnr()" ) ) ,vim.eval( "expand(\"'.str.'\")" ), 0)') + return py3eval( '_vimspector_session.ShowEvalBalloon( int( vim.eval( "winnr()" ) ), "'.expr.'", 0 )' ) endfunction diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 86611f6..bc445ba 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -21,6 +21,11 @@ set cpoptions&vim scriptencoding utf-8 +" Returns: py.ShowBalloon( winnr, expresssion ) +function! vimspector#internal#balloon#HoverTooltip() abort + return py3eval('_vimspector_session.ShowTooltip(int( vim.eval( "v:beval_winnr" ) ) + 1 ,vim.eval( "v:beval_text"), 1)') +endfunction + let s:float_win = 0 let s:nvim_related_win = 0 " diff --git a/plugin/vimspector.vim b/plugin/vimspector.vim index 05245cd..6465c21 100644 --- a/plugin/vimspector.vim +++ b/plugin/vimspector.vim @@ -60,6 +60,12 @@ nnoremap VimspectorStepOut nnoremap VimspectorRunToCursor \ :call vimspector#RunToCursor() +nnoremap VimspectorBalloonEval + \ :call vimspector#ShowEvalBalloon(0) + +xnoremap VimspectorBalloonEval + \ :call vimspector#ShowEvalBalloon(1) + if s:mappings ==# 'VISUAL_STUDIO' nmap VimspectorContinue nmap VimspectorStop diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index e6fff61..db14ebc 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -539,6 +539,25 @@ class DebugSession( object ): self._variablesView.DeleteWatch() + @IfConnected() + def ShowEvalBalloon( self, winnr, expression, is_hover ): + frame = self._stackTraceView.GetCurrentFrame() + # Check if RIP is in a frame + if frame is None: + self._logger.debug( 'Tooltip: Not in a stack frame' ) + return '' + + # Check if cursor in code window + if winnr != int( self._codeView._window.number ): + self._logger.debug( 'Winnr %s is not the code window %s', + winnr, + self._codeView._window.number ) + return '' + + # Return variable aware function + return self._variablesView.VariableEval( frame, expression, is_hover ) + + @IfConnected() def ShowTooltip( self, winnr, expression, is_hover ): """Proxy: ballonexpr -> variables.ShowTooltip""" diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index 2bd3c08..287f919 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -34,6 +34,12 @@ _log_handler = logging.FileHandler( LOG_FILE, mode = 'w' ) _log_handler.setFormatter( logging.Formatter( '%(asctime)s - %(levelname)s - %(message)s' ) ) +# this is the "large number" that vim returns for col num, when getting '> mark +# with getpos() for line wise visual selection(V) +# see https://github.com/vim/vim/blob/eed9d46293f0842aad0d50ff3a526f9a48b12421/src/evalfunc.c#L4077 +# and https://github.com/vim/vim/blob/064095012c0b8e4e43e75834b337115950898fbf/src/vim.h#L1699 +MAX_COL = 2147483647 + def SetUpLogging( logger ): logger.setLevel( logging.DEBUG ) @@ -642,7 +648,7 @@ def DisplayBalloon( is_term, display, is_hover = False ): rc = int( vim.eval( "vimspector#internal#balloon#CreateTooltip({}, {})".format( - is_hover, json.dumps( display ) + int( is_hover ), json.dumps( display ) ) ) ) @@ -725,6 +731,21 @@ def GetBufferFiletypes( buf ): return ft.split( '.' ) +def GetVisualSelection( bufnr ): + start_line, start_col = vim.current.buffer.mark( "<" ) + end_line, end_col = vim.current.buffer.mark( ">" ) + + # lines are 1 based, but columns are 0 based + # don't as me why... + lines = vim.buffers[ bufnr ][ start_line - 1 : end_line ] + lines[ 0 ] = lines[ 0 ][ start_col : ] + # only trim the end if we are not in line-wise select mode + if( end_col < MAX_COL ): + lines[ -1 ] = lines[ -1 ][ : end_col + 1 ] + + return lines + + def DisplaySplash( api_prefix, splash, text ): if splash: return Call( f'vimspector#internal#{api_prefix}popup#UpdateSplash',