--- a/src/eric7/MicroPython/MicroPythonWidget.py Wed May 03 10:12:03 2023 +0200 +++ b/src/eric7/MicroPython/MicroPythonWidget.py Thu May 04 11:22:11 2023 +0200 @@ -7,28 +7,17 @@ Module implementing the MicroPython REPL widget. """ -# TODO: refactor the code such to have the MicroPythonWidget as the top level -# container and a MicroPythonReplWidget containing the REPL related stuff -# (incl. device status line and zoom widget ?) - import contextlib import functools import os -import re import time -from PyQt6.QtCore import QEvent, QPoint, Qt, pyqtSignal, pyqtSlot -from PyQt6.QtGui import QBrush, QClipboard, QColor, QKeySequence, QTextCursor +from PyQt6.QtCore import Qt, pyqtSignal, pyqtSlot from PyQt6.QtWidgets import ( - QApplication, QDialog, - QHBoxLayout, QInputDialog, - QLabel, QLineEdit, QMenu, - QSizePolicy, - QTextEdit, QToolButton, QWidget, ) @@ -41,7 +30,6 @@ from eric7.EricWidgets.EricListSelectionDialog import EricListSelectionDialog from eric7.EricWidgets.EricPlainTextDialog import EricPlainTextDialog from eric7.EricWidgets.EricProcessDialog import EricProcessDialog -from eric7.EricWidgets.EricZoomWidget import EricZoomWidget from eric7.SystemUtilities import FileSystemUtilities, OSUtilities from eric7.UI.Info import BugAddress @@ -68,136 +56,6 @@ except ImportError: HAS_QTSERIALPORT = False -# ANSI Colors (see https://en.wikipedia.org/wiki/ANSI_escape_code) -AnsiColorSchemes = { - "Windows 7": { - 0: QBrush(QColor(0, 0, 0)), - 1: QBrush(QColor(128, 0, 0)), - 2: QBrush(QColor(0, 128, 0)), - 3: QBrush(QColor(128, 128, 0)), - 4: QBrush(QColor(0, 0, 128)), - 5: QBrush(QColor(128, 0, 128)), - 6: QBrush(QColor(0, 128, 128)), - 7: QBrush(QColor(192, 192, 192)), - 10: QBrush(QColor(128, 128, 128)), - 11: QBrush(QColor(255, 0, 0)), - 12: QBrush(QColor(0, 255, 0)), - 13: QBrush(QColor(255, 255, 0)), - 14: QBrush(QColor(0, 0, 255)), - 15: QBrush(QColor(255, 0, 255)), - 16: QBrush(QColor(0, 255, 255)), - 17: QBrush(QColor(255, 255, 255)), - }, - "Windows 10": { - 0: QBrush(QColor(12, 12, 12)), - 1: QBrush(QColor(197, 15, 31)), - 2: QBrush(QColor(19, 161, 14)), - 3: QBrush(QColor(193, 156, 0)), - 4: QBrush(QColor(0, 55, 218)), - 5: QBrush(QColor(136, 23, 152)), - 6: QBrush(QColor(58, 150, 221)), - 7: QBrush(QColor(204, 204, 204)), - 10: QBrush(QColor(118, 118, 118)), - 11: QBrush(QColor(231, 72, 86)), - 12: QBrush(QColor(22, 198, 12)), - 13: QBrush(QColor(249, 241, 165)), - 14: QBrush(QColor(59, 12, 255)), - 15: QBrush(QColor(180, 0, 158)), - 16: QBrush(QColor(97, 214, 214)), - 17: QBrush(QColor(242, 242, 242)), - }, - "PuTTY": { - 0: QBrush(QColor(0, 0, 0)), - 1: QBrush(QColor(187, 0, 0)), - 2: QBrush(QColor(0, 187, 0)), - 3: QBrush(QColor(187, 187, 0)), - 4: QBrush(QColor(0, 0, 187)), - 5: QBrush(QColor(187, 0, 187)), - 6: QBrush(QColor(0, 187, 187)), - 7: QBrush(QColor(187, 187, 187)), - 10: QBrush(QColor(85, 85, 85)), - 11: QBrush(QColor(255, 85, 85)), - 12: QBrush(QColor(85, 255, 85)), - 13: QBrush(QColor(255, 255, 85)), - 14: QBrush(QColor(85, 85, 255)), - 15: QBrush(QColor(255, 85, 255)), - 16: QBrush(QColor(85, 255, 255)), - 17: QBrush(QColor(255, 255, 255)), - }, - "xterm": { - 0: QBrush(QColor(0, 0, 0)), - 1: QBrush(QColor(205, 0, 0)), - 2: QBrush(QColor(0, 205, 0)), - 3: QBrush(QColor(205, 205, 0)), - 4: QBrush(QColor(0, 0, 238)), - 5: QBrush(QColor(205, 0, 205)), - 6: QBrush(QColor(0, 205, 205)), - 7: QBrush(QColor(229, 229, 229)), - 10: QBrush(QColor(127, 127, 127)), - 11: QBrush(QColor(255, 0, 0)), - 12: QBrush(QColor(0, 255, 0)), - 13: QBrush(QColor(255, 255, 0)), - 14: QBrush(QColor(0, 0, 255)), - 15: QBrush(QColor(255, 0, 255)), - 16: QBrush(QColor(0, 255, 255)), - 17: QBrush(QColor(255, 255, 255)), - }, - "Ubuntu": { - 0: QBrush(QColor(1, 1, 1)), - 1: QBrush(QColor(222, 56, 43)), - 2: QBrush(QColor(57, 181, 74)), - 3: QBrush(QColor(255, 199, 6)), - 4: QBrush(QColor(0, 11, 184)), - 5: QBrush(QColor(118, 38, 113)), - 6: QBrush(QColor(44, 181, 233)), - 7: QBrush(QColor(204, 204, 204)), - 10: QBrush(QColor(128, 128, 128)), - 11: QBrush(QColor(255, 0, 0)), - 12: QBrush(QColor(0, 255, 0)), - 13: QBrush(QColor(255, 255, 0)), - 14: QBrush(QColor(0, 0, 255)), - 15: QBrush(QColor(255, 0, 255)), - 16: QBrush(QColor(0, 255, 255)), - 17: QBrush(QColor(255, 255, 255)), - }, - "Ubuntu (dark)": { - 0: QBrush(QColor(96, 96, 96)), - 1: QBrush(QColor(235, 58, 45)), - 2: QBrush(QColor(57, 181, 74)), - 3: QBrush(QColor(255, 199, 29)), - 4: QBrush(QColor(25, 56, 230)), - 5: QBrush(QColor(200, 64, 193)), - 6: QBrush(QColor(48, 200, 255)), - 7: QBrush(QColor(204, 204, 204)), - 10: QBrush(QColor(128, 128, 128)), - 11: QBrush(QColor(255, 0, 0)), - 12: QBrush(QColor(0, 255, 0)), - 13: QBrush(QColor(255, 255, 0)), - 14: QBrush(QColor(0, 0, 255)), - 15: QBrush(QColor(255, 0, 255)), - 16: QBrush(QColor(0, 255, 255)), - 17: QBrush(QColor(255, 255, 255)), - }, - "Breeze (dark)": { - 0: QBrush(QColor(35, 38, 39)), - 1: QBrush(QColor(237, 21, 21)), - 2: QBrush(QColor(17, 209, 22)), - 3: QBrush(QColor(246, 116, 0)), - 4: QBrush(QColor(29, 153, 243)), - 5: QBrush(QColor(155, 89, 182)), - 6: QBrush(QColor(26, 188, 156)), - 7: QBrush(QColor(252, 252, 252)), - 10: QBrush(QColor(127, 140, 141)), - 11: QBrush(QColor(192, 57, 43)), - 12: QBrush(QColor(28, 220, 154)), - 13: QBrush(QColor(253, 188, 75)), - 14: QBrush(QColor(61, 174, 233)), - 15: QBrush(QColor(142, 68, 173)), - 16: QBrush(QColor(22, 160, 133)), - 17: QBrush(QColor(255, 255, 255)), - }, -} - class MicroPythonWidget(QWidget, Ui_MicroPythonWidget): """ @@ -207,9 +65,6 @@ connection for further processing """ - ZoomMin = -10 - ZoomMax = 20 - DeviceTypeRole = Qt.ItemDataRole.UserRole DeviceBoardRole = Qt.ItemDataRole.UserRole + 1 DevicePortRole = Qt.ItemDataRole.UserRole + 2 @@ -269,27 +124,6 @@ self.chartButton.setIcon(EricPixmapCache.getIcon("chart")) self.connectButton.setIcon(EricPixmapCache.getIcon("linkConnect")) - self.__zoomLayout = QHBoxLayout() - self.__osdLabel = QLabel() - self.__osdLabel.setSizePolicy( - QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred - ) - self.__zoomLayout.addWidget(self.__osdLabel) - - self.__zoom0 = self.replEdit.fontPointSize() - self.__zoomWidget = EricZoomWidget( - EricPixmapCache.getPixmap("zoomOut"), - EricPixmapCache.getPixmap("zoomIn"), - EricPixmapCache.getPixmap("zoomReset"), - self, - ) - self.__zoomLayout.addWidget(self.__zoomWidget) - self.layout().insertLayout(self.layout().count() - 1, self.__zoomLayout) - self.__zoomWidget.setMinimum(self.ZoomMin) - self.__zoomWidget.setMaximum(self.ZoomMax) - self.__zoomWidget.valueChanged.connect(self.__doZoom) - self.__currentZoom = 0 - self.__fileManager = None self.__fileManagerWidget = None self.__chartWidget = None @@ -306,10 +140,8 @@ self.__linkConnected = False self.__setConnected(False) - self.__replBuffer = b"" - if not HAS_QTSERIALPORT: - self.replEdit.setHtml( + self.replWidget.replEdit().setHtml( self.tr( "<h3>The QtSerialPort package is not available.<br/>" "MicroPython support is deactivated.</h3>" @@ -318,29 +150,14 @@ self.setEnabled(False) return - self.__vt100Re = re.compile( - r"(?P<count>\d*)(?P<color>(?:;?\d*)*)(?P<action>[ABCDKm])" - ) - self.__populateDeviceTypeComboBox() self.repopulateButton.clicked.connect(self.__populateDeviceTypeComboBox) self.webreplConfigButton.clicked.connect(self.__configureWebreplUrls) - - self.replEdit.installEventFilter(self) - # Hack to intercept middle button paste - self.__origReplEditMouseReleaseEvent = self.replEdit.mouseReleaseEvent - self.replEdit.mouseReleaseEvent = self.__replEditMouseReleaseEvent - - self.replEdit.customContextMenuRequested.connect(self.__showContextMenu) self.__ui.preferencesChanged.connect(self.__handlePreferencesChanged) self.__handlePreferencesChanged() - charFormat = self.replEdit.currentCharFormat() - self.DefaultForeground = charFormat.foreground() - self.DefaultBackground = charFormat.background() - def __populateDeviceTypeComboBox(self): """ Private method to populate the device type selector. @@ -431,9 +248,7 @@ index, webreplUrlsDict[name]["url"], self.DeviceWebreplUrlRole ) webreplMessage = ( - self.tr( - "\n%n WebREPL connection(s) defined.", "", len(webreplUrlsDict) - ) + self.tr("\n%n WebREPL connection(s) defined.", "", len(webreplUrlsDict)) if webreplUrlsDict else "" ) @@ -507,16 +322,7 @@ """ Private slot to handle a change in preferences. """ - self.__colorScheme = Preferences.getMicroPython("ColorScheme") - - self.__font = Preferences.getEditorOtherFonts("MonospacedFont") - self.replEdit.setFontFamily(self.__font.family()) - self.replEdit.setFontPointSize(self.__font.pointSize()) - - if Preferences.getMicroPython("ReplLineWrap"): - self.replEdit.setLineWrapMode(QTextEdit.LineWrapMode.WidgetWidth) - else: - self.replEdit.setLineWrapMode(QTextEdit.LineWrapMode.NoWrap) + self.replWidget.replEdit().handlePreferencesChanged() if self.__interface is not None: self.__interface.handlePreferencesChanged @@ -623,50 +429,6 @@ kwargs["chart"] and HAS_QTCHART and self.__connected ) - @pyqtSlot(QPoint) - def __showContextMenu(self, pos): - """ - Private slot to show the REPL context menu. - - @param pos position to show the menu at - @type QPoint - """ - if OSUtilities.isMacPlatform(): - copyKeys = QKeySequence("Ctrl+C") - pasteKeys = QKeySequence("Ctrl+V") - selectAllKeys = QKeySequence("Ctrl+A") - else: - copyKeys = QKeySequence("Ctrl+Shift+C") - pasteKeys = QKeySequence("Ctrl+Shift+V") - selectAllKeys = QKeySequence("Ctrl+Shift+A") - - menu = QMenu(self) - menu.addAction( - EricPixmapCache.getIcon("editDelete"), self.tr("Clear"), self.__clear - ).setEnabled(bool(self.replEdit.toPlainText())) - menu.addSeparator() - menu.addAction( - EricPixmapCache.getIcon("editCopy"), - self.tr("Copy"), - copyKeys, - self.replEdit.copy, - ).setEnabled(self.replEdit.textCursor().hasSelection()) - menu.addAction( - EricPixmapCache.getIcon("editPaste"), - self.tr("Paste"), - pasteKeys, - self.__paste, - ).setEnabled(self.replEdit.canPaste() and self.__connected) - menu.addSeparator() - menu.addAction( - EricPixmapCache.getIcon("editSelectAll"), - self.tr("Select All"), - selectAllKeys, - self.replEdit.selectAll, - ).setEnabled(bool(self.replEdit.toPlainText())) - - menu.exec(self.replEdit.mapToGlobal(pos)) - def __setConnected(self, connected): """ Private method to set the connection status LED. @@ -761,8 +523,10 @@ ) return - self.replEdit.clear() - self.__interface.dataReceived.connect(self.__processData) + self.replWidget.replEdit().clear() + self.__interface.dataReceived.connect( + self.replWidget.replEdit().processData + ) if not self.__interface.isConnected(): self.__connectToDevice() @@ -773,11 +537,13 @@ self.__interface.write(b"\x03") self.__device.setRepl(True) - self.replEdit.setFocus(Qt.FocusReason.OtherFocusReason) + self.replWidget.replEdit().setFocus(Qt.FocusReason.OtherFocusReason) else: with contextlib.suppress(TypeError): if self.__interface is not None: - self.__interface.dataReceived.disconnect(self.__processData) + self.__interface.dataReceived.disconnect( + self.replWidget.replEdit().processData + ) if not self.chartButton.isChecked() and not self.filesButton.isChecked(): self.__disconnectFromDevice() self.__device.setRepl(False) @@ -789,7 +555,7 @@ Private slot to connect to the selected device or disconnect from the currently connected device. """ - self.__osdLabel.clear() + self.replWidget.clearOSD() if self.__linkConnected: with EricOverrideCursor(): self.__disconnectFromDevice() @@ -804,374 +570,6 @@ with EricOverrideCursor(): self.__connectToDevice(withAutostart=True) - @pyqtSlot() - def __clear(self): - """ - Private slot to clear the REPL pane. - """ - self.replEdit.clear() - if bool(self.__interface) and self.__interface.isConnected(): - self.__interface.write(b"\r") - - @pyqtSlot() - def __paste(self, mode=QClipboard.Mode.Clipboard): - """ - Private slot to perform a paste operation. - - @param mode paste mode (defaults to QClipboard.Mode.Clipboard) - @type QClipboard.Mode (optional) - """ - # add support for paste by mouse middle button - clipboard = QApplication.clipboard() - if clipboard: - pasteText = clipboard.text(mode=mode) - if pasteText: - pasteText = pasteText.replace("\n\r", "\r") - pasteText = pasteText.replace("\n", "\r") - if bool(self.__interface) and self.__interface.isConnected(): - self.__interface.write(b"\x05") - self.__interface.write(pasteText.encode("utf-8")) - self.__interface.write(b"\x04") - - def eventFilter(self, obj, evt): - """ - Public method to process events for the REPL pane. - - @param obj reference to the object the event was meant for - @type QObject - @param evt reference to the event object - @type QEvent - @return flag to indicate that the event was handled - @rtype bool - """ - if obj is self.replEdit and evt.type() == QEvent.Type.KeyPress: - # handle the key press event on behalf of the REPL pane - key = evt.key() - msg = bytes(evt.text(), "utf8") - if key == Qt.Key.Key_Backspace: - msg = b"\b" - elif key == Qt.Key.Key_Delete: - msg = b"\x1B[\x33\x7E" - elif key == Qt.Key.Key_Up: - msg = b"\x1B[A" - elif key == Qt.Key.Key_Down: - msg = b"\x1B[B" - elif key == Qt.Key.Key_Right: - msg = b"\x1B[C" - elif key == Qt.Key.Key_Left: - msg = b"\x1B[D" - elif key == Qt.Key.Key_Home: - msg = b"\x1B[H" - elif key == Qt.Key.Key_End: - msg = b"\x1B[F" - elif ( - OSUtilities.isMacPlatform() - and evt.modifiers() == Qt.KeyboardModifier.MetaModifier - ) or ( - not OSUtilities.isMacPlatform() - and evt.modifiers() == Qt.KeyboardModifier.ControlModifier - ): - if Qt.Key.Key_A <= key <= Qt.Key.Key_Z: - # devices treat an input of \x01 as Ctrl+A, etc. - msg = bytes([1 + key - Qt.Key.Key_A]) - elif evt.modifiers() == ( - Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.ShiftModifier - ) or ( - OSUtilities.isMacPlatform() - and evt.modifiers() == Qt.KeyboardModifier.ControlModifier - ): - if key == Qt.Key.Key_C: - self.replEdit.copy() - msg = b"" - elif key == Qt.Key.Key_V: - self.__paste() - msg = b"" - elif key == Qt.Key.Key_A: - self.replEdit.selectAll() - msg = b"" - elif key in (Qt.Key.Key_Return, Qt.Key.Key_Enter): - tc = self.replEdit.textCursor() - tc.movePosition(QTextCursor.MoveOperation.EndOfLine) - self.replEdit.setTextCursor(tc) - if bool(self.__interface) and self.__interface.isConnected(): - self.__interface.write(msg) - return True - else: - # standard event processing - return super().eventFilter(obj, evt) - - def __replEditMouseReleaseEvent(self, evt): - """ - Private method handling mouse release events for the replEdit widget. - - Note: this is a hack because QTextEdit does not allow filtering of - QEvent.Type.MouseButtonRelease. To make middle button paste work, we - had to intercept the protected event method (some kind of - reimplementing it). - - @param evt reference to the event object - @type QMouseEvent - """ - if evt.button() == Qt.MouseButton.MiddleButton: - self.__paste(mode=QClipboard.Mode.Selection) - msg = b"" - if bool(self.__interface) and self.__interface.isConnected(): - self.__interface.write(msg) - evt.accept() - else: - self.__origReplEditMouseReleaseEvent(evt) - - def __processData(self, data): - """ - Private slot to process bytes received from the device. - - @param data bytes received from the device - @type bytes - """ - tc = self.replEdit.textCursor() - # the text cursor must be on the last line - while tc.movePosition(QTextCursor.MoveOperation.Down): - pass - - # set the font - charFormat = tc.charFormat() - charFormat.setFontFamilies([self.__font.family()]) - charFormat.setFontPointSize(self.__font.pointSize()) - tc.setCharFormat(charFormat) - - # add received data to the buffered one - data = self.__replBuffer + data - - index = 0 - while index < len(data): - if data[index] == 8: # \b - tc.movePosition(QTextCursor.MoveOperation.Left) - self.replEdit.setTextCursor(tc) - elif data[index] in (4, 13): # EOT, \r - pass - elif len(data) > index + 1 and data[index] == 27 and data[index + 1] == 91: - # VT100 cursor command detected: <Esc>[ - index += 2 # move index to after the [ - match = self.__vt100Re.search( - data[index:].decode("utf-8", errors="replace") - ) - if match: - # move to last position in control sequence - # ++ will be done at end of loop - index += match.end() - 1 - - action = match.group("action") - if action in "ABCD": - if match.group("count") == "": - count = 1 - else: - count = int(match.group("count")) - - if action == "A": # up - tc.movePosition(QTextCursor.MoveOperation.Up, n=count) - self.replEdit.setTextCursor(tc) - elif action == "B": # down - tc.movePosition(QTextCursor.MoveOperation.Down, n=count) - self.replEdit.setTextCursor(tc) - elif action == "C": # right - tc.movePosition(QTextCursor.MoveOperation.Right, n=count) - self.replEdit.setTextCursor(tc) - elif action == "D": # left - tc.movePosition(QTextCursor.MoveOperation.Left, n=count) - self.replEdit.setTextCursor(tc) - elif action == "K": # delete things - if match.group("count") in ("", "0"): - # delete to end of line - tc.movePosition( - QTextCursor.MoveOperation.EndOfLine, - mode=QTextCursor.MoveMode.KeepAnchor, - ) - tc.removeSelectedText() - self.replEdit.setTextCursor(tc) - elif match.group("count") == "1": - # delete to beginning of line - tc.movePosition( - QTextCursor.MoveOperation.StartOfLine, - mode=QTextCursor.MoveMode.KeepAnchor, - ) - tc.removeSelectedText() - self.replEdit.setTextCursor(tc) - elif match.group("count") == "2": - # delete whole line - tc.movePosition(QTextCursor.MoveOperation.EndOfLine) - tc.movePosition( - QTextCursor.MoveOperation.StartOfLine, - mode=QTextCursor.MoveMode.KeepAnchor, - ) - tc.removeSelectedText() - self.replEdit.setTextCursor(tc) - elif action == "m": - self.__setCharFormat(match.group(0)[:-1].split(";"), tc) - elif ( - len(data) > index + 1 - and data[index] == 27 - and data[index + 1 : index + 4] == b"]0;" - ): - if b"\x1b\\" in data[index + 4 :]: - # 'set window title' command detected: <Esc>]0;...<Esc>\ - # __IGNORE_WARNING_M891__ - titleData = data[index + 4 :].split(b"\x1b\\")[0] - title = titleData.decode() - index += len(titleData) + 5 # one more is done at the end - self.__osdLabel.setText(title) - else: - # data is incomplete; buffer and stop processing - self.__replBuffer = data[index:] - return - else: - tc.deleteChar() - self.replEdit.setTextCursor(tc) - self.replEdit.insertPlainText(chr(data[index])) - - index += 1 - - self.replEdit.ensureCursorVisible() - self.__replBuffer = b"" - - def __setCharFormat(self, formatCodes, textCursor): - """ - Private method setting the current text format of the REPL pane based - on the passed ANSI codes. - - Following codes are used: - <ul> - <li>0: Reset</li> - <li>1: Bold font (weight 75)</li> - <li>2: Light font (weight 25)</li> - <li>3: Italic font</li> - <li>4: Underlined font</li> - <li>9: Strikeout font</li> - <li>21: Bold off (weight 50)</li> - <li>22: Light off (weight 50)</li> - <li>23: Italic off</li> - <li>24: Underline off</li> - <li>29: Strikeout off</li> - <li>30: foreground Black</li> - <li>31: foreground Dark Red</li> - <li>32: foreground Dark Green</li> - <li>33: foreground Dark Yellow</li> - <li>34: foreground Dark Blue</li> - <li>35: foreground Dark Magenta</li> - <li>36: foreground Dark Cyan</li> - <li>37: foreground Light Gray</li> - <li>39: reset foreground to default</li> - <li>40: background Black</li> - <li>41: background Dark Red</li> - <li>42: background Dark Green</li> - <li>43: background Dark Yellow</li> - <li>44: background Dark Blue</li> - <li>45: background Dark Magenta</li> - <li>46: background Dark Cyan</li> - <li>47: background Light Gray</li> - <li>49: reset background to default</li> - <li>53: Overlined font</li> - <li>55: Overline off</li> - <li>90: bright foreground Dark Gray</li> - <li>91: bright foreground Red</li> - <li>92: bright foreground Green</li> - <li>93: bright foreground Yellow</li> - <li>94: bright foreground Blue</li> - <li>95: bright foreground Magenta</li> - <li>96: bright foreground Cyan</li> - <li>97: bright foreground White</li> - <li>100: bright background Dark Gray</li> - <li>101: bright background Red</li> - <li>102: bright background Green</li> - <li>103: bright background Yellow</li> - <li>104: bright background Blue</li> - <li>105: bright background Magenta</li> - <li>106: bright background Cyan</li> - <li>107: bright background White</li> - </ul> - - @param formatCodes list of format codes - @type list of str - @param textCursor reference to the text cursor - @type QTextCursor - """ - if not formatCodes: - # empty format codes list is treated as a reset - formatCodes = ["0"] - - charFormat = textCursor.charFormat() - for formatCode in formatCodes: - try: - formatCode = int(formatCode) - except ValueError: - # ignore non digit values - continue - - if formatCode == 0: - charFormat.setFontWeight(50) - charFormat.setFontItalic(False) - charFormat.setFontUnderline(False) - charFormat.setFontStrikeOut(False) - charFormat.setFontOverline(False) - charFormat.setForeground(self.DefaultForeground) - charFormat.setBackground(self.DefaultBackground) - elif formatCode == 1: - charFormat.setFontWeight(75) - elif formatCode == 2: - charFormat.setFontWeight(25) - elif formatCode == 3: - charFormat.setFontItalic(True) - elif formatCode == 4: - charFormat.setFontUnderline(True) - elif formatCode == 9: - charFormat.setFontStrikeOut(True) - elif formatCode in (21, 22): - charFormat.setFontWeight(50) - elif formatCode == 23: - charFormat.setFontItalic(False) - elif formatCode == 24: - charFormat.setFontUnderline(False) - elif formatCode == 29: - charFormat.setFontStrikeOut(False) - elif formatCode == 53: - charFormat.setFontOverline(True) - elif formatCode == 55: - charFormat.setFontOverline(False) - elif formatCode in (30, 31, 32, 33, 34, 35, 36, 37): - charFormat.setForeground( - AnsiColorSchemes[self.__colorScheme][formatCode - 30] - ) - elif formatCode in (40, 41, 42, 43, 44, 45, 46, 47): - charFormat.setBackground( - AnsiColorSchemes[self.__colorScheme][formatCode - 40] - ) - elif formatCode in (90, 91, 92, 93, 94, 95, 96, 97): - charFormat.setForeground( - AnsiColorSchemes[self.__colorScheme][formatCode - 80] - ) - elif formatCode in (100, 101, 102, 103, 104, 105, 106, 107): - charFormat.setBackground( - AnsiColorSchemes[self.__colorScheme][formatCode - 90] - ) - elif formatCode == 39: - charFormat.setForeground(self.DefaultForeground) - elif formatCode == 49: - charFormat.setBackground(self.DefaultBackground) - - textCursor.setCharFormat(charFormat) - - def __doZoom(self, value): - """ - Private slot to zoom the REPL pane. - - @param value zoom value - @type int - """ - if value < self.__currentZoom: - self.replEdit.zoomOut(self.__currentZoom - value) - elif value > self.__currentZoom: - self.replEdit.zoomIn(value - self.__currentZoom) - self.__currentZoom = value - def getCurrentPort(self): """ Public method to determine the port path of the selected device. @@ -1287,6 +685,7 @@ return self.__interface = MicroPythonWebreplDeviceInterface(self) + self.replWidget.replEdit().setInterface(self.__interface) if self.__interface.connectToDevice(port): deviceResponding = self.__interface.probeDevice() @@ -1340,6 +739,7 @@ self.__interface.disconnectFromDevice() self.__interface.deleteLater() self.__interface = None + self.replWidget.replEdit().setInterface(None) @pyqtSlot() def on_runButton_clicked(self):