vibefpmgui.debug_panel
The Debug panel: the session's state and controls (the Debug menu's
actions), the call stack, the variables (expanded as asked for: an array's
elements, a type's components) and the console: the program's output and the
debugger's messages, with a field to evaluate an expression in the frame
shown. It shows what vibefpmgui.debug_session.DebugSession says; the window
(vibefpmgui.window.debugging) connects them.
1"""The Debug panel: the session's state and controls (the Debug menu's 2actions), the call stack, the variables (expanded as asked for: an array's 3elements, a type's components) and the console: the program's output and the 4debugger's messages, with a field to evaluate an expression in the frame 5shown. It shows what `vibefpmgui.debug_session.DebugSession` says; the window 6(`vibefpmgui.window.debugging`) connects them. 7""" 8 9from __future__ import annotations 10 11from qtpy.QtCore import QSize, Qt, Signal 12from qtpy.QtGui import QAction, QTextCursor 13from qtpy.QtWidgets import ( 14 QHBoxLayout, 15 QLabel, 16 QListWidget, 17 QListWidgetItem, 18 QPlainTextEdit, 19 QSplitter, 20 QToolButton, 21 QTreeWidget, 22 QTreeWidgetItem, 23 QVBoxLayout, 24 QWidget, 25) 26 27from .breakpoints_list import BreakpointsList 28from .build_monitor import PALETTES, TitleIcon, app_is_light 29from .debug_session import ( 30 IDLE, 31 RUNNING, 32 STARTING, 33 STOPPED, 34 DebugSession, 35 Frame, 36 Scope, 37 Variable, 38) 39from .widgets import HistoryLineEdit 40 41REFERENCE_ROLE = Qt.UserRole + 1 # a variable's item: its variablesReference (0: no parts) 42LOADED_ROLE = Qt.UserRole + 2 # its parts asked for already 43PLACEHOLDER = "…" # (an item's child until its parts are asked for) 44 45STATE_TEXT = {IDLE: "Not debugging", STARTING: "Starting…", RUNNING: "Running", STOPPED: "Paused"} 46 47 48class DebugPanel(QWidget): 49 frame_chosen = Signal(int) # a call stack row clicked (its index) 50 51 def __init__(self, session: DebugSession, actions: list[QAction], breakpoint_actions: list[QAction] = (), 52 parent=None): 53 """``actions``: the buttons (the Debug menu's); ``breakpoint_actions``: in 54 the breakpoints list's right-click menu (Disable All, Remove All).""" 55 super().__init__(parent) 56 self.session = session 57 self.title_icon = TitleIcon("bug") # (as the other panels': see refresh_palette) 58 self.title = QLabel() 59 self.title.setTextInteractionFlags(Qt.TextSelectableByMouse) 60 header = QHBoxLayout() 61 header.setContentsMargins(8, 4, 6, 2) 62 header.addWidget(self.title_icon) 63 header.addSpacing(2) 64 header.addWidget(self.title, 1) 65 for action in actions: # (the Debug menu's: Continue, Step Over…; their icons, tooltips saying which) 66 button = QToolButton() 67 button.setDefaultAction(action) 68 button.setToolButtonStyle(Qt.ToolButtonIconOnly) 69 button.setIconSize(QSize(18, 18)) 70 button.setAutoRaise(True) 71 header.addWidget(button) 72 73 self.stack = QListWidget() 74 self.stack.currentRowChanged.connect(self._frame_clicked) 75 self.variables = QTreeWidget() 76 self.variables.setHeaderLabels(["Name", "Value"]) 77 self.variables.setColumnWidth(0, 160) 78 self.variables.itemExpanded.connect(self._expanded) 79 self.console = QPlainTextEdit() 80 self.console.setReadOnly(True) 81 self.console.setMaximumBlockCount(5000) 82 self.evaluate_edit = HistoryLineEdit() # (Up, Down: the expressions evaluated before) 83 self.evaluate_edit.setPlaceholderText("Evaluate in the frame shown (e.g. a(2:3), p%x), Enter; ↑↓ earlier ones") 84 self.evaluate_edit.submitted.connect(self._evaluate) 85 86 self.breakpoints = BreakpointsList(breakpoint_actions) # (filled by the window: see window.debugging) 87 left = QSplitter(Qt.Vertical) 88 left.addWidget(_titled("Call Stack", self.stack)) 89 left.addWidget(_titled("Breakpoints", self.breakpoints)) 90 middle = _titled("Variables", self.variables) 91 console_box = QWidget() 92 console_layout = QVBoxLayout(console_box) 93 console_layout.setContentsMargins(0, 0, 0, 0) 94 console_layout.setSpacing(2) 95 console_layout.addWidget(_titled("Console", self.console), 1) 96 console_layout.addWidget(self.evaluate_edit) 97 split = QSplitter(Qt.Horizontal) 98 split.addWidget(left) 99 split.addWidget(middle) 100 split.addWidget(console_box) 101 split.setStretchFactor(0, 2) 102 split.setStretchFactor(1, 3) 103 split.setStretchFactor(2, 3) 104 layout = QVBoxLayout(self) 105 layout.setContentsMargins(0, 0, 0, 0) 106 layout.setSpacing(2) 107 layout.addLayout(header) 108 layout.addWidget(split, 1) 109 110 session.state_changed.connect(self._state_changed) 111 session.stopped_at.connect(self._stopped) 112 session.scopes_ready.connect(self._scopes) 113 session.output.connect(self.append) 114 session.ended.connect(lambda why: self.append("console", f"[{why}]\n")) 115 self._state_changed(session.state) 116 self.refresh_palette() 117 118 def refresh_palette(self): 119 """The icon in the theme's text color (again when the theme changes).""" 120 self.title_icon.draw(PALETTES["light" if app_is_light() else "dark"]["text"], self.title) 121 122 # ---------------------------------------------------------- state 123 def _state_changed(self, state: str): 124 adapter = self.session.adapter 125 debugger = f" · {adapter.title}" if adapter is not None and state != IDLE else "" 126 self.title.setText(f"<b>{STATE_TEXT.get(state, state)}</b>{debugger}") 127 self.evaluate_edit.setEnabled(state == STOPPED) 128 if state != STOPPED: 129 self.stack.clear() 130 self.variables.clear() 131 132 def begin(self, what: str): 133 """A new session (``what``: the program): the console cleared.""" 134 self.console.clear() 135 self.append("console", f"[debugging {what}]\n") 136 137 def append(self, category: str, text: str): 138 cursor = self.console.textCursor() 139 cursor.movePosition(QTextCursor.End) 140 cursor.insertText(text) 141 self.console.setTextCursor(cursor) 142 self.console.ensureCursorVisible() 143 144 # ---------------------------------------------------------- the stack 145 def _stopped(self, frames: list[Frame], _why: str): 146 self.stack.blockSignals(True) 147 self.stack.clear() 148 for frame in frames: 149 where = f"{frame.path.rsplit('/', 1)[-1]}:{frame.line}" if frame.path else "(no source)" 150 item = QListWidgetItem(f"{frame_name(frame.name)} · {where}") 151 item.setToolTip(f"{frame.path}:{frame.line}" if frame.path else frame.name) 152 if not frame.path: 153 item.setForeground(self.palette().placeholderText()) 154 self.stack.addItem(item) 155 self.stack.setCurrentRow(self.session.frame_index) 156 self.stack.blockSignals(False) 157 158 def _frame_clicked(self, row: int): 159 if row >= 0: 160 self.frame_chosen.emit(row) 161 162 # ---------------------------------------------------------- the variables 163 def _scopes(self, _index: int, scopes: list[Scope]): 164 self.variables.clear() 165 for number, scope in enumerate(scopes): 166 item = QTreeWidgetItem([scope.name, ""]) 167 item.setData(0, REFERENCE_ROLE, scope.reference) 168 font = item.font(0) 169 font.setBold(True) 170 item.setFont(0, font) 171 self.variables.addTopLevelItem(item) 172 item.addChild(QTreeWidgetItem([PLACEHOLDER, ""])) 173 if number == 0 or not scope.expensive and scope.name.lower() in ("locals", "arguments"): 174 item.setExpanded(True) 175 176 def _expanded(self, item: QTreeWidgetItem): 177 if item.data(0, LOADED_ROLE): 178 return 179 item.setData(0, LOADED_ROLE, True) 180 reference = int(item.data(0, REFERENCE_ROLE) or 0) 181 self.session.variables(reference, lambda variables, more, it=item: self._fill(it, variables, more)) 182 183 def _fill(self, item: QTreeWidgetItem, variables: list[Variable], more: bool): 184 try: 185 item.takeChildren() 186 except RuntimeError: 187 return # (cleared meanwhile: the program moved on) 188 for variable in variables: 189 child = QTreeWidgetItem([variable.name, variable.value]) 190 child.setToolTip(1, variable.value) 191 if variable.type: 192 child.setToolTip(0, variable.type) 193 child.setData(0, REFERENCE_ROLE, variable.reference) 194 if variable.reference: 195 child.addChild(QTreeWidgetItem([PLACEHOLDER, ""])) 196 item.addChild(child) 197 if more: 198 item.addChild(QTreeWidgetItem(["…", "more: evaluate a section, e.g. a(1001:1100)"])) 199 if not variables: 200 item.addChild(QTreeWidgetItem(["(none)", ""])) 201 202 def variable_rows(self) -> list[tuple[str, str]]: 203 """(name, value) of the variables shown, depth first (for the tests).""" 204 rows = [] 205 206 def visit(item: QTreeWidgetItem): 207 for i in range(item.childCount()): 208 child = item.child(i) 209 if child.text(0) != PLACEHOLDER: 210 rows.append((child.text(0), child.text(1))) 211 visit(child) 212 213 for i in range(self.variables.topLevelItemCount()): 214 visit(self.variables.topLevelItem(i)) 215 return rows 216 217 # ---------------------------------------------------------- evaluate 218 def _evaluate(self, expression: str): 219 self.append("console", f"> {expression}\n") 220 self.session.evaluate(expression, lambda ok, text, _ref: self.append("console", f"{text}\n")) 221 222 223def frame_name(name: str) -> str: 224 """A frame's procedure as a Fortran programmer knows it (gfortran calls 225 the main program MAIN__).""" 226 return "main program" if name == "MAIN__" else name 227 228 229def _titled(title: str, widget: QWidget) -> QWidget: 230 box = QWidget() 231 layout = QVBoxLayout(box) 232 layout.setContentsMargins(0, 0, 0, 0) 233 layout.setSpacing(0) 234 label = QLabel(title) 235 label.setContentsMargins(6, 2, 6, 2) 236 font = label.font() 237 font.setBold(True) 238 label.setFont(font) 239 layout.addWidget(label) 240 layout.addWidget(widget, 1) 241 return box
49class DebugPanel(QWidget): 50 frame_chosen = Signal(int) # a call stack row clicked (its index) 51 52 def __init__(self, session: DebugSession, actions: list[QAction], breakpoint_actions: list[QAction] = (), 53 parent=None): 54 """``actions``: the buttons (the Debug menu's); ``breakpoint_actions``: in 55 the breakpoints list's right-click menu (Disable All, Remove All).""" 56 super().__init__(parent) 57 self.session = session 58 self.title_icon = TitleIcon("bug") # (as the other panels': see refresh_palette) 59 self.title = QLabel() 60 self.title.setTextInteractionFlags(Qt.TextSelectableByMouse) 61 header = QHBoxLayout() 62 header.setContentsMargins(8, 4, 6, 2) 63 header.addWidget(self.title_icon) 64 header.addSpacing(2) 65 header.addWidget(self.title, 1) 66 for action in actions: # (the Debug menu's: Continue, Step Over…; their icons, tooltips saying which) 67 button = QToolButton() 68 button.setDefaultAction(action) 69 button.setToolButtonStyle(Qt.ToolButtonIconOnly) 70 button.setIconSize(QSize(18, 18)) 71 button.setAutoRaise(True) 72 header.addWidget(button) 73 74 self.stack = QListWidget() 75 self.stack.currentRowChanged.connect(self._frame_clicked) 76 self.variables = QTreeWidget() 77 self.variables.setHeaderLabels(["Name", "Value"]) 78 self.variables.setColumnWidth(0, 160) 79 self.variables.itemExpanded.connect(self._expanded) 80 self.console = QPlainTextEdit() 81 self.console.setReadOnly(True) 82 self.console.setMaximumBlockCount(5000) 83 self.evaluate_edit = HistoryLineEdit() # (Up, Down: the expressions evaluated before) 84 self.evaluate_edit.setPlaceholderText("Evaluate in the frame shown (e.g. a(2:3), p%x), Enter; ↑↓ earlier ones") 85 self.evaluate_edit.submitted.connect(self._evaluate) 86 87 self.breakpoints = BreakpointsList(breakpoint_actions) # (filled by the window: see window.debugging) 88 left = QSplitter(Qt.Vertical) 89 left.addWidget(_titled("Call Stack", self.stack)) 90 left.addWidget(_titled("Breakpoints", self.breakpoints)) 91 middle = _titled("Variables", self.variables) 92 console_box = QWidget() 93 console_layout = QVBoxLayout(console_box) 94 console_layout.setContentsMargins(0, 0, 0, 0) 95 console_layout.setSpacing(2) 96 console_layout.addWidget(_titled("Console", self.console), 1) 97 console_layout.addWidget(self.evaluate_edit) 98 split = QSplitter(Qt.Horizontal) 99 split.addWidget(left) 100 split.addWidget(middle) 101 split.addWidget(console_box) 102 split.setStretchFactor(0, 2) 103 split.setStretchFactor(1, 3) 104 split.setStretchFactor(2, 3) 105 layout = QVBoxLayout(self) 106 layout.setContentsMargins(0, 0, 0, 0) 107 layout.setSpacing(2) 108 layout.addLayout(header) 109 layout.addWidget(split, 1) 110 111 session.state_changed.connect(self._state_changed) 112 session.stopped_at.connect(self._stopped) 113 session.scopes_ready.connect(self._scopes) 114 session.output.connect(self.append) 115 session.ended.connect(lambda why: self.append("console", f"[{why}]\n")) 116 self._state_changed(session.state) 117 self.refresh_palette() 118 119 def refresh_palette(self): 120 """The icon in the theme's text color (again when the theme changes).""" 121 self.title_icon.draw(PALETTES["light" if app_is_light() else "dark"]["text"], self.title) 122 123 # ---------------------------------------------------------- state 124 def _state_changed(self, state: str): 125 adapter = self.session.adapter 126 debugger = f" · {adapter.title}" if adapter is not None and state != IDLE else "" 127 self.title.setText(f"<b>{STATE_TEXT.get(state, state)}</b>{debugger}") 128 self.evaluate_edit.setEnabled(state == STOPPED) 129 if state != STOPPED: 130 self.stack.clear() 131 self.variables.clear() 132 133 def begin(self, what: str): 134 """A new session (``what``: the program): the console cleared.""" 135 self.console.clear() 136 self.append("console", f"[debugging {what}]\n") 137 138 def append(self, category: str, text: str): 139 cursor = self.console.textCursor() 140 cursor.movePosition(QTextCursor.End) 141 cursor.insertText(text) 142 self.console.setTextCursor(cursor) 143 self.console.ensureCursorVisible() 144 145 # ---------------------------------------------------------- the stack 146 def _stopped(self, frames: list[Frame], _why: str): 147 self.stack.blockSignals(True) 148 self.stack.clear() 149 for frame in frames: 150 where = f"{frame.path.rsplit('/', 1)[-1]}:{frame.line}" if frame.path else "(no source)" 151 item = QListWidgetItem(f"{frame_name(frame.name)} · {where}") 152 item.setToolTip(f"{frame.path}:{frame.line}" if frame.path else frame.name) 153 if not frame.path: 154 item.setForeground(self.palette().placeholderText()) 155 self.stack.addItem(item) 156 self.stack.setCurrentRow(self.session.frame_index) 157 self.stack.blockSignals(False) 158 159 def _frame_clicked(self, row: int): 160 if row >= 0: 161 self.frame_chosen.emit(row) 162 163 # ---------------------------------------------------------- the variables 164 def _scopes(self, _index: int, scopes: list[Scope]): 165 self.variables.clear() 166 for number, scope in enumerate(scopes): 167 item = QTreeWidgetItem([scope.name, ""]) 168 item.setData(0, REFERENCE_ROLE, scope.reference) 169 font = item.font(0) 170 font.setBold(True) 171 item.setFont(0, font) 172 self.variables.addTopLevelItem(item) 173 item.addChild(QTreeWidgetItem([PLACEHOLDER, ""])) 174 if number == 0 or not scope.expensive and scope.name.lower() in ("locals", "arguments"): 175 item.setExpanded(True) 176 177 def _expanded(self, item: QTreeWidgetItem): 178 if item.data(0, LOADED_ROLE): 179 return 180 item.setData(0, LOADED_ROLE, True) 181 reference = int(item.data(0, REFERENCE_ROLE) or 0) 182 self.session.variables(reference, lambda variables, more, it=item: self._fill(it, variables, more)) 183 184 def _fill(self, item: QTreeWidgetItem, variables: list[Variable], more: bool): 185 try: 186 item.takeChildren() 187 except RuntimeError: 188 return # (cleared meanwhile: the program moved on) 189 for variable in variables: 190 child = QTreeWidgetItem([variable.name, variable.value]) 191 child.setToolTip(1, variable.value) 192 if variable.type: 193 child.setToolTip(0, variable.type) 194 child.setData(0, REFERENCE_ROLE, variable.reference) 195 if variable.reference: 196 child.addChild(QTreeWidgetItem([PLACEHOLDER, ""])) 197 item.addChild(child) 198 if more: 199 item.addChild(QTreeWidgetItem(["…", "more: evaluate a section, e.g. a(1001:1100)"])) 200 if not variables: 201 item.addChild(QTreeWidgetItem(["(none)", ""])) 202 203 def variable_rows(self) -> list[tuple[str, str]]: 204 """(name, value) of the variables shown, depth first (for the tests).""" 205 rows = [] 206 207 def visit(item: QTreeWidgetItem): 208 for i in range(item.childCount()): 209 child = item.child(i) 210 if child.text(0) != PLACEHOLDER: 211 rows.append((child.text(0), child.text(1))) 212 visit(child) 213 214 for i in range(self.variables.topLevelItemCount()): 215 visit(self.variables.topLevelItem(i)) 216 return rows 217 218 # ---------------------------------------------------------- evaluate 219 def _evaluate(self, expression: str): 220 self.append("console", f"> {expression}\n") 221 self.session.evaluate(expression, lambda ok, text, _ref: self.append("console", f"{text}\n"))
QWidget(self, /, parent: PySide6.QtWidgets.QWidget | None = None, f: PySide6.QtCore.Qt.WindowType = Default(Qt.WindowFlags), *, modal: bool | None = None, windowModality: PySide6.QtCore.Qt.WindowModality | None = None, enabled: bool | None = None, geometry: PySide6.QtCore.QRect | None = None, frameGeometry: PySide6.QtCore.QRect | None = None, normalGeometry: PySide6.QtCore.QRect | None = None, x: int | None = None, y: int | None = None, pos: PySide6.QtCore.QPoint | None = None, frameSize: PySide6.QtCore.QSize | None = None, size: PySide6.QtCore.QSize | None = None, width: int | None = None, height: int | None = None, rect: PySide6.QtCore.QRect | None = None, childrenRect: PySide6.QtCore.QRect | None = None, childrenRegion: PySide6.QtGui.QRegion | None = None, sizePolicy: PySide6.QtWidgets.QSizePolicy | None = None, minimumSize: PySide6.QtCore.QSize | None = None, maximumSize: PySide6.QtCore.QSize | None = None, minimumWidth: int | None = None, minimumHeight: int | None = None, maximumWidth: int | None = None, maximumHeight: int | None = None, sizeIncrement: PySide6.QtCore.QSize | None = None, baseSize: PySide6.QtCore.QSize | None = None, palette: PySide6.QtGui.QPalette | None = None, font: PySide6.QtGui.QFont | None = None, cursor: PySide6.QtGui.QCursor | None = None, mouseTracking: bool | None = None, tabletTracking: bool | None = None, isActiveWindow: bool | None = None, focusPolicy: PySide6.QtCore.Qt.FocusPolicy | None = None, focus: bool | None = None, contextMenuPolicy: PySide6.QtCore.Qt.ContextMenuPolicy | None = None, updatesEnabled: bool | None = None, visible: bool | None = None, minimized: bool | None = None, maximized: bool | None = None, fullScreen: bool | None = None, sizeHint: PySide6.QtCore.QSize | None = None, minimumSizeHint: PySide6.QtCore.QSize | None = None, acceptDrops: bool | None = None, windowTitle: str | None = None, windowIcon: PySide6.QtGui.QIcon | None = None, windowIconText: str | None = None, windowOpacity: float | None = None, windowModified: bool | None = None, toolTip: str | None = None, toolTipDuration: int | None = None, statusTip: str | None = None, whatsThis: str | None = None, accessibleName: str | None = None, accessibleDescription: str | None = None, accessibleIdentifier: str | None = None, layoutDirection: PySide6.QtCore.Qt.LayoutDirection | None = None, autoFillBackground: bool | None = None, styleSheet: str | None = None, locale: PySide6.QtCore.QLocale | None = None, windowFilePath: str | None = None, inputMethodHints: PySide6.QtCore.Qt.InputMethodHint | None = None) -> None
52 def __init__(self, session: DebugSession, actions: list[QAction], breakpoint_actions: list[QAction] = (), 53 parent=None): 54 """``actions``: the buttons (the Debug menu's); ``breakpoint_actions``: in 55 the breakpoints list's right-click menu (Disable All, Remove All).""" 56 super().__init__(parent) 57 self.session = session 58 self.title_icon = TitleIcon("bug") # (as the other panels': see refresh_palette) 59 self.title = QLabel() 60 self.title.setTextInteractionFlags(Qt.TextSelectableByMouse) 61 header = QHBoxLayout() 62 header.setContentsMargins(8, 4, 6, 2) 63 header.addWidget(self.title_icon) 64 header.addSpacing(2) 65 header.addWidget(self.title, 1) 66 for action in actions: # (the Debug menu's: Continue, Step Over…; their icons, tooltips saying which) 67 button = QToolButton() 68 button.setDefaultAction(action) 69 button.setToolButtonStyle(Qt.ToolButtonIconOnly) 70 button.setIconSize(QSize(18, 18)) 71 button.setAutoRaise(True) 72 header.addWidget(button) 73 74 self.stack = QListWidget() 75 self.stack.currentRowChanged.connect(self._frame_clicked) 76 self.variables = QTreeWidget() 77 self.variables.setHeaderLabels(["Name", "Value"]) 78 self.variables.setColumnWidth(0, 160) 79 self.variables.itemExpanded.connect(self._expanded) 80 self.console = QPlainTextEdit() 81 self.console.setReadOnly(True) 82 self.console.setMaximumBlockCount(5000) 83 self.evaluate_edit = HistoryLineEdit() # (Up, Down: the expressions evaluated before) 84 self.evaluate_edit.setPlaceholderText("Evaluate in the frame shown (e.g. a(2:3), p%x), Enter; ↑↓ earlier ones") 85 self.evaluate_edit.submitted.connect(self._evaluate) 86 87 self.breakpoints = BreakpointsList(breakpoint_actions) # (filled by the window: see window.debugging) 88 left = QSplitter(Qt.Vertical) 89 left.addWidget(_titled("Call Stack", self.stack)) 90 left.addWidget(_titled("Breakpoints", self.breakpoints)) 91 middle = _titled("Variables", self.variables) 92 console_box = QWidget() 93 console_layout = QVBoxLayout(console_box) 94 console_layout.setContentsMargins(0, 0, 0, 0) 95 console_layout.setSpacing(2) 96 console_layout.addWidget(_titled("Console", self.console), 1) 97 console_layout.addWidget(self.evaluate_edit) 98 split = QSplitter(Qt.Horizontal) 99 split.addWidget(left) 100 split.addWidget(middle) 101 split.addWidget(console_box) 102 split.setStretchFactor(0, 2) 103 split.setStretchFactor(1, 3) 104 split.setStretchFactor(2, 3) 105 layout = QVBoxLayout(self) 106 layout.setContentsMargins(0, 0, 0, 0) 107 layout.setSpacing(2) 108 layout.addLayout(header) 109 layout.addWidget(split, 1) 110 111 session.state_changed.connect(self._state_changed) 112 session.stopped_at.connect(self._stopped) 113 session.scopes_ready.connect(self._scopes) 114 session.output.connect(self.append) 115 session.ended.connect(lambda why: self.append("console", f"[{why}]\n")) 116 self._state_changed(session.state) 117 self.refresh_palette()
actions: the buttons (the Debug menu's); breakpoint_actions: in
the breakpoints list's right-click menu (Disable All, Remove All).
119 def refresh_palette(self): 120 """The icon in the theme's text color (again when the theme changes).""" 121 self.title_icon.draw(PALETTES["light" if app_is_light() else "dark"]["text"], self.title)
The icon in the theme's text color (again when the theme changes).
133 def begin(self, what: str): 134 """A new session (``what``: the program): the console cleared.""" 135 self.console.clear() 136 self.append("console", f"[debugging {what}]\n")
A new session (what: the program): the console cleared.
203 def variable_rows(self) -> list[tuple[str, str]]: 204 """(name, value) of the variables shown, depth first (for the tests).""" 205 rows = [] 206 207 def visit(item: QTreeWidgetItem): 208 for i in range(item.childCount()): 209 child = item.child(i) 210 if child.text(0) != PLACEHOLDER: 211 rows.append((child.text(0), child.text(1))) 212 visit(child) 213 214 for i in range(self.variables.topLevelItemCount()): 215 visit(self.variables.topLevelItem(i)) 216 return rows
(name, value) of the variables shown, depth first (for the tests).
224def frame_name(name: str) -> str: 225 """A frame's procedure as a Fortran programmer knows it (gfortran calls 226 the main program MAIN__).""" 227 return "main program" if name == "MAIN__" else name
A frame's procedure as a Fortran programmer knows it (gfortran calls the main program MAIN__).