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): |
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 |
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): |