WIP: Guided config for c++
This adds some templates to the gadget config, organised by "category" (human-readable) and presented in a menu. The configuration thus created is just run normally through the variable replacements. Also: - Fix default value replacements which come from the calculus - Add default-value _lists_. This uses select-from-list UI. Useful for enumerated values. Allow specifying a default.
This commit is contained in:
parent
b6048fc5c6
commit
acd0f31573
5 changed files with 186 additions and 34 deletions
|
|
@ -76,10 +76,10 @@ class DebugSession( object ):
|
|||
self._server_capabilities = {}
|
||||
self.ClearTemporaryBreakpoints()
|
||||
|
||||
def GetConfigurations( self, adapters ):
|
||||
def GetConfigurations( self ):
|
||||
current_file = utils.GetBufferFilepath( vim.current.buffer )
|
||||
filetypes = utils.GetBufferFiletypes( vim.current.buffer )
|
||||
return launch.GetConfigurations( adapters, current_file, filetypes )
|
||||
return launch.GetConfigurations( {}, current_file, filetypes )[ 1 ]
|
||||
|
||||
|
||||
def Start( self, launch_variables = None ):
|
||||
|
|
@ -96,33 +96,40 @@ class DebugSession( object ):
|
|||
|
||||
current_file = utils.GetBufferFilepath( vim.current.buffer )
|
||||
filetypes = utils.GetBufferFiletypes( vim.current.buffer )
|
||||
adapters = launch.GetAdapters( current_file, filetypes )
|
||||
adapters = launch.GetAdapters( current_file )
|
||||
launch_config_file, configurations = launch.GetConfigurations( adapters,
|
||||
current_file,
|
||||
filetypes )
|
||||
|
||||
if not configurations:
|
||||
utils.UserMessage( 'Unable to find any debug configurations. '
|
||||
'You need to tell vimspector how to launch your '
|
||||
'application.' )
|
||||
return
|
||||
|
||||
if launch_config_file:
|
||||
self._workspace_root = os.path.dirname( launch_config_file )
|
||||
else:
|
||||
self._workspace_root = os.path.dirname( current_file )
|
||||
|
||||
configuration_name, configuration = launch.SelectConfiguration(
|
||||
launch_variables,
|
||||
configurations )
|
||||
|
||||
if not configurations:
|
||||
configuration_name, configuration = launch.SuggestConfiguration(
|
||||
filetypes )
|
||||
else:
|
||||
configuration_name, configuration = launch.SelectConfiguration(
|
||||
launch_variables,
|
||||
configurations )
|
||||
|
||||
if not configuration:
|
||||
utils.UserMessage( 'Unable to find any debug configurations. '
|
||||
'You need to tell vimspector how to launch your '
|
||||
'application.' )
|
||||
return
|
||||
|
||||
adapter = launch.SelectAdapter( self._api_prefix,
|
||||
self,
|
||||
configuration_name,
|
||||
configuration,
|
||||
adapters,
|
||||
launch_variables,
|
||||
self )
|
||||
launch_variables )
|
||||
if not adapter:
|
||||
return
|
||||
|
||||
try:
|
||||
launch.ResolveConfiguration( adapter,
|
||||
configuration,
|
||||
|
|
|
|||
|
|
@ -49,6 +49,40 @@ GADGETS = {
|
|||
}
|
||||
},
|
||||
},
|
||||
'templates': [
|
||||
{
|
||||
'description': 'gdb/lldb local debugging with vscode-cpptools',
|
||||
'filetypes': ( 'c', 'cpp', 'objc', 'rust' ),
|
||||
'configurations': [
|
||||
{
|
||||
'description': 'Launch local process',
|
||||
'launch_configuration': {
|
||||
'adapter': 'vscode-cpptools',
|
||||
'configuration': {
|
||||
'request': 'launch',
|
||||
'program': '${Binary:${fileBasenameNoExtension\\}}',
|
||||
'args': [ '*${CommandLineArguments}' ],
|
||||
'cwd': '${WorkingDir:${fileDirname\\}}',
|
||||
'externalConsole#json': '${UseExternalConsole:true\nfalse}',
|
||||
'stopAtEntry#json': '${StopAtEntry:true\nfalse}',
|
||||
'MIMode': '${Debugger:gdb\nlldb}',
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'description': 'Attach to local process by PID',
|
||||
'launch_configuration': {
|
||||
'adapter': 'vscode-cpptools',
|
||||
'configuration': {
|
||||
'request': 'attach',
|
||||
'program': '${Binary:${fileBasenameNoExtension\\}}',
|
||||
'MIMode': '${Debugger:gdb\nlldb}',
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
'linux': {
|
||||
'file_name': 'cpptools-linux.vsix',
|
||||
|
|
@ -452,6 +486,42 @@ GADGETS = {
|
|||
},
|
||||
'all': {
|
||||
'version': 'v1.5.3',
|
||||
'templates': [
|
||||
{
|
||||
'description': 'LLDB local debugging with CodeLLDB',
|
||||
'filetypes': ( 'c', 'cpp', 'objc', 'rust' ),
|
||||
'configurations': [
|
||||
{
|
||||
'description': 'Launch local process',
|
||||
'launch_configuration': {
|
||||
'adapter': 'CodeLLDB',
|
||||
'configuration': {
|
||||
'request': 'launch',
|
||||
'program': '${Binary:${fileBasenameNoExtension\\}}',
|
||||
'args': [ '*${CommandLineArguments}' ],
|
||||
'cwd': '${WorkingDir:${fileDirname\\}}',
|
||||
'terminal': '${Console:none\nintegrated\nexternal}',
|
||||
'stopOnEntry#json': '${StopOnEntry:true\nfalse}',
|
||||
'expressions': '${ExpressionType:native\nsimple\npython}'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'description': 'Attach to local process by PID',
|
||||
'launch_configuration': {
|
||||
'adapter': 'CodeLLDB',
|
||||
'configuration': {
|
||||
'request': 'attach',
|
||||
'program': '${Binary:${fileBasenameNoExtension\\}}',
|
||||
'pid#json': "${pid}",
|
||||
'stopOnEntry#json': '${StopOnEntry:true\nfalse}',
|
||||
'expressions': '${ExpressionType:native\nsimple\npython}'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
'macos': {
|
||||
'file_name': 'codelldb-x86_64-darwin.vsix',
|
||||
|
|
@ -486,6 +556,7 @@ GADGETS = {
|
|||
'name': 'CodeLLDB',
|
||||
'type': 'CodeLLDB',
|
||||
"command": [
|
||||
# FIXME: This probably doesn't work on windows.
|
||||
"${gadgetDir}/CodeLLDB/adapter/codelldb",
|
||||
"--port", "${unusedLocalPort}"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import json
|
|||
import glob
|
||||
import shlex
|
||||
|
||||
from vimspector import install, installer, utils
|
||||
from vimspector import install, installer, utils, gadgets
|
||||
from vimspector.vendor.json_minify import minify
|
||||
|
||||
_logger = logging.getLogger( __name__ )
|
||||
|
|
@ -33,7 +33,7 @@ USER_CHOICES = {}
|
|||
|
||||
|
||||
|
||||
def GetAdapters( current_file, filetypes ):
|
||||
def GetAdapters( current_file ):
|
||||
adapters = {}
|
||||
for gadget_config_file in PathsToAllGadgetConfigs( VIMSPECTOR_HOME,
|
||||
current_file ):
|
||||
|
|
@ -120,13 +120,57 @@ def SelectConfiguration( launch_variables, configurations ):
|
|||
return configuration_name, configuration
|
||||
|
||||
|
||||
def SuggestConfiguration( filetypes ):
|
||||
nothing = None, None
|
||||
templates = []
|
||||
filetypes = set( filetypes )
|
||||
|
||||
for gadget_name, gadget in gadgets.GADGETS.items():
|
||||
spec = {}
|
||||
spec.update( gadget.get( 'all', {} ) )
|
||||
spec.update( gadget.get( install.GetOS(), {} ) )
|
||||
|
||||
for template in spec.get( 'templates', [] ):
|
||||
if filetypes.intersection( template.get( 'filetypes', set() ) ):
|
||||
templates.append( template )
|
||||
|
||||
if not templates:
|
||||
return nothing
|
||||
|
||||
template_idx = utils.SelectFromList(
|
||||
'No debug configurations were found for this project, '
|
||||
'Would you like to use one of the following templates?',
|
||||
[ t[ 'description' ] for t in templates ],
|
||||
ret = 'index' )
|
||||
|
||||
if template_idx is None:
|
||||
return nothing
|
||||
|
||||
template = templates[ template_idx ]
|
||||
|
||||
config_index = utils.SelectFromList(
|
||||
'Which configuration?',
|
||||
[ c[ 'description' ] for c in template[ 'configurations' ] ],
|
||||
ret = 'index' )
|
||||
|
||||
if config_index is None:
|
||||
return nothing
|
||||
|
||||
configuration = template[ 'configurations' ][ config_index ]
|
||||
configuration_name = utils.AskForInput( 'Give the config a name: ',
|
||||
configuration[ 'description' ] )
|
||||
|
||||
|
||||
return configuration_name, configuration[ 'launch_configuration' ]
|
||||
|
||||
|
||||
def SelectAdapter( api_prefix,
|
||||
debug_session,
|
||||
configuration_name,
|
||||
configuration,
|
||||
adapters,
|
||||
launch_variables,
|
||||
debug_session ):
|
||||
adapter = configuration.get( 'adapter' )
|
||||
launch_variables ):
|
||||
adapter = configuration.get( 'adapter' )
|
||||
|
||||
if isinstance( adapter, str ):
|
||||
adapter_dict = adapters.get( adapter )
|
||||
|
|
@ -136,7 +180,7 @@ def SelectAdapter( api_prefix,
|
|||
if suggested_gadgets:
|
||||
response = utils.AskForInput(
|
||||
f"The specified adapter '{adapter}' is not "
|
||||
"installed. Would you like to install the following gadgets? ",
|
||||
"installed. Would you like to install the following gadgets? ",
|
||||
' '.join( suggested_gadgets ) )
|
||||
if response:
|
||||
new_launch_variables = dict( launch_variables )
|
||||
|
|
@ -147,7 +191,7 @@ def SelectAdapter( api_prefix,
|
|||
False, # Don't leave open
|
||||
*shlex.split( response ),
|
||||
then = debug_session.Start( new_launch_variables ) )
|
||||
return
|
||||
return None
|
||||
elif response is None:
|
||||
return None
|
||||
|
||||
|
|
|
|||
|
|
@ -333,25 +333,41 @@ def UserMessage( msg, persist=False, error=False ):
|
|||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def InputSave():
|
||||
def AskingForUserInput():
|
||||
vim.eval( 'inputsave()' )
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
vim.eval( 'inputrestore()' )
|
||||
# Clear the command line so that subsequent
|
||||
vim.command( 'redraw' )
|
||||
|
||||
|
||||
def SelectFromList( prompt, options ):
|
||||
with InputSave():
|
||||
def SelectFromList( prompt,
|
||||
options,
|
||||
ret = 'text',
|
||||
default_index = None ):
|
||||
with AskingForUserInput():
|
||||
display_options = [ prompt ]
|
||||
display_options.extend( [ '{0}: {1}'.format( i + 1, v )
|
||||
for i, v in enumerate( options ) ] )
|
||||
display_options.extend( [
|
||||
'{0}{1}: {2}'.format( '*' if i == default_index else ' ',
|
||||
i + 1,
|
||||
v )
|
||||
for i, v in enumerate( options )
|
||||
] )
|
||||
try:
|
||||
selection = int( vim.eval(
|
||||
'inputlist( ' + json.dumps( display_options ) + ' )' ) ) - 1
|
||||
if selection < 0 or selection >= len( options ):
|
||||
return None
|
||||
return options[ selection ]
|
||||
if default_index is not None:
|
||||
selection = default_index
|
||||
else:
|
||||
return None
|
||||
|
||||
if ret == 'text':
|
||||
return options[ selection ]
|
||||
else:
|
||||
return selection
|
||||
except ( KeyboardInterrupt, vim.error ):
|
||||
return None
|
||||
|
||||
|
|
@ -362,7 +378,7 @@ def AskForInput( prompt, default_value = None ):
|
|||
else:
|
||||
default_option = ", '{}'".format( Escape( default_value ) )
|
||||
|
||||
with InputSave():
|
||||
with AskingForUserInput():
|
||||
try:
|
||||
return vim.eval( "input( '{}' {} )".format( Escape( prompt ),
|
||||
default_option ) )
|
||||
|
|
@ -531,11 +547,25 @@ def ExpandReferencesInString( orig_s,
|
|||
if default_value is None and e.default_value is not None:
|
||||
try:
|
||||
default_value = _Substitute( e.default_value, mapping )
|
||||
except MissingSubstitution:
|
||||
default_value = e.default_value
|
||||
except MissingSubstitution as f:
|
||||
if f.name in calculus:
|
||||
default_value = calculus[ f.name ]()
|
||||
else:
|
||||
default_value = e.default_value
|
||||
|
||||
mapping[ key ] = AskForInput( 'Enter value for {}: '.format( key ),
|
||||
default_value )
|
||||
value_list = None
|
||||
if default_value:
|
||||
default_value_list = default_value.split( '\n' )
|
||||
if len( default_value_list ) > 1:
|
||||
value_list = default_value_list
|
||||
|
||||
if value_list:
|
||||
mapping[ key ] = SelectFromList( f'Select value for { key }: ',
|
||||
default_value_list,
|
||||
default_index = 0 )
|
||||
else:
|
||||
mapping[ key ] = AskForInput( 'Enter value for {}: '.format( key ),
|
||||
default_value )
|
||||
|
||||
if mapping[ key ] is None:
|
||||
raise KeyboardInterrupt
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue