def InstallGagdet(name, gadget, succeeded, failed, all_adapters): try: print(f"Installing {name}...") v = {} v.update(gadget.get('all', {})) v.update(gadget.get(install.GetOS(), {})) if 'download' in gadget: if 'file_name' not in v: raise RuntimeError("Unsupported OS {} for gadget {}".format( install.GetOS(), name)) destination = os.path.join( install.GetGadgetDir(options.vimspector_base), 'download', name, v['version']) url = string.Template(gadget['download']['url']).substitute(v) file_path = DownloadFileTo( url, destination, file_name=gadget['download'].get('target'), checksum=v.get('checksum'), check_certificate=not options.no_check_certificate) root = os.path.join(destination, 'root') ExtractZipTo(file_path, root, format=gadget['download'].get('format', 'zip')) elif 'repo' in gadget: url = string.Template(gadget['repo']['url']).substitute(v) ref = string.Template(gadget['repo']['ref']).substitute(v) destination = os.path.join( install.GetGadgetDir(options.vimspector_base), 'download', name) CloneRepoTo(url, ref, destination) root = destination if 'do' in gadget: gadget['do'](name, root, v) else: InstallGeneric(name, root, v) # Allow per-OS adapter overrides. v already did that for us... all_adapters.update(v.get('adapters', {})) # Add any other "all" adapters all_adapters.update(gadget.get('adapters', {})) succeeded.append(name) print(f" - Done installing {name}") except Exception as e: if not options.quiet: traceback.print_exc() failed.append(name) print(f" - FAILED installing {name}: {e}".format(name, e))
def InstallTclProDebug(name, root, gadget): configure = ['sh', './configure'] if install.GetOS() == 'macos': # Apple removed the headers from system frameworks because they are # determined to make life difficult. And the TCL configure scripts are super # old so don't know about this. So we do their job for them and try and find # a tclConfig.sh. # # NOTE however that in Apple's infinite wisdom, installing the "headers" in # the other location is actually broken because the paths in the # tclConfig.sh are pointing at the _old_ location. You actually do have to # run the package installation which puts the headers back in order to work. # This is why the below list is does not contain stuff from # /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform # '/Applications/Xcode.app/Contents/Developer/Platforms' # '/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System' # '/Library/Frameworks/Tcl.framework', # '/Applications/Xcode.app/Contents/Developer/Platforms' # '/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System' # '/Library/Frameworks/Tcl.framework/Versions' # '/Current', for p in ['/usr/local/opt/tcl-tk/lib']: if os.path.exists(os.path.join(p, 'tclConfig.sh')): configure.append('--with-tcl=' + p) break with CurrentWorkingDir(os.path.join(root, 'lib', 'tclparser')): CheckCall(configure) CheckCall(['make']) MakeSymlink(name, root)
def FindExecutable(executable: str, paths=None): if not paths: paths = GetPATHAsList() if install.GetOS() == 'windows': extensions = ['.exe', '.bat', '.cmd'] else: extensions = [''] for extension in extensions: if executable.endswith(extension): candidate = executable else: candidate = executable + extension for path in paths: filename = os.path.abspath(os.path.join(path, candidate)) if not os.path.isfile(filename): continue if not os.access(filename, os.F_OK | os.X_OK): continue return filename raise MissingExecutable( f"Unable to find executable { executable } in path")
def _CreateBuffer(self, category, file_name=None, cmd=None, completion_handler=None, syntax=None): buf_to_delete = None if (not self._buffers and self._window is not None and self._window.valid and not self._window.buffer.name): # If there's an empty buffer in the current window that we're not using, # delete it. We could try and use it, but that complicates the call to # SetUpCommandBuffer buf_to_delete = self._window.buffer if file_name is not None: assert cmd is None if install.GetOS() == "windows": # FIXME: Can't display fiels in windows (yet?) return cmd = ['tail', '-F', '-n', '+1', '--', file_name] if cmd is not None: out = utils.SetUpCommandBuffer( cmd, category, self._api_prefix, completion_handler=completion_handler) self._buffers[category] = TabBuffer(out, len(self._buffers)) self._buffers[category].is_job = True self._RenderWinBar(category) else: if category == 'Console': name = 'vimspector.Console' else: name = 'vimspector.Output:{0}'.format(category) tab_buffer = TabBuffer(utils.NewEmptyBuffer(), len(self._buffers)) self._buffers[category] = tab_buffer if category == 'Console': utils.SetUpPromptBuffer(tab_buffer.buf, name, '> ', 'vimspector#EvaluateConsole', 'vimspector#OmniFuncConsole') else: utils.SetUpHiddenBuffer(tab_buffer.buf, name) self._RenderWinBar(category) self._buffers[category].syntax = utils.SetSyntax( self._buffers[category].syntax, syntax, self._buffers[category].buf) if buf_to_delete: with utils.RestoreCurrentWindow(): self._ShowOutput(category) utils.CleanUpHiddenBuffer(buf_to_delete)
def InstallCppTools( name, root, gadget ): extension = os.path.join( root, 'extension' ) # It's hilarious, but the execute bits aren't set in the vsix. So they # actually have javascript code which does this. It's just a horrible horrible # hack that really is not funny. for binary in [ 'OpenDebugAD7', 'OpenDebugAD7.exe' ]: path = os.path.join( extension, 'debugAdapters', 'bin', binary ) if os.path.exists( path ): MakeExecutable( path ) # See makeBinariesExecutable from the cpptools extension code: # https://github.com/microsoft/vscode-cpptools/blob/main/Extension/src/main.ts#L97 if install.GetOS() == 'macos': MakeExecutable( os.path.join( extension, 'debugAdapters', 'lldb-mi', 'bin', 'lldb-mi' ) ) if install.GetPlatform() == 'x86_64': for binary in [ "debugserver", "lldb-mi", "lldb-argdumper", "lldb-launcher" ]: MakeExecutable( os.path.join( extension, 'debugAdapters', 'bin', binary ) ) MakeExtensionSymlink( name, root )
def __init__( self, api_prefix ): self._logger = logging.getLogger( __name__ ) utils.SetUpLogging( self._logger ) self._api_prefix = api_prefix self._logger.info( "**** INITIALISING NEW VIMSPECTOR SESSION ****" ) self._logger.info( "API is: {}".format( api_prefix ) ) self._logger.info( 'VIMSPECTOR_HOME = %s', VIMSPECTOR_HOME ) self._logger.info( 'gadgetDir = %s', install.GetGadgetDir( VIMSPECTOR_HOME, install.GetOS() ) ) self._uiTab = None self._stackTraceView = None self._variablesView = None self._outputView = None self._breakpoints = breakpoints.ProjectBreakpoints() self._splash_screen = None self._run_on_server_exit = None self._configuration = None self._adapter = None self._ResetServerState()
def PathToAnyWorkingPython3(): # We can't rely on sys.executable because it's usually 'vim' (fixme, not with # neovim?) paths = os.environ['PATH'].split(os.pathsep) if install.GetOS() == 'windows': paths.insert(0, os.getcwd()) candidates = [ os.path.join(sys.exec_prefix, 'python.exe'), 'python.exe' ] else: candidates = [ os.path.join(sys.exec_prefix, 'bin', 'python3'), 'python3', 'python' ] for candidate in candidates: for path in paths: filename = os.path.abspath(os.path.join(path, candidate)) if not os.path.isfile(filename): continue if not os.access(filename, os.F_OK | os.X_OK): continue return filename raise RuntimeError("Unable to find a working python3")
def FindGadgetForAdapter(adapter_name): candidates = [] for name, gadget in gadgets.GADGETS.items(): v = {} v.update(gadget.get('all', {})) v.update(gadget.get(install.GetOS(), {})) adapters = {} adapters.update(v.get('adapters', {})) adapters.update(gadget.get('adapters', {})) if adapter_name in adapters: candidates.append(name) return candidates
def _CreateBuffer( self, category, file_name = None, cmd = None, completion_handler = None, syntax = None ): if file_name is not None: assert cmd is None if install.GetOS() == "windows": # FIXME: Can't display fiels in windows (yet?) return cmd = [ 'tail', '-F', '-n', '+1', '--', file_name ] if cmd is not None: out = utils.SetUpCommandBuffer( cmd, category, self._api_prefix, completion_handler = completion_handler ) self._buffers[ category ] = TabBuffer( out, len( self._buffers ) ) self._buffers[ category ].is_job = True self._RenderWinBar( category ) else: if category == 'Console': name = 'vimspector.Console' else: name = 'vimspector.Output:{0}'.format( category ) tab_buffer = TabBuffer( utils.NewEmptyBuffer(), len( self._buffers ) ) self._buffers[ category ] = tab_buffer if category == 'Console': utils.SetUpPromptBuffer( tab_buffer.buf, name, '> ', 'vimspector#EvaluateConsole' ) else: utils.SetUpHiddenBuffer( tab_buffer.buf, name ) self._RenderWinBar( category ) self._buffers[ category ].syntax = utils.SetSyntax( self._buffers[ category ].syntax, syntax, self._buffers[ category ].buf )
def __init__(self): self._logger = logging.getLogger(__name__) utils.SetUpLogging(self._logger) self._logger.info('VIMSPECTOR_HOME = %s', VIMSPECTOR_HOME) self._logger.info( 'gadgetDir = %s', install.GetGadgetDir(VIMSPECTOR_HOME, install.GetOS())) self._uiTab = None self._stackTraceView = None self._variablesView = None self._outputView = None self._breakpoints = breakpoints.ProjectBreakpoints() self._run_on_server_exit = None self._ResetServerState()
def MakeSymlink(in_folder, link, pointing_to): RemoveIfExists(os.path.join(in_folder, link)) in_folder = os.path.abspath(in_folder) pointing_to_relative = os.path.relpath(os.path.abspath(pointing_to), in_folder) link_path = os.path.join(in_folder, link) if install.GetOS() == 'windows': # While symlinks do exist on Windows, they require elevated privileges, so # let's use a directory junction which is all we need. link_path = os.path.abspath(link_path) if os.path.isdir(link_path): os.rmdir(link_path) subprocess.check_call( ['cmd.exe', '/c', 'mklink', '/J', link_path, pointing_to]) else: os.symlink(pointing_to_relative, link_path)
def SetUpDebugpy(wait=False, port=5678): sys.path.insert( 1, os.path.join( install.GetGadgetDir(utils.GetVimspectorBase(), install.GetOS()), 'debugpy', 'build', 'lib')) import debugpy exe = sys.executable try: # debugpy uses sys.executable (which is `vim`, so we hack it) sys.executable = 'python3' debugpy.listen(port) finally: sys.executable = exe if wait: debugpy.wait_for_client()
def _CreateBuffer(self, category, file_name=None, cmd=None): win = self._window if not win.valid: # We need to borrow the current window win = vim.current.window with utils.LetCurrentWindow(win): with utils.RestoreCurrentBuffer(win): if file_name is not None: assert cmd is None if install.GetOS() == "windows": # FIXME: Can't display fiels in windows (yet?) return cmd = ['tail', '-F', '-n', '+1', '--', file_name] if cmd is not None: out, err = utils.SetUpCommandBuffer( cmd, category, self._api_prefix) self._buffers[category + '-out'] = TabBuffer( out, len(self._buffers)) self._buffers[category + '-out'].is_job = True self._buffers[category + '-out'].job_category = category self._buffers[category + '-err'] = TabBuffer( err, len(self._buffers)) self._buffers[category + '-err'].is_job = False self._RenderWinBar(category + '-out') self._RenderWinBar(category + '-err') else: vim.command('enew') tab_buffer = TabBuffer(vim.current.buffer, len(self._buffers)) self._buffers[category] = tab_buffer if category == 'Console': utils.SetUpPromptBuffer(tab_buffer.buf, 'vimspector.Console', '> ', 'vimspector#EvaluateConsole') else: utils.SetUpHiddenBuffer( tab_buffer.buf, 'vimspector.Output:{0}'.format(category)) self._RenderWinBar(category)
def PathToAnyWorkingPython3(): # We can't rely on sys.executable because it's usually 'vim' (fixme, not with # neovim?) paths = GetPATHAsList() if install.GetOS() == 'windows': candidates = [ os.path.join( sys.exec_prefix, 'python.exe' ), 'python.exe' ] else: candidates = [ os.path.join( sys.exec_prefix, 'bin', 'python3' ), 'python3', 'python' ] for candidate in candidates: try: return FindExecutable( candidate, paths=paths ) except MissingExecutable: pass raise RuntimeError( "Unable to find a working python3" )
def MakeSymlink(link, pointing_to, in_folder=None): if not in_folder: in_folder = install.GetGadgetDir(options.vimspector_base) RemoveIfExists(os.path.join(in_folder, link)) in_folder = os.path.abspath(in_folder) pointing_to_relative = os.path.relpath(os.path.abspath(pointing_to), in_folder) link_path = os.path.join(in_folder, link) if install.GetOS() == 'windows': # While symlinks do exist on Windows, they require elevated privileges, so # let's use a directory junction which is all we need. link_path = os.path.abspath(link_path) if os.path.isdir(link_path): os.rmdir(link_path) CheckCall(['cmd.exe', '/c', 'mklink', '/J', link_path, pointing_to]) else: os.symlink(pointing_to_relative, link_path)
def Start(self, 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: launch_variables = {} self._logger.info("User requested start debug session with %s", launch_variables) self._configuration = None self._adapter = None current_file = utils.GetBufferFilepath(vim.current.buffer) filetypes = utils.GetBufferFiletypes(vim.current.buffer) configurations = {} adapters = {} glob.glob(install.GetGadgetDir(VIMSPECTOR_HOME, install.GetOS())) for gadget_config_file in PathsToAllGadgetConfigs( VIMSPECTOR_HOME, current_file): self._logger.debug(f'Reading gadget config: {gadget_config_file}') if not gadget_config_file or not os.path.exists( gadget_config_file): continue with open(gadget_config_file, 'r') as f: adapters.update(json.load(f).get('adapters') or {}) for launch_config_file in PathsToAllConfigFiles( VIMSPECTOR_HOME, current_file, filetypes): self._logger.debug( f'Reading configurations from: {launch_config_file}') if not launch_config_file or not os.path.exists( launch_config_file): continue with open(launch_config_file, 'r') as f: database = json.load(f) adapters.update(database.get('adapters') or {}) configurations.update(database.get('configurations' or {})) if not configurations: utils.UserMessage('Unable to find any debug configurations. ' 'You need to tell vimspector how to launch your ' 'application.') return if 'configuration' in launch_variables: configuration_name = launch_variables.pop('configuration') elif len(configurations) == 1: configuration_name = next(iter(configurations.keys())) else: configuration_name = utils.SelectFromList( 'Which launch configuration?', sorted(configurations.keys())) if not configuration_name or configuration_name not in configurations: return if launch_config_file: self._workspace_root = os.path.dirname(launch_config_file) else: self._workspace_root = os.path.dirname(current_file) configuration = configurations[configuration_name] adapter = configuration.get('adapter') if isinstance(adapter, str): adapter = adapters.get(adapter) # TODO: Do we want some form of persistence ? e.g. self._staticVariables, # set from an api call like SetLaunchParam( 'var', 'value' ), perhaps also a # way to load .vimspector.local.json which just sets variables # # Additional vars as defined by VSCode: # # ${workspaceFolder} - the path of the folder opened in VS Code # ${workspaceFolderBasename} - the name of the folder opened in VS Code # without any slashes (/) # ${file} - the current opened file # ${relativeFile} - the current opened file relative to workspaceFolder # ${fileBasename} - the current opened file's basename # ${fileBasenameNoExtension} - the current opened file's basename with no # file extension # ${fileDirname} - the current opened file's dirname # ${fileExtname} - the current opened file's extension # ${cwd} - the task runner's current working directory on startup # ${lineNumber} - the current selected line number in the active file # ${selectedText} - the current selected text in the active file # ${execPath} - the path to the running VS Code executable def relpath(p, relative_to): if not p: return '' return os.path.relpath(p, relative_to) def splitext(p): if not p: return ['', ''] return os.path.splitext(p) self._variables = { 'dollar': '$', # HACK. Hote '$$' also works. 'workspaceRoot': self._workspace_root, 'workspaceFolder': self._workspace_root, 'gadgetDir': install.GetGadgetDir(VIMSPECTOR_HOME, install.GetOS()), 'file': current_file, 'relativeFile': relpath(current_file, self._workspace_root), 'fileBasename': os.path.basename(current_file), 'fileBasenameNoExtension': splitext(os.path.basename(current_file))[0], 'fileDirname': os.path.dirname(current_file), 'fileExtname': splitext(os.path.basename(current_file))[1], # NOTE: this is the window-local cwd for the current window, *not* Vim's # working directory. 'cwd': os.getcwd(), } # Pretend that vars passed to the launch command were typed in by the user # (they may have been in theory) USER_CHOICES.update(launch_variables) self._variables.update(launch_variables) self._variables.update( utils.ParseVariables(adapter.get('variables', {}), self._variables, USER_CHOICES)) self._variables.update( utils.ParseVariables(configuration.get('variables', {}), self._variables, USER_CHOICES)) utils.ExpandReferencesInDict(configuration, self._variables, USER_CHOICES) utils.ExpandReferencesInDict(adapter, self._variables, USER_CHOICES) if not adapter: utils.UserMessage( 'No adapter configured for {}'.format(configuration_name), persist=True) return self._StartWithConfiguration(configuration, adapter)
if 'do' in gadget: gadget['do'](name, root, v) else: installer.MakeExtensionSymlink(vimspector_base, name, root) all_adapters.update(gadget.get('adapters', {})) print("Done installing {}".format(name)) except Exception as e: traceback.print_exc() failed.append(name) print("FAILED installing {}: {}".format(name, e)) vimspector_base = os.path.dirname(__file__) OS = install.GetOS() gadget_dir = install.GetGadgetDir(vimspector_base, OS) print('OS = ' + OS) print('gadget_dir = ' + gadget_dir) parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, description='Install DAP Servers for use with Vimspector.', epilog=""" If you're not sure, normally --all is enough to get started. Custom server definitions can be defined in JSON files, allowing installation of arbitrary servers packaged in one of the ways that this installer understands.
def Start( self, 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: launch_variables = {} self._logger.info( "User requested start debug session with %s", launch_variables ) self._configuration = None self._adapter = None current_file = utils.GetBufferFilepath( vim.current.buffer ) filetypes = utils.GetBufferFiletypes( vim.current.buffer ) configurations = {} adapters = {} glob.glob( install.GetGadgetDir( VIMSPECTOR_HOME, install.GetOS() ) ) for gadget_config_file in PathsToAllGadgetConfigs( VIMSPECTOR_HOME, current_file ): self._logger.debug( f'Reading gadget config: {gadget_config_file}' ) if not gadget_config_file or not os.path.exists( gadget_config_file ): continue with open( gadget_config_file, 'r' ) as f: a = json.loads( minify( f.read() ) ).get( 'adapters' ) or {} adapters.update( a ) for launch_config_file in PathsToAllConfigFiles( VIMSPECTOR_HOME, current_file, filetypes ): self._logger.debug( f'Reading configurations from: {launch_config_file}' ) if not launch_config_file or not os.path.exists( launch_config_file ): continue with open( launch_config_file, 'r' ) as f: database = json.loads( minify( f.read() ) ) adapters.update( database.get( 'adapters' ) or {} ) configurations.update( database.get( 'configurations' or {} ) ) if not configurations: utils.UserMessage( 'Unable to find any debug configurations. ' 'You need to tell vimspector how to launch your ' 'application.' ) return if 'configuration' in launch_variables: configuration_name = launch_variables.pop( 'configuration' ) elif ( len( configurations ) == 1 and next( iter( configurations.values() ) ).get( "autoselect", True ) ): configuration_name = next( iter( configurations.keys() ) ) else: # Find a single configuration with 'default' True and autoselect not False defaults = { n: c for n, c in configurations.items() if c.get( 'default', False ) is True and c.get( 'autoselect', True ) is not False } if len( defaults ) == 1: configuration_name = next( iter( defaults.keys() ) ) else: configuration_name = utils.SelectFromList( 'Which launch configuration?', sorted( configurations.keys() ) ) if not configuration_name or configuration_name not in configurations: return if launch_config_file: self._workspace_root = os.path.dirname( launch_config_file ) else: self._workspace_root = os.path.dirname( current_file ) configuration = configurations[ configuration_name ] adapter = configuration.get( 'adapter' ) if isinstance( adapter, str ): adapter_dict = adapters.get( adapter ) if adapter_dict is None: utils.UserMessage( f"The specified adapter '{adapter}' is not " "available. Did you forget to run " "'install_gadget.py'?", persist = True, error = True ) return adapter = adapter_dict # Additional vars as defined by VSCode: # # ${workspaceFolder} - the path of the folder opened in VS Code # ${workspaceFolderBasename} - the name of the folder opened in VS Code # without any slashes (/) # ${file} - the current opened file # ${relativeFile} - the current opened file relative to workspaceFolder # ${fileBasename} - the current opened file's basename # ${fileBasenameNoExtension} - the current opened file's basename with no # file extension # ${fileDirname} - the current opened file's dirname # ${fileExtname} - the current opened file's extension # ${cwd} - the task runner's current working directory on startup # ${lineNumber} - the current selected line number in the active file # ${selectedText} - the current selected text in the active file # ${execPath} - the path to the running VS Code executable def relpath( p, relative_to ): if not p: return '' return os.path.relpath( p, relative_to ) def splitext( p ): if not p: return [ '', '' ] return os.path.splitext( p ) variables = { 'dollar': '$', # HACK. Hote '$$' also works. 'workspaceRoot': self._workspace_root, 'workspaceFolder': self._workspace_root, 'gadgetDir': install.GetGadgetDir( VIMSPECTOR_HOME, install.GetOS() ), 'file': current_file, } calculus = { 'relativeFile': lambda: relpath( current_file, self._workspace_root ), 'fileBasename': lambda: os.path.basename( current_file ), 'fileBasenameNoExtension': lambda: splitext( os.path.basename( current_file ) )[ 0 ], 'fileDirname': lambda: os.path.dirname( current_file ), 'fileExtname': lambda: splitext( os.path.basename( current_file ) )[ 1 ], # NOTE: this is the window-local cwd for the current window, *not* Vim's # working directory. 'cwd': os.getcwd, 'unusedLocalPort': utils.GetUnusedLocalPort, } # Pretend that vars passed to the launch command were typed in by the user # (they may have been in theory) USER_CHOICES.update( launch_variables ) variables.update( launch_variables ) try: variables.update( utils.ParseVariables( adapter.get( 'variables', {} ), variables, calculus, USER_CHOICES ) ) variables.update( utils.ParseVariables( configuration.get( 'variables', {} ), variables, calculus, USER_CHOICES ) ) utils.ExpandReferencesInDict( configuration, variables, calculus, USER_CHOICES ) utils.ExpandReferencesInDict( adapter, variables, calculus, USER_CHOICES ) except KeyboardInterrupt: self._Reset() return if not adapter: utils.UserMessage( 'No adapter configured for {}'.format( configuration_name ), persist=True ) return self._StartWithConfiguration( configuration, adapter )
def Start( self, launch_variables = {} ): self._logger.info( "User requested start debug session with %s", launch_variables ) self._configuration = None self._adapter = None launch_config_file = utils.PathToConfigFile( '.vimspector.json' ) if not launch_config_file: utils.UserMessage( 'Unable to find .vimspector.json. You need to tell ' 'vimspector how to launch your application' ) return with open( launch_config_file, 'r' ) as f: database = json.load( f ) configurations = database.get( 'configurations' ) adapters = {} for gadget_config_file in [ install.GetGadgetConfigFile( VIMSPECTOR_HOME ), utils.PathToConfigFile( '.gadgets.json' ) ]: if gadget_config_file and os.path.exists( gadget_config_file ): with open( gadget_config_file, 'r' ) as f: adapters.update( json.load( f ).get( 'adapters' ) or {} ) adapters.update( database.get( 'adapters' ) or {} ) if len( configurations ) == 1: configuration_name = next( iter( configurations.keys() ) ) else: configuration_name = utils.SelectFromList( 'Which launch configuration?', sorted( list( configurations.keys() ) ) ) if not configuration_name or configuration_name not in configurations: return self._workspace_root = os.path.dirname( launch_config_file ) configuration = configurations[ configuration_name ] adapter = configuration.get( 'adapter' ) if isinstance( adapter, str ): adapter = adapters.get( adapter ) # TODO: Do we want some form of persistence ? e.g. self._staticVariables, # set from an api call like SetLaunchParam( 'var', 'value' ), perhaps also a # way to load .vimspector.local.json which just sets variables # # Additional vars as defined by VSCode: # # ${workspaceFolder} - the path of the folder opened in VS Code # ${workspaceFolderBasename} - the name of the folder opened in VS Code # without any slashes (/) # ${file} - the current opened file # ${relativeFile} - the current opened file relative to workspaceFolder # ${fileBasename} - the current opened file's basename # ${fileBasenameNoExtension} - the current opened file's basename with no # file extension # ${fileDirname} - the current opened file's dirname # ${fileExtname} - the current opened file's extension # ${cwd} - the task runner's current working directory on startup # ${lineNumber} - the current selected line number in the active file # ${selectedText} - the current selected text in the active file # ${execPath} - the path to the running VS Code executable current_file = utils.GetBufferFilepath( vim.current.buffer ) self._variables = { 'dollar': '$', # HACK. Hote '$$' also works. 'workspaceRoot': self._workspace_root, 'workspaceFolder': self._workspace_root, 'gadgetDir': install.GetGadgetDir( VIMSPECTOR_HOME, install.GetOS() ), 'file': current_file, 'relativeFile': os.path.relpath( current_file, self._workspace_root ), 'fileBasename': os.path.basename( current_file ), 'fileBasenameNoExtension': os.path.splitext( os.path.basename( current_file ) )[ 0 ], 'fileDirname': os.path.dirname( current_file ), 'fileExtname': os.path.splitext( os.path.basename( current_file ) )[ 1 ], 'cwd': os.getcwd(), } self._variables.update( utils.ParseVariables( adapter.get( 'variables', {} ), self._variables ) ) self._variables.update( utils.ParseVariables( configuration.get( 'variables', {} ), self._variables ) ) self._variables.update( launch_variables ) utils.ExpandReferencesInDict( configuration, self._variables ) utils.ExpandReferencesInDict( adapter, self._variables ) if not adapter: utils.UserMessage( 'No adapter configured for {}'.format( configuration_name ), persist=True ) return self._StartWithConfiguration( configuration, adapter )
def MakeExtensionSymlink( vimspector_base, name, root ): MakeSymlink( install.GetGadgetDir( vimspector_base, install.GetOS() ), name, os.path.join( root, 'extension' ) ),
def GetPATHAsList(): paths = os.environ['PATH'].split(os.pathsep) if install.GetOS() == 'windows': paths.insert(0, os.getcwd()) return paths
def InstallGagdet(name: str, gadget: dict, manifest: Manifest, succeeded: list, failed: list, all_adapters: dict): try: # Spec is an os-specific definition of the gadget spec = {} spec.update(gadget.get('all', {})) spec.update(gadget.get(install.GetOS(), {})) def save_adapters(): # allow per-os adapter overrides. v already did that for us... all_adapters.update(spec.get('adapters', {})) # add any other "all" adapters all_adapters.update(gadget.get('adapters', {})) if 'download' in gadget: if 'file_name' not in spec: raise RuntimeError("Unsupported OS {} for gadget {}".format( install.GetOS(), name)) print(f"Installing {name}@{spec[ 'version' ]}...") spec['download'] = gadget['download'] if not manifest.RequiresUpdate(name, spec): save_adapters() print(" - Skip - up to date") return destination = os.path.join( install.GetGadgetDir(options.vimspector_base), 'download', name, spec['version']) url = string.Template(gadget['download']['url']).substitute(spec) file_path = DownloadFileTo( url, destination, file_name=gadget['download'].get('target'), checksum=spec.get('checksum'), check_certificate=not options.no_check_certificate) root = os.path.join(destination, 'root') ExtractZipTo(file_path, root, format=gadget['download'].get('format', 'zip')) elif 'repo' in gadget: url = string.Template(gadget['repo']['url']).substitute(spec) ref = string.Template(gadget['repo']['ref']).substitute(spec) print(f"Installing {name}@{ref}...") spec['repo'] = gadget['repo'] if not manifest.RequiresUpdate(name, spec): save_adapters() print(" - Skip - up to date") return destination = os.path.join( install.GetGadgetDir(options.vimspector_base), 'download', name) CloneRepoTo(url, ref, destination) root = destination if 'do' in gadget: gadget['do'](name, root, spec) else: InstallGeneric(name, root, spec) save_adapters() manifest.Update(name, spec) succeeded.append(name) print(f" - Done installing {name}") except Exception as e: if not options.quiet: traceback.print_exc() failed.append(name) print(f" - FAILED installing {name}: {e}".format(name, e))
def Start(self, launch_variables={}): self._configuration = None self._adapter = None launch_config_file = utils.PathToConfigFile('.vimspector.json') if not launch_config_file: utils.UserMessage( 'Unable to find .vimspector.json. You need to tell ' 'vimspector how to launch your application') return with open(launch_config_file, 'r') as f: database = json.load(f) configurations = database.get('configurations') adapters = {} for gadget_config_file in [ install.GetGadgetConfigFile(VIMSPECTOR_HOME), utils.PathToConfigFile('.gadgets.json') ]: if gadget_config_file and os.path.exists(gadget_config_file): with open(gadget_config_file, 'r') as f: adapters.update(json.load(f).get('adapters') or {}) adapters.update(database.get('adapters') or {}) if len(configurations) == 1: configuration_name = next(iter(configurations.keys())) else: configuration_name = utils.SelectFromList( 'Which launch configuration?', sorted(list(configurations.keys()))) if not configuration_name or configuration_name not in configurations: return self._workspace_root = os.path.dirname(launch_config_file) configuration = configurations[configuration_name] adapter = configuration.get('adapter') if isinstance(adapter, str): adapter = adapters.get(adapter) # TODO: Do we want some form of persistence ? e.g. self._staticVariables, # set from an api call like SetLaunchParam( 'var', 'value' ), perhaps also a # way to load .vimspector.local.json which just sets variables self._variables = { 'dollar': '$', # HACK. Hote '$$' also works. 'workspaceRoot': self._workspace_root, 'gadgetDir': install.GetGadgetDir(VIMSPECTOR_HOME, install.GetOS()) } self._variables.update( utils.ParseVariables(adapter.get('variables', {}))) self._variables.update( utils.ParseVariables(configuration.get('variables', {}))) self._variables.update(launch_variables) utils.ExpandReferencesInDict(configuration, self._variables) utils.ExpandReferencesInDict(adapter, self._variables) if not adapter: utils.UserMessage( 'No adapter configured for {}'.format(configuration_name), persist=True) return self._StartWithConfiguration(configuration, adapter)