src/eric7/QScintilla/Shell.py

branch
eric7
changeset 10191
dc47d7d2ff34
parent 10167
0a62a4bf749c
child 10232
fbfb347f7b5b
equal deleted inserted replaced
10190:dbe6394786ea 10191:dc47d7d2ff34
30 from eric7 import Preferences, Utilities 30 from eric7 import Preferences, Utilities
31 from eric7.Debugger.DebugClientCapabilities import HasCompleter 31 from eric7.Debugger.DebugClientCapabilities import HasCompleter
32 from eric7.EricGui import EricPixmapCache 32 from eric7.EricGui import EricPixmapCache
33 from eric7.EricWidgets import EricFileDialog, EricMessageBox 33 from eric7.EricWidgets import EricFileDialog, EricMessageBox
34 from eric7.EricWidgets.EricApplication import ericApp 34 from eric7.EricWidgets.EricApplication import ericApp
35 from eric7.EricWidgets.EricSimpleHelpDialog import EricSimpleHelpDialog
35 from eric7.UI.SearchWidget import SearchWidget 36 from eric7.UI.SearchWidget import SearchWidget
36 37
37 from . import Lexers 38 from . import Lexers
38 from .QsciScintillaCompat import QsciScintillaCompat 39 from .QsciScintillaCompat import QsciScintillaCompat
39 40
150 self.__mainWindow = parent 151 self.__mainWindow = parent
151 self.__lastSearch = () 152 self.__lastSearch = ()
152 self.__windowed = windowedVariant 153 self.__windowed = windowedVariant
153 self.__currentVenv = "" 154 self.__currentVenv = ""
154 self.__currentWorkingDirectory = "" 155 self.__currentWorkingDirectory = ""
156 self.__helpDialog = None
155 157
156 self.linesepRegExp = r"\r\n|\n|\r" 158 self.linesepRegExp = r"\r\n|\n|\r"
157 159
158 self.passive = (not self.__windowed) and Preferences.getDebugger( 160 self.passive = (not self.__windowed) and Preferences.getDebugger(
159 "PassiveDbgEnabled" 161 "PassiveDbgEnabled"
172 """ using the up and down cursor keys while holding down the""" 174 """ using the up and down cursor keys while holding down the"""
173 """ Ctrl-key. This can be switched to just the up and down""" 175 """ Ctrl-key. This can be switched to just the up and down"""
174 """ cursor keys on the Shell page of the configuration""" 176 """ cursor keys on the Shell page of the configuration"""
175 """ dialog. Pressing these keys after some text has been""" 177 """ dialog. Pressing these keys after some text has been"""
176 """ entered will start an incremental search.</p>""" 178 """ entered will start an incremental search.</p>"""
177 """<p>The shell has some special commands. '%restart' kills""" 179 """<p>The shell has some special commands. Type '%help' to get"""
178 """ the shell and starts a new one. '%clear' clears the""" 180 """ a list of these commands.</p>"""
179 """ display of the shell window. '%start' is used to start a"""
180 """ shell for a virtual environment and should be followed"""
181 """ by a virtual environment name. '%start' without a"""
182 """ virtual environment name starts the default shell."""
183 """ Available virtual environments may be listed with the"""
184 """ '%envs' or '%environments' commands. The active virtual"""
185 """ environment can be questioned by the '%which' command."""
186 """ '%quit' or '%exit' is used to exit the application."""
187 """ These commands (except '%environments', '%envs' and"""
188 """ '%which') are available through the window menus as"""
189 """ well.</p>"""
190 """<p>Pressing the Tab key after some text has been entered""" 181 """<p>Pressing the Tab key after some text has been entered"""
191 """ will show a list of possible completions. The relevant""" 182 """ will show a list of possible completions. The relevant"""
192 """ entry may be selected from this list. If only one entry""" 183 """ entry may be selected from this list. If only one entry"""
193 """ is available, this will be inserted automatically.</p>""" 184 """ is available, this will be inserted automatically.</p>"""
194 ) 185 )
206 """ using the up and down cursor keys while holding down the""" 197 """ using the up and down cursor keys while holding down the"""
207 """ Ctrl-key. This can be switched to just the up and down""" 198 """ Ctrl-key. This can be switched to just the up and down"""
208 """ cursor keys on the Shell page of the configuration""" 199 """ cursor keys on the Shell page of the configuration"""
209 """ dialog. Pressing these keys after some text has been""" 200 """ dialog. Pressing these keys after some text has been"""
210 """ entered will start an incremental search.</p>""" 201 """ entered will start an incremental search.</p>"""
211 """<p>The shell has some special commands. '%restart' kills""" 202 """<p>The shell has some special commands. Type '%help' to get"""
212 """ the shell and starts a new one. '%clear' clears the""" 203 """ a list of these commands.</p>"""
213 """ display of the shell window. '%start' is used to start a"""
214 """ shell for a virtual environment and should be followed"""
215 """ by a virtual environment name. '%start' without a"""
216 """ virtual environment name starts the default shell."""
217 """ Available virtual environments may be listed with the"""
218 """ '%envs' or '%environments' commands. The active virtual"""
219 """ environment can be questioned by the '%which' command."""
220 """ These commands (except '%environments' and '%envs') are"""
221 """ available through the context menu as well.</p>"""
222 """<p>Pressing the Tab key after some text has been entered""" 204 """<p>Pressing the Tab key after some text has been entered"""
223 """ will show a list of possible completions. The relevant""" 205 """ will show a list of possible completions. The relevant"""
224 """ entry may be selected from this list. If only one entry""" 206 """ entry may be selected from this list. If only one entry"""
225 """ is available, this will be inserted automatically.</p>""" 207 """ is available, this will be inserted automatically.</p>"""
226 """<p>In passive debugging mode the shell is only available""" 208 """<p>In passive debugging mode the shell is only available"""
316 self.menu = QMenu(self) 298 self.menu = QMenu(self)
317 self.menu.addAction(self.tr("Cut"), self.cut) 299 self.menu.addAction(self.tr("Cut"), self.cut)
318 self.menu.addAction(self.tr("Copy"), self.copy) 300 self.menu.addAction(self.tr("Copy"), self.copy)
319 self.menu.addAction(self.tr("Paste"), self.paste) 301 self.menu.addAction(self.tr("Paste"), self.paste)
320 self.menu.addMenu(self.hmenu).setEnabled(self.isHistoryEnabled()) 302 self.menu.addMenu(self.hmenu).setEnabled(self.isHistoryEnabled())
321
322 self.menu.addSeparator() 303 self.menu.addSeparator()
323 self.menu.addAction(self.tr("Find"), self.__find) 304 self.menu.addAction(self.tr("Find"), self.__find)
324 self.menu.addSeparator() 305 self.menu.addSeparator()
325 self.menu.addAction(self.tr("Clear"), self.clear) 306 self.menu.addAction(self.tr("Clear"), self.clear)
326 self.menu.addAction(self.tr("Restart"), self.doRestart) 307 self.menu.addAction(self.tr("Restart"), self.doRestart)
330 self.menu.addAction(self.tr("Active Name"), self.__showVenvName) 311 self.menu.addAction(self.tr("Active Name"), self.__showVenvName)
331 self.menu.addSeparator() 312 self.menu.addSeparator()
332 self.menu.addAction(self.tr("Save Contents..."), self.saveContents) 313 self.menu.addAction(self.tr("Save Contents..."), self.saveContents)
333 self.menu.addSeparator() 314 self.menu.addSeparator()
334 self.menu.addAction(self.tr("Configure..."), self.__configure) 315 self.menu.addAction(self.tr("Configure..."), self.__configure)
316 self.menu.addSeparator()
317 self.menu.addAction(self.tr("Special Commands Help"), self.__showHelp)
335 318
336 self.customContextMenuRequested.connect(self.__showContextMenu) 319 self.customContextMenuRequested.connect(self.__showContextMenu)
337 self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) 320 self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
338 321
339 self.__bindLexer() 322 self.__bindLexer()
781 elif clientType in self.__historyLists: 764 elif clientType in self.__historyLists:
782 return self.__historyLists[clientType] 765 return self.__historyLists[clientType]
783 else: 766 else:
784 return [] 767 return []
785 768
786 def clearHistory(self): 769 @pyqtSlot()
770 def clearHistory(self, ask=True):
787 """ 771 """
788 Public slot to clear the current history. 772 Public slot to clear the current history.
789 """ 773
774 @param ask flag indicating to ask for confirmation (defaults to True)
775 @type bool (optional)
776 """
777 if ask:
778 ok = EricMessageBox.yesNo(
779 self,
780 self.tr("Clear History"),
781 self.tr("""Shall the current history really be cleared?"""),
782 )
783 if not ok:
784 return
785
790 if self.clientType: 786 if self.clientType:
791 self.__historyLists[self.clientType] = [] 787 self.__historyLists[self.clientType] = []
792 self.__history = self.__historyLists[self.clientType] 788 self.__history = self.__historyLists[self.clientType]
793 else: 789 else:
794 self.__history = [] 790 self.__history = []
795 self.__setHistoryIndex(index=-1) 791 self.__setHistoryIndex(index=-1)
796 792
793 @pyqtSlot()
797 def selectHistory(self): 794 def selectHistory(self):
798 """ 795 """
799 Public slot to select a history entry to execute. 796 Public slot to select a history entry to execute.
800 """ 797 """
801 current = self.__histidx 798 current = self.__histidx
810 False, 807 False,
811 ) 808 )
812 if ok: 809 if ok:
813 self.__insertHistory(cmd) 810 self.__insertHistory(cmd)
814 811
815 def showHistory(self): 812 @pyqtSlot()
813 def showHistory(self, histSize=None):
816 """ 814 """
817 Public slot to show the shell history dialog. 815 Public slot to show the shell history dialog.
816
817 @param histSize number of history entries to be shown (None = show all
818 entrys) (defaults to None)
819 @type int (optional)
818 """ 820 """
819 from .ShellHistoryDialog import ShellHistoryDialog 821 from .ShellHistoryDialog import ShellHistoryDialog
820 822
821 dlg = ShellHistoryDialog(self.__history, self.vm, self) 823 dlg = (
822 if dlg.exec() == QDialog.DialogCode.Accepted: 824 ShellHistoryDialog(self.__history, self.vm, self)
825 if histSize is None
826 else ShellHistoryDialog(self.__history[-histSize:], self.vm, self)
827 )
828 if dlg.exec() == QDialog.DialogCode.Accepted and histSize is None:
823 self.__historyLists[self.clientType], idx = dlg.getHistory() 829 self.__historyLists[self.clientType], idx = dlg.getHistory()
824 self.__history = self.__historyLists[self.clientType] 830 self.__history = self.__historyLists[self.clientType]
825 self.__setHistoryIndex(index=idx) 831 self.__setHistoryIndex(index=idx)
826 832
827 def clearAllHistories(self): 833 def clearAllHistories(self):
832 for clientType in Preferences.getSettings().childKeys(): 838 for clientType in Preferences.getSettings().childKeys():
833 self.__historyLists[clientType] = [] 839 self.__historyLists[clientType] = []
834 self.saveHistory(clientType) 840 self.saveHistory(clientType)
835 Preferences.getSettings().endGroup() 841 Preferences.getSettings().endGroup()
836 842
837 self.clearHistory() 843 self.clearHistory(ask=False)
838 844
839 def getClientType(self): 845 def getClientType(self):
840 """ 846 """
841 Public slot to get the clients type. 847 Public slot to get the clients type.
842 848
1083 """ 1089 """
1084 if self.__inRawMode: 1090 if self.__inRawMode:
1085 # we are processing another raw input event already 1091 # we are processing another raw input event already
1086 self.__rawModeQueue.append((debuggerId, prompt, echo)) 1092 self.__rawModeQueue.append((debuggerId, prompt, echo))
1087 else: 1093 else:
1088 self.setFocus() 1094 self.setFocus(Qt.FocusReason.OtherFocusReason)
1089 self.__inRawMode = True 1095 self.__inRawMode = True
1090 self.__echoInput = echo 1096 self.__echoInput = echo
1091 self.__rawModeDebuggerId = debuggerId 1097 self.__rawModeDebuggerId = debuggerId
1092 1098
1093 # Get all text which is still waiting for output 1099 # Get all text which is still waiting for output
1259 """ 1265 """
1260 Protected method to handle the mouse press event. 1266 Protected method to handle the mouse press event.
1261 1267
1262 @param event the mouse press event (QMouseEvent) 1268 @param event the mouse press event (QMouseEvent)
1263 """ 1269 """
1264 self.setFocus() 1270 self.setFocus(Qt.FocusReason.MouseFocusReason)
1265 if event.button() == Qt.MouseButton.MiddleButton: 1271 if event.button() == Qt.MouseButton.MiddleButton:
1266 lines = QApplication.clipboard().text(QClipboard.Mode.Selection) 1272 lines = QApplication.clipboard().text(QClipboard.Mode.Selection)
1267 self.paste(lines) 1273 self.paste(lines)
1268 else: 1274 else:
1269 super().mousePressEvent(event) 1275 super().mousePressEvent(event)
1827 ): 1833 ):
1828 self.__setHistoryIndex(index=-1) 1834 self.__setHistoryIndex(index=-1)
1829 else: 1835 else:
1830 self.__setHistoryIndex(historyIndex) 1836 self.__setHistoryIndex(historyIndex)
1831 1837
1832 # TODO: add a '%help' command listing available % commands
1833 # TODO: add '%history [n]' command to show the 'n' most recently used
1834 # commands (default: n = 10)
1835 if cmd.startswith("%"): 1838 if cmd.startswith("%"):
1836 if cmd == "%start" or cmd.startswith("%start "): 1839 if cmd == "%start" or cmd.startswith("%start "):
1837 if not self.passive: 1840 if not self.passive:
1838 cmdList = cmd.split(None, 1) 1841 cmdList = cmd.split(None, 1)
1839 if len(cmdList) < 2: 1842 if len(cmdList) < 2:
1864 ) 1867 )
1865 # same as reset 1868 # same as reset
1866 else: 1869 else:
1867 self.dbs.startClient(False, venvName=venvName) 1870 self.dbs.startClient(False, venvName=venvName)
1868 self.__currentWorkingDirectory = "" 1871 self.__currentWorkingDirectory = ""
1869 self.__getBanner() 1872 self.__getBanner()
1870 return
1871 elif cmd == "%clear": 1873 elif cmd == "%clear":
1872 # Display the banner. 1874 # Display the banner.
1873 self.__getBanner() 1875 self.__getBanner()
1874 if not self.passive:
1875 return
1876 else:
1877 cmd = ""
1878 elif cmd in ["%reset", "%restart"]: 1876 elif cmd in ["%reset", "%restart"]:
1879 self.dbs.startClient( 1877 self.dbs.startClient(
1880 False, 1878 False,
1881 venvName=self.__currentVenv, 1879 venvName=self.__currentVenv,
1882 workingDir=self.__currentWorkingDirectory, 1880 workingDir=self.__currentWorkingDirectory,
1883 ) 1881 )
1884 if self.passive:
1885 return
1886 else:
1887 cmd = ""
1888 elif cmd in ["%envs", "%environments"]: 1882 elif cmd in ["%envs", "%environments"]:
1889 venvs = ( 1883 venvs = (
1890 ericApp().getObject("VirtualEnvManager").getVirtualenvNames() 1884 ericApp().getObject("VirtualEnvManager").getVirtualenvNames()
1891 ) 1885 )
1892 s = self.tr("Available Virtual Environments:\n{0}\n").format( 1886 s = self.tr("Available Virtual Environments:\n{0}\n").format(
1893 "\n".join("- {0}".format(venv) for venv in sorted(venvs)) 1887 "\n".join("- {0}".format(venv) for venv in sorted(venvs))
1894 ) 1888 )
1895 self.__write(s) 1889 self.__write(s)
1896 self.__clientStatement(False) 1890 self.__clientStatement(False)
1897 return
1898 elif cmd == "%which": 1891 elif cmd == "%which":
1899 s = self.tr("Current Virtual Environment: '{0}'\n").format( 1892 s = self.tr("Current Virtual Environment: '{0}'\n").format(
1900 self.__currentVenv 1893 self.__currentVenv
1901 ) 1894 )
1902 self.__write(s) 1895 self.__write(s)
1903 self.__clientStatement(False) 1896 self.__clientStatement(False)
1904 return
1905 elif ( 1897 elif (
1906 cmd in ["%quit", "%quit()", "%exit", "%exit()"] and self.__windowed 1898 cmd in ["%quit", "%quit()", "%exit", "%exit()"] and self.__windowed
1907 ): 1899 ):
1908 # call main window quit() 1900 # call main window quit()
1909 self.vm.quit() 1901 self.vm.quit()
1910 return 1902 elif cmd in ("%hist", "%history") or cmd.startswith(
1903 ("%hist ", "%history ")
1904 ):
1905 cmdList = cmd.split(None, 1)
1906 if len(cmdList) == 2:
1907 try:
1908 histSize = int(cmdList[1])
1909 except ValueError:
1910 s = self.tr("Error: Argument must be an integer value.\n")
1911 self.__write(s)
1912 self.__clientStatement(False)
1913 return
1914 else:
1915 histSize = None
1916 self.showHistory(histSize)
1917 self.__clientStatement(False)
1918 elif cmd in ("%shist", "%shistory", "%select_history"):
1919 self.selectHistory()
1920 elif cmd in ("%chist", "%chistory", "%clear_history"):
1921 self.clearHistory()
1922 self.__clientStatement(False)
1923 elif cmd == "%help":
1924 self.__showHelp()
1925 self.__clientStatement(False)
1926 else:
1927 s = self.tr("Error: Command '{0}' is not supported.\n").format(cmd)
1928 self.__write(s)
1929 self.__clientStatement(False)
1930 self.setFocus(Qt.FocusReason.OtherFocusReason)
1911 else: 1931 else:
1912 self.dbs.remoteStatement(self.__getSelectedDebuggerId(), cmd) 1932 self.dbs.remoteStatement(self.__getSelectedDebuggerId(), cmd)
1913 while self.inCommandExecution: 1933 while self.inCommandExecution:
1914 with contextlib.suppress(KeyboardInterrupt): 1934 with contextlib.suppress(KeyboardInterrupt):
1915 QApplication.processEvents() 1935 QApplication.processEvents()
2453 "<p>The file <b>{0}</b> could not be saved.<br/>" 2473 "<p>The file <b>{0}</b> could not be saved.<br/>"
2454 "Reason: {1}</p>" 2474 "Reason: {1}</p>"
2455 ).format(fpath, str(why)), 2475 ).format(fpath, str(why)),
2456 ) 2476 )
2457 2477
2478 @pyqtSlot()
2479 def __showHelp(self):
2480 """
2481 Private slot to show the list of supported special commands (i.e. those
2482 starting with a '%' character.
2483 """
2484 if self.__helpDialog is None:
2485 helpStr = "<table>"
2486 helpStr += self.tr(
2487 "<tr><td>%restart</td>"
2488 "<td>Kill the shell and start a new one.</td></tr>"
2489 "<tr><td>%clear</td>"
2490 "<td>Clear the display of the shell window.</td></tr>"
2491 "<tr><td>%start [environment]</td>"
2492 "<td>Start a shell for a virtual environment with the given name."
2493 " If no name if given, a default shell is started.</td></tr>"
2494 "<tr><td>%envs<br/>%environments</td>"
2495 "<td>Show a list of known virtual environment names.</td></tr>"
2496 "<tr><td>%which</td>"
2497 "<td>Show the name of the active virtual environment.</td></tr>"
2498 "<tr><td>%hist [n]<br/>%history [n]</td>"
2499 "<td>Show the most recent 'n' entries of the history. If 'n' is"
2500 " not given, show all entries.</td></tr>"
2501 "<tr><td>%shist<br/>%shistory<br/>%select_history</td>"
2502 "<td>Select a command from the history.</td></tr>"
2503 "<tr><td>%chist<br/>%chistory<br/>%clear_history</td>"
2504 "<td>Clear the current history after confirmation.</td></tr>"
2505 "<tr><td>%help</td><td>Show this help text.</td></tr>"
2506 )
2507 if self.__windowed:
2508 helpStr += self.tr(
2509 "<tr><td>%quit<br/>%quit()<br/>%exit<br/>%exit()</td>"
2510 "<td>Exit the application.</td></tr>"
2511 "</table>"
2512 "<p>These commands are available through the window menus as well."
2513 "</p>"
2514 )
2515 else:
2516 helpStr += self.tr(
2517 "</table>"
2518 "<p>These commands are available through the context menu as well."
2519 "</p>"
2520 )
2521
2522 self.__helpDialog = EricSimpleHelpDialog(
2523 title=self.tr("Shell Special Commands"),
2524 label=self.tr("The shell supports these special commands:"),
2525 helpStr=helpStr,
2526 parent=self,
2527 )
2528 self.__helpDialog.show()
2529
2458 ################################################################# 2530 #################################################################
2459 ## Project Support 2531 ## Project Support
2460 ################################################################# 2532 #################################################################
2461 2533
2462 def __projectOpened(self): 2534 def __projectOpened(self):

eric ide

mercurial