eric6/QScintilla/Shell.py

branch
maintenance
changeset 8043
0acf98cd089a
parent 7924
8a96736d465e
parent 7990
3b865f4b7dff
child 8142
43248bafe9b2
equal deleted inserted replaced
7991:866adc8c315b 8043:0acf98cd089a
10 import sys 10 import sys
11 import re 11 import re
12 12
13 from enum import Enum 13 from enum import Enum
14 14
15 from PyQt5.QtCore import pyqtSignal, QFileInfo, Qt, QEvent 15 from PyQt5.QtCore import pyqtSignal, pyqtSlot, QFileInfo, Qt, QEvent
16 from PyQt5.QtGui import QClipboard, QPalette, QFont 16 from PyQt5.QtGui import QClipboard, QPalette, QFont
17 from PyQt5.QtWidgets import ( 17 from PyQt5.QtWidgets import (
18 QDialog, QInputDialog, QApplication, QMenu, QWidget, QHBoxLayout, 18 QDialog, QInputDialog, QApplication, QMenu, QWidget, QHBoxLayout,
19 QVBoxLayout, QShortcut, QSizePolicy 19 QVBoxLayout, QShortcut, QSizePolicy
20 ) 20 )
238 dbs.clientException.connect(self.__clientException) 238 dbs.clientException.connect(self.__clientException)
239 dbs.clientSyntaxError.connect(self.__clientSyntaxError) 239 dbs.clientSyntaxError.connect(self.__clientSyntaxError)
240 dbs.clientSignal.connect(self.__clientSignal) 240 dbs.clientSignal.connect(self.__clientSignal)
241 self.dbs = dbs 241 self.dbs = dbs
242 242
243 self.__debugUI = None
244
243 # Initialize instance variables. 245 # Initialize instance variables.
244 self.__initialise() 246 self.__initialise()
245 self.prline = 0 247 self.prline = 0
246 self.prcol = 0 248 self.prcol = 0
247 self.inDragDrop = False 249 self.inDragDrop = False
601 Public method to set the debugger UI. 603 Public method to set the debugger UI.
602 604
603 @param ui reference to the debugger UI object (DebugUI) 605 @param ui reference to the debugger UI object (DebugUI)
604 """ 606 """
605 ui.exceptionInterrupt.connect(self.__writePrompt) 607 ui.exceptionInterrupt.connect(self.__writePrompt)
608 self.__debugUI = ui
606 609
607 def __initialise(self): 610 def __initialise(self):
608 """ 611 """
609 Private method to get ready for a new remote interpreter. 612 Private method to get ready for a new remote interpreter.
610 """ 613 """
611 self.buff = "" 614 self.buff = ""
612 self.inContinue = False 615 self.inContinue = False
613 self.inRawMode = False 616 self.__inRawMode = False
614 self.echoInput = True 617 self.__echoInput = True
618 self.__rawModeDebuggerId = None
619 self.__rawModeQueue = []
615 self.clientCapabilities = 0 620 self.clientCapabilities = 0
616 self.inCommandExecution = False 621 self.inCommandExecution = False
617 self.interruptCommandExecution = False 622 self.interruptCommandExecution = False
618 623
619 def __clientCapabilities(self, cap, clType, venvName): 624 def __clientCapabilities(self, cap, clType, venvName):
815 if self.passive: 820 if self.passive:
816 self.__writeBanner('', '', '', '') 821 self.__writeBanner('', '', '', '')
817 else: 822 else:
818 self.dbs.remoteBanner() 823 self.dbs.remoteBanner()
819 824
820 def __writeBanner(self, version, platform, dbgclient, venvName): 825 def __writeBanner(self, version, platform, venvName):
821 """ 826 """
822 Private method to write a banner with info from the debug client. 827 Private method to write a banner with info from the debug client.
823 828
824 @param version interpreter version string 829 @param version interpreter version string
825 @type str 830 @type str
826 @param platform platform of the remote interpreter 831 @param platform platform of the remote interpreter
827 @type str 832 @type str
828 @param dbgclient debug client variant used
829 @type str
830 @param venvName name of the virtual environment 833 @param venvName name of the virtual environment
831 @type str 834 @type str
832 """ 835 """
833 super(Shell, self).clear() 836 super(Shell, self).clear()
834 if self.passive and not self.dbs.isConnected(): 837 if self.passive and not self.dbs.isConnected():
835 self.__write(self.tr('Passive Debug Mode')) 838 self.__write(self.tr('Passive Debug Mode'))
836 self.__write(self.tr('\nNot connected')) 839 self.__write(self.tr('\nNot connected'))
837 else: 840 else:
838 self.__currentVenv = venvName 841 self.__currentVenv = venvName
839 version = version.replace("#", self.tr("No.")) 842 version = version.replace("#", self.tr("No."))
840 if platform != "" and dbgclient != "": 843 if platform != "":
841 self.__write( 844 self.__write(self.tr('{0} on {1}').format(version, platform))
842 self.tr('{0} on {1}, {2}')
843 .format(version, platform, dbgclient))
844 else: 845 else:
845 self.__write(version) 846 self.__write(version)
846 if venvName: 847 if venvName:
847 self.__write("\n[{0}]".format(venvName)) 848 self.__write("\n[{0}]".format(venvName))
848 849
860 861
861 def __clientStatement(self, more): 862 def __clientStatement(self, more):
862 """ 863 """
863 Private method to handle the response from the debugger client. 864 Private method to handle the response from the debugger client.
864 865
865 @param more flag indicating that more user input is required (boolean) 866 @param more flag indicating that more user input is required
866 """ 867 @type bool
867 if not self.inRawMode: 868 """
869 if not self.__inRawMode:
868 self.inContinue = more 870 self.inContinue = more
869 self.__writePrompt() 871 self.__writePrompt()
870 self.inCommandExecution = False 872 self.inCommandExecution = False
871 873
872 def __clientException(self, exceptionType, exceptionMessage, stackTrace): 874 def __clientException(self, exceptionType, exceptionMessage, stackTrace):
1035 1037
1036 @param s text to be displayed (string) 1038 @param s text to be displayed (string)
1037 """ 1039 """
1038 self.__write(self.tr("StdErr: {0}").format(s)) 1040 self.__write(self.tr("StdErr: {0}").format(s))
1039 1041
1040 def __raw_input(self, prompt, echo): 1042 def __raw_input(self, prompt, echo, debuggerId):
1041 """ 1043 """
1042 Private method to handle raw input. 1044 Private method to handle raw input.
1043 1045
1044 @param prompt prompt to be displayed 1046 @param prompt the input prompt
1045 @type str 1047 @type str
1046 @param echo Flag indicating echoing of the input 1048 @param echo flag indicating an echoing of the input
1047 @type bool 1049 @type bool
1048 """ 1050 @param debuggerId ID of the debugger backend
1049 self.setFocus() 1051 @type str
1050 self.inRawMode = True 1052 """
1051 self.echoInput = echo 1053 if self.__inRawMode:
1052 1054 # we are processing another raw input event already
1053 # Get all text which is still waiting for output 1055 self.__rawModeQueue.append((debuggerId, prompt, echo))
1054 QApplication.processEvents() 1056 else:
1055 self.__flushQueuedText() 1057 self.setFocus()
1056 1058 self.__inRawMode = True
1057 self.__write(prompt) 1059 self.__echoInput = echo
1058 line, col = self.__getEndPos() 1060 self.__rawModeDebuggerId = debuggerId
1059 self.setCursorPosition(line, col) 1061
1060 buf = self.text(line) 1062 # Get all text which is still waiting for output
1061 if buf.startswith(sys.ps1): 1063 QApplication.processEvents()
1062 buf = buf.replace(sys.ps1, "") 1064 self.__flushQueuedText()
1063 if buf.startswith(sys.ps2): 1065
1064 buf = buf.replace(sys.ps2, "") 1066 self.__write(self.tr("<{0}> {1}").format(debuggerId, prompt))
1065 self.prompt = buf 1067 line, col = self.__getEndPos()
1066 # move cursor to end of line 1068 self.setCursorPosition(line, col)
1067 self.moveCursorToEOL() 1069 buf = self.text(line)
1068 1070 if buf.startswith(sys.ps1):
1069 def paste(self): 1071 buf = buf.replace(sys.ps1, "")
1072 if buf.startswith(sys.ps2):
1073 buf = buf.replace(sys.ps2, "")
1074 self.prompt = buf
1075 # move cursor to end of line
1076 self.moveCursorToEOL()
1077
1078 def paste(self, lines=None):
1070 """ 1079 """
1071 Public slot to handle the paste action. 1080 Public slot to handle the paste action.
1081
1082 @param lines list of lines to be inserted
1083 @type list of str
1072 """ 1084 """
1073 if self.__isCursorOnLastLine(): 1085 if self.__isCursorOnLastLine():
1074 line, col = self.getCursorPosition() 1086 line, col = self.getCursorPosition()
1075 lastLine = self.text(line) 1087 lastLine = self.text(line)
1076 if lastLine.startswith(sys.ps1): 1088 if lastLine.startswith(sys.ps1):
1102 col = indexFrom 1114 col = indexFrom
1103 1115
1104 self.setCursorPosition(line, len(prompt)) 1116 self.setCursorPosition(line, len(prompt))
1105 self.deleteLineRight() 1117 self.deleteLineRight()
1106 1118
1107 lines = QApplication.clipboard().text() 1119 if lines is None:
1120 lines = QApplication.clipboard().text()
1121
1108 lines = lastLine[:col] + lines + lastLine[col:] 1122 lines = lastLine[:col] + lines + lastLine[col:]
1109 self.executeLines(lines) 1123 self.executeLines(lines)
1110 line, _ = self.getCursorPosition() 1124 line, _ = self.getCursorPosition()
1111 pos = len(self.text(line)) - (len(lastLine) - col) 1125 pos = len(self.text(line)) - (len(lastLine) - col)
1112 self.setCursorPosition(line, pos) 1126 self.setCursorPosition(line, pos)
1113 1127
1114 def __middleMouseButton(self):
1115 """
1116 Private method to handle the middle mouse button press.
1117 """
1118 lines = QApplication.clipboard().text(QClipboard.Selection)
1119 self.executeLines(lines)
1120
1121 def executeLines(self, lines, historyIndex=None): 1128 def executeLines(self, lines, historyIndex=None):
1122 """ 1129 """
1123 Public method to execute a set of lines as multiple commands. 1130 Public method to execute a set of lines as multiple commands.
1124 1131
1125 @param lines multiple lines of text to be executed as 1132 @param lines multiple lines of text to be executed as
1139 elif line.startswith(sys.ps2): 1146 elif line.startswith(sys.ps2):
1140 line = line[len(sys.ps2) + indentLen:] 1147 line = line[len(sys.ps2) + indentLen:]
1141 else: 1148 else:
1142 line = line[indentLen:] 1149 line = line[indentLen:]
1143 1150
1144 if line.endswith("\r\n"): 1151 if line.endswith(("\r\n", "\r", "\n")):
1145 fullline = True 1152 fullline = True
1146 cmd = line[:-2] 1153 cmd = line.rstrip()
1147 elif line.endswith("\r") or line.endswith("\n"):
1148 fullline = True
1149 cmd = line[:-1]
1150 else: 1154 else:
1151 fullline = False 1155 fullline = False
1152 1156
1153 self.incrementalSearchActive = True 1157 self.incrementalSearchActive = True
1154 self.__insertTextAtEnd(line) 1158 self.__insertTextAtEnd(line)
1226 1230
1227 @param event the mouse press event (QMouseEvent) 1231 @param event the mouse press event (QMouseEvent)
1228 """ 1232 """
1229 self.setFocus() 1233 self.setFocus()
1230 if event.button() == Qt.MidButton: 1234 if event.button() == Qt.MidButton:
1231 self.__middleMouseButton() 1235 lines = QApplication.clipboard().text(QClipboard.Selection)
1236 self.paste(lines)
1232 else: 1237 else:
1233 super(Shell, self).mousePressEvent(event) 1238 super(Shell, self).mousePressEvent(event)
1234 1239
1235 def wheelEvent(self, evt): 1240 def wheelEvent(self, evt):
1236 """ 1241 """
1318 if len(txt) and txt >= " ": 1323 if len(txt) and txt >= " ":
1319 if not self.__isCursorOnLastLine(): 1324 if not self.__isCursorOnLastLine():
1320 line, col = self.__getEndPos() 1325 line, col = self.__getEndPos()
1321 self.setCursorPosition(line, col) 1326 self.setCursorPosition(line, col)
1322 self.prline, self.prcol = self.getCursorPosition() 1327 self.prline, self.prcol = self.getCursorPosition()
1323 if self.echoInput: 1328 if self.__echoInput:
1324 ac = self.isListActive() 1329 ac = self.isListActive()
1325 super(Shell, self).keyPressEvent(ev) 1330 super(Shell, self).keyPressEvent(ev)
1326 self.incrementalSearchActive = True 1331 self.incrementalSearchActive = True
1327 if ac and self.racEnabled: 1332 if ac and self.racEnabled:
1328 self.dbs.remoteCompletion(self.completionText + txt) 1333 self.dbs.remoteCompletion(
1334 self.__debugUI.getSelectedDebuggerId(),
1335 self.completionText + txt
1336 )
1329 else: 1337 else:
1330 self.__insertTextNoEcho(txt) 1338 self.__insertTextNoEcho(txt)
1331 else: 1339 else:
1332 ev.ignore() 1340 ev.ignore()
1333 1341
1355 if buf.startswith(sys.ps2): 1363 if buf.startswith(sys.ps2):
1356 buf = buf.replace(sys.ps2, "") 1364 buf = buf.replace(sys.ps2, "")
1357 if self.inContinue and not buf[:index - len(sys.ps2)].strip(): 1365 if self.inContinue and not buf[:index - len(sys.ps2)].strip():
1358 self.SendScintilla(cmd) 1366 self.SendScintilla(cmd)
1359 elif self.racEnabled: 1367 elif self.racEnabled:
1360 self.dbs.remoteCompletion(buf) 1368 self.dbs.remoteCompletion(
1369 self.__debugUI.getSelectedDebuggerId(),
1370 buf
1371 )
1361 1372
1362 def __QScintillaLeftDeleteCommand(self, method): 1373 def __QScintillaLeftDeleteCommand(self, method):
1363 """ 1374 """
1364 Private method to handle a QScintilla delete command working to 1375 Private method to handle a QScintilla delete command working to
1365 the left. 1376 the left.
1383 elif col > 0: 1394 elif col > 0:
1384 method() 1395 method()
1385 db = 1 1396 db = 1
1386 if db and ac and self.racEnabled and self.completionText: 1397 if db and ac and self.racEnabled and self.completionText:
1387 delta = len(self.text(line)) - oldLength 1398 delta = len(self.text(line)) - oldLength
1388 self.dbs.remoteCompletion(self.completionText[:delta]) 1399 self.dbs.remoteCompletion(
1400 self.__debugUI.getSelectedDebuggerId(),
1401 self.completionText[:delta]
1402 )
1389 1403
1390 def __QScintillaDeleteBack(self): 1404 def __QScintillaDeleteBack(self):
1391 """ 1405 """
1392 Private method to handle the Backspace key. 1406 Private method to handle the Backspace key.
1393 """ 1407 """
1760 @param cmd command to be executed by debug client 1774 @param cmd command to be executed by debug client
1761 @type str 1775 @type str
1762 @param historyIndex history index to be set 1776 @param historyIndex history index to be set
1763 @type int 1777 @type int
1764 """ 1778 """
1765 if not self.inRawMode: 1779 if not self.__inRawMode:
1766 self.inCommandExecution = True 1780 self.inCommandExecution = True
1767 self.interruptCommandExecution = False 1781 self.interruptCommandExecution = False
1768 if not cmd: 1782 if not cmd:
1769 # make sure cmd is a string 1783 # make sure cmd is a string
1770 cmd = '' 1784 cmd = ''
1850 ): 1864 ):
1851 # call main window quit() 1865 # call main window quit()
1852 self.vm.quit() 1866 self.vm.quit()
1853 return 1867 return
1854 1868
1855 self.dbs.remoteStatement(cmd) 1869 self.dbs.remoteStatement(self.__debugUI.getSelectedDebuggerId(),
1870 cmd)
1856 while self.inCommandExecution: 1871 while self.inCommandExecution:
1857 try: 1872 try:
1858 QApplication.processEvents() 1873 QApplication.processEvents()
1859 except KeyboardInterrupt: 1874 except KeyboardInterrupt:
1860 pass 1875 pass
1861 else: 1876 else:
1862 if not self.echoInput: 1877 if not self.__echoInput:
1863 cmd = self.buff 1878 cmd = self.buff
1864 self.buff = "" 1879 self.buff = ""
1865 elif cmd: 1880 elif cmd:
1866 cmd = cmd[len(self.prompt):] 1881 cmd = cmd[len(self.prompt):]
1867 self.inRawMode = False 1882 self.__inRawMode = False
1868 self.echoInput = True 1883 self.__echoInput = True
1869 1884
1870 self.dbs.remoteRawInput(cmd) 1885 self.dbs.remoteRawInput(self.__rawModeDebuggerId, cmd)
1886
1887 if self.__rawModeQueue:
1888 debuggerId, prompt, echo = self.__rawModeQueue.pop(0)
1889 self.__raw_input(prompt, echo, debuggerId)
1871 1890
1872 def __showVenvName(self): 1891 def __showVenvName(self):
1873 """ 1892 """
1874 Private method to show the name of the active virtual environment. 1893 Private method to show the name of the active virtual environment.
1875 """ 1894 """
2062 self.dbs.clientProcessStderr.connect(self.__writeStdErr) 2081 self.dbs.clientProcessStderr.connect(self.__writeStdErr)
2063 else: 2082 else:
2064 self.dbs.clientProcessStdout.disconnect(self.__writeStdOut) 2083 self.dbs.clientProcessStdout.disconnect(self.__writeStdOut)
2065 self.dbs.clientProcessStderr.disconnect(self.__writeStdErr) 2084 self.dbs.clientProcessStderr.disconnect(self.__writeStdErr)
2066 self.__showStdOutErr = showStdOutErr 2085 self.__showStdOutErr = showStdOutErr
2067 2086
2087 @pyqtSlot(list, str)
2068 def __showCompletions(self, completions, text): 2088 def __showCompletions(self, completions, text):
2069 """ 2089 """
2070 Private method to display the possible completions. 2090 Private method to display the possible completions.
2071 2091
2072 @param completions list of possible completions (list of strings) 2092 @param completions list of possible completions (list of strings)

eric ide

mercurial