diff --git a/plugins/extensions/pykrita/plugin/plugins/scripter/debugcontroller.py b/plugins/extensions/pykrita/plugin/plugins/scripter/debugcontroller.py --- a/plugins/extensions/pykrita/plugin/plugins/scripter/debugcontroller.py +++ b/plugins/extensions/pykrita/plugin/plugins/scripter/debugcontroller.py @@ -46,15 +46,27 @@ def currentLine(self): try: if self._debugger: - return int(self._debugger.application_data['lineNumber']) + return int(self._debugger.application_data['code']['lineNumber']) except: return 0 def updateUIDebugger(self): + widget = self.scripter.uicontroller.findStackWidget('Debugger') + if not self.isActive or self._quitDebugger(): - widget = self.scripter.uicontroller.findStackWidget('Debugger') widget.disableToolbar(True) + self.scripter.uicontroller.repaintDebugArea() + widget.updateWidget() + + @property + def debuggerData(self): + try: + if self._debugger: + return self._debugger.application_data + except: + return + def _quitDebugger(self): try: diff --git a/plugins/extensions/pykrita/plugin/plugins/scripter/debugger_scripter/debugger.py b/plugins/extensions/pykrita/plugin/plugins/scripter/debugger_scripter/debugger.py --- a/plugins/extensions/pykrita/plugin/plugins/scripter/debugger_scripter/debugger.py +++ b/plugins/extensions/pykrita/plugin/plugins/scripter/debugger_scripter/debugger.py @@ -2,6 +2,7 @@ import asyncio import inspect import multiprocessing +import re class Debugger(bdb.Bdb): @@ -26,17 +27,26 @@ def user_line(self, frame): """Handler that executes with every line of code""" - self.setCurrentLine(frame.f_lineno) - self.applicationq.put({ "lineNumber": self.getCurrentLine()}) + co = frame.f_code + self.currentLine = frame.f_lineno + self.applicationq.put({ "code": { "file": co.co_filename, + "name": co.co_name, + "lineNumber": str(frame.f_lineno) + }, + "frame": { "firstLineNumber": co.co_firstlineno, + "locals": self.format_data(frame.f_locals), + "globals": self.format_data(frame.f_globals) + }, + "trace": "line" + }) if self.quit: return self.set_quit() - if self.getCurrentLine()==0: + if self.currentLine==0: return else: # Get a reference to the code object and source - co = frame.f_code source = inspect.getsourcelines(co)[0] # Wait for a debug command @@ -58,19 +68,28 @@ def user_exception(self, frame, exception): name = frame.f_code.co_name or "" - def getCurrentLine(self): - return self.currentLine + def format_data(self, data): + globals()['types'] = __import__('types') + + exclude_keys = ['copyright', 'credits', 'False', + 'True', 'None', 'Ellipsis', 'quit'] + exclude_valuetypes = [types.BuiltinFunctionType, + types.BuiltinMethodType, + types.ModuleType, + types.FunctionType] + + return [{k: v} for k, v in data.items() if not (k in exclude_keys or + type(v) in exclude_valuetypes or + re.search(r'^(__).*\1$', k))] - def setCurrentLine(self, line): - self.currentLine = line async def display(self): """Coroutine for updating the UI""" # Wait for the application queue to have an update to the GUI while True: if self.applicationq.empty(): - await asyncio.sleep(0.5) + await asyncio.sleep(0.3) else: # The application queue has at least one item, let's act on every item that's in it while not self.applicationq.empty(): @@ -91,3 +110,5 @@ async def stop(self): # Tell the debugger we're stopping execution self.debugq.put("stop") + self.applicationq.put({ "quit": True}) + await self.display() diff --git a/plugins/extensions/pykrita/plugin/plugins/scripter/ui_scripter/editor/pythoneditor.py b/plugins/extensions/pykrita/plugin/plugins/scripter/ui_scripter/editor/pythoneditor.py --- a/plugins/extensions/pykrita/plugin/plugins/scripter/ui_scripter/editor/pythoneditor.py +++ b/plugins/extensions/pykrita/plugin/plugins/scripter/ui_scripter/editor/pythoneditor.py @@ -105,7 +105,7 @@ bottom = top + int(self.blockBoundingRect(block).height()) painter = QPainter(self.debugArea) - painter.fillRect(0, top, self.debugAreaWidth()-3, int(self.blockBoundingRect(block).height()), QColor(Qt.yellow).darker(300)) + painter.fillRect(0, top, self.debugAreaWidth()-3, int(self.blockBoundingRect(block).height()), QColor(Qt.yellow)) def highlightCurrentLine(self): """Highlight current line under cursor""" diff --git a/plugins/extensions/pykrita/plugin/plugins/scripter/ui_scripter/stackwidgets/debuggerwidget/debuggertable.py b/plugins/extensions/pykrita/plugin/plugins/scripter/ui_scripter/stackwidgets/debuggerwidget/debuggertable.py new file mode 100644 --- /dev/null +++ b/plugins/extensions/pykrita/plugin/plugins/scripter/ui_scripter/stackwidgets/debuggerwidget/debuggertable.py @@ -0,0 +1,38 @@ +from PyQt5.QtWidgets import QTableWidget, QTableWidgetItem + + +class DebuggerTable(QTableWidget): + + def __init__(self, parent=None): + super(DebuggerTable, self).__init__(parent) + + self.setRowCount(10) + self.setColumnCount(4) + + tableHeader = ['Scope', 'Name', 'Value', 'Type'] + self.setHorizontalHeaderLabels(tableHeader) + self.setEditTriggers(self.NoEditTriggers) + + def updateTable(self, data): + self.clearContents() + + if data and not data.get('quit'): + line = 0 + locals_list = data['frame']['locals'] + globals_list = data['frame']['globals'] + + for item in locals_list: + for key, value in item.items(): + self.setItem(line, 0, QTableWidgetItem('locals')) + self.setItem(line, 1, QTableWidgetItem(key)) + self.setItem(line, 2, QTableWidgetItem(str(value))) + self.setItem(line, 3, QTableWidgetItem(str(type(value)))) + line += 1 + + for item in globals_list: + for key, value in item.items(): + self.setItem(line, 0, QTableWidgetItem('globals')) + self.setItem(line, 1, QTableWidgetItem(key)) + self.setItem(line, 2, QTableWidgetItem(str(value))) + self.setItem(line, 3, QTableWidgetItem(str(type(value)))) + line += 1 diff --git a/plugins/extensions/pykrita/plugin/plugins/scripter/ui_scripter/stackwidgets/debuggerwidget/debuggerwidget.py b/plugins/extensions/pykrita/plugin/plugins/scripter/ui_scripter/stackwidgets/debuggerwidget/debuggerwidget.py --- a/plugins/extensions/pykrita/plugin/plugins/scripter/ui_scripter/stackwidgets/debuggerwidget/debuggerwidget.py +++ b/plugins/extensions/pykrita/plugin/plugins/scripter/ui_scripter/stackwidgets/debuggerwidget/debuggerwidget.py @@ -1,5 +1,5 @@ from PyQt5.QtWidgets import QWidget, QVBoxLayout, QToolBar, QTableWidget, QAction -from . import stepaction, stopaction +from . import stepaction, stopaction, debuggertable class DebuggerWidget(QWidget): @@ -18,7 +18,7 @@ self.toolbar.addAction(self.stepAction) self.disableToolbar(True) - self.table = QTableWidget(4, 4) + self.table = debuggertable.DebuggerTable() self.layout.addWidget(self.toolbar) self.layout.addWidget(self.table) @@ -30,3 +30,7 @@ def disableToolbar(self, status): for action in self.toolbar.actions(): action.setDisabled(status) + + def updateWidget(self): + data = self.scripter.debugcontroller.debuggerData + self.table.updateTable(data)