easycoder 251104.2__py2.py3-none-any.whl → 260108.1__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of easycoder might be problematic. Click here for more details.
- easycoder/__init__.py +6 -3
- easycoder/debugger/__init__.py +5 -0
- easycoder/debugger/ec_dbg_value_display copy.py +195 -0
- easycoder/debugger/ec_dbg_value_display.py +24 -0
- easycoder/debugger/ec_dbg_watch_list copy.py +219 -0
- easycoder/debugger/ec_dbg_watchlist.py +293 -0
- easycoder/debugger/ec_debug.py +1025 -0
- easycoder/ec_border.py +15 -11
- easycoder/ec_classes.py +493 -11
- easycoder/ec_compiler.py +81 -44
- easycoder/ec_condition.py +1 -1
- easycoder/ec_core.py +1043 -1089
- easycoder/ec_gclasses.py +236 -0
- easycoder/ec_graphics.py +1683 -0
- easycoder/ec_handler.py +18 -13
- easycoder/ec_keyboard.py +50 -50
- easycoder/ec_mqtt.py +249 -0
- easycoder/ec_program.py +308 -156
- easycoder/ec_psutil.py +48 -0
- easycoder/ec_timestamp.py +2 -1
- easycoder/ec_value.py +65 -47
- easycoder/icons/exit.png +0 -0
- easycoder/icons/run.png +0 -0
- easycoder/icons/step.png +0 -0
- easycoder/icons/stop.png +0 -0
- easycoder/pre/README.md +3 -0
- easycoder/pre/__init__.py +17 -0
- easycoder/pre/debugger/__init__.py +5 -0
- easycoder/pre/debugger/ec_dbg_value_display copy.py +195 -0
- easycoder/pre/debugger/ec_dbg_value_display.py +24 -0
- easycoder/pre/debugger/ec_dbg_watch_list copy.py +219 -0
- easycoder/pre/debugger/ec_dbg_watchlist.py +293 -0
- easycoder/pre/debugger/ec_debug.py +1014 -0
- easycoder/pre/ec_border.py +67 -0
- easycoder/pre/ec_classes.py +470 -0
- easycoder/pre/ec_compiler.py +291 -0
- easycoder/pre/ec_condition.py +27 -0
- easycoder/pre/ec_core.py +2772 -0
- easycoder/pre/ec_gclasses.py +230 -0
- easycoder/{ec_pyside.py → pre/ec_graphics.py} +631 -496
- easycoder/pre/ec_handler.py +79 -0
- easycoder/pre/ec_keyboard.py +439 -0
- easycoder/pre/ec_program.py +557 -0
- easycoder/pre/ec_psutil.py +48 -0
- easycoder/pre/ec_timestamp.py +11 -0
- easycoder/pre/ec_value.py +124 -0
- easycoder/pre/icons/close.png +0 -0
- easycoder/pre/icons/exit.png +0 -0
- easycoder/pre/icons/run.png +0 -0
- easycoder/pre/icons/step.png +0 -0
- easycoder/pre/icons/stop.png +0 -0
- easycoder/pre/icons/tick.png +0 -0
- {easycoder-251104.2.dist-info → easycoder-260108.1.dist-info}/METADATA +11 -1
- easycoder-260108.1.dist-info/RECORD +59 -0
- easycoder/ec_debug.py +0 -464
- easycoder-251104.2.dist-info/RECORD +0 -20
- /easycoder/{close.png → icons/close.png} +0 -0
- /easycoder/{tick.png → icons/tick.png} +0 -0
- {easycoder-251104.2.dist-info → easycoder-260108.1.dist-info}/WHEEL +0 -0
- {easycoder-251104.2.dist-info → easycoder-260108.1.dist-info}/entry_points.txt +0 -0
- {easycoder-251104.2.dist-info → easycoder-260108.1.dist-info}/licenses/LICENSE +0 -0
easycoder/ec_debug.py
DELETED
|
@@ -1,464 +0,0 @@
|
|
|
1
|
-
import sys, os, json, html
|
|
2
|
-
from PySide6.QtWidgets import (
|
|
3
|
-
QMainWindow,
|
|
4
|
-
QWidget,
|
|
5
|
-
QFrame,
|
|
6
|
-
QHBoxLayout,
|
|
7
|
-
QVBoxLayout,
|
|
8
|
-
QLabel,
|
|
9
|
-
QSplitter,
|
|
10
|
-
QFileDialog,
|
|
11
|
-
QMessageBox,
|
|
12
|
-
QScrollArea,
|
|
13
|
-
QSizePolicy,
|
|
14
|
-
QToolBar
|
|
15
|
-
)
|
|
16
|
-
from PySide6.QtGui import QAction, QKeySequence, QTextCursor
|
|
17
|
-
from PySide6.QtCore import Qt, QTimer, QProcess
|
|
18
|
-
from typing import Any
|
|
19
|
-
|
|
20
|
-
class Object():
|
|
21
|
-
"""Dynamic object that allows arbitrary attribute assignment"""
|
|
22
|
-
def __setattr__(self, name: str, value: Any) -> None:
|
|
23
|
-
self.__dict__[name] = value
|
|
24
|
-
|
|
25
|
-
def __getattr__(self, name: str) -> Any:
|
|
26
|
-
return self.__dict__.get(name)
|
|
27
|
-
|
|
28
|
-
class Debugger(QMainWindow):
|
|
29
|
-
|
|
30
|
-
###########################################################################
|
|
31
|
-
# The left-hand column of the main window
|
|
32
|
-
class MainLeftColumn(QWidget):
|
|
33
|
-
def __init__(self, parent=None):
|
|
34
|
-
super().__init__(parent)
|
|
35
|
-
layout = QVBoxLayout(self)
|
|
36
|
-
layout.addWidget(QLabel("Left column"))
|
|
37
|
-
layout.addStretch()
|
|
38
|
-
|
|
39
|
-
###########################################################################
|
|
40
|
-
# The right-hand column of the main window
|
|
41
|
-
class MainRightColumn(QWidget):
|
|
42
|
-
scroll: QScrollArea
|
|
43
|
-
layout: QHBoxLayout # type: ignore[assignment]
|
|
44
|
-
blob: QLabel
|
|
45
|
-
|
|
46
|
-
def __init__(self, parent=None):
|
|
47
|
-
super().__init__(parent)
|
|
48
|
-
|
|
49
|
-
# Create a scroll area - its content widget holds the lines
|
|
50
|
-
self.scroll = QScrollArea(self)
|
|
51
|
-
self.scroll.setWidgetResizable(True)
|
|
52
|
-
|
|
53
|
-
# Ensure this widget and the scroll area expand to fill available space
|
|
54
|
-
self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
|
55
|
-
self.scroll.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
|
56
|
-
|
|
57
|
-
self.content = QWidget()
|
|
58
|
-
# let the content expand horizontally but have flexible height
|
|
59
|
-
self.content.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
|
|
60
|
-
|
|
61
|
-
self.inner_layout = QVBoxLayout(self.content)
|
|
62
|
-
# spacing and small top/bottom margins to separate lines
|
|
63
|
-
self.inner_layout.setSpacing(0)
|
|
64
|
-
self.inner_layout.setContentsMargins(0, 0, 0, 0)
|
|
65
|
-
|
|
66
|
-
self.scroll.setWidget(self.content)
|
|
67
|
-
|
|
68
|
-
# outer layout for this widget contains only the scroll area
|
|
69
|
-
main_layout = QVBoxLayout(self)
|
|
70
|
-
main_layout.setContentsMargins(0, 0, 0, 0)
|
|
71
|
-
main_layout.addWidget(self.scroll)
|
|
72
|
-
# ensure the scroll area gets the stretch so it fills the parent
|
|
73
|
-
main_layout.setStretch(0, 1)
|
|
74
|
-
|
|
75
|
-
#######################################################################
|
|
76
|
-
# Add a line to the right-hand column
|
|
77
|
-
def addLine(self, spec):
|
|
78
|
-
class Label(QLabel):
|
|
79
|
-
def __init__(self, text, fixed_width=None, align=Qt.AlignmentFlag.AlignLeft, on_click=spec.onClick):
|
|
80
|
-
super().__init__()
|
|
81
|
-
self.setText(text)
|
|
82
|
-
# remove QLabel's internal margins/padding to reduce top/bottom space
|
|
83
|
-
self.setMargin(0)
|
|
84
|
-
self.setContentsMargins(0, 0, 0, 0)
|
|
85
|
-
self.setStyleSheet("padding:0px; margin:0px; font-family: mono")
|
|
86
|
-
fm = self.fontMetrics()
|
|
87
|
-
# set a compact fixed height based on font metrics
|
|
88
|
-
self.setFixedHeight(fm.height())
|
|
89
|
-
# optional fixed width (used for the lino column)
|
|
90
|
-
if fixed_width is not None:
|
|
91
|
-
self.setFixedWidth(fixed_width)
|
|
92
|
-
# align horizontally (keep vertically centered)
|
|
93
|
-
self.setAlignment(align | Qt.AlignmentFlag.AlignVCenter)
|
|
94
|
-
# optional click callback
|
|
95
|
-
self._on_click = on_click
|
|
96
|
-
|
|
97
|
-
def mousePressEvent(self, event):
|
|
98
|
-
if self._on_click:
|
|
99
|
-
try:
|
|
100
|
-
self._on_click()
|
|
101
|
-
except Exception:
|
|
102
|
-
pass
|
|
103
|
-
super().mousePressEvent(event)
|
|
104
|
-
|
|
105
|
-
spec.label = self
|
|
106
|
-
panel = QWidget()
|
|
107
|
-
# ensure the panel itself has no margins
|
|
108
|
-
try:
|
|
109
|
-
panel.setContentsMargins(0, 0, 0, 0)
|
|
110
|
-
except Exception:
|
|
111
|
-
pass
|
|
112
|
-
# tidy layout: remove spacing/margins so lines sit flush
|
|
113
|
-
layout = QHBoxLayout(panel)
|
|
114
|
-
layout.setSpacing(0)
|
|
115
|
-
layout.setContentsMargins(0, 0, 0, 0)
|
|
116
|
-
self.layout: QHBoxLayout = layout # type: ignore
|
|
117
|
-
# make panel take minimal vertical space
|
|
118
|
-
panel.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
|
119
|
-
# compute width to fit a 4-digit line number using this widget's font
|
|
120
|
-
fm_main = self.fontMetrics()
|
|
121
|
-
width_4 = fm_main.horizontalAdvance('0000') + 8
|
|
122
|
-
|
|
123
|
-
# create the red blob (always present). We'll toggle its opacity
|
|
124
|
-
# by changing the stylesheet (rgba alpha 255/0). Do NOT store it
|
|
125
|
-
# on the MainRightColumn instance — keep it per-line.
|
|
126
|
-
blob = QLabel()
|
|
127
|
-
blob_size = 10
|
|
128
|
-
blob.setFixedSize(blob_size, blob_size)
|
|
129
|
-
|
|
130
|
-
def set_blob_visible(widget, visible):
|
|
131
|
-
alpha = 255 if visible else 0
|
|
132
|
-
widget.setStyleSheet(f"background-color: rgba(255,0,0,{alpha}); border-radius: {blob_size//2}px; margin:0px; padding:0px;")
|
|
133
|
-
widget._blob_visible = visible
|
|
134
|
-
# force repaint
|
|
135
|
-
widget.update()
|
|
136
|
-
|
|
137
|
-
# attach methods to this blob so callers can toggle it via spec.label
|
|
138
|
-
blob.showBlob = lambda: set_blob_visible(blob, True) # type: ignore[attr-defined]
|
|
139
|
-
blob.hideBlob = lambda: set_blob_visible(blob, False) # type: ignore[attr-defined]
|
|
140
|
-
|
|
141
|
-
# initialize according to spec flag
|
|
142
|
-
if spec.bp:
|
|
143
|
-
blob.showBlob() # type: ignore[attr-defined]
|
|
144
|
-
else:
|
|
145
|
-
blob.hideBlob() # type: ignore[attr-defined]
|
|
146
|
-
|
|
147
|
-
# expose the blob to the outside via spec['label'] so onClick can call showBlob/hideBlob
|
|
148
|
-
spec.label = blob
|
|
149
|
-
|
|
150
|
-
# create the line-number label; clicking it reports back to the caller
|
|
151
|
-
lino_label = Label(str(spec.lino+1), fixed_width=width_4, align=Qt.AlignmentFlag.AlignRight,
|
|
152
|
-
on_click=lambda: spec.onClick(spec.lino))
|
|
153
|
-
lino_label.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
|
|
154
|
-
# create the text label for the line itself
|
|
155
|
-
text_label = Label(spec.line, fixed_width=None, align=Qt.AlignmentFlag.AlignLeft)
|
|
156
|
-
text_label.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
|
157
|
-
layout.addWidget(lino_label)
|
|
158
|
-
layout.addSpacing(10)
|
|
159
|
-
layout.addWidget(blob, 0, Qt.AlignmentFlag.AlignVCenter)
|
|
160
|
-
layout.addSpacing(3)
|
|
161
|
-
layout.addWidget(text_label)
|
|
162
|
-
self.inner_layout.addWidget(panel)
|
|
163
|
-
return panel
|
|
164
|
-
|
|
165
|
-
def showBlob(self):
|
|
166
|
-
self.blob.setStyleSheet("background-color: red; border-radius: 5px; margin:0px; padding:0px;")
|
|
167
|
-
|
|
168
|
-
def hideBlob(self):
|
|
169
|
-
self.blob.setStyleSheet("background-color: none; border-radius: 5px; margin:0px; padding:0px;")
|
|
170
|
-
|
|
171
|
-
def addStretch(self):
|
|
172
|
-
self.layout.addStretch()
|
|
173
|
-
|
|
174
|
-
###########################################################################
|
|
175
|
-
# Main debugger class initializer
|
|
176
|
-
def __init__(self, program, width=800, height=600, ratio=0.2):
|
|
177
|
-
super().__init__()
|
|
178
|
-
self.program = program
|
|
179
|
-
self.setWindowTitle("EasyCoder Debugger")
|
|
180
|
-
self.setMinimumSize(width, height)
|
|
181
|
-
self.stopped = True
|
|
182
|
-
|
|
183
|
-
# try to load saved geometry from ~/.ecdebug.conf
|
|
184
|
-
cfg_path = os.path.join(os.path.expanduser("~"), ".ecdebug.conf")
|
|
185
|
-
initial_width = width
|
|
186
|
-
# default console height (pixels) if not stored in cfg
|
|
187
|
-
console_height = 150
|
|
188
|
-
try:
|
|
189
|
-
if os.path.exists(cfg_path):
|
|
190
|
-
with open(cfg_path, "r", encoding="utf-8") as f:
|
|
191
|
-
cfg = json.load(f)
|
|
192
|
-
x = int(cfg.get("x", 0))
|
|
193
|
-
y = int(cfg.get("y", 0))
|
|
194
|
-
w = int(cfg.get("width", width))
|
|
195
|
-
h = int(cfg.get("height", height))
|
|
196
|
-
ratio =float(cfg.get("ratio", ratio))
|
|
197
|
-
# load console height if present
|
|
198
|
-
console_height = int(cfg.get("console_height", console_height))
|
|
199
|
-
# Apply loaded geometry
|
|
200
|
-
self.setGeometry(x, y, w, h)
|
|
201
|
-
initial_width = w
|
|
202
|
-
except Exception:
|
|
203
|
-
# ignore errors and continue with defaults
|
|
204
|
-
initial_width = width
|
|
205
|
-
|
|
206
|
-
# process handle for running scripts
|
|
207
|
-
self._proc = None
|
|
208
|
-
# in-process Program instance and writer
|
|
209
|
-
self._program = None
|
|
210
|
-
self._writer = None
|
|
211
|
-
self._orig_stdout = None
|
|
212
|
-
self._orig_stderr = None
|
|
213
|
-
self._flush_timer = None
|
|
214
|
-
|
|
215
|
-
# Keep a ratio so proportions are preserved when window is resized
|
|
216
|
-
self.ratio = ratio
|
|
217
|
-
|
|
218
|
-
# Central horizontal splitter (left/right)
|
|
219
|
-
self.hsplitter = QSplitter(Qt.Orientation.Horizontal, self)
|
|
220
|
-
self.hsplitter.setHandleWidth(8)
|
|
221
|
-
self.hsplitter.splitterMoved.connect(self.on_splitter_moved)
|
|
222
|
-
|
|
223
|
-
# Left pane
|
|
224
|
-
left = QFrame()
|
|
225
|
-
left.setFrameShape(QFrame.Shape.StyledPanel)
|
|
226
|
-
left_layout = QVBoxLayout(left)
|
|
227
|
-
left_layout.setContentsMargins(8, 8, 8, 8)
|
|
228
|
-
self.leftColumn = self.MainLeftColumn()
|
|
229
|
-
left_layout.addWidget(self.leftColumn)
|
|
230
|
-
left_layout.addStretch()
|
|
231
|
-
|
|
232
|
-
# Right pane
|
|
233
|
-
right = QFrame()
|
|
234
|
-
right.setFrameShape(QFrame.Shape.StyledPanel)
|
|
235
|
-
right_layout = QVBoxLayout(right)
|
|
236
|
-
right_layout.setContentsMargins(8, 8, 8, 8)
|
|
237
|
-
self.rightColumn = self.MainRightColumn()
|
|
238
|
-
# Give the rightColumn a stretch factor so its scroll area fills the vertical space
|
|
239
|
-
right_layout.addWidget(self.rightColumn, 1)
|
|
240
|
-
|
|
241
|
-
# Add panes to horizontal splitter
|
|
242
|
-
self.hsplitter.addWidget(left)
|
|
243
|
-
self.hsplitter.addWidget(right)
|
|
244
|
-
|
|
245
|
-
# Initial sizes (proportional) for horizontal splitter
|
|
246
|
-
total = initial_width
|
|
247
|
-
self.hsplitter.setSizes([int(self.ratio * total), int((1 - self.ratio) * total)])
|
|
248
|
-
|
|
249
|
-
# Create a vertical splitter so we can add a resizable console panel at the bottom
|
|
250
|
-
self.vsplitter = QSplitter(Qt.Orientation.Vertical, self)
|
|
251
|
-
self.vsplitter.setHandleWidth(6)
|
|
252
|
-
# top: the existing horizontal splitter
|
|
253
|
-
self.vsplitter.addWidget(self.hsplitter)
|
|
254
|
-
|
|
255
|
-
# bottom: console panel
|
|
256
|
-
console_frame = QFrame()
|
|
257
|
-
console_frame.setFrameShape(QFrame.Shape.StyledPanel)
|
|
258
|
-
console_layout = QVBoxLayout(console_frame)
|
|
259
|
-
console_layout.setContentsMargins(4, 4, 4, 4)
|
|
260
|
-
# simple read-only text console for script output and messages
|
|
261
|
-
from PySide6.QtWidgets import QTextEdit
|
|
262
|
-
self.console = QTextEdit()
|
|
263
|
-
self.console.setReadOnly(True)
|
|
264
|
-
console_layout.addWidget(self.console)
|
|
265
|
-
self.vsplitter.addWidget(console_frame)
|
|
266
|
-
|
|
267
|
-
# Set initial vertical sizes: prefer saved console_height if available
|
|
268
|
-
try:
|
|
269
|
-
total_h = int(h) if 'h' in locals() else max(300, self.height())
|
|
270
|
-
ch = max(50, min(total_h - 50, console_height))
|
|
271
|
-
self.vsplitter.setSizes([int(total_h - ch), int(ch)])
|
|
272
|
-
except Exception:
|
|
273
|
-
pass
|
|
274
|
-
|
|
275
|
-
# Use the vertical splitter as the central widget
|
|
276
|
-
self.setCentralWidget(self.vsplitter)
|
|
277
|
-
self.parse(program.script.lines)
|
|
278
|
-
self.show()
|
|
279
|
-
|
|
280
|
-
def on_splitter_moved(self, pos, index):
|
|
281
|
-
# Update stored ratio when user drags the splitter
|
|
282
|
-
left_width = self.hsplitter.widget(0).width()
|
|
283
|
-
total = max(1, sum(w.width() for w in (self.hsplitter.widget(0), self.hsplitter.widget(1))))
|
|
284
|
-
self.ratio = left_width / total
|
|
285
|
-
|
|
286
|
-
def resizeEvent(self, event):
|
|
287
|
-
# Preserve the proportional widths when the window is resized
|
|
288
|
-
total_width = max(1, self.width())
|
|
289
|
-
left_w = max(0, int(self.ratio * total_width))
|
|
290
|
-
right_w = max(0, total_width - left_w)
|
|
291
|
-
self.hsplitter.setSizes([left_w, right_w])
|
|
292
|
-
super().resizeEvent(event)
|
|
293
|
-
|
|
294
|
-
###########################################################################
|
|
295
|
-
# Parse a script into the right-hand column
|
|
296
|
-
def parse(self, script):
|
|
297
|
-
self.scriptLines = []
|
|
298
|
-
# Clear existing lines from the right column layout
|
|
299
|
-
layout = self.rightColumn.inner_layout
|
|
300
|
-
while layout.count():
|
|
301
|
-
item = layout.takeAt(0)
|
|
302
|
-
widget = item.widget()
|
|
303
|
-
if widget:
|
|
304
|
-
widget.deleteLater()
|
|
305
|
-
|
|
306
|
-
# Parse and add new lines
|
|
307
|
-
lino = 0
|
|
308
|
-
for line in script:
|
|
309
|
-
if len(line) > 0:
|
|
310
|
-
line = line.replace("\t", " ")
|
|
311
|
-
line = self.coloriseLine(line, lino)
|
|
312
|
-
else:
|
|
313
|
-
# still need to call coloriseLine to keep token list in sync
|
|
314
|
-
self.coloriseLine(line, lino)
|
|
315
|
-
lineSpec = Object()
|
|
316
|
-
lineSpec.lino = lino
|
|
317
|
-
lineSpec.line = line
|
|
318
|
-
lineSpec.bp = False
|
|
319
|
-
lineSpec.onClick = self.onClickLino
|
|
320
|
-
lino += 1
|
|
321
|
-
self.scriptLines.append(lineSpec)
|
|
322
|
-
lineSpec.panel = self.rightColumn.addLine(lineSpec)
|
|
323
|
-
self.rightColumn.addStretch()
|
|
324
|
-
|
|
325
|
-
###########################################################################
|
|
326
|
-
# Colorise a line of script for HTML display
|
|
327
|
-
def coloriseLine(self, line, lino=None):
|
|
328
|
-
output = ''
|
|
329
|
-
|
|
330
|
-
# Preserve leading spaces (render as except the first)
|
|
331
|
-
if len(line) > 0 and line[0] == ' ':
|
|
332
|
-
output += '<span>'
|
|
333
|
-
n = 0
|
|
334
|
-
while n < len(line) and line[n] == ' ': n += 1
|
|
335
|
-
output += ' ' * (n - 1)
|
|
336
|
-
output += '</span>'
|
|
337
|
-
|
|
338
|
-
# Find the first unquoted ! (not inside backticks)
|
|
339
|
-
comment_start = None
|
|
340
|
-
in_backtick = False
|
|
341
|
-
for idx, c in enumerate(line):
|
|
342
|
-
if c == '`':
|
|
343
|
-
in_backtick = not in_backtick
|
|
344
|
-
elif c == '!' and not in_backtick:
|
|
345
|
-
comment_start = idx
|
|
346
|
-
break
|
|
347
|
-
|
|
348
|
-
if comment_start is not None:
|
|
349
|
-
code_part = line[:comment_start]
|
|
350
|
-
comment_part = line[comment_start:]
|
|
351
|
-
else:
|
|
352
|
-
code_part = line
|
|
353
|
-
comment_part = None
|
|
354
|
-
|
|
355
|
-
# Tokenize code_part as before (respecting backticks)
|
|
356
|
-
tokens = []
|
|
357
|
-
i = 0
|
|
358
|
-
L = len(code_part)
|
|
359
|
-
while i < L:
|
|
360
|
-
if code_part[i].isspace():
|
|
361
|
-
i += 1
|
|
362
|
-
continue
|
|
363
|
-
if code_part[i] == '`':
|
|
364
|
-
j = code_part.find('`', i + 1)
|
|
365
|
-
if j == -1:
|
|
366
|
-
tokens.append(code_part[i:])
|
|
367
|
-
break
|
|
368
|
-
else:
|
|
369
|
-
tokens.append(code_part[i:j+1])
|
|
370
|
-
i = j + 1
|
|
371
|
-
else:
|
|
372
|
-
j = i
|
|
373
|
-
while j < L and not code_part[j].isspace():
|
|
374
|
-
j += 1
|
|
375
|
-
tokens.append(code_part[i:j])
|
|
376
|
-
i = j
|
|
377
|
-
|
|
378
|
-
# Colour code tokens and generate a list of elements
|
|
379
|
-
for token in tokens:
|
|
380
|
-
if token == '':
|
|
381
|
-
continue
|
|
382
|
-
elif token[0].isupper():
|
|
383
|
-
esc = html.escape(token)
|
|
384
|
-
element = f' <span style="color: purple; font-weight: bold;">{esc}</span>'
|
|
385
|
-
elif token[0].isdigit():
|
|
386
|
-
esc = html.escape(token)
|
|
387
|
-
element = f' <span style="color: green;">{esc}</span>'
|
|
388
|
-
elif token[0] == '`':
|
|
389
|
-
esc = html.escape(token)
|
|
390
|
-
element = f' <span style="color: peru;">{esc}</span>'
|
|
391
|
-
else:
|
|
392
|
-
esc = html.escape(token)
|
|
393
|
-
element = f' <span>{esc}</span>'
|
|
394
|
-
output += element
|
|
395
|
-
# Colour comment if present
|
|
396
|
-
if comment_part is not None:
|
|
397
|
-
esc = html.escape(comment_part)
|
|
398
|
-
output += f'<span style="color: green;"> {esc}</span>'
|
|
399
|
-
|
|
400
|
-
return output
|
|
401
|
-
|
|
402
|
-
###########################################################################
|
|
403
|
-
# Here when the user clicks a line number
|
|
404
|
-
def onClickLino(self, lino):
|
|
405
|
-
lineSpec = self.scriptLines[lino]
|
|
406
|
-
lineSpec.bp = not lineSpec.bp
|
|
407
|
-
if lineSpec.bp: lineSpec.label.showBlob()
|
|
408
|
-
else: lineSpec.label.hideBlob()
|
|
409
|
-
# Set a breakpoint on this command
|
|
410
|
-
command = self.program.code[self.program.pc]
|
|
411
|
-
command['bp'] = True
|
|
412
|
-
self.program.code[self.program.pc] = command
|
|
413
|
-
|
|
414
|
-
###########################################################################
|
|
415
|
-
# Scroll to a given line number
|
|
416
|
-
def scrollTo(self, lino):
|
|
417
|
-
# Ensure the line number is valid
|
|
418
|
-
if lino < 0 or lino >= len(self.scriptLines):
|
|
419
|
-
return
|
|
420
|
-
|
|
421
|
-
# Get the panel widget for this line
|
|
422
|
-
lineSpec = self.scriptLines[lino]
|
|
423
|
-
panel = lineSpec.panel
|
|
424
|
-
|
|
425
|
-
if not panel:
|
|
426
|
-
return
|
|
427
|
-
|
|
428
|
-
# Get the scroll area from the right column
|
|
429
|
-
scroll_area = self.rightColumn.scroll
|
|
430
|
-
|
|
431
|
-
# Get the vertical position of the panel relative to the content widget
|
|
432
|
-
panel_y = panel.y()
|
|
433
|
-
panel_height = panel.height()
|
|
434
|
-
|
|
435
|
-
# Get the viewport height (visible area)
|
|
436
|
-
viewport_height = scroll_area.viewport().height()
|
|
437
|
-
|
|
438
|
-
# Calculate the target scroll position to center the panel
|
|
439
|
-
# We want the panel's center to align with the viewport's center
|
|
440
|
-
target_scroll = panel_y + (panel_height // 2) - (viewport_height // 2)
|
|
441
|
-
|
|
442
|
-
# Clamp to valid scroll range
|
|
443
|
-
scrollbar = scroll_area.verticalScrollBar()
|
|
444
|
-
target_scroll = max(scrollbar.minimum(), min(target_scroll, scrollbar.maximum()))
|
|
445
|
-
|
|
446
|
-
# Smoothly scroll to the target position
|
|
447
|
-
scrollbar.setValue(target_scroll)
|
|
448
|
-
|
|
449
|
-
# Bring the window to the front
|
|
450
|
-
self.raise_()
|
|
451
|
-
self.activateWindow()
|
|
452
|
-
|
|
453
|
-
###########################################################################
|
|
454
|
-
# Here when each instruction is about to run
|
|
455
|
-
def step(self):
|
|
456
|
-
if self.stopped:
|
|
457
|
-
lino=self.program.code[self.program.pc]['lino']
|
|
458
|
-
print(lino)
|
|
459
|
-
self.scrollTo(lino)
|
|
460
|
-
return False
|
|
461
|
-
else:
|
|
462
|
-
if self.program.code[self.program.pc]['bp']:
|
|
463
|
-
pass
|
|
464
|
-
return True
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
easycoder/__init__.py,sha256=MRZ5qqYf7XUeRfrculBoOmXvlayyAdVqU7wI5n47Bqs,339
|
|
2
|
-
easycoder/close.png,sha256=3B9ueRNtEu9E4QNmZhdyC4VL6uqKvGmdfeFxIV9aO_Y,9847
|
|
3
|
-
easycoder/ec_border.py,sha256=KpOy0Jq8jI_6DYGo4jaFvoBP_jTIoAYWrmuHhl-FXA4,2355
|
|
4
|
-
easycoder/ec_classes.py,sha256=EWpB3Wta_jvKZ8SNIWua_ElIbw1FzKMyM3_IiXBn-lg,1995
|
|
5
|
-
easycoder/ec_compiler.py,sha256=Q6a9nMmZogJzHu8OB4VeMzmBBarVEl3-RkqH2gW4LiU,6599
|
|
6
|
-
easycoder/ec_condition.py,sha256=uamZrlW3Ej3R4bPDuduGB2f00M80Z1D0qV8muDx4Qfw,784
|
|
7
|
-
easycoder/ec_core.py,sha256=F8MQ1dJfzQoYxTrCyJ7aUrmyxjQEW4dmWd9uq71rR0w,100876
|
|
8
|
-
easycoder/ec_debug.py,sha256=JrF8GDzymB2YCOuULtlot4jO1yiVEbt_hQqjZPDcPEI,18785
|
|
9
|
-
easycoder/ec_handler.py,sha256=doGCMXBCQxvSaD3omKMlXoR_LvQODxV7dZyoWafecyg,2336
|
|
10
|
-
easycoder/ec_keyboard.py,sha256=H8DhPT8-IvAIGgRxCs4qSaF_AQLaS6lxxtDteejbktM,19010
|
|
11
|
-
easycoder/ec_program.py,sha256=biRWYKUs7ywFEgTte0oerTyPxgZlP4odfv_xJAN7ao8,10696
|
|
12
|
-
easycoder/ec_pyside.py,sha256=WDzJn64fPKMJCwTBXjngCRkJyS4fA72FmwfUoqul-Hw,58400
|
|
13
|
-
easycoder/ec_timestamp.py,sha256=myQnnF-mT31_1dpQKv2VEAu4BCcbypvMdzq7_DUi1xc,277
|
|
14
|
-
easycoder/ec_value.py,sha256=zgDJTJhIg3yOvmnnKIfccIizmIhGbtvL_ghLTL1T5fg,2516
|
|
15
|
-
easycoder/tick.png,sha256=OedASXJJTYvnza4J6Kv5m5lz6DrBfy667zX_WGgtbmM,9127
|
|
16
|
-
easycoder-251104.2.dist-info/entry_points.txt,sha256=JXAZbenl0TnsIft2FcGJbJ-4qoztVu2FuT8PFmWFexM,44
|
|
17
|
-
easycoder-251104.2.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
18
|
-
easycoder-251104.2.dist-info/WHEEL,sha256=Dyt6SBfaasWElUrURkknVFAZDHSTwxg3PaTza7RSbkY,100
|
|
19
|
-
easycoder-251104.2.dist-info/METADATA,sha256=SFh8m9keUUTbvuC0q4R3n7lCuBA_whA4Q2Pt8s1EMWc,6897
|
|
20
|
-
easycoder-251104.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|