Mon, 10 Jul 2017 18:24:35 +0200
Finished improving the Shell window history handling.
--- a/Preferences/ConfigurationPages/ShellPage.py Sun Jul 09 19:44:33 2017 +0200 +++ b/Preferences/ConfigurationPages/ShellPage.py Mon Jul 10 18:24:35 2017 +0200 @@ -60,6 +60,10 @@ index = self.shellHistoryStyleComboBox.findData( Preferences.getShell("HistoryStyle")) self.shellHistoryStyleComboBox.setCurrentIndex(index) + self.shellHistoryWrapCheckBox.setChecked( + Preferences.getShell("HistoryWrap")) + self.shellHistoryCursorKeysCheckBox.setChecked( + Preferences.getShell("HistoryNavigateByCursor")) self.stdOutErrCheckBox.setChecked( Preferences.getShell("ShowStdOutErr")) @@ -96,6 +100,12 @@ "HistoryStyle", self.shellHistoryStyleComboBox.currentData()) Preferences.setShell( + "HistoryWrap", + self.shellHistoryWrapCheckBox.isChecked()) + Preferences.setShell( + "HistoryNavigateByCursor", + self.shellHistoryCursorKeysCheckBox.isChecked()) + Preferences.setShell( "ShowStdOutErr", self.stdOutErrCheckBox.isChecked())
--- a/Preferences/ConfigurationPages/ShellPage.ui Sun Jul 09 19:44:33 2017 +0200 +++ b/Preferences/ConfigurationPages/ShellPage.ui Mon Jul 10 18:24:35 2017 +0200 @@ -150,6 +150,30 @@ </property> </widget> </item> + <item row="2" column="0" colspan="3"> + <widget class="QCheckBox" name="shellHistoryWrapCheckBox"> + <property name="toolTip"> + <string>Select to wrap around while navigating through the history</string> + </property> + <property name="text"> + <string>Wrap around while navigating</string> + </property> + </widget> + </item> + <item row="3" column="0" colspan="3"> + <widget class="QCheckBox" name="shellHistoryCursorKeysCheckBox"> + <property name="toolTip"> + <string>Select to make Up- and Down-keys move in history</string> + </property> + <property name="whatsThis"> + <string><b>Up/Down keys navigate in history<b> +<p>Select this entry to make Up- and Down-keys navigate in history. If unselected history navigation may be performed by Ctrl-Up or Ctrl-Down.</p></string> + </property> + <property name="text"> + <string>Up/Down keys navigate in history</string> + </property> + </widget> + </item> </layout> </widget> </item> @@ -263,6 +287,8 @@ <tabstop>shellCTEnabledCheckBox</tabstop> <tabstop>shellHistorySpinBox</tabstop> <tabstop>shellHistoryStyleComboBox</tabstop> + <tabstop>shellHistoryWrapCheckBox</tabstop> + <tabstop>shellHistoryCursorKeysCheckBox</tabstop> <tabstop>monospacedFontButton</tabstop> <tabstop>monospacedCheckBox</tabstop> <tabstop>linenumbersFontButton</tabstop>
--- a/Preferences/__init__.py Sun Jul 09 19:44:33 2017 +0200 +++ b/Preferences/__init__.py Mon Jul 10 18:24:35 2017 +0200 @@ -1228,6 +1228,8 @@ "WrapEnabled": True, "MaxHistoryEntries": 100, "HistoryStyle": ShellHistoryStyle.LinuxStyle, + "HistoryWrap": False, + "HistoryNavigateByCursor": False, "SyntaxHighlightingEnabled": True, "ShowStdOutErr": True, "UseMonospacedFont": False,
--- a/QScintilla/Shell.py Sun Jul 09 19:44:33 2017 +0200 +++ b/QScintilla/Shell.py Mon Jul 10 18:24:35 2017 +0200 @@ -106,11 +106,11 @@ @signal searchStringFound(bool) emitted to indicate the search result - @signal historyStyleChanged(int) emitted to indicate a change of - the history style + @signal historyStyleChanged(ShellHistoryStyle) emitted to indicate a + change of the history style """ searchStringFound = pyqtSignal(bool) - historyStyleChanged = pyqtSignal(int) + historyStyleChanged = pyqtSignal(ShellHistoryStyle) def __init__(self, dbs, vm, windowedVariant, parent=None): """ @@ -220,18 +220,19 @@ self.lexer_ = None self.completionText = "" + self.clientType = '' + # Initialize history self.__historyLists = {} self.__maxHistoryEntries = Preferences.getShell("MaxHistoryEntries") self.__historyStyle = Preferences.getShell("HistoryStyle") + self.__historyWrap = Preferences.getShell("HistoryWrap") self.__history = [] self.__setHistoryIndex() # remove obsolete shell histories (Python and Ruby) for clientType in ["Python", "Ruby"]: Preferences.Prefs.settings.remove("Shell/Histories/" + clientType) - self.clientType = '' - # clear QScintilla defined keyboard commands # we do our own handling through the view manager self.clearAlternateKeys() @@ -316,10 +317,6 @@ QsciScintilla.SCI_WORDRIGHT: self.__QScintillaWordRight, QsciScintilla.SCI_VCHOME: self.__QScintillaVCHome, QsciScintilla.SCI_LINEEND: self.__QScintillaLineEnd, - QsciScintilla.SCI_LINEUP: self.__QScintillaCommand, - QsciScintilla.SCI_LINEDOWN: self.__QScintillaCommand, - QsciScintilla.SCI_LINESCROLLUP: self.__QScintillaHistoryUp, - QsciScintilla.SCI_LINESCROLLDOWN: self.__QScintillaHistoryDown, QsciScintilla.SCI_PAGEUP: self.__QScintillaAutoCompletionCommand, QsciScintilla.SCI_PAGEDOWN: self.__QScintillaAutoCompletionCommand, @@ -334,9 +331,29 @@ QsciScintilla.SCI_CANCEL: self.__QScintillaCancel, } + self.__setupCursorKeys() self.grabGesture(Qt.PinchGesture) - + + def __setupCursorKeys(self): + """ + Private method to setup the cursor up and down mode. + """ + if Preferences.getShell("HistoryNavigateByCursor"): + self.supportedEditorCommands.update({ + QsciScintilla.SCI_LINEUP: self.__QScintillaHistoryUp, + QsciScintilla.SCI_LINEDOWN: self.__QScintillaHistoryDown, + QsciScintilla.SCI_LINESCROLLUP: self.__QScintillaLineUp, + QsciScintilla.SCI_LINESCROLLDOWN: self.__QScintillaLineDown, + }) + else: + self.supportedEditorCommands.update({ + QsciScintilla.SCI_LINEUP: self.__QScintillaLineUp, + QsciScintilla.SCI_LINEDOWN: self.__QScintillaLineDown, + QsciScintilla.SCI_LINESCROLLUP: self.__QScintillaHistoryUp, + QsciScintilla.SCI_LINESCROLLDOWN: self.__QScintillaHistoryDown, + }) + def __showLanguageMenu(self): """ Private slot to prepare the language submenu. @@ -594,9 +611,12 @@ """ if index is None: # determine based on history style - if self.__historyStyle == ShellHistoryStyle.WindowsStyle: + if self.clientType and \ + self.__historyStyle == ShellHistoryStyle.WindowsStyle: idx = int(Preferences.Prefs.settings.value( "Shell/HistoryIndexes/" + self.clientType, -1)) + if idx >= len(self.__history): + idx = -1 self.__histidx = idx else: self.__histidx = -1 @@ -618,6 +638,15 @@ """ return (0 <= self.__histidx < len(self.__history)) + def getHistoryIndex(self): + """ + Public method to get the current value of the history index. + + @return history index + @rtype int + """ + return self.__histidx + def loadHistory(self, clientType): """ Public method to load the history for the given client type. @@ -963,12 +992,15 @@ lines = QApplication.clipboard().text(QClipboard.Selection) self.executeLines(lines) - def executeLines(self, lines): + def executeLines(self, lines, historyIndex=None): """ Public method to execute a set of lines as multiple commands. - @param lines multiple lines of text to be executed as single - commands (string) + @param lines multiple lines of text to be executed as + single commands + @type str + @param historyIndex history index to be set + @type int """ for line in lines.splitlines(True): if line.endswith("\r\n"): @@ -989,7 +1021,7 @@ elif cmd.startswith(sys.ps2): cmd = cmd[len(sys.ps2):] - self.__executeCommand(cmd) + self.__executeCommand(cmd, historyIndex=historyIndex) if self.interruptCommandExecution: self.__executeCommand("") break @@ -1394,10 +1426,26 @@ self.SendScintilla(cmd) elif self.__isCursorOnLastLine(): self.moveCursorToEOL() + + def __QScintillaLineUp(self, cmd): + """ + Private method to handle the cursor up command. + @param cmd QScintilla command + """ + self.SendScintilla(QsciScintilla.SCI_LINEUP) + + def __QScintillaLineDown(self, cmd): + """ + Private method to handle the cursor down command. + + @param cmd QScintilla command + """ + self.SendScintilla(QsciScintilla.SCI_LINEDOWN) + def __QScintillaHistoryUp(self, cmd): """ - Private method to handle the Ctrl+Up key. + Private method to handle the history up command. @param cmd QScintilla command """ @@ -1423,16 +1471,24 @@ self.incrementalSearchString = buf self.__useHistory() else: - if self.__histidx < 0: - # wrap around - self.__setHistoryIndex(index=len(self.__history) - 1) + if self.__historyWrap: + if self.__histidx < 0: + # wrap around + self.__setHistoryIndex(index=len(self.__history) - 1) + else: + self.__setHistoryIndex(index=self.__histidx - 1) + self.__useHistory() else: - self.__setHistoryIndex(index=self.__histidx - 1) - self.__useHistory() + if self.__histidx < 0: + self.__setHistoryIndex(index=len(self.__history) - 1) + self.__useHistory() + elif self.__histidx > 0: + self.__setHistoryIndex(index=self.__histidx - 1) + self.__useHistory() def __QScintillaHistoryDown(self, cmd): """ - Private method to handle the Ctrl+Down key. + Private method to handle the history down command. @param cmd QScintilla command """ @@ -1458,12 +1514,17 @@ self.incrementalSearchString = buf self.__useHistory() else: - if self.__histidx >= len(self.__history) - 1: - # wrap around - self.__setHistoryIndex(index=0) + if self.__historyWrap: + if self.__histidx >= len(self.__history) - 1: + # wrap around + self.__setHistoryIndex(index=0) + else: + self.__setHistoryIndex(index=self.__histidx + 1) + self.__useHistory() else: - self.__setHistoryIndex(index=self.__histidx + 1) - self.__useHistory() + if self.__isHistoryIndexValid(): + self.__setHistoryIndex(index=self.__histidx + 1) + self.__useHistory() def __QScintillaCancel(self): """ @@ -1511,11 +1572,14 @@ if self.isListActive() or self.isCallTipActive(): self.SendScintilla(cmd) - def __executeCommand(self, cmd): + def __executeCommand(self, cmd, historyIndex=None): """ Private slot to execute a command. - @param cmd command to be executed by debug client (string) + @param cmd command to be executed by debug client + @type str + @param historyIndex history index to be set + @type int """ if not self.inRawMode: self.inCommandExecution = True @@ -1523,16 +1587,23 @@ if not cmd: # make sure cmd is a string cmd = '' - # TODO: change according to history style - # Linux - append (i.e. keep as is) - # Windows - modify current entry if index not at end, add otherwise + + # History Handling if self.isHistoryEnabled(): if cmd != "" and ( len(self.__history) == 0 or self.__history[-1] != cmd): if len(self.__history) == self.__maxHistoryEntries: del self.__history[0] self.__history.append(cmd) - self.__histidx = -1 + if self.__historyStyle == ShellHistoryStyle.LinuxStyle: + self.__setHistoryIndex(index=-1) + elif self.__historyStyle == ShellHistoryStyle.WindowsStyle: + if historyIndex is None: + if cmd != self.__history[self.__histidx - 1]: + self.__setHistoryIndex(index=-1) + else: + self.__setHistoryIndex(historyIndex) + if cmd.startswith('start '): if not self.passive: cmdList = cmd.split(None, 1) @@ -1751,10 +1822,12 @@ self.__historyLists[key] = \ self.__historyLists[key][-self.__maxHistoryEntries:] self.__historyStyle = Preferences.getShell("HistoryStyle") + self.__historyWrap = Preferences.getShell("HistoryWrap") self.__setHistoryIndex() - self.historyStyleChanged.emit(self.__historyStyle) if not self.__windowed: self.hmenu.menuAction().setEnabled(self.isHistoryEnabled()) + self.__setupCursorKeys() + self.historyStyleChanged.emit(self.__historyStyle) # do stdout /stderr stuff showStdOutErr = Preferences.getShell("ShowStdOutErr")
--- a/QScintilla/ShellHistoryDialog.py Sun Jul 09 19:44:33 2017 +0200 +++ b/QScintilla/ShellHistoryDialog.py Mon Jul 10 18:24:35 2017 +0200 @@ -11,7 +11,7 @@ import os -from PyQt5.QtCore import pyqtSlot, QItemSelectionModel +from PyQt5.QtCore import pyqtSlot, Qt, QItemSelectionModel from PyQt5.QtWidgets import QListWidgetItem, QDialog from .Ui_ShellHistoryDialog import Ui_ShellHistoryDialog @@ -25,20 +25,27 @@ """ Constructor - @param history reference to the current shell history (list of strings) + @param history reference to the current shell history + @type list of str @param vm reference to the viewmanager object + @type ViewManager @param shell reference to the shell object + @type Shell """ super(ShellHistoryDialog, self).__init__(shell) self.setupUi(self) + self.__vm = vm + self.__shell = shell + self.historyList.addItems(history) - self.historyList.setCurrentRow( - self.historyList.count() - 1, QItemSelectionModel.Clear) + index = shell.getHistoryIndex() + if index < 0 or index >= len(history): + self.historyList.setCurrentRow( + self.historyList.count() - 1, QItemSelectionModel.Select) + else: + self.historyList.setCurrentRow(index, QItemSelectionModel.Select) self.historyList.scrollToItem(self.historyList.currentItem()) - - self.vm = vm - self.shell = shell @pyqtSlot() def on_historyList_itemSelectionChanged(self): @@ -47,7 +54,7 @@ """ selected = len(self.historyList.selectedItems()) > 0 self.copyButton.setEnabled(selected and - self.vm.activeWindow() is not None) + self.__vm.activeWindow() is not None) self.deleteButton.setEnabled(selected) self.executeButton.setEnabled(selected) @@ -77,7 +84,7 @@ """ Private slot to copy the selected entries to the current editor. """ - aw = self.vm.activeWindow() + aw = self.__vm.activeWindow() if aw is not None: lines = [] for index in range(self.historyList.count()): @@ -102,7 +109,9 @@ if itm.isSelected(): lines.append(itm.text()) cmds = os.linesep.join(lines) + os.linesep - self.shell.executeLines(cmds) + self.__shell.executeLines( + cmds, + historyIndex=self.historyList.currentRow()) # reload the list because shell modified it self.on_reloadButton_clicked() @@ -112,13 +121,20 @@ """ Private slot to reload the history. """ - history = self.shell.getHistory(None) + history = self.__shell.getHistory(None) + index = self.__shell.getHistoryIndex() + self.historyList.clear() self.historyList.addItems(history) - self.historyList.setCurrentRow( - self.historyList.count() - 1, QItemSelectionModel.Clear) + if index < 0 or index >= len(history): + self.historyList.setCurrentRow( + self.historyList.count() - 1, QItemSelectionModel.Select) + else: + self.historyList.setCurrentRow(index, QItemSelectionModel.Select) self.historyList.scrollToItem(self.historyList.currentItem()) + self.historyList.setFocus(Qt.OtherFocusReason) + def getHistory(self): """ Public method to retrieve the history from the dialog.
--- a/QScintilla/ShellWindow.py Sun Jul 09 19:44:33 2017 +0200 +++ b/QScintilla/ShellWindow.py Mon Jul 10 18:24:35 2017 +0200 @@ -40,7 +40,6 @@ from eric6config import getConfig -# TODO: implement history handling changes (Shell.historyStyleChanged) class ShellWindow(E5MainWindow): """ Class implementing a stand alone shell window. @@ -93,6 +92,8 @@ self.__readSettings() + self.__shell.historyStyleChanged.connect(self.__historyStyleChanged) + # now start the debug client self.__debugServer.startClient(False) @@ -1133,6 +1134,7 @@ self.__historyMenu.addAction(self.selectHistoryAct) self.__historyMenu.addAction(self.showHistoryAct) self.__historyMenu.addAction(self.clearHistoryAct) + self.__historyMenu.setEnabled(self.__shell.isHistoryEnabled()) self.__startMenu = self.menuBar().addMenu(self.tr("&Start")) self.__startMenu.aboutToShow.connect(self.__showLanguageMenu) @@ -1204,10 +1206,11 @@ viewtb.addAction(self.zoomResetAct) viewtb.addAction(self.zoomToAct) - historytb = self.addToolBar(self.tr("History")) - historytb.setIconSize(UI.Config.ToolBarIconSize) - historytb.addAction(self.showHistoryAct) - historytb.addAction(self.clearHistoryAct) + self.__historyToolbar = self.addToolBar(self.tr("History")) + self.__historyToolbar.setIconSize(UI.Config.ToolBarIconSize) + self.__historyToolbar.addAction(self.showHistoryAct) + self.__historyToolbar.addAction(self.clearHistoryAct) + self.__historyToolbar.setEnabled(self.__shell.isHistoryEnabled()) helptb = self.addToolBar(self.tr("Help")) helptb.setIconSize(UI.Config.ToolBarIconSize) @@ -1236,3 +1239,14 @@ self.__sbZoom.valueChanged.connect(self.__zoomTo) self.__sbZoom.setValue(0) + + def __historyStyleChanged(self, historyStyle): + """ + Private slot to handle a change of the shell history style. + + @param historyStyle style to be used for the history + @type ShellHistoryStyle + """ + enabled = self.__shell.isHistoryEnabled() + self.__historyMenu.setEnabled(enabled) + self.__historyToolbar.setEnabled(enabled)