def run_build(window: sublime.Window, on_output_callback, args) -> core.awaitable[int]: global on_finished_futures global id id += 1 future = core.create_future() on_finished_futures[id] = future on_output_callbacks[id] = on_output_callback window.run_command("debugger_build_exec", { "id": id, "args": args, }) try: exit_code = yield from future return exit_code except core.CancelledError as e: core.log_info("Cancel build") window.run_command("debugger_build_exec", { "id": id, "args": { "kill": True }, }) raise e
def update_diagnostics_panel(window: sublime.Window): assert window, "missing window!" base_dir = get_project_path(window) panel = ensure_diagnostics_panel(window) if not panel and not window.is_valid(): return assert panel, "must have a panel now!" diagnostics_by_file = get_window_diagnostics(window) if diagnostics_by_file is not None: active_panel = window.active_panel() is_active_panel = (active_panel == "output.diagnostics") panel.settings().set("result_base_dir", base_dir) panel.set_read_only(False) if diagnostics_by_file: to_render = [] for file_path, source_diagnostics in diagnostics_by_file.items(): try: relative_file_path = os.path.relpath(file_path, base_dir) if base_dir else file_path except ValueError: relative_file_path = file_path if source_diagnostics: to_render.append(format_diagnostics(relative_file_path, source_diagnostics)) panel.run_command("code_intel_update_panel", {"characters": "\n".join(to_render)}) if settings.auto_show_diagnostics_panel and not active_panel: window.run_command("show_panel", {"panel": "output.diagnostics"}) else: panel.run_command("code_intel_clear_panel") if is_active_panel: window.run_command("hide_panel", {"panel": "output.diagnostics"}) panel.set_read_only(True)
def __init__(self, window: sublime.Window): super().__init__() # ensure we are being run inside a sublime project # if not prompt the user to create one project_name = window.project_file_name() while not project_name: r = sublime.ok_cancel_dialog("Debugger requires a sublime project. Would you like to create a new sublime project?", "Save Project As...") if r: window.run_command('save_project_and_workspace_as') else: raise core.Error("Debugger must be run inside a sublime project") project_name = window.project_file_name() self.name = project_name self.window = window self.on_updated: core.Event[None] = core.Event() self.tasks: List[Task] = [] self.compounds: List[ConfigurationCompound] = [] self.configurations: List[Configuration] = [] self.configuration_or_compound: Optional[Union[Configuration, ConfigurationCompound]] = None self.external_terminal_kind = 'platform' self.ui_scale = 12 self.bring_window_to_front_on_pause = False # add the empty debugger configurations settings if needed data = window.project_data() or {} data.setdefault('debugger_configurations', []) window.set_project_data(data) self.disposables += Settings.updated.add(self.reload) self.reload()
def __init__(self, window: sublime.Window, on_output, args): global debugger_exec_for_id global id id += 1 debugger_exec_for_id[id] = self self.future = core.create_future() self.on_output_callback = on_output window.run_command("debugger_exec", { "id": id, "args": args, }) async def kill_if_canceled(): try: await self.future except core.CancelledError as e: core.log_info("Cancel task") window.run_command("debugger_exec", { "id": id, "args": { "kill": True }, }) raise e core.run(kill_if_canceled())
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 send_terminus_repl(window: sublime.Window, code_block: str): # ensure code block ends with newline, so that it will be executed in REPL if not code_block.endswith("\n"): code_block += "\n" window.run_command("terminus_send_string", { "string": code_block, "tag": JULIA_REPL_TAG })
def show_error_result(window: sublime.Window, message: str) -> None: """show error panel""" panel = window.create_output_panel(ERROR_RESPONSE_PANEL_NAME) panel.set_read_only(False) panel.run_command( "append", {"characters": message}, ) window.run_command("show_panel", {"panel": f"output.{ERROR_RESPONSE_PANEL_NAME}"})
def update_diagnostics_panel(window: sublime.Window): assert window, "missing window!" if not window.is_valid(): debug('ignoring update to closed window') return base_dir = get_project_path(window) diagnostics_by_file = get_window_diagnostics(window) if diagnostics_by_file is not None: active_panel = window.active_panel() is_active_panel = (active_panel == "output.diagnostics") if diagnostics_by_file: panel = ensure_diagnostics_panel(window) assert panel, "must have a panel now!" panel.settings().set("result_base_dir", base_dir) auto_open_panel = False to_render = [] for file_path, source_diagnostics in diagnostics_by_file.items(): try: relative_file_path = os.path.relpath( file_path, base_dir) if base_dir else file_path except ValueError: relative_file_path = file_path if source_diagnostics: formatted = format_diagnostics(relative_file_path, source_diagnostics) if formatted: to_render.append(formatted) if not auto_open_panel: auto_open_panel = has_relevant_diagnostics( source_diagnostics) panel.set_read_only(False) panel.run_command("lsp_update_panel", {"characters": "\n".join(to_render)}) panel.set_read_only(True) if settings.auto_show_diagnostics_panel and not active_panel: if auto_open_panel: window.run_command("show_panel", {"panel": "output.diagnostics"}) else: panel = window.find_output_panel("diagnostics") if panel: panel.run_command("lsp_clear_panel") if is_active_panel: window.run_command("hide_panel", {"panel": "output.diagnostics"})
def run(window: sublime.Window, on_output_callback, args) -> core.awaitable[None]: global on_finished_futures global id id += 1 future = core.create_future() on_finished_futures[id] = future on_output_callbacks[id] = on_output_callback print(args) window.run_command("debugger_build_exec", { "id": id, "args": args, }) return future
def start_terminus_repl(window: sublime.Window, focus: bool): settings = sublime.load_settings(SETTINGS_FILE) julia_executable = settings.get("julia_executable_path") or "julia" # start in current project environment if available cmd = [julia_executable, "--banner=no", "--project"] window.run_command( "terminus_open", { "cmd": cmd, "cwd": "${file_path:${folder}}", "panel_name": JULIA_REPL_NAME, "focus": focus, "tag": JULIA_REPL_TAG, "env": settings.get("repl_env_variables") })
def close_window(window: sublime.Window, *, force: bool = False) -> None: """Close the given window, discarding unsaved changes if `force` is ``True``. :raise ValueError: if any view in the window has unsaved changes and `force` is not ``True``. .. versionadded:: 1.2 """ for view in window.views(): if view.is_dirty() and not view.is_scratch(): if force: view.set_scratch(True) else: raise ValueError('A view has unsaved changes.') window.run_command('close_window')
def sublime_show_input_panel_async( window: sublime.Window, caption: str, initial_text: str, on_change: Optional[Callable[[str], None]] = None) -> awaitable[Optional[str]]: result = create_future() active_panel = window.active_panel() def on_done(value: str) -> None: call_soon_threadsafe(result.set_result, value) def on_cancel() -> None: call_soon_threadsafe(result.set_result, None) view = window.show_input_panel(caption, initial_text, on_done, on_change, on_cancel) r = yield from result # restore the previous panel window.run_command('show_panel', {'panel': '{}'.format(active_panel)}) return r
def close_window(window: sublime.Window, *, force: bool = False) -> None: """Close the given window, discarding unsaved changes if `force` is ``True``. :raise ValueError: if any view in the window has unsaved changes and `force` is not ``True``. .. versionadded:: 1.2 """ unsaved = [ view for view in window.views() if view.is_dirty() and not view.is_scratch() ] if unsaved: if not force: raise ValueError('A view has unsaved changes.') with _temporarily_scratch_unsaved_views(unsaved): window.run_command('close_window') else: window.run_command('close_window')
def open_settings(window: sublime.Window): window.run_command( 'edit_settings', {'base_file': '${packages}/Debugger/debugger.sublime-settings'})
def __init__(self, window: sublime.Window) -> None: # ensure we are being run inside a sublime project # if not prompt the user to create one while True: data = window.project_data() project_name = window.project_file_name() while not data or not project_name: r = sublime.ok_cancel_dialog("Debugger requires a sublime project. Would you like to create a new sublime project?", "Save Project As...") if r: window.run_command('save_project_and_workspace_as') else: raise core.Error("Debugger must be run inside a sublime project") # ensure we have debug configurations added to the project file data.setdefault('settings', {}).setdefault('debug.configurations', []) window.set_project_data(data) break self.project = DebuggerProject(window) autocomplete = Autocomplete.create_for_window(window) self.window = window self.disposeables = [] #type: List[Any] self.breakpoints = Breakpoints(); self.callstack_panel = CallStackPanel() self.breakpoints_panel = BreakpointsPanel(self.breakpoints) self.debugger_panel = DebuggerPanel(self, self.breakpoints_panel) def on_state_changed(state: int) -> None: if state == DebuggerStateful.stopped: self.debugger_panel.setState(STOPPED) self.show_console_panel() elif state == DebuggerStateful.running: self.debugger_panel.setState(RUNNING) elif state == DebuggerStateful.paused: self.debugger_panel.setState(PAUSED) if get_setting(self.view, 'bring_window_to_front_on_pause', False): # is there a better way to bring sublime to the front?? # this probably doesn't work for most people. subl needs to be in PATH file = self.window.active_view().file_name() if file: # ignore any errors try: subprocess.call(["subl", file]) except Exception: pass self.show_call_stack_panel() elif state == DebuggerStateful.stopping or state == DebuggerStateful.starting: self.debugger_panel.setState(LOADING) def on_scopes(scopes: List[dap.Scope]) -> None: self.variables_panel.set_scopes(scopes) def on_selected_frame(thread: Optional[dap.Thread], frame: Optional[dap.StackFrame]) -> None: if frame and thread and frame.source: self.source_provider.select(frame.source, frame.line, thread.stopped_text) else: self.source_provider.clear() def on_output(event: dap.OutputEvent) -> None: self.terminal.program_output(self.debugger.adapter, event) def on_threads_stateful(threads: Any): self.callstack_panel.update(self.debugger, threads) from .diff import DiffCollection from .terminal import Terminal def on_terminal_added(terminal: Terminal): component = TerminalComponent(terminal) panel = TabbedPanelItem(id(terminal), component, terminal.name(), 0, component.action_buttons()) def on_modified(): self.panels.modified(panel) terminal.on_updated.add(on_modified) self.panels.add([panel]) def on_terminal_removed(terminal: Terminal): self.panels.remove(id(terminal)) terminals = DiffCollection(on_terminal_added, on_terminal_removed) def on_terminals(list: Any): terminals.update(list) self.debugger = DebuggerStateful( self.breakpoints, on_state_changed=on_state_changed, on_scopes=on_scopes, on_output=on_output, on_selected_frame=on_selected_frame, on_threads_stateful=on_threads_stateful, on_terminals=on_terminals) self.variables_panel = VariablesPanel(self.breakpoints, self.debugger.watch) self.panel = OutputPhantomsPanel(window, 'Debugger') self.panel.show() self.view = self.panel.view #type: sublime.View self.persistance = PersistedData(project_name) self.load_data() self.load_settings_and_configurations() self.disposeables.extend([ self.panel, ]) self.disposeables.append(WindowSettingsCallback(self.window, self.on_settings_updated)) phantom_location = self.panel.phantom_location() phantom_view = self.panel.phantom_view() self.disposeables.extend([ ui.Phantom(self.debugger_panel, phantom_view, sublime.Region(phantom_location, phantom_location + 0), sublime.LAYOUT_INLINE), ]) callstack_panel_item = TabbedPanelItem(id(self.callstack_panel), self.callstack_panel, "Call Stack", 0) variables_panel_item = TabbedPanelItem(id(self.variables_panel), self.variables_panel, "Variables", 1) self.terminal = DebuggerTerminal( on_run_command=self.on_run_command, on_clicked_source=self.on_navigate_to_source ) terminal_component = TerminalComponent(self.terminal) terminal_panel_item = TabbedPanelItem(id(self.terminal), terminal_component, self.terminal.name(), 0) modules_panel = TabbedPanelItem(id(self.debugger.modules), ModulesView(self.debugger.modules), "Modules", 1) sources_panel = TabbedPanelItem(id(self.debugger.sources), SourcesView(self.debugger.sources), "Sources", 1) self.terminal.log_info('Opened In Workspace: {}'.format(os.path.dirname(project_name))) self.panels = Panels(phantom_view, phantom_location + 1, 3) self.panels.add([ callstack_panel_item, variables_panel_item, terminal_panel_item, modules_panel, sources_panel ]) view_hover = ViewHoverProvider(self.project, self.debugger) self.disposeables.append(view_hover) self.source_provider = ViewSelectedSourceProvider(self.project, self.debugger) self.disposeables.append(self.source_provider) self.breakpoints_provider = BreakpointCommandsProvider(self.project, self.debugger, self.breakpoints) self.disposeables.append(self.breakpoints_provider)
def toggle_output_panel(window: Window, panel_type: str) -> None: panel_name = "output.{}".format(panel_type) command = "{}_panel".format("hide" if window.active_panel() == panel_name else "show") window.run_command(command, {"panel": panel_name})
def __init__(self, window: sublime.Window): super().__init__() # ensure we are being run inside a sublime project # if not prompt the user to create one while True: data = window.project_data() project_name = window.project_file_name() while not project_name: r = sublime.ok_cancel_dialog( "Debugger requires a sublime project. Would you like to create a new sublime project?", "Save Project As...") if r: window.run_command('save_project_and_workspace_as') else: raise core.Error( "Debugger must be run inside a sublime project") # ensure we have debug configurations added to the project file data.setdefault('settings', {}).setdefault('debug.configurations', []) window.set_project_data(data) break self.name = project_name self.window = window self.on_updated: core.Event[None] = core.Event() self.compounds: List[ConfigurationCompound] = [] self.configurations: List[Configuration] = [] self.external_terminal_kind = 'platform' self.ui_scale = 12 self.bring_window_to_front_on_pause = False self.panel = self.window.create_output_panel("Debugger") self.panel_show() # we need enough space to place our phantoms in increasing regions (1, 1), (1, 2)... etc # otherwise they will get reordered when one of them gets redrawn # we use new lines so we don't have extra space on the rhs self.panel.run_command('insert', {'characters': _phantom_text}) settings = self.panel.settings() settings.set("margin", 0) settings.set('line_padding_top', 1) settings.set('gutter', False) settings.set('word_wrap', False) settings.set('line_spacing', 0) settings.set('context_menu', 'Widget Debug.sublime-menu') self.panel.sel().clear() # hack to get view to not freak out when clicking the edge of the window self.panel.set_viewport_position((_panel_position, 0), animate=False) async def later(): await core.sleep(0) self.panel.set_viewport_position((_panel_position, 0), animate=False) core.run(later()) self.reload()