eric6/MicroPython/MicroPythonReplWidget.py

branch
micropython
changeset 7069
a09a30251d4e
parent 7067
3fc4082fc6ba
child 7077
3b7475b7a1ef
equal deleted inserted replaced
7068:e3200e4dfa63 7069:a09a30251d4e
13 13
14 from PyQt5.QtCore import ( 14 from PyQt5.QtCore import (
15 pyqtSlot, pyqtSignal, Qt, QPoint, QEvent, QIODevice, QTimer 15 pyqtSlot, pyqtSignal, Qt, QPoint, QEvent, QIODevice, QTimer
16 ) 16 )
17 from PyQt5.QtGui import ( 17 from PyQt5.QtGui import (
18 QColor, QKeySequence, QTextCursor, QBrush, QTextCharFormat 18 QColor, QKeySequence, QTextCursor, QBrush
19 ) 19 )
20 from PyQt5.QtWidgets import ( 20 from PyQt5.QtWidgets import (
21 QWidget, QMenu, QApplication, QHBoxLayout, QSpacerItem, QSizePolicy 21 QWidget, QMenu, QApplication, QHBoxLayout, QSpacerItem, QSizePolicy
22 ) 22 )
23 try: 23 try:
41 41
42 import Globals 42 import Globals
43 import UI.PixmapCache 43 import UI.PixmapCache
44 import Preferences 44 import Preferences
45 45
46 # ANSI Colors (see https://en.wikipedia.org/wiki/ANSI_escape_code)
47 AnsiColorSchemes = {
48 "Windows 7": {
49 0: QBrush(QColor(0, 0, 0)),
50 1: QBrush(QColor(128, 0, 0)),
51 2: QBrush(QColor(0, 128, 0)),
52 3: QBrush(QColor(128, 128, 0)),
53 4: QBrush(QColor(0, 0, 128)),
54 5: QBrush(QColor(128, 0, 128)),
55 6: QBrush(QColor(0, 128, 128)),
56 7: QBrush(QColor(192, 192, 192)),
57 10: QBrush(QColor(128, 128, 128)),
58 11: QBrush(QColor(255, 0, 0)),
59 12: QBrush(QColor(0, 255, 0)),
60 13: QBrush(QColor(255, 255, 0)),
61 14: QBrush(QColor(0, 0, 255)),
62 15: QBrush(QColor(255, 0, 255)),
63 16: QBrush(QColor(0, 255, 255)),
64 17: QBrush(QColor(255, 255, 255)),
65 },
66 "Windows 10": {
67 0: QBrush(QColor(12, 12, 12)),
68 1: QBrush(QColor(197, 15, 31)),
69 2: QBrush(QColor(19, 161, 14)),
70 3: QBrush(QColor(193, 156, 0)),
71 4: QBrush(QColor(0, 55, 218)),
72 5: QBrush(QColor(136, 23, 152)),
73 6: QBrush(QColor(58, 150, 221)),
74 7: QBrush(QColor(204, 204, 204)),
75 10: QBrush(QColor(118, 118, 118)),
76 11: QBrush(QColor(231, 72, 86)),
77 12: QBrush(QColor(22, 198, 12)),
78 13: QBrush(QColor(249, 241, 165)),
79 14: QBrush(QColor(59, 12, 255)),
80 15: QBrush(QColor(180, 0, 158)),
81 16: QBrush(QColor(97, 214, 214)),
82 17: QBrush(QColor(242, 242, 242)),
83 },
84 "PuTTY": {
85 0: QBrush(QColor(0, 0, 0)),
86 1: QBrush(QColor(187, 0, 0)),
87 2: QBrush(QColor(0, 187, 0)),
88 3: QBrush(QColor(187, 187, 0)),
89 4: QBrush(QColor(0, 0, 187)),
90 5: QBrush(QColor(187, 0, 187)),
91 6: QBrush(QColor(0, 187, 187)),
92 7: QBrush(QColor(187, 187, 187)),
93 10: QBrush(QColor(85, 85, 85)),
94 11: QBrush(QColor(255, 85, 85)),
95 12: QBrush(QColor(85, 255, 85)),
96 13: QBrush(QColor(255, 255, 85)),
97 14: QBrush(QColor(85, 85, 255)),
98 15: QBrush(QColor(255, 85, 255)),
99 16: QBrush(QColor(85, 255, 255)),
100 17: QBrush(QColor(255, 255, 255)),
101 },
102 "xterm": {
103 0: QBrush(QColor(0, 0, 0)),
104 1: QBrush(QColor(205, 0, 0)),
105 2: QBrush(QColor(0, 205, 0)),
106 3: QBrush(QColor(205, 205, 0)),
107 4: QBrush(QColor(0, 0, 238)),
108 5: QBrush(QColor(205, 0, 205)),
109 6: QBrush(QColor(0, 205, 205)),
110 7: QBrush(QColor(229, 229, 229)),
111 10: QBrush(QColor(127, 127, 127)),
112 11: QBrush(QColor(255, 0, 0)),
113 12: QBrush(QColor(0, 255, 0)),
114 13: QBrush(QColor(255, 255, 0)),
115 14: QBrush(QColor(0, 0, 255)),
116 15: QBrush(QColor(255, 0, 255)),
117 16: QBrush(QColor(0, 255, 255)),
118 17: QBrush(QColor(255, 255, 255)),
119 },
120 "Ubuntu": {
121 0: QBrush(QColor(1, 1, 1)),
122 1: QBrush(QColor(222, 56, 43)),
123 2: QBrush(QColor(57, 181, 74)),
124 3: QBrush(QColor(255, 199, 6)),
125 4: QBrush(QColor(0, 11, 184)),
126 5: QBrush(QColor(118, 38, 113)),
127 6: QBrush(QColor(44, 181, 233)),
128 7: QBrush(QColor(204, 204, 204)),
129 10: QBrush(QColor(128, 128, 128)),
130 11: QBrush(QColor(255, 0, 0)),
131 12: QBrush(QColor(0, 255, 0)),
132 13: QBrush(QColor(255, 255, 0)),
133 14: QBrush(QColor(0, 0, 255)),
134 15: QBrush(QColor(255, 0, 255)),
135 16: QBrush(QColor(0, 255, 255)),
136 17: QBrush(QColor(255, 255, 255)),
137 },
138 }
139
46 140
47 class MicroPythonReplWidget(QWidget, Ui_MicroPythonReplWidget): 141 class MicroPythonReplWidget(QWidget, Ui_MicroPythonReplWidget):
48 """ 142 """
49 Class implementing the MicroPython REPL widget. 143 Class implementing the MicroPython REPL widget.
50 144
57 DeviceTypeRole = Qt.UserRole 151 DeviceTypeRole = Qt.UserRole
58 DevicePortRole = Qt.UserRole + 1 152 DevicePortRole = Qt.UserRole + 1
59 153
60 dataReceived = pyqtSignal(bytes) 154 dataReceived = pyqtSignal(bytes)
61 155
62 # ANSI Colors
63 AnsiColors = {
64 0: QBrush(Qt.black),
65 1: QBrush(Qt.darkRed),
66 2: QBrush(Qt.darkGreen),
67 3: QBrush(Qt.darkYellow),
68 4: QBrush(Qt.darkBlue),
69 5: QBrush(Qt.darkMagenta),
70 6: QBrush(Qt.darkCyan),
71 7: QBrush(Qt.lightGray),
72 10: QBrush(Qt.darkGray),
73 11: QBrush(Qt.red),
74 12: QBrush(Qt.green),
75 13: QBrush(Qt.yellow),
76 14: QBrush(Qt.blue),
77 15: QBrush(Qt.magenta),
78 16: QBrush(Qt.cyan),
79 17: QBrush(Qt.white),
80 }
81
82 def __init__(self, parent=None): 156 def __init__(self, parent=None):
83 """ 157 """
84 Constructor 158 Constructor
85 159
86 @param parent reference to the parent widget 160 @param parent reference to the parent widget
87 @type QWidget 161 @type QWidget
88 """ 162 """
89 super(MicroPythonReplWidget, self).__init__(parent) 163 super(MicroPythonReplWidget, self).__init__(parent)
90 self.setupUi(self) 164 self.setupUi(self)
165
166 self.__ui = parent
91 167
92 self.deviceIconLabel.setPixmap(MicroPythonDevices.getDeviceIcon( 168 self.deviceIconLabel.setPixmap(MicroPythonDevices.getDeviceIcon(
93 "", False)) 169 "", False))
94 170
95 self.openButton.setIcon(UI.PixmapCache.getIcon("open")) 171 self.openButton.setIcon(UI.PixmapCache.getIcon("open"))
119 self.__zoomWidget.setMinimum(self.ZoomMin) 195 self.__zoomWidget.setMinimum(self.ZoomMin)
120 self.__zoomWidget.setMaximum(self.ZoomMax) 196 self.__zoomWidget.setMaximum(self.ZoomMax)
121 self.__zoomWidget.valueChanged.connect(self.__doZoom) 197 self.__zoomWidget.valueChanged.connect(self.__doZoom)
122 self.__currentZoom = 0 198 self.__currentZoom = 0
123 199
124 self.__ui = None
125
126 self.__serial = None 200 self.__serial = None
127 self.__device = None 201 self.__device = None
128 self.setConnected(False) 202 self.setConnected(False)
129 203
130 self.__replRunning = False 204 self.__replRunning = False
141 self.__vt100Re = re.compile( 215 self.__vt100Re = re.compile(
142 r'(?P<count>\d*)(?P<color>(?:;?\d*)*)(?P<action>[ABCDKm])') 216 r'(?P<count>\d*)(?P<color>(?:;?\d*)*)(?P<action>[ABCDKm])')
143 217
144 self.__populateDeviceTypeComboBox() 218 self.__populateDeviceTypeComboBox()
145 219
146 self.replEdit.setAcceptRichText(False)
147 self.replEdit.setUndoRedoEnabled(False)
148 self.replEdit.setContextMenuPolicy(Qt.CustomContextMenu) 220 self.replEdit.setContextMenuPolicy(Qt.CustomContextMenu)
149 221
150 self.replEdit.installEventFilter(self) 222 self.replEdit.installEventFilter(self)
151 223
152 self.replEdit.customContextMenuRequested.connect( 224 self.replEdit.customContextMenuRequested.connect(
153 self.__showContextMenu) 225 self.__showContextMenu)
154 226 self.__ui.preferencesChanged.connect(self.__handlePreferencesChanged)
155 font = Preferences.getEditorOtherFonts("MonospacedFont") 227
156 self.replEdit.setFontFamily(font.family()) 228 self.__handlePreferencesChanged()
157 self.replEdit.setFontPointSize(font.pointSize()) 229
158 self.DefaultCharFormat = self.replEdit.currentCharFormat() 230 charFormat = self.replEdit.currentCharFormat()
159 self.DefaultForeground = self.DefaultCharFormat.foreground() 231 self.DefaultForeground = charFormat.foreground()
160 self.DefaultBackground = self.DefaultCharFormat.background() 232 self.DefaultBackground = charFormat.background()
161 233
162 def __populateDeviceTypeComboBox(self): 234 def __populateDeviceTypeComboBox(self):
163 """ 235 """
164 Private method to populate the device type selector. 236 Private method to populate the device type selector.
165 """ 237 """
185 else: 257 else:
186 self.deviceInfoLabel.setText( 258 self.deviceInfoLabel.setText(
187 self.tr("No supported devices detected.")) 259 self.tr("No supported devices detected."))
188 260
189 self.on_deviceTypeComboBox_activated(0) 261 self.on_deviceTypeComboBox_activated(0)
262
263 def __handlePreferencesChanged(self):
264 """
265 Private slot to handle a change in preferences.
266 """
267 self.__colorScheme = Preferences.getMicroPython("ColorScheme")
268
269 self.__font = Preferences.getEditorOtherFonts("MonospacedFont")
270
271 self.replEdit.setFontFamily(self.__font.family())
272 self.replEdit.setFontPointSize(self.__font.pointSize())
190 273
191 @pyqtSlot(int) 274 @pyqtSlot(int)
192 def on_deviceTypeComboBox_activated(self, index): 275 def on_deviceTypeComboBox_activated(self, index):
193 """ 276 """
194 Private slot handling the selection of a device type. 277 Private slot handling the selection of a device type.
417 tc = self.replEdit.textCursor() 500 tc = self.replEdit.textCursor()
418 # the text cursor must be on the last line 501 # the text cursor must be on the last line
419 while tc.movePosition(QTextCursor.Down): 502 while tc.movePosition(QTextCursor.Down):
420 pass 503 pass
421 504
505 # set the font
506 charFormat = tc.charFormat()
507 charFormat.setFontFamily(self.__font.family())
508 charFormat.setFontPointSize(self.__font.pointSize())
509 tc.setCharFormat(charFormat)
510
422 index = 0 511 index = 0
423 while index < len(data): 512 while index < len(data):
424 if data[index] == 8: # \b 513 if data[index] == 8: # \b
425 tc.movePosition(QTextCursor.Left) 514 tc.movePosition(QTextCursor.Left)
426 self.replEdit.setTextCursor(tc) 515 self.replEdit.setTextCursor(tc)
435 if match: 524 if match:
436 # move to last position in control sequence 525 # move to last position in control sequence
437 # ++ will be done at end of loop 526 # ++ will be done at end of loop
438 index += match.end() - 1 527 index += match.end() - 1
439 528
440 if match.group("count") == "":
441 count = 1
442 else:
443 count = int(match.group("count"))
444
445 action = match.group("action") 529 action = match.group("action")
446 if action == "A": # up 530 if action in "ABCD":
447 tc.movePosition(QTextCursor.Up, n=count) 531 if match.group("count") == "":
448 self.replEdit.setTextCursor(tc) 532 count = 1
449 elif action == "B": # down 533 else:
450 tc.movePosition(QTextCursor.Down, n=count) 534 count = int(match.group("count"))
451 self.replEdit.setTextCursor(tc) 535
452 elif action == "C": # right 536 if action == "A": # up
453 tc.movePosition(QTextCursor.Right, n=count) 537 tc.movePosition(QTextCursor.Up, n=count)
454 self.replEdit.setTextCursor(tc) 538 self.replEdit.setTextCursor(tc)
455 elif action == "D": # left 539 elif action == "B": # down
456 tc.movePosition(QTextCursor.Left, n=count) 540 tc.movePosition(QTextCursor.Down, n=count)
457 self.replEdit.setTextCursor(tc) 541 self.replEdit.setTextCursor(tc)
542 elif action == "C": # right
543 tc.movePosition(QTextCursor.Right, n=count)
544 self.replEdit.setTextCursor(tc)
545 elif action == "D": # left
546 tc.movePosition(QTextCursor.Left, n=count)
547 self.replEdit.setTextCursor(tc)
458 elif action == "K": # delete things 548 elif action == "K": # delete things
459 if match.group("count") == "": # delete to eol 549 if match.group("count") in ("", "0"):
550 # delete to end of line
460 tc.movePosition(QTextCursor.EndOfLine, 551 tc.movePosition(QTextCursor.EndOfLine,
552 mode=QTextCursor.KeepAnchor)
553 tc.removeSelectedText()
554 self.replEdit.setTextCursor(tc)
555 elif match.group("count") == "1":
556 # delete to beinning of line
557 tc.movePosition(QTextCursor.StartOfLine,
558 mode=QTextCursor.KeepAnchor)
559 tc.removeSelectedText()
560 self.replEdit.setTextCursor(tc)
561 elif match.group("count") == "2":
562 # delete whole line
563 tc.movePosition(QTextCursor.EndOfLine)
564 tc.movePosition(QTextCursor.StartOfLine,
461 mode=QTextCursor.KeepAnchor) 565 mode=QTextCursor.KeepAnchor)
462 tc.removeSelectedText() 566 tc.removeSelectedText()
463 self.replEdit.setTextCursor(tc) 567 self.replEdit.setTextCursor(tc)
464 elif action == "m": 568 elif action == "m":
465 self.__setCharFormat(match.group(0)[:-1].split(";"), 569 self.__setCharFormat(match.group(0)[:-1].split(";"),
466 tc) 570 tc)
467 elif data[index] == 10: # \n 571 ## elif data[index] == 10: # \n
468 tc.movePosition(QTextCursor.End) 572 ## tc.movePosition(QTextCursor.End)
469 self.replEdit.setTextCursor(tc) 573 ## self.replEdit.setTextCursor(tc)
470 self.replEdit.insertPlainText(chr(data[index])) 574 ## self.replEdit.insertPlainText(chr(data[index]))
471 self.__setCharFormat(["0"], tc) # reset format after a \n 575 ## self.__setCharFormat(["0"], tc) # reset format after a \n
472 else: 576 else:
473 tc.deleteChar() 577 tc.deleteChar()
474 self.replEdit.setTextCursor(tc) 578 self.replEdit.setTextCursor(tc)
475 self.replEdit.insertPlainText(chr(data[index])) 579 self.replEdit.insertPlainText(chr(data[index]))
476 580
502 <li>33: foreground Dark Yellow</li> 606 <li>33: foreground Dark Yellow</li>
503 <li>34: foreground Dark Blue</li> 607 <li>34: foreground Dark Blue</li>
504 <li>35: foreground Dark Magenta</li> 608 <li>35: foreground Dark Magenta</li>
505 <li>36: foreground Dark Cyan</li> 609 <li>36: foreground Dark Cyan</li>
506 <li>37: foreground Light Gray</li> 610 <li>37: foreground Light Gray</li>
611 <li>39: reset foreground to default</li>
507 <li>40: background Black</li> 612 <li>40: background Black</li>
508 <li>41: background Dark Red</li> 613 <li>41: background Dark Red</li>
509 <li>42: background Dark Green</li> 614 <li>42: background Dark Green</li>
510 <li>43: background Dark Yellow</li> 615 <li>43: background Dark Yellow</li>
511 <li>44: background Dark Blue</li> 616 <li>44: background Dark Blue</li>
512 <li>45: background Dark Magenta</li> 617 <li>45: background Dark Magenta</li>
513 <li>46: background Dark Cyan</li> 618 <li>46: background Dark Cyan</li>
514 <li>47: background Light Gray</li> 619 <li>47: background Light Gray</li>
620 <li>49: reset background to default</li>
515 <li>53: Overlined font</li> 621 <li>53: Overlined font</li>
516 <li>55: Overline off</li> 622 <li>55: Overline off</li>
517 <li>90: bright foreground Dark Gray</li> 623 <li>90: bright foreground Dark Gray</li>
518 <li>91: bright foreground Red</li> 624 <li>91: bright foreground Red</li>
519 <li>92: bright foreground Green</li> 625 <li>92: bright foreground Green</li>
578 elif formatCode == 53: 684 elif formatCode == 53:
579 charFormat.setFontOverline(True) 685 charFormat.setFontOverline(True)
580 elif formatCode == 55: 686 elif formatCode == 55:
581 charFormat.setFontOverline(False) 687 charFormat.setFontOverline(False)
582 elif formatCode in (30, 31, 32, 33, 34, 35, 36, 37): 688 elif formatCode in (30, 31, 32, 33, 34, 35, 36, 37):
583 charFormat.setForeground(self.AnsiColors[formatCode - 30]) 689 charFormat.setForeground(
690 AnsiColorSchemes[self.__colorScheme][formatCode - 30])
584 elif formatCode in (40, 41, 42, 43, 44, 45, 46, 47): 691 elif formatCode in (40, 41, 42, 43, 44, 45, 46, 47):
585 charFormat.setBackground(self.AnsiColors[formatCode - 40]) 692 charFormat.setBackground(
693 AnsiColorSchemes[self.__colorScheme][formatCode - 40])
586 elif formatCode in (90, 91, 92, 93, 94, 95, 96, 97): 694 elif formatCode in (90, 91, 92, 93, 94, 95, 96, 97):
587 charFormat.setForeground(self.AnsiColors[formatCode - 80]) 695 charFormat.setForeground(
696 AnsiColorSchemes[self.__colorScheme][formatCode - 80])
588 elif formatCode in (100, 101, 102, 103, 104, 105, 106, 107): 697 elif formatCode in (100, 101, 102, 103, 104, 105, 106, 107):
589 charFormat.setBackground(self.AnsiColors[formatCode - 90]) 698 charFormat.setBackground(
699 AnsiColorSchemes[self.__colorScheme][formatCode - 90])
700 elif formatCode == 39:
701 charFormat.setForeground(self.DefaultForeground)
702 elif formatCode == 49:
703 charFormat.setBackground(self.DefaultBackground)
590 704
591 textCursor.setCharFormat(charFormat) 705 textCursor.setCharFormat(charFormat)
592 706
593 def __doZoom(self, value): 707 def __doZoom(self, value):
594 """ 708 """

eric ide

mercurial