From 6aecfb969b56d9f642a308e8cb9a8066f6846699 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sun, 27 May 2018 20:23:25 +0100 Subject: [PATCH] Very basic balloon support. This is a huge hack, setting it manually and never resetting it. Just displaying the value (no breakdown) etc. I'm tempted to drop this functionality altogether as it is of limited use when you have the locals and watch windows. --- autoload/vimspector/internal/balloon.vim | 34 +++++++++++++++++++++ python3/vimspector/debug_session.py | 39 ++++++++---------------- python3/vimspector/stack_trace.py | 4 +++ python3/vimspector/variables.py | 26 ++++++++++++++++ 4 files changed, 76 insertions(+), 27 deletions(-) create mode 100644 autoload/vimspector/internal/balloon.vim diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim new file mode 100644 index 0000000..783c516 --- /dev/null +++ b/autoload/vimspector/internal/balloon.vim @@ -0,0 +1,34 @@ +" vimspector - A multi-language debugging system for Vim +" Copyright 2018 Ben Jackson +" +" Licensed under the Apache License, Version 2.0 (the "License"); +" you may not use this file except in compliance with the License. +" You may obtain a copy of the License at +" +" http://www.apache.org/licenses/LICENSE-2.0 +" +" Unless required by applicable law or agreed to in writing, software +" distributed under the License is distributed on an "AS IS" BASIS, +" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +" See the License for the specific language governing permissions and +" limitations under the License. + + +" Boilerplate {{{ +let s:save_cpo = &cpo +set cpo&vim +" }}} + +function vimspector#internal#balloon#BalloonExpr() + " winnr + 1 because for *no good reason* winnr is 0 based here unlike + " everywhere else + " int() because for *no good reason* winnr is a string. + py3 _vimspector_session.ShowBalloon( int( vim.eval( 'v:beval_winnr' ) ) + 1, + \ vim.eval( 'v:beval_text' ) ) + return '' +endfunction + +" Boilerplate {{{ +let &cpo=s:save_cpo +unlet s:save_cpo +" }}} diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 76267a2..9260b4b 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -186,6 +186,14 @@ class DebugSession( object ): def DeleteWatch( self ): self._variablesView.DeleteWatch() + def ShowBalloon( self, winnr, expression ): + if winnr == int( self._codeView._window.number ): + self._variablesView.ShowBalloon( self._currentFrame, expression ) + else: + self._logger.debug( 'Winnr {0} is not the code window {1}'.format( + winnr, + self._codeView._window.number ) ) + def GoToFrame( self ): self._stackTraceView.GoToFrame() @@ -244,11 +252,11 @@ class DebugSession( object ): self._logger.info( 'Debug Adapter Started' ) def _StopDebugAdapter( self, callback = None ): - self._codeView.Clear() - def handler( message ): vim.eval( 'vimspector#internal#job#StopDebugSession()' ) self._connection = None + self._stackTraceView.ConnectionClosed() + self._variablesView.ConnectionClosed() if callback: callback() @@ -261,7 +269,6 @@ class DebugSession( object ): def _Initialise( self ): - # TODO: name is mandatory. forcefully add it self._connection.DoRequest( None, { 'command': 'initialize', 'arguments': { @@ -271,6 +278,8 @@ class DebugSession( object ): 'pathFormat': 'path', }, } ) + # FIXME: name is mandatory. Forcefully add it (we should really use the + # _actual_ name, but that isn't actually remembered at this point) if 'name' not in self._configuration[ 'configuration' ]: self._configuration[ 'configuration' ][ 'name' ] = 'test' @@ -294,27 +303,17 @@ class DebugSession( object ): pass def OnEvent_breakpoint( self, message ): - # Useful: - # - # /** The reason for the event. - # Values: 'changed', 'new', 'removed', etc. - # */ - reason = message[ 'body' ][ 'reason' ] bp = message[ 'body' ][ 'breakpoint' ] if reason == 'changed': self._codeView.UpdateBreakpoint( bp ) elif reason == 'new': self._codeView.AddBreakpoints( None, bp ) - elif reason == 'removed': - # TODO - pass else: utils.UserMessage( 'Unrecognised breakpoint event (undocumented): {0}'.format( reason ), persist = True ) - def OnEvent_terminated( self, message ): utils.UserMessage( "The program was terminated because: {0}".format( message.get( 'body', {} ).get( 'reason', "No specific reason" ) ) ) @@ -326,7 +325,6 @@ class DebugSession( object ): with utils.ModifiableScratchBuffer( self._threadsBuffer ): self._threadsBuffer[:] = None - def _SendBreakpoints( self ): for file_name, line_breakpoints in self._breakpoints.items(): breakpoints = [] @@ -360,19 +358,6 @@ class DebugSession( object ): } ) - # TODO: Remove this! - # self._connection.DoRequest( - # functools.partial( self._UpdateBreakpoints, None ), - # { - # 'command': 'setFunctionBreakpoints', - # 'arguments': { - # 'breakpoints': [ - # { 'name': 'main' }, - # ], - # }, - # } - # ) - self._connection.DoRequest( None, { 'command': 'configurationDone', } ) diff --git a/python3/vimspector/stack_trace.py b/python3/vimspector/stack_trace.py index 84f271f..4cd790b 100644 --- a/python3/vimspector/stack_trace.py +++ b/python3/vimspector/stack_trace.py @@ -34,6 +34,10 @@ class StackTraceView( object ): with utils.ModifiableScratchBuffer( self._buf ): self._buf[:] = None + def ConnectionClosed( self ): + self.Clear() + self._connection = None + def LoadStackTrace( self, thread_id ): self._connection.DoRequest( self._PrintStackTrace, { 'command': 'stackTrace', diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index c3dd5f4..517d670 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -51,10 +51,19 @@ class VariablesView( object ): utils.SetUpScratchBuffer( self._buf, 'vimspector.Variables' ) + vim.options[ 'balloonexpr' ] = 'vimspector#internal#balloon#BalloonExpr()' + vim.options[ 'ballooneval' ] = True + vim.options[ 'balloonevalterm' ] = True + vim.options[ 'balloondelay' ] = 250 + def Clear( self ): with utils.ModifiableScratchBuffer( self._buf ): self._buf[:] = None + def ConnectionClosed( self ): + self.Clear() + self._connection = None + def LoadScopes( self, frame ): def scopes_consumer( message ): self._scopes = [] @@ -198,3 +207,20 @@ class VariablesView( object ): parent[ '_variables' ].append( variable ) self._DrawScopesAndWatches() + + def ShowBalloon( self, frame, expression ): + if not self._connection: + return + + def handler( message ): + vim.eval( "balloon_show( '{0}' )".format( + message[ 'body' ][ 'result' ] ) ) + + self._connection.DoRequest( handler, { + 'command': 'evaluate', + 'arguments': { + 'expression': expression, + 'frameId': frame[ 'id' ], + 'context': 'hover', + } + } )