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.
This commit is contained in:
Ben Jackson 2018-05-27 20:23:25 +01:00
commit 6aecfb969b
4 changed files with 76 additions and 27 deletions

View file

@ -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
" }}}

View file

@ -186,6 +186,14 @@ class DebugSession( object ):
def DeleteWatch( self ): def DeleteWatch( self ):
self._variablesView.DeleteWatch() 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 ): def GoToFrame( self ):
self._stackTraceView.GoToFrame() self._stackTraceView.GoToFrame()
@ -244,11 +252,11 @@ class DebugSession( object ):
self._logger.info( 'Debug Adapter Started' ) self._logger.info( 'Debug Adapter Started' )
def _StopDebugAdapter( self, callback = None ): def _StopDebugAdapter( self, callback = None ):
self._codeView.Clear()
def handler( message ): def handler( message ):
vim.eval( 'vimspector#internal#job#StopDebugSession()' ) vim.eval( 'vimspector#internal#job#StopDebugSession()' )
self._connection = None self._connection = None
self._stackTraceView.ConnectionClosed()
self._variablesView.ConnectionClosed()
if callback: if callback:
callback() callback()
@ -261,7 +269,6 @@ class DebugSession( object ):
def _Initialise( self ): def _Initialise( self ):
# TODO: name is mandatory. forcefully add it
self._connection.DoRequest( None, { self._connection.DoRequest( None, {
'command': 'initialize', 'command': 'initialize',
'arguments': { 'arguments': {
@ -271,6 +278,8 @@ class DebugSession( object ):
'pathFormat': 'path', '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' ]: if 'name' not in self._configuration[ 'configuration' ]:
self._configuration[ 'configuration' ][ 'name' ] = 'test' self._configuration[ 'configuration' ][ 'name' ] = 'test'
@ -294,27 +303,17 @@ class DebugSession( object ):
pass pass
def OnEvent_breakpoint( self, message ): def OnEvent_breakpoint( self, message ):
# Useful:
#
# /** The reason for the event.
# Values: 'changed', 'new', 'removed', etc.
# */
reason = message[ 'body' ][ 'reason' ] reason = message[ 'body' ][ 'reason' ]
bp = message[ 'body' ][ 'breakpoint' ] bp = message[ 'body' ][ 'breakpoint' ]
if reason == 'changed': if reason == 'changed':
self._codeView.UpdateBreakpoint( bp ) self._codeView.UpdateBreakpoint( bp )
elif reason == 'new': elif reason == 'new':
self._codeView.AddBreakpoints( None, bp ) self._codeView.AddBreakpoints( None, bp )
elif reason == 'removed':
# TODO
pass
else: else:
utils.UserMessage( utils.UserMessage(
'Unrecognised breakpoint event (undocumented): {0}'.format( reason ), 'Unrecognised breakpoint event (undocumented): {0}'.format( reason ),
persist = True ) persist = True )
def OnEvent_terminated( self, message ): def OnEvent_terminated( self, message ):
utils.UserMessage( "The program was terminated because: {0}".format( utils.UserMessage( "The program was terminated because: {0}".format(
message.get( 'body', {} ).get( 'reason', "No specific reason" ) ) ) message.get( 'body', {} ).get( 'reason', "No specific reason" ) ) )
@ -326,7 +325,6 @@ class DebugSession( object ):
with utils.ModifiableScratchBuffer( self._threadsBuffer ): with utils.ModifiableScratchBuffer( self._threadsBuffer ):
self._threadsBuffer[:] = None self._threadsBuffer[:] = None
def _SendBreakpoints( self ): def _SendBreakpoints( self ):
for file_name, line_breakpoints in self._breakpoints.items(): for file_name, line_breakpoints in self._breakpoints.items():
breakpoints = [] 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, { self._connection.DoRequest( None, {
'command': 'configurationDone', 'command': 'configurationDone',
} ) } )

View file

@ -34,6 +34,10 @@ class StackTraceView( object ):
with utils.ModifiableScratchBuffer( self._buf ): with utils.ModifiableScratchBuffer( self._buf ):
self._buf[:] = None self._buf[:] = None
def ConnectionClosed( self ):
self.Clear()
self._connection = None
def LoadStackTrace( self, thread_id ): def LoadStackTrace( self, thread_id ):
self._connection.DoRequest( self._PrintStackTrace, { self._connection.DoRequest( self._PrintStackTrace, {
'command': 'stackTrace', 'command': 'stackTrace',

View file

@ -51,10 +51,19 @@ class VariablesView( object ):
utils.SetUpScratchBuffer( self._buf, 'vimspector.Variables' ) 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 ): def Clear( self ):
with utils.ModifiableScratchBuffer( self._buf ): with utils.ModifiableScratchBuffer( self._buf ):
self._buf[:] = None self._buf[:] = None
def ConnectionClosed( self ):
self.Clear()
self._connection = None
def LoadScopes( self, frame ): def LoadScopes( self, frame ):
def scopes_consumer( message ): def scopes_consumer( message ):
self._scopes = [] self._scopes = []
@ -198,3 +207,20 @@ class VariablesView( object ):
parent[ '_variables' ].append( variable ) parent[ '_variables' ].append( variable )
self._DrawScopesAndWatches() 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',
}
} )