From cb0fdc7613db4be80e70854135403be1a1f95c12 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 26 Feb 2021 19:21:40 +0000 Subject: [PATCH 1/6] Add a way to have adapter specific message handlers --- python3/vimspector/custom/java.py | 34 +++++++++++++++++++ .../vimspector/debug_adapter_connection.py | 32 ++++++++--------- python3/vimspector/debug_session.py | 16 ++++++++- python3/vimspector/gadgets.py | 3 +- support/test/java/test_project/pom.xml | 4 +-- 5 files changed, 67 insertions(+), 22 deletions(-) create mode 100644 python3/vimspector/custom/java.py diff --git a/python3/vimspector/custom/java.py b/python3/vimspector/custom/java.py new file mode 100644 index 0000000..ebfec35 --- /dev/null +++ b/python3/vimspector/custom/java.py @@ -0,0 +1,34 @@ +# vimspector - A multi-language debugging system for Vim +# Copyright 2021 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. + +from vimspector.debug_session import DebugSession +from vimspector import utils + + +class JavaDebugAdapter( object ): + def __init__( self, debug_session: DebugSession ): + self.debug_session = debug_session + + def OnEvent_hotcodereplace( self, message ): + # Hack for java debug server hot-code-replace + if utils.Call( 'confirm', + 'Code has changed, hot reload?', + '&Yes,&No', + 1, + 'Question' ) == 1: + self.debug_session._connection.DoRequest( None, { + 'command': 'redefineClasses', + 'arguments': {}, + } ) diff --git a/python3/vimspector/debug_adapter_connection.py b/python3/vimspector/debug_adapter_connection.py index 283c40c..df2ef13 100644 --- a/python3/vimspector/debug_adapter_connection.py +++ b/python3/vimspector/debug_adapter_connection.py @@ -29,14 +29,14 @@ class PendingRequest( object ): class DebugAdapterConnection( object ): - def __init__( self, handler, send_func ): + def __init__( self, handlers, send_func ): self._logger = logging.getLogger( __name__ ) utils.SetUpLogging( self._logger ) self._Write = send_func self._SetState( 'READ_HEADER' ) self._buffer = bytes() - self._handler = handler + self._handlers = handlers self._next_message_id = 0 self._outstanding_requests = {} @@ -124,7 +124,7 @@ class DebugAdapterConnection( object ): def Reset( self ): self._Write = None - self._handler = None + self._handlers = None while self._outstanding_requests: _, request = self._outstanding_requests.popitem() @@ -237,7 +237,7 @@ class DebugAdapterConnection( object ): def _OnMessageReceived( self, message ): - if not self._handler: + if not self._handlers: return if message[ 'type' ] == 'response': @@ -270,25 +270,21 @@ class DebugAdapterConnection( object ): self._logger.error( 'Request failed: {0}'.format( reason ) ) if request.failure_handler: request.failure_handler( reason, message ) - elif 'OnFailure' in dir( self._handler ): - self._handler.OnFailure( reason, request.msg, message ) else: - utils.UserMessage( 'Request failed: {0}'.format( reason ) ) + for h in self._handlers: + if 'OnFailure' in dir( h ): + h.OnFailure( reason, request.msg, message ) + elif message[ 'type' ] == 'event': method = 'OnEvent_' + message[ 'event' ] - if method in dir( self._handler ): - getattr( self._handler, method )( message ) - else: - utils.UserMessage( 'Unhandled event: {0}'.format( message[ 'event' ] ), - persist = True ) + for h in self._handlers: + if method in dir( h ): + getattr( h, method )( message ) elif message[ 'type' ] == 'request': method = 'OnRequest_' + message[ 'command' ] - if method in dir( self._handler ): - getattr( self._handler, method )( message ) - else: - utils.UserMessage( - 'Unhandled request: {0}'.format( message[ 'command' ] ), - persist = True ) + for h in self._handlers: + if method in dir( h ): + getattr( h, method )( message ) def _KillTimer( request ): diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 6fb0b16..ae7de72 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -21,6 +21,7 @@ import shlex import subprocess import functools import vim +import importlib from vimspector import ( breakpoints, code, @@ -781,8 +782,21 @@ class DebugSession( object ): self._splash_screen, "Unable to start adapter" ) else: + if 'custom_handler' in self._adapter: + spec = self._adapter[ 'custom_handler' ] + if isinstance( spec, dict ): + module = spec[ 'module' ] + cls = spec[ 'class' ] + else: + module, cls = spec.rsplit( '.', 1 ) + + CustomHandler = getattr( importlib.import_module( module ), cls ) + handlers = [ CustomHandler( self ), self ] + else: + handlers = [ self ] + self._connection = debug_adapter_connection.DebugAdapterConnection( - self, + handlers, lambda msg: utils.Call( "vimspector#internal#{}#Send".format( self._connection_type ), msg ) ) diff --git a/python3/vimspector/gadgets.py b/python3/vimspector/gadgets.py index d1b6872..5c61074 100644 --- a/python3/vimspector/gadgets.py +++ b/python3/vimspector/gadgets.py @@ -159,7 +159,8 @@ GADGETS = { "port": "${DAPPort}", "configuration": { "cwd": "${workspaceRoot}" - } + }, + 'custom_handler': 'vimspector.custom.java.JavaDebugAdapter' } }, }, diff --git a/support/test/java/test_project/pom.xml b/support/test/java/test_project/pom.xml index 890e7e8..e6dc4d3 100644 --- a/support/test/java/test_project/pom.xml +++ b/support/test/java/test_project/pom.xml @@ -4,7 +4,7 @@ TestApplication 1 - 8 - 8 + 11 + 11 From f92f2c5d93c20fe9b4789ed3949ad8f2d5cbeca9 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Tue, 2 Mar 2021 10:48:55 +0000 Subject: [PATCH 2/6] Print hotcodereplace messages --- python3/vimspector/custom/java.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/python3/vimspector/custom/java.py b/python3/vimspector/custom/java.py index ebfec35..0dfa89c 100644 --- a/python3/vimspector/custom/java.py +++ b/python3/vimspector/custom/java.py @@ -23,12 +23,18 @@ class JavaDebugAdapter( object ): def OnEvent_hotcodereplace( self, message ): # Hack for java debug server hot-code-replace - if utils.Call( 'confirm', - 'Code has changed, hot reload?', - '&Yes,&No', - 1, - 'Question' ) == 1: - self.debug_session._connection.DoRequest( None, { - 'command': 'redefineClasses', - 'arguments': {}, - } ) + body = message.get( 'body' ) or {} + + if body.get( 'type' ) != 'hotcodereplace': + return + + if body.get( 'changeType' ) == 'BUILD_COMPLETE': + if utils.AskForInput( 'Code has changed, hot reload? [Y/N] ', + 'Y' ).upper()[ 0 ] == 'Y': + self.debug_session._connection.DoRequest( None, { + 'command': 'redefineClasses', + 'arguments': {}, + } ) + elif body.get( 'message' ): + utils.UserMessage( 'Hot code replace: ' + body[ 'message' ] ) + From f4831657b848911a9c20a021080b0389b49463d7 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 4 Mar 2021 21:44:54 +0000 Subject: [PATCH 3/6] Use popup for confirmations (note these have to be async) --- autoload/vimspector/internal/neopopup.vim | 22 ++++++++ autoload/vimspector/internal/popup.vim | 31 +++++++++++ python3/vimspector/custom/java.py | 17 +++--- python3/vimspector/debug_session.py | 63 ++++++++++++++--------- python3/vimspector/utils.py | 29 ++++++++++- 5 files changed, 129 insertions(+), 33 deletions(-) diff --git a/autoload/vimspector/internal/neopopup.vim b/autoload/vimspector/internal/neopopup.vim index fe5fe05..cc25020 100644 --- a/autoload/vimspector/internal/neopopup.vim +++ b/autoload/vimspector/internal/neopopup.vim @@ -80,6 +80,28 @@ function! vimspector#internal#neopopup#HideSplash( id ) abort unlet s:db[ a:id ] endfunction +function! vimspector#internal#neopopup#Confirm( confirm_id, + \ text, + \ default_value ) abort + let result = confirm( a:text, '&Yes &No &Default', 3 ) + + " Map the results to what popup_menu_filter would return (ok s:ConfirmCallback + " in popup.vim) + if result == 2 + " No is represented as 0 + let result = 0 + elseif result == 0 + " User pressed ESC/ctrl-c + let result = -1 + elseif result == 3 + " Default + let result = a:default_value + endif + + py3 __import__( 'vimspector', fromlist = [ 'utils' ] ).utils.ConfirmCallback( + \ int( vim.eval( 'a:confirm_id' ) ), + \ int( vim.eval( 'result' ) ) ) +endfunction " Boilerplate {{{ let &cpoptions=s:save_cpo unlet s:save_cpo diff --git a/autoload/vimspector/internal/popup.vim b/autoload/vimspector/internal/popup.vim index fc8820b..e8658ab 100644 --- a/autoload/vimspector/internal/popup.vim +++ b/autoload/vimspector/internal/popup.vim @@ -32,6 +32,37 @@ function! vimspector#internal#popup#HideSplash( id ) abort call popup_hide( a:id ) endfunction +function! s:YesNoDefaultFilter( default_value, id, key ) abort + if a:key ==# "\" || a:key ==# 'D' || a:key ==# 'd' + call popup_close( a:id, a:default_value ) + endif + + return popup_filter_yesno( a:id, a:key ) +endfunction + +function! s:ConfirmCallback( confirm_id, id, result ) abort + py3 __import__( 'vimspector', fromlist = [ 'utils' ] ).utils.ConfirmCallback( + \ int( vim.eval( 'a:confirm_id' ) ), + \ int( vim.eval( 'a:result' ) ) ) +endfunction + +function! vimspector#internal#popup#Confirm( + \ confirm_id, + \ text, + \ default_value ) abort + let text = a:text + if type( a:text ) != v:t_list + let text = [ a:text ] + endif + + call extend( text, [ '', '(Y)es (N)o (D)efault' ] ) + + return popup_dialog( text, { + \ 'callback': function( 's:ConfirmCallback', [ a:confirm_id ] ), + \ 'filter': function( 's:YesNoDefaultFilter', [ a:default_value ] ) + \ } ) +endfunction + " Boilerplate {{{ let &cpoptions=s:save_cpo unlet s:save_cpo diff --git a/python3/vimspector/custom/java.py b/python3/vimspector/custom/java.py index 0dfa89c..83705c1 100644 --- a/python3/vimspector/custom/java.py +++ b/python3/vimspector/custom/java.py @@ -29,12 +29,15 @@ class JavaDebugAdapter( object ): return if body.get( 'changeType' ) == 'BUILD_COMPLETE': - if utils.AskForInput( 'Code has changed, hot reload? [Y/N] ', - 'Y' ).upper()[ 0 ] == 'Y': - self.debug_session._connection.DoRequest( None, { - 'command': 'redefineClasses', - 'arguments': {}, - } ) + def handler( result ): + if result == 1: + self.debug_session._connection.DoRequest( None, { + 'command': 'redefineClasses', + 'arguments': {}, + } ) + + utils.Confirm( self.debug_session._api_prefix, + 'Code has changed, hot reload?', + handler ) elif body.get( 'message' ): utils.UserMessage( 'Hot code replace: ' + body[ 'message' ] ) - diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index ae7de72..9f6e863 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -804,39 +804,52 @@ class DebugSession( object ): self._logger.info( 'Debug Adapter Started' ) def _StopDebugAdapter( self, interactive = False, callback = None ): - self._splash_screen = utils.DisplaySplash( - self._api_prefix, - self._splash_screen, - "Shutting down debug adapter..." ) + def disconnect( arguments = {} ): + self._splash_screen = utils.DisplaySplash( + self._api_prefix, + self._splash_screen, + "Shutting down debug adapter..." ) - def handler( *args ): - self._splash_screen = utils.HideSplash( self._api_prefix, - self._splash_screen ) + def handler( *args ): + self._splash_screen = utils.HideSplash( self._api_prefix, + self._splash_screen ) - if callback: - self._logger.debug( "Setting server exit handler before disconnect" ) - assert not self._run_on_server_exit - self._run_on_server_exit = callback + if callback: + self._logger.debug( "Setting server exit handler before disconnect" ) + assert not self._run_on_server_exit + self._run_on_server_exit = callback - vim.eval( 'vimspector#internal#{}#StopDebugSession()'.format( - self._connection_type ) ) + vim.eval( 'vimspector#internal#{}#StopDebugSession()'.format( + self._connection_type ) ) - arguments = {} - if ( interactive and - self._server_capabilities.get( 'supportTerminateDebuggee' ) ): - if self._stackTraceView.AnyThreadsRunning(): - choice = utils.AskForInput( "Terminate debuggee [Y/N/default]? ", "" ) - if choice == "Y" or choice == "y": + self._connection.DoRequest( handler, { + 'command': 'disconnect', + 'arguments': {}, + }, failure_handler = handler, timeout = 5000 ) + + if not interactive: + disconnect() + elif not self._server_capabilities.get( 'supportTerminateDebuggee' ): + disconnect() + elif not self._stackTraceView.AnyThreadsRunning(): + disconnect() + else: + def handle_choice( choice ): + arguments = {} + if choice == 1: arguments[ 'terminateDebuggee' ] = True - elif choice == "N" or choice == 'n': + elif choice == 0: arguments[ 'terminateDebuggee' ] = False + elif choice == -1: + # Abort + return - self._connection.DoRequest( handler, { - 'command': 'disconnect', - 'arguments': arguments, - }, failure_handler = handler, timeout = 5000 ) + disconnect( arguments ) - # TODO: Use the 'tarminate' request if supportsTerminateRequest set + utils.Confirm( self._api_prefix, + "Terminate debuggee?", + handle_choice, + default_value = 3 ) def _PrepareAttach( self, adapter_config, launch_config ): diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index e7cb537..5aefc37 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -375,6 +375,31 @@ def AskForInput( prompt, default_value = None, completion = None ): return None +CONFIRM = {} +CONFIRM_ID = 0 + +def ConfirmCallback( confirm_id, result ): + try: + handler = CONFIRM.pop( confirm_id ) + except KeyError: + UserMessage( f"Internal error: unexpected callback id { confirm_id }", + persist = True, + error = True ) + return + + handler( result ) + + +def Confirm( api_prefix, prompt, handler, default_value = 1 ): + global CONFIRM_ID + CONFIRM_ID += 1 + CONFIRM[ CONFIRM_ID ] = handler + Call( f'vimspector#internal#{ api_prefix }popup#Confirm', + CONFIRM_ID, + prompt, + default_value ) + + def AppendToBuffer( buf, line_or_lines, modified=False ): line = 1 try: @@ -403,8 +428,10 @@ def AppendToBuffer( buf, line_or_lines, modified=False ): -def ClearBuffer( buf ): +def ClearBuffer( buf, modified = False ): buf[ : ] = None + if not modified: + buf.options[ 'modified' ] = False def SetBufferContents( buf, lines, modified=False ): From 32360236ff93f924b579933acbb249ba62ca6615 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 5 Mar 2021 21:09:39 +0000 Subject: [PATCH 4/6] Allow forcing selection from the menu with F5 --- autoload/vimspector.vim | 4 ++-- plugin/vimspector.vim | 3 +++ python3/vimspector/debug_session.py | 7 ++++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index e94a177..c4a1756 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -41,11 +41,11 @@ function! s:Enabled() abort return s:enabled endfunction -function! vimspector#Launch() abort +function! vimspector#Launch( ... ) abort if !s:Enabled() return endif - py3 _vimspector_session.Start() + py3 _vimspector_session.Start( *vim.eval( 'a:000' ) ) endfunction function! vimspector#LaunchWithSettings( settings ) abort diff --git a/plugin/vimspector.vim b/plugin/vimspector.vim index 53855ef..24f8914 100644 --- a/plugin/vimspector.vim +++ b/plugin/vimspector.vim @@ -35,6 +35,8 @@ let s:mappings = get( g:, 'vimspector_enable_mappings', '' ) nnoremap VimspectorContinue \ :call vimspector#Continue() +nnoremap VimspectorLaunch + \ :call vimspector#Launch( v:true ) nnoremap VimspectorStop \ :call vimspector#Stop() nnoremap VimspectorRestart @@ -79,6 +81,7 @@ if s:mappings ==# 'VISUAL_STUDIO' nmap VimspectorStepOut elseif s:mappings ==# 'HUMAN' nmap VimspectorContinue + nmap VimspectorLaunch nmap VimspectorStop nmap VimspectorRestart nmap VimspectorPause diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 9f6e863..03874f3 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -100,7 +100,7 @@ class DebugSession( object ): return launch_config_file, configurations - def Start( self, launch_variables = None ): + def Start( self, force_choose=False, launch_variables = None ): # We mutate launch_variables, so don't mutate the default argument. # https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments if launch_variables is None: @@ -135,6 +135,11 @@ class DebugSession( object ): if 'configuration' in launch_variables: configuration_name = launch_variables.pop( 'configuration' ) + elif force_choose: + # Always display the menu + configuration_name = utils.SelectFromList( + 'Which launch configuration?', + sorted( configurations.keys() ) ) elif ( len( configurations ) == 1 and next( iter( configurations.values() ) ).get( "autoselect", True ) ): configuration_name = next( iter( configurations.keys() ) ) From c2353b388d027e35be9b069b60214e8395a8ed54 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 5 Mar 2021 21:10:08 +0000 Subject: [PATCH 5/6] WIP: Data breakpoints (though can't find a server which supports them) --- autoload/vimspector.vim | 8 +++++ python3/vimspector/breakpoints.py | 39 ++++++++++++++++++++++ python3/vimspector/debug_session.py | 15 +++++++++ python3/vimspector/variables.py | 27 +++++++++++++++ support/test/go/hello_world/hello-world.go | 19 +++++++++++ 5 files changed, 108 insertions(+) diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index c4a1756..39af248 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -220,6 +220,14 @@ function! vimspector#SetVariableValue( ... ) abort endif endfunction +function! vimspector#AddDataBreakpoint( ... ) abort + if !s:Enabled() + return + endif + " TODO: how to set options? + py3 _vimspector_session.AddDataBreakpoint( {} ) +endfunction + function! vimspector#DeleteWatch() abort if !s:Enabled() return diff --git a/python3/vimspector/breakpoints.py b/python3/vimspector/breakpoints.py index 7aa50ce..5c21140 100644 --- a/python3/vimspector/breakpoints.py +++ b/python3/vimspector/breakpoints.py @@ -45,6 +45,7 @@ class ProjectBreakpoints( object ): self._func_breakpoints = [] self._exception_breakpoints = None self._configured_breakpoints = {} + self._data_breakponts = [] # FIXME: Remove this. Remove breakpoints nonesense from code.py self._breakpoints_handler = None @@ -270,6 +271,18 @@ class ProjectBreakpoints( object ): # TODO: We don't really have aanything to update here, but if we're going to # have a UI list of them we should update that at this point + # but note that while debugging, this is when we actually _send_ the + # breakpoints. + self.UpdateUI() + + + def AddDataBreakpoint( self, dataId, options ): + self._data_breakponts.append( { + 'state': 'ENABLED', + 'dataId': dataId, + 'options': options, + } ) + self.UpdateUI() @@ -402,6 +415,27 @@ class ProjectBreakpoints( object ): failure_handler = response_received ) + if self._data_breakponts and self._server_capabilities[ + 'supportsDataBreakpoints' ]: + awaiting += 1 + breakpoints = [] + for bp in self._data_breakponts: + if bp[ 'state' ] != 'ENABLED': + continue + data_bp = {} + data_bp.update( bp[ 'options' ] ) + data_bp[ 'dataId' ] = bp[ 'dataId' ] + breakpoints.append( data_bp ) + + self._connection.DoRequest( + lambda msg: response_handler( None, None ), + { + 'command': 'setDataBreakpoints', + 'arguments': breakpoints, + }, + failure_handler = response_received + ) + if self._exception_breakpoints: awaiting = awaiting + 1 self._connection.DoRequest( @@ -494,6 +528,11 @@ class ProjectBreakpoints( object ): file_name, bp[ 'line' ] ) + # TODO could/should we show a sign in the variables view when there's a data + # brakpoint on the variable? Not sure how best to actually do that, but + # maybe the variable view can pass that info when calling AddDataBreakpoint, + # such as the variablesReference/name + def _SignToLine( self, file_name, bp ): if 'sign_id' not in bp: diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 03874f3..80fe75f 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -535,6 +535,21 @@ class DebugSession( object ): def SetVariableValue( self, new_value = None, buf = None, line_num = None ): self._variablesView.SetVariableValue( new_value, buf, line_num ) + @IfConnected() + def AddDataBreakpoint( self, opts, buf = None, line_num = None ): + def add_bp( breakpoint_info ): + if breakpoint_info[ 'dataId' ] is None: + utils.UserMessage( + "Can't set data breakpoint here: { breakpoint_info[ 'description' ] }" + ) + return + + # TODO: Ask the user about the possible DataBreakpointAccessType's and add + # that in to opts here + self._breakpoints.AddDataBreakpoint( breakpoint_info[ 'dataId' ], opts ) + + self._variablesView.GetDataBreakpointInfo( add_bp, buf, line_num ) + @IfConnected() def AddWatch( self, expression ): self._variablesView.AddWatch( self._stackTraceView.GetCurrentFrame(), diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index 8dcb493..8d8498a 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -580,6 +580,33 @@ class VariablesView( object ): }, failure_handler = failure_handler ) + def GetDataBreakpointInfo( self, + then, + buf = None, + line_num = None ): + variable: Variable + view: View + + if not self._server_capabilities.get( 'supportsDataBreakpoints' ): + return None + + variable, view = self._GetVariable( buf, line_num ) + if variable is None: + return None + + arguments = { + 'name': variable.variable[ 'name' ], + } + if variable.IsContained(): + arguments[ 'variablesReference' ] = ( + variable.container.VariablesReference() ) + + self._connection.DoRequest( lambda msg: then( msg[ 'body' ] ), { + 'command': 'dataBreakpointInfo', + 'arguments': arguments, + } ) + + def _DrawVariables( self, view, variables, indent, is_short = False ): assert indent > 0 diff --git a/support/test/go/hello_world/hello-world.go b/support/test/go/hello_world/hello-world.go index 673d1b2..efff2c0 100644 --- a/support/test/go/hello_world/hello-world.go +++ b/support/test/go/hello_world/hello-world.go @@ -1,6 +1,25 @@ package main import "fmt" + +type Toaster struct { + Power int + Colour string +} + +type Test struct { + Test string + Toast Toaster +} + func main() { var v = "test" + test := Test{ + Test: "This is\na\ntest", + Toast: Toaster{ + Power: 10, + Colour: "green", + }, + } fmt.Println("hello world: " + v) + fmt.Println("Hi " + test.Test) } From af57d2dbdb6e0d6a5f7cec6914492da574ec806a Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 5 Mar 2021 21:19:37 +0000 Subject: [PATCH 6/6] Print server capabilities in a readable way --- python3/vimspector/debug_session.py | 4 ++++ python3/vimspector/output.py | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 80fe75f..8c671af 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -1049,6 +1049,10 @@ class DebugSession( object ): # def handle_initialize_response( msg ): self._server_capabilities = msg.get( 'body' ) or {} + self._outputView.Print( + 'server', + 'Server Capabilities:\n' + json.dumps( self._server_capabilities, + indent = 2 ) ) self._breakpoints.SetServerCapabilities( self._server_capabilities ) self._variablesView.SetServerCapabilities( self._server_capabilities ) self._Launch() diff --git a/python3/vimspector/output.py b/python3/vimspector/output.py index c453417..df1e0c6 100644 --- a/python3/vimspector/output.py +++ b/python3/vimspector/output.py @@ -64,8 +64,8 @@ class OutputView( object ): self._api_prefix = api_prefix VIEWS.add( self ) - def Print( self, categroy, text ): - self._Print( 'server', text.splitlines() ) + def Print( self, category, text ): + self._Print( category, text.splitlines() ) def OnOutput( self, event ): category = CategoryToBuffer( event.get( 'category' ) or 'output' )