Exemple #1
0
	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()
Exemple #2
0
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]
Exemple #3
0
	async def _insert_snippet(window: sublime.Window, snippet: dict[str, Any]):
		for (key, value) in snippet.items():
			if isinstance(value, str) and value.startswith('^"') and value.endswith('"'):
				snippet[key] = value[2:-1]

		content = json.dumps(snippet, indent="\t")
		content = content.replace('\\\\', '\\') # remove json encoded \ ...
		content = content.replace('${workspaceFolder}', '${folder}')

		try:

			project = window.project_file_name()
			if not project:
				raise core.Error('Expected project file in window')

			view = await core.sublime_open_file_async(window, project)
			region = view.find(r'''"\s*debugger_configurations\s*"\s*:\s*\[''', 0)
			if not region:
				raise core.Error('Unable to find debugger_configurations')

			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 + ','
			})
		except core.Error as e:
			sublime.set_clipboard(content)
			core.display('Unable to insert configuration into sublime-project file: Copied to clipboard instead')
Exemple #4
0
 async def _insert_snippet(window: sublime.Window, snippet: dict):
     content = json.dumps(snippet, indent="\t")
     content = content.replace('\\\\', '\\')  # remove json encoded \ ...
     project = window.project_file_name()
     if project:
         view = await 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'
         )
Exemple #5
0
	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)
Exemple #6
0
	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)
Exemple #7
0
    def __init__(self, window: sublime.Window) -> None:

        data = window.project_data()
        project_name = window.project_file_name()
        if not data or not project_name:
            sublime.error_message(
                "Debugger must be run inside a sublime project")
            return

        # ensure we have debug configurations added to the project file
        data.setdefault('settings', {}).setdefault('debug.configurations', [])
        window.set_project_data(data)

        ui.set_create_input_handler(window, self.create_input_handler)
        self.input_open = False
        self.window = window
        self.disposeables = []  #type: List[Any]
        self.breakpoints = Breakpoints()

        self.console_panel = ConsolePanel(self.open_repl_console)
        self.variables_panel = VariablesPanel()
        self.callstack_panel = CallStackPanel()
        self.breakpoints_panel = BreakpointsComponent(
            self.breakpoints, self.onSelectedBreakpoint)

        self.pages_panel = TabbedPanel([
            ("Breakpoints", self.breakpoints_panel, None),
            ("Call Stack", self.callstack_panel, None),
            ("Console", self.console_panel, self.console_panel.change_filter),
        ], 0)
        self.debugger_panel = DebuggerPanel(self.breakpoints, self)

        self.selected_frame_line = None  #type: Optional[SelectedLine]
        self.selected_frame_generated_view = None  #type: Optional[sublime.View]

        self.breakpointInformation = None  #type: Optional[Any]

        def on_state_changed(state: int) -> None:
            if state == DebuggerState.stopped:
                self.breakpoints.clear_breakpoint_results()
                self.debugger_panel.setState(STOPPED)
                self.show_console_panel()
            elif state == DebuggerState.running:
                self.debugger_panel.setState(RUNNING)
            elif state == DebuggerState.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 == DebuggerState.stopping or state == DebuggerState.starting:
                self.debugger_panel.setState(LOADING)

        def on_threads(threads: List[Thread]) -> None:
            self.callstack_panel.update(self.debugger, threads)

        def on_scopes(scopes: List[Scope]) -> None:
            self.variables_panel.set_scopes(scopes)

        def on_selected_frame(thread: Optional[Thread],
                              frame: Optional[StackFrame]) -> None:
            if frame and thread:
                self.run_async(self.navigate_to_frame(thread, frame))
            else:
                self.dispose_selected_frame()

        def on_output(event: OutputEvent) -> None:
            category = event.category
            msg = event.text
            variablesReference = event.variablesReference

            if variablesReference and self.debugger.adapter:
                # this seems to be what vscode does it ignores the actual message here.
                # Some of the messages are junk like "output" that we probably don't want to display
                @core. async
                def appendVariabble() -> core.awaitable[None]:
                    variables = yield from self.debugger.adapter.GetVariables(
                        variablesReference)
                    for variable in variables:
                        variable.name = ""  # this is what vs code does?
                        self.console_panel.AddVariable(variable)
                    self.pages_panel.modified(2)

                # this could make variable messages appear out of order. Do we care??
                self.run_async(appendVariabble())

            elif category == "stdout":
                self.console_panel.AddStdout(msg)
                self.pages_panel.modified(2)
            elif category == "stderr":
                self.console_panel.AddStderr(msg)
                self.pages_panel.modified(2)
            elif category == "telemetry":
                pass
            elif category == "output":
                self.console_panel.AddStdout(msg)
                self.pages_panel.modified(2)
            elif category == "error":
                self.console_panel.AddStderr(msg)
                self.pages_panel.modified(2)
            elif category == "info":
                self.console_panel.Add(msg)
                self.pages_panel.modified(2)
            else:
                self.console_panel.AddOutputOther(msg)
                self.pages_panel.modified(2)

        self.debugger = DebuggerState(on_state_changed=on_state_changed,
                                      on_threads=on_threads,
                                      on_scopes=on_scopes,
                                      on_output=on_output,
                                      on_selected_frame=on_selected_frame)

        self.panel = OutputPhantomsPanel(window, 'Debugger')
        self.panel.show()
        self.view = self.panel.view  #type: sublime.View

        self.persistance = PersistedData(project_name)

        for breakpoint in self.persistance.load_breakpoints():
            self.breakpoints.add(breakpoint)

        self.load_configurations()

        self.stopped_reason = ''
        self.path = window.project_file_name()
        if self.path:
            self.path = os.path.dirname(self.path)
            self.console_panel.Add('Opened In Workspace: {}'.format(self.path))
        else:
            self.console_panel.AddStderr(
                'warning: debugger opened in a window that is not part of a project'
            )

        print('Creating a window: h')

        self.disposeables.extend([
            self.panel,
            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),
        ])

        offset = self.panel.phantom_location()

        self.disposeables.extend([
            ui.Phantom(self.debugger_panel, self.view,
                       sublime.Region(offset, offset + 0),
                       sublime.LAYOUT_INLINE),
            ui.Phantom(self.pages_panel, self.view,
                       sublime.Region(offset, offset + 1),
                       sublime.LAYOUT_INLINE),
            ui.Phantom(self.variables_panel, self.view,
                       sublime.Region(offset, offset + 2),
                       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)

        active_view = self.window.active_view()

        if active_view:
            self.disposeables.append(
                register_on_changed_setting(active_view,
                                            self.on_settings_updated))
        else:
            print('Failed to find active view to listen for settings changes')
    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()