def select_configuration( window: sublime.Window, index: int) -> core.awaitable[Optional[Configuration]]: try: configs = all_configurations(window) except Exception as e: core.display(e) show_settings(window) done = core.main_loop.create_future() names = list(map(lambda x: x.name, configs)) + ["-" ] + ["Add configuration"] index = yield from core.sublime_show_quick_panel_async( window, names, index) if index < 0: return None if index >= len(configs): project = window.project_file_name() if project: sublime.run_command("new_window") window = sublime.active_window() window.open_file(project) else: window.run_command( 'edit_settings', {"base_file": "${packages}/sublime_db/debug.sublime-settings"}) return None return configs[index]
def LaunchDebugger(self) -> core.awaitable[None]: self.console_panel.clear() self.console_panel.Add('Console cleared...') try: if not self.configuration: yield from self.SelectConfiguration() if not self.configuration: return configuration = self.configuration adapter_configuration = self.adapters.get(configuration.type) if not adapter_configuration: raise Exception( 'Unable to find debug adapter with the type name "{}"'. format(configuration.type)) except Exception as e: core.log_exception() core.display(e) return yield from self.debugger.launch(adapter_configuration, configuration, self.breakpoints)
def _set_value(self, value: str) -> core.awaitable[None]: try: variable = yield from self.variable.client.setVariable(self.variable, value) self.variable = variable if self.fetched: self._fetch_if_needed(True) self.on_updated() except Exception as e: core.log_exception() core.display(e)
def insert_snippet(window: sublime.Window, snippet: dict) -> core.awaitable[None]: content = json.dumps(snippet, indent="\t") content = content.replace('\\\\', '\\') # remove json encoded \ ... project = window.project_file_name() if project: view = yield from core.sublime_open_file_async(window, project) region = view.find('''"\s*debug.configurations\s*"\s*:\s*\[''', 0) view.sel().clear() view.sel().add(sublime.Region(region.b, region.b)) view.run_command('insert', { 'characters': '\n' }) view.run_command('insert_snippet', { 'contents': content + ',' }) else: sublime.set_clipboard(content) core.display('Unable to insert configuration into sublime-project file: Copied to clipboard instead')
def load_configurations(self) -> None: adapters = {} for adapter_name, adapter_json in get_setting( self.window.active_view(), 'adapters', {}).items(): try: adapter = AdapterConfiguration.from_json( adapter_name, adapter_json, self.window) adapters[adapter.type] = adapter except Exception as e: core.display( 'There was an error creating a AdapterConfiguration {}'. format(e)) configurations = [] configurations_json = [] #type: list data = self.window.project_data() if data: configurations_json = data.setdefault('settings', {}).setdefault( 'debug.configurations', []) for index, configuration_json in enumerate(configurations_json): configuration = Configuration.from_json(configuration_json) configuration.all = sublime.expand_variables( configuration.all, extract_variables(self.window)) configuration.index = index configurations.append(configuration) self.adapters = adapters self.configurations = configurations self.configuration = self.persistance.load_configuration_option( configurations) if self.configuration: self.debugger_panel.set_name(self.configuration.name) else: self.debugger_panel.set_name('select config') assert self.view self.view.settings().set('font_size', get_setting(self.view, 'ui_scale', 12))
def __init__(self, window: sublime.Window) -> None: print('new Main for window', window.id()) self.window = window self.disposeables = [] #type: List[Any] self.breakpoints = Breakpoints() self.view = None #type: Optional[sublime.View] self.eventLog = EventLogComponent() self.variablesComponent = VariablesComponent() self.callstackComponent = CallStackComponent() self.debuggerComponent = DebuggerComponent(self.breakpoints, self) self.debugAdapterClient = None #type: Optional[DebugAdapterClient] self.selectedFrameComponent = None #type: Optional[ui.Phantom] self.breakpointInformation = None #type: Optional[ui.Phantom] self.pausedWithError = False self.process = None #type: Optional[Process] self.disconnecting = False self.project_name = window.project_file_name() or "user" data = config.persisted_for_project(self.project_name) config_name = data.get('config_name') config_maybe_at_index = data.get('config_maybe_at_index') for bp in data.get('breakpoints', []): self.breakpoints.add(Breakpoint.from_json(bp)) if config_name: self.configuration = get_configuration_for_name(window, config_name, config_maybe_at_index) else: self.configuration = None if self.configuration: self.debuggerComponent.set_name(self.configuration.name) else: self.debuggerComponent.set_name('select config') self.stopped_reason = '' self.path = window.project_file_name() if self.path: self.path = os.path.dirname(self.path) self.eventLog.Add('Opened In Workspace: {}'.format(self.path)) else: self.eventLog.AddStderr('warning: debugger opened in a window that is not part of a project') print('Creating a window: h') self.disposeables.extend([ ui.view_gutter_hovered.add(self.on_gutter_hovered), ui.view_text_hovered.add(self.on_text_hovered), ui.view_drag_select.add(self.on_drag_select), ]) mode = get_setting(window.active_view(), 'display') if mode == 'window': sublime.run_command("new_window") new_window = sublime.active_window() output = new_window.new_file() new_window.set_minimap_visible(False) new_window.set_sidebar_visible(False) new_window.set_tabs_visible(False) new_window.set_menu_visible(False) new_window.set_status_bar_visible(False) elif mode == 'view': output = self.window.new_file() elif mode == 'output': output = self.window.create_output_panel('debugger') self.window.run_command('show_panel', { 'panel': 'output.debugger' }) else: core.display('expected setting "mode" to be one of "window", "view" or "output", found "{}"'.format(mode)) return output.run_command('insert', { 'characters': " " }) output.set_scratch(True) output.set_read_only(True) output.set_name('Debugger') view_settings = output.settings() view_settings.set("is_widget", True) view_settings.set("gutter", False) view_settings.set("margin", 0) view_settings.set("always_show_minimap_viewport", False) self.view = output self.disposeables.extend([ ui.Phantom(self.debuggerComponent, output, sublime.Region(1, 1), sublime.LAYOUT_INLINE), ui.Phantom(self.callstackComponent, output, sublime.Region(1, 2), sublime.LAYOUT_INLINE), ui.Phantom(self.variablesComponent, output, sublime.Region(1, 3), sublime.LAYOUT_INLINE), ui.Phantom(self.eventLog, output, sublime.Region(1, 4), sublime.LAYOUT_INLINE) ]) self.breakpoints.onRemovedBreakpoint.add(lambda b: self.clearBreakpointInformation()) self.breakpoints.onChangedBreakpoint.add(self.onChangedBreakpoint) self.breakpoints.onChangedFilter.add(self.onChangedFilter) self.breakpoints.onSelectedBreakpoint.add(self.onSelectedBreakpoint)
def LaunchDebugger (self) -> Generator[Any, None, None]: self.KillDebugger() self.eventLog.clear() self.eventLog.Add('Starting debugger...') self.debuggerComponent.setState(LOADING) try: if not self.configuration: yield from self.EditSettings() if not self.configuration: return config = self.configuration debuggers = get_setting(self.window.active_view(), 'adapters', {}) debugger = debuggers.get(config.type) assert debugger, 'no debugger named {}'.format(config.type) adapter_type_config = sublime.expand_variables(debugger, self.window.extract_variables()) command = adapter_type_config.get('command') assert command, 'expected "command" in debugger settings' port = adapter_type_config.get('tcp_port') #If there is a command to run for this debugger run it now if port: print('Starting Process: {}'.format(command)) try: self.process = Process(command, on_stdout = lambda msg: self.eventLog.Add(msg), on_stderr = lambda msg: self.eventLog.Add(msg)) except Exception as e: self.eventLog.AddStderr('Failed to start debug adapter process: {}'.format(e)) self.eventLog.AddStderr('Command in question: {}'.format(command)) core.display('Failed to start debug adapter process: Check the Event Log for more details') address = adapter_type_config.get('tcp_address', 'localhost') try: transport = yield from start_tcp_transport(address, port) except Exception as e: self.eventLog.AddStderr('Failed to connect to debug adapter: {}'.format(e)) self.eventLog.AddStderr('address: {} port: {}'.format(address, port)) core.display('Failed to connect to debug adapter: Check the Event Log for more details and messages from the debug adapter process?') return else: # dont monitor stdout the StdioTransport users it self.process = Process(command, on_stdout = None, on_stderr = lambda msg: self.eventLog.Add(msg)) transport = StdioTransport(self.process) except Exception as e: core.display(e) return debugAdapterClient = DebugAdapterClient(transport) self.debugAdapterClient = debugAdapterClient def onOutput(event: OutputEvent) -> None: category = event.category msg = event.text variablesReference = event.variablesReference if variablesReference and self.debugAdapterClient: variable = Variable(self.debugAdapterClient, msg, '', variablesReference) self.eventLog.AddVariable(variable) elif category == "stdout": self.eventLog.AddStdout(msg) elif category == "stderr": self.eventLog.AddStderr(msg) elif category == "console": self.eventLog.Add(msg) def onStopped(event: StoppedEvent) -> None: self.pausedWithError = debugAdapterClient.stoppedOnError self.debuggerComponent.setState(PAUSED) self.eventLog.Add(event.reason) self.stopped_reason = event.reason if event.text: self.eventLog.Add(event.text) def onContinued(event: Any) -> None: self.debuggerComponent.setState(RUNNING) def onExited(event: Any) -> None: self.KillDebugger() def onThreads(event: Any) -> None: self.callstackComponent.setThreads(debugAdapterClient, debugAdapterClient.threads, self.pausedWithError) def onVariables(event: Any) -> None: self.variablesComponent.set_variables(debugAdapterClient.variables) def onSelectedStackFrame(frame: Optional[StackFrame]) -> None: self.onSelectedStackFrame(frame) self.callstackComponent.dirty_threads() def on_error(error: str) -> None: self.eventLog.AddStderr(error) debugAdapterClient.onSelectedStackFrame.add(onSelectedStackFrame) debugAdapterClient.onExited.add(onExited) debugAdapterClient.onOutput.add(onOutput) debugAdapterClient.onStopped.add(onStopped) debugAdapterClient.onContinued.add(onContinued) debugAdapterClient.onThreads.add(onThreads) debugAdapterClient.onVariables.add(onVariables) debugAdapterClient.on_error_event.add(on_error) # this is a bit of a weird case. Initialized will happen at some point in time # it depends on when the debug adapter chooses it is ready for configuration information # when it does happen we can then add all the breakpoints and complete the configuration @core.async def Initialized() -> Generator[Any, None, None]: yield from debugAdapterClient.Initialized() yield from debugAdapterClient.AddBreakpoints(self.breakpoints) yield from debugAdapterClient.ConfigurationDone() core.run(Initialized()) adapter_config = sublime.expand_variables(config.all, self.window.extract_variables()) print ('Adapter initialize') body = yield from debugAdapterClient.Initialize() for filter in body.get('exceptionBreakpointFilters', []): id = filter['filter'] name = filter['label'] default = filter.get('default', False) self.breakpoints.add_filter(id, name, default) print ('Adapter initialized: success!') if config.request == 'launch': yield from debugAdapterClient.Launch(adapter_config) elif config.request == 'attach': yield from debugAdapterClient.Attach(adapter_config) else: raise Exception('expected configuration to have request of either "launch" or "attach" found {}'.format(config.request)) print ('Adapter has been launched/attached') # At this point we are running? self.debuggerComponent.setState(RUNNING)
def _launch(self, adapter_configuration: AdapterConfiguration, configuration: Configuration, breakpoints: Breakpoints) -> core.awaitable[None]: if self.state != DebuggerState.stopped: print('stopping debug adapter') yield from self.stop() assert(self.state == DebuggerState.stopped, "debugger not in stopped state?") self.state = DebuggerState.starting self.adapter_configuration = adapter_configuration self.configuration = configuration if not adapter_configuration.installed: raise Exception('Debug adapter with type name "{}" is not installed. You can install it by running Debugger: Install Adapters'.format(adapter_configuration.type)) # If there is a command to run for this debugger run it now if adapter_configuration.tcp_port: self.log_info('starting debug adapter...') try: self.process = Process(adapter_configuration.command, on_stdout=self.log_info, on_stderr=self.log_info) except Exception as e: self.log_error('Failed to start debug adapter process: {}'.format(e)) self.log_error('Command in question: {}'.format(adapter_configuration.command)) core.display('Failed to start debug adapter process: Check the Event Log for more details') raise Exception("failed to start debug adapter process") tcp_address = adapter_configuration.tcp_address or 'localhost' try: transport = yield from start_tcp_transport(tcp_address, adapter_configuration.tcp_port) except Exception as e: self.log_error('Failed to connect to debug adapter: {}'.format(e)) self.log_error('address: {} port: {}'.format(tcp_address, adapter_configuration.tcp_port)) core.display('Failed to connect to debug adapter: Check the Event Log for more details and messages from the debug adapter process?') raise Exception("failed to start debug adapter process") self.log_info('... debug adapter started') else: # dont monitor stdout the StdioTransport users it self.process = Process(adapter_configuration.command, on_stdout=None, on_stderr=self.log_info) transport = StdioTransport(self.process) adapter = DebugAdapterClient(transport) adapter.onThreads.add(self._on_threads_event) adapter.onOutput.add(self._on_output_event) adapter.onStopped.add(self._on_stopped_event) adapter.onContinued.add(self._on_continued_event) adapter.onExited.add(self._on_exited_event) self.log_info("starting debugger... ") # this is a bit of a weird case. Initialized will happen at some point in time # it depends on when the debug adapter chooses it is ready for configuration information # when it does happen we can then add all the breakpoints and complete the configuration @core.async def Initialized() -> core.awaitable[None]: yield from adapter.Initialized() yield from adapter.AddBreakpoints(breakpoints) yield from adapter.ConfigurationDone() core.run(Initialized()) capabilities = yield from adapter.Initialize() for filter in capabilities.exceptionBreakpointFilters: breakpoints.add_filter(filter.id, filter.label, filter.default) if configuration.request == 'launch': self.launch_request = True yield from adapter.Launch(configuration.all) elif configuration.request == 'attach': self.launch_request = False yield from adapter.Attach(configuration.all) else: raise Exception('expected configuration to have request of either "launch" or "attach" found {}'.format(configuration.request)) self.adapter = adapter # At this point we are running? self.state = DebuggerState.running