--- a/QScintilla/Terminal.py Sat Mar 09 17:05:49 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1128 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright (c) 2008 - 2013 Detlev Offenbach <detlev@die-offenbachs.de> -# - -""" -Module implementing a simple terminal based on QScintilla. -""" - -import sys -import os -import re - -from PyQt4.QtCore import pyqtSignal, QSignalMapper, QTimer, QByteArray, QProcess, Qt, \ - QEvent -from PyQt4.QtGui import QDialog, QInputDialog, QApplication, QMenu, QPalette, QFont, \ - QWidget, QHBoxLayout, QShortcut -from PyQt4.Qsci import QsciScintilla - -from E5Gui.E5Application import e5App - -from . import Lexers -from .QsciScintillaCompat import QsciScintillaCompat - -import Preferences -import Utilities - -import UI.PixmapCache -from UI.SearchWidget import SearchWidget - -from .ShellHistoryDialog import ShellHistoryDialog - - -class TerminalAssembly(QWidget): - """ - Class implementing the containing widget for the terminal. - """ - def __init__(self, vm, parent=None): - """ - Constructor - - @param vm reference to the viewmanager object - @param parent reference to the parent widget (QWidget) - """ - super().__init__(parent) - - self.setWindowIcon(UI.PixmapCache.getIcon("eric.png")) - - self.__terminal = Terminal(vm, self) - self.__searchWidget = SearchWidget(self.__terminal, self) - self.__searchWidget.hide() - - self.__layout = QHBoxLayout(self) - self.__layout.setContentsMargins(1, 1, 1, 1) - self.__layout.addWidget(self.__terminal) - self.__layout.addWidget(self.__searchWidget) - - self.__searchWidget.searchNext.connect(self.__terminal.searchNext) - self.__searchWidget.searchPrevious.connect(self.__terminal.searchPrev) - self.__terminal.searchStringFound.connect(self.__searchWidget.searchStringFound) - - def showFind(self, txt=""): - """ - Public method to display the search widget. - - @param txt text to be shown in the combo (string) - """ - self.__searchWidget.showFind(txt) - - def terminal(self): - """ - Public method to get a reference to the terminal widget. - - @return reference to the terminal widget (Terminal) - """ - return self.__terminal - - -class Terminal(QsciScintillaCompat): - """ - Class implementing a simple terminal based on QScintilla. - - A user can enter commands that are executed by a shell process. - - @signal searchStringFound(found) emitted to indicate the search result (boolean) - """ - searchStringFound = pyqtSignal(bool) - - def __init__(self, vm, parent=None): - """ - Constructor - - @param vm reference to the viewmanager object - @param parent parent widget (QWidget) - """ - super().__init__(parent) - self.setUtf8(True) - - self.vm = vm - self.__mainWindow = parent - self.__lastSearch = () - - self.linesepRegExp = r"\r\n|\n|\r" - - self.setWindowTitle(self.trUtf8('Terminal')) - - self.setWhatsThis(self.trUtf8( - """<b>The Terminal Window</b>""" - """<p>This is a very simple terminal like window, that runs a shell""" - """ process in the background.</p>""" - """<p>The process can be stopped and started via the context menu. Some""" - """ Ctrl command may be sent as well. However, the shell may ignore""" - """ them.</p>""" - """<p>You can use the cursor keys while entering commands. There is also a""" - """ history of commands that can be recalled using the up and down cursor""" - """ keys. Pressing the up or down key after some text has been entered will""" - """ start an incremental search.</p>""" - )) - - self.ansi_re = re.compile("\033\[\??[\d;]*\w") - - # Initialise instance variables. - self.prline = 0 - self.prcol = 0 - self.inDragDrop = False - self.lexer_ = None - - # Initialize history - self.maxHistoryEntries = Preferences.getTerminal("MaxHistoryEntries") - self.history = [] - self.histidx = -1 - - # clear QScintilla defined keyboard commands - # we do our own handling through the view manager - self.clearAlternateKeys() - self.clearKeys() - self.__actionsAdded = False - - # Create the history context menu - self.hmenu = QMenu(self.trUtf8('History')) - self.hmenu.addAction(self.trUtf8('Select entry'), self.__selectHistory) - self.hmenu.addAction(self.trUtf8('Show'), self.__showHistory) - self.hmenu.addAction(self.trUtf8('Clear'), self.__clearHistory) - - # Create a little context menu to send Ctrl-C, Ctrl-D or Ctrl-Z - self.csm = QSignalMapper(self) - self.csm.mapped[int].connect(self.__sendCtrl) - - self.cmenu = QMenu(self.trUtf8('Ctrl Commands')) - act = self.cmenu.addAction(self.trUtf8('Ctrl-C')) - self.csm.setMapping(act, 3) - act.triggered[()].connect(self.csm.map) - act = self.cmenu.addAction(self.trUtf8('Ctrl-D')) - self.csm.setMapping(act, 4) - act.triggered[()].connect(self.csm.map) - act = self.cmenu.addAction(self.trUtf8('Ctrl-Z')) - self.csm.setMapping(act, 26) - act.triggered[()].connect(self.csm.map) - - # Create a little context menu - self.menu = QMenu(self) - self.menu.addAction(self.trUtf8('Cut'), self.cut) - self.menu.addAction(self.trUtf8('Copy'), self.copy) - self.menu.addAction(self.trUtf8('Paste'), self.paste) - self.menu.addSeparator() - self.menu.addAction(self.trUtf8('Find'), self.__find) - self.menu.addSeparator() - self.menu.addMenu(self.hmenu) - self.menu.addSeparator() - self.menu.addAction(self.trUtf8('Clear'), self.clear) - self.__startAct = self.menu.addAction(self.trUtf8("Start"), self.__startShell) - self.__stopAct = self.menu.addAction(self.trUtf8("Stop"), self.__stopShell) - self.__resetAct = self.menu.addAction(self.trUtf8('Reset'), self.__reset) - self.menu.addSeparator() - self.__ctrlAct = self.menu.addMenu(self.cmenu) - self.menu.addSeparator() - self.menu.addAction(self.trUtf8("Configure..."), self.__configure) - - self.__bindLexer() - self.__setTextDisplay() - self.__setMargin0() - - self.setWindowIcon(UI.PixmapCache.getIcon("eric.png")) - - self.incrementalSearchString = "" - self.incrementalSearchActive = False - - self.supportedEditorCommands = { - QsciScintilla.SCI_LINEDELETE: self.__clearCurrentLine, - QsciScintilla.SCI_NEWLINE: self.__QScintillaNewline, - - QsciScintilla.SCI_DELETEBACK: self.__QScintillaDeleteBack, - QsciScintilla.SCI_CLEAR: self.__QScintillaDelete, - QsciScintilla.SCI_DELWORDLEFT: self.__QScintillaDeleteWordLeft, - QsciScintilla.SCI_DELWORDRIGHT: self.__QScintillaDeleteWordRight, - QsciScintilla.SCI_DELLINELEFT: self.__QScintillaDeleteLineLeft, - QsciScintilla.SCI_DELLINERIGHT: self.__QScintillaDeleteLineRight, - - QsciScintilla.SCI_CHARLEFT: self.__QScintillaCharLeft, - QsciScintilla.SCI_CHARRIGHT: self.__QScintillaCharRight, - QsciScintilla.SCI_WORDLEFT: self.__QScintillaWordLeft, - QsciScintilla.SCI_WORDRIGHT: self.__QScintillaWordRight, - QsciScintilla.SCI_VCHOME: self.__QScintillaVCHome, - QsciScintilla.SCI_LINEEND: self.__QScintillaLineEnd, - QsciScintilla.SCI_LINEUP: self.__QScintillaLineUp, - QsciScintilla.SCI_LINEDOWN: self.__QScintillaLineDown, - - QsciScintilla.SCI_CHARLEFTEXTEND: self.__QScintillaCharLeftExtend, - QsciScintilla.SCI_CHARRIGHTEXTEND: self.extendSelectionRight, - QsciScintilla.SCI_WORDLEFTEXTEND: self.__QScintillaWordLeftExtend, - QsciScintilla.SCI_WORDRIGHTEXTEND: self.extendSelectionWordRight, - QsciScintilla.SCI_VCHOMEEXTEND: self.__QScintillaVCHomeExtend, - QsciScintilla.SCI_LINEENDEXTEND: self.extendSelectionToEOL, - } - - self.__ioEncoding = Preferences.getSystem("IOEncoding") - - self.__process = QProcess() - self.__process.setProcessChannelMode(QProcess.MergedChannels) - self.__process.setReadChannel(QProcess.StandardOutput) - - self.__process.readyReadStandardOutput.connect(self.__readOutput) - self.__process.started.connect(self.__started) - self.__process.finished.connect(self.__finished) - - self.__ctrl = {} - for ascii_number, letter in enumerate("abcdefghijklmnopqrstuvwxyz"): - self.__ctrl[letter] = chr(ascii_number + 1) - - self.__lastPos = (0, 0) - - self.grabGesture(Qt.PinchGesture) - - self.__startShell() - - def __readOutput(self): - """ - Private method to process the output of the shell. - """ - output = str(self.__process.readAllStandardOutput(), - self.__ioEncoding, 'replace') - self.__write(self.ansi_re.sub("", output)) - self.__lastPos = self.__getEndPos() - - def __started(self): - """ - Private method called, when the shell process has started. - """ - if not Utilities.isWindowsPlatform(): - QTimer.singleShot(250, self.clear) - - self.__startAct.setEnabled(False) - self.__stopAct.setEnabled(True) - self.__resetAct.setEnabled(True) - self.__ctrlAct.setEnabled(True) - - def __finished(self): - """ - Private method called, when the shell process has finished. - """ - super().clear() - - self.__startAct.setEnabled(True) - self.__stopAct.setEnabled(False) - self.__resetAct.setEnabled(False) - self.__ctrlAct.setEnabled(False) - - def __send(self, data): - """ - Private method to send data to the shell process. - - @param data data to be sent to the shell process (string) - """ - pdata = QByteArray() - pdata.append(bytes(data, encoding="utf-8")) - self.__process.write(pdata) - - def __sendCtrl(self, cmd): - """ - Private slot to send a control command to the shell process. - - @param the control command to be sent (integer) - """ - self.__send(chr(cmd)) - - def closeTerminal(self): - """ - Public method to shutdown the terminal. - """ - self.__stopShell() - self.saveHistory() - - def __bindLexer(self): - """ - Private slot to set the lexer. - """ - if Utilities.isWindowsPlatform(): - self.language = "Batch" - else: - self.language = "Bash" - if Preferences.getTerminal("SyntaxHighlightingEnabled"): - self.lexer_ = Lexers.getLexer(self.language, self) - else: - self.lexer_ = None - - if self.lexer_ is None: - self.setLexer(None) - font = Preferences.getTerminal("MonospacedFont") - self.monospacedStyles(font) - return - - # get the font for style 0 and set it as the default font - key = 'Scintilla/{0}/style0/font'.format(self.lexer_.language()) - fdesc = Preferences.Prefs.settings.value(key) - if fdesc is not None: - font = QFont(fdesc[0], int(fdesc[1])) - self.lexer_.setDefaultFont(font) - self.setLexer(self.lexer_) - self.lexer_.readSettings(Preferences.Prefs.settings, "Scintilla") - - self.lexer_.setDefaultColor(self.lexer_.color(0)) - self.lexer_.setDefaultPaper(self.lexer_.paper(0)) - - def __setMargin0(self): - """ - Private method to configure margin 0. - """ - # set the settings for all margins - self.setMarginsFont(Preferences.getTerminal("MarginsFont")) - self.setMarginsForegroundColor(Preferences.getEditorColour("MarginsForeground")) - self.setMarginsBackgroundColor(Preferences.getEditorColour("MarginsBackground")) - - # set margin 0 settings - linenoMargin = Preferences.getTerminal("LinenoMargin") - self.setMarginLineNumbers(0, linenoMargin) - if linenoMargin: - self.setMarginWidth(0, ' ' + '8' * Preferences.getTerminal("LinenoWidth")) - else: - self.setMarginWidth(0, 0) - - # disable margins 1 and 2 - self.setMarginWidth(1, 0) - self.setMarginWidth(2, 0) - - def __setTextDisplay(self): - """ - Private method to configure the text display. - """ - self.setTabWidth(Preferences.getEditor("TabWidth")) - if Preferences.getEditor("ShowWhitespace"): - self.setWhitespaceVisibility(QsciScintilla.WsVisible) - try: - self.setWhitespaceForegroundColor( - Preferences.getEditorColour("WhitespaceForeground")) - self.setWhitespaceBackgroundColor( - Preferences.getEditorColour("WhitespaceBackground")) - self.setWhitespaceSize( - Preferences.getEditor("WhitespaceSize")) - except AttributeError: - # QScintilla before 2.5 doesn't support this - pass - else: - self.setWhitespaceVisibility(QsciScintilla.WsInvisible) - self.setEolVisibility(Preferences.getEditor("ShowEOL")) - if Preferences.getEditor("BraceHighlighting"): - self.setBraceMatching(QsciScintilla.SloppyBraceMatch) - else: - self.setBraceMatching(QsciScintilla.NoBraceMatch) - self.setMatchedBraceForegroundColor( - Preferences.getEditorColour("MatchingBrace")) - self.setMatchedBraceBackgroundColor( - Preferences.getEditorColour("MatchingBraceBack")) - self.setUnmatchedBraceForegroundColor( - Preferences.getEditorColour("NonmatchingBrace")) - self.setUnmatchedBraceBackgroundColor( - Preferences.getEditorColour("NonmatchingBraceBack")) - if Preferences.getEditor("CustomSelectionColours"): - self.setSelectionBackgroundColor( - Preferences.getEditorColour("SelectionBackground")) - else: - self.setSelectionBackgroundColor( - QApplication.palette().color(QPalette.Highlight)) - if Preferences.getEditor("ColourizeSelText"): - self.resetSelectionForegroundColor() - elif Preferences.getEditor("CustomSelectionColours"): - self.setSelectionForegroundColor( - Preferences.getEditorColour("SelectionForeground")) - else: - self.setSelectionForegroundColor( - QApplication.palette().color(QPalette.HighlightedText)) - self.setSelectionToEol(Preferences.getEditor("ExtendSelectionToEol")) - self.setCaretForegroundColor( - Preferences.getEditorColour("CaretForeground")) - self.setCaretLineBackgroundColor( - Preferences.getEditorColour("CaretLineBackground")) - self.setCaretLineVisible(Preferences.getEditor("CaretLineVisible")) - self.caretWidth = Preferences.getEditor("CaretWidth") - self.setCaretWidth(self.caretWidth) - self.setWrapMode(QsciScintilla.WrapNone) - self.useMonospaced = Preferences.getTerminal("UseMonospacedFont") - self.__setMonospaced(self.useMonospaced) - - self.setCursorFlashTime(QApplication.cursorFlashTime()) - - if Preferences.getEditor("OverrideEditAreaColours"): - self.setColor(Preferences.getEditorColour("EditAreaForeground")) - self.setPaper(Preferences.getEditorColour("EditAreaBackground")) - - def __setMonospaced(self, on): - """ - Private method to set/reset a monospaced font. - - @param on flag to indicate usage of a monospace font (boolean) - """ - if on: - f = Preferences.getTerminal("MonospacedFont") - self.monospacedStyles(f) - else: - if not self.lexer_: - self.clearStyles() - self.__setMargin0() - self.setFont(Preferences.getTerminal("MonospacedFont")) - - self.useMonospaced = on - - def loadHistory(self): - """ - Public method to load the history. - """ - hl = Preferences.Prefs.settings.value("Terminal/History") - if hl is not None: - self.history = hl[-self.maxHistoryEntries:] - else: - self.history = [] - - def reloadHistory(self): - """ - Public method to reload the history. - """ - self.loadHistory(self.clientType) - self.history = self.historyLists[self.clientType] - self.histidx = -1 - - def saveHistory(self): - """ - Public method to save the history. - """ - Preferences.Prefs.settings.setValue("Terminal/History", self.history) - - def getHistory(self): - """ - Public method to get the history. - - @return reference to the history list (list of strings) - """ - return self.history - - def __clearHistory(self): - """ - Private slot to clear the current history. - """ - self.history = [] - - def __selectHistory(self): - """ - Private slot to select a history entry to execute. - """ - cmd, ok = QInputDialog.getItem( - self, - self.trUtf8("Select History"), - self.trUtf8("Select the history entry to execute (most recent shown last)."), - self.history, - 0, False) - if ok: - self.__insertHistory(cmd) - - def __showHistory(self): - """ - Private slot to show the shell history dialog. - """ - dlg = ShellHistoryDialog(self.history, self.vm, self) - if dlg.exec_() == QDialog.Accepted: - self.history = dlg.getHistory() - self.histidx = -1 - - def __getEndPos(self): - """ - Private method to return the line and column of the last character. - - @return tuple of two values (int, int) giving the line and column - """ - line = self.lines() - 1 - return (line, len(self.text(line))) - - def __write(self, s): - """ - Private method to display some text. - - @param s text to be displayed (string) - """ - line, col = self.__getEndPos() - self.setCursorPosition(line, col) - self.insert(s) - self.prline, self.prcol = self.getCursorPosition() - self.ensureCursorVisible() - self.ensureLineVisible(self.prline) - - def __clearCurrentLine(self): - """ - Private method to clear the line containing the cursor. - """ - line, col = self.getCursorPosition() - if self.text(line).startswith(sys.ps1): - col = len(sys.ps1) - elif self.text(line).startswith(sys.ps2): - col = len(sys.ps2) - else: - col = 0 - self.setCursorPosition(line, col) - self.deleteLineRight() - - def __insertText(self, s): - """ - Private method to insert some text at the current cursor position. - - @param s text to be inserted (string) - """ - line, col = self.getCursorPosition() - self.insertAt(s, line, col) - self.setCursorPosition(line, col + len(s)) - - def __insertTextAtEnd(self, s): - """ - Private method to insert some text at the end of the command line. - - @param s text to be inserted (string) - """ - line, col = self.__getEndPos() - self.setCursorPosition(line, col) - self.insert(s) - self.prline, self.prcol = self.getCursorPosition() - - def mousePressEvent(self, event): - """ - Protected method to handle the mouse press event. - - @param event the mouse press event (QMouseEvent) - """ - self.setFocus() - super().mousePressEvent(event) - - def wheelEvent(self, evt): - """ - Protected method to handle wheel events. - - @param evt reference to the wheel event (QWheelEvent) - """ - if evt.modifiers() & Qt.ControlModifier: - if evt.delta() < 0: - self.zoomOut() - else: - self.zoomIn() - evt.accept() - return - - super().wheelEvent(evt) - - - def event(self, evt): - """ - Protected method handling events. - - @param evt reference to the event (QEvent) - @return flag indicating, if the event was handled (boolean) - """ - if evt.type() == QEvent.Gesture: - self.gestureEvent(evt) - return True - - return super().event(evt) - - def gestureEvent(self, evt): - """ - Protected method handling gesture events. - - @param evt reference to the gesture event (QGestureEvent - """ - pinch = evt.gesture(Qt.PinchGesture) - if pinch: - if pinch.state() == Qt.GestureStarted: - zoom = (self.getZoom() + 10) / 10.0 - pinch.setScaleFactor(zoom) - else: - zoom = int(pinch.scaleFactor() * 10) - 10 - if zoom <= -9: - zoom = -9 - pinch.setScaleFactor(0.1) - elif zoom >= 20: - zoom = 20 - pinch.setScaleFactor(3.0) - self.zoomTo(zoom) - evt.accept() - - def editorCommand(self, cmd): - """ - Public method to perform an editor command. - - @param cmd the scintilla command to be performed - """ - try: - self.supportedEditorCommands[cmd]() - except TypeError: - self.supportedEditorCommands[cmd](cmd) - except KeyError: - pass - - def __isCursorOnLastLine(self): - """ - Private method to check, if the cursor is on the last line. - """ - cline, ccol = self.getCursorPosition() - return cline == self.lines() - 1 - - def keyPressEvent(self, ev): - """ - Re-implemented to handle the user input a key at a time. - - @param ev key event (QKeyEvent) - """ - txt = ev.text() - - # See it is text to insert. - if len(txt) and txt >= " ": - if not self.__isCursorOnLastLine(): - line, col = self.__getEndPos() - self.setCursorPosition(line, col) - self.prline, self.prcol = self.getCursorPosition() - super().keyPressEvent(ev) - self.incrementalSearchActive = True - else: - ev.ignore() - - def __QScintillaLeftDeleteCommand(self, method): - """ - Private method to handle a QScintilla delete command working to the left. - - @param method shell method to execute - """ - if self.__isCursorOnLastLine(): - line, col = self.getCursorPosition() - if col > self.__lastPos[1]: - method() - - def __QScintillaDeleteBack(self): - """ - Private method to handle the Backspace key. - """ - self.__QScintillaLeftDeleteCommand(self.deleteBack) - - def __QScintillaDeleteWordLeft(self): - """ - Private method to handle the Delete Word Left command. - """ - self.__QScintillaLeftDeleteCommand(self.deleteWordLeft) - - def __QScintillaDelete(self): - """ - Private method to handle the delete command. - """ - if self.__isCursorOnLastLine(): - if self.hasSelectedText(): - lineFrom, indexFrom, lineTo, indexTo = self.getSelection() - if indexFrom >= self.__lastPos[1]: - self.delete() - self.setSelection(lineTo, indexTo, lineTo, indexTo) - else: - self.delete() - - def __QScintillaDeleteLineLeft(self): - """ - Private method to handle the Delete Line Left command. - """ - if self.__isCursorOnLastLine(): - if self.isListActive(): - self.cancelList() - - line, col = self.getCursorPosition() - prompt = self.text(line)[:self.__lastPos[1]] - self.deleteLineLeft() - self.insertAt(prompt, line, 0) - self.setCursorPosition(line, len(prompt)) - - def __QScintillaNewline(self, cmd): - """ - Private method to handle the Return key. - - @param cmd QScintilla command - """ - if self.__isCursorOnLastLine(): - self.incrementalSearchString = "" - self.incrementalSearchActive = False - line, col = self.__getEndPos() - self.setCursorPosition(line, col) - self.setSelection(*(self.__lastPos + self.getCursorPosition())) - buf = self.selectedText() - self.setCursorPosition(line, col) # select nothin - self.insert('\n') - self.__executeCommand(buf) - - def __QScintillaLeftCommand(self, method, allLinesAllowed=False): - """ - Private method to handle a QScintilla command working to the left. - - @param method shell method to execute - """ - if self.__isCursorOnLastLine() or allLinesAllowed: - line, col = self.getCursorPosition() - if col > self.__lastPos[1]: - method() - - def __QScintillaCharLeft(self): - """ - Private method to handle the Cursor Left command. - """ - self.__QScintillaLeftCommand(self.moveCursorLeft) - - def __QScintillaWordLeft(self): - """ - Private method to handle the Cursor Word Left command. - """ - self.__QScintillaLeftCommand(self.moveCursorWordLeft) - - def __QScintillaRightCommand(self, method): - """ - Private method to handle a QScintilla command working to the right. - - @param method shell method to execute - """ - if self.__isCursorOnLastLine(): - method() - - def __QScintillaCharRight(self): - """ - Private method to handle the Cursor Right command. - """ - self.__QScintillaRightCommand(self.moveCursorRight) - - def __QScintillaWordRight(self): - """ - Private method to handle the Cursor Word Right command. - """ - self.__QScintillaRightCommand(self.moveCursorWordRight) - - def __QScintillaDeleteWordRight(self): - """ - Private method to handle the Delete Word Right command. - """ - self.__QScintillaRightCommand(self.deleteWordRight) - - def __QScintillaDeleteLineRight(self): - """ - Private method to handle the Delete Line Right command. - """ - self.__QScintillaRightCommand(self.deleteLineRight) - - def __QScintillaVCHome(self, cmd): - """ - Private method to handle the Home key. - - @param cmd QScintilla command - """ - self.setCursorPosition(*self.__lastPos) - - def __QScintillaLineEnd(self, cmd): - """ - Private method to handle the End key. - - @param cmd QScintilla command - """ - self.moveCursorToEOL() - - def __QScintillaLineUp(self, cmd): - """ - Private method to handle the Up key. - - @param cmd QScintilla command - """ - line, col = self.__getEndPos() - buf = self.text(line)[self.__lastPos[1]:] - if buf and self.incrementalSearchActive: - if self.incrementalSearchString: - idx = self.__rsearchHistory(self.incrementalSearchString, - self.histidx) - if idx >= 0: - self.histidx = idx - self.__useHistory() - else: - idx = self.__rsearchHistory(buf) - if idx >= 0: - self.histidx = idx - self.incrementalSearchString = buf - self.__useHistory() - else: - if self.histidx < 0: - self.histidx = len(self.history) - if self.histidx > 0: - self.histidx = self.histidx - 1 - self.__useHistory() - - def __QScintillaLineDown(self, cmd): - """ - Private method to handle the Down key. - - @param cmd QScintilla command - """ - line, col = self.__getEndPos() - buf = self.text(line)[self.__lastPos[1]:] - if buf and self.incrementalSearchActive: - if self.incrementalSearchString: - idx = self.__searchHistory(self.incrementalSearchString, self.histidx) - if idx >= 0: - self.histidx = idx - self.__useHistory() - else: - idx = self.__searchHistory(buf) - if idx >= 0: - self.histidx = idx - self.incrementalSearchString = buf - self.__useHistory() - else: - if self.histidx >= 0 and self.histidx < len(self.history): - self.histidx += 1 - self.__useHistory() - - def __QScintillaCharLeftExtend(self): - """ - Private method to handle the Extend Selection Left command. - """ - self.__QScintillaLeftCommand(self.extendSelectionLeft, True) - - def __QScintillaWordLeftExtend(self): - """ - Private method to handle the Extend Selection Left one word command. - """ - self.__QScintillaLeftCommand(self.extendSelectionWordLeft, True) - - def __QScintillaVCHomeExtend(self): - """ - Private method to handle the Extend Selection to start of line command. - """ - col = self.__lastPos[1] - self.extendSelectionToBOL() - while col > 0: - self.extendSelectionRight() - col -= 1 - - def __executeCommand(self, cmd): - """ - Private slot to execute a command. - - @param cmd command to be executed by debug client (string) - """ - if not cmd: - cmd = '' - if 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 cmd.lower() in ["clear", "cls"]: - self.clear() - return - else: - if not cmd.endswith("\n"): - cmd = "{0}\n".format(cmd) - self.__send(cmd) - - def __useHistory(self): - """ - Private method to display a command from the history. - """ - if self.histidx < len(self.history): - cmd = self.history[self.histidx] - else: - cmd = "" - self.incrementalSearchString = "" - self.incrementalSearchActive = False - - self.__insertHistory(cmd) - - def __insertHistory(self, cmd): - """ - Private method to insert a command selected from the history. - - @param cmd history entry to be inserted (string) - """ - self.setCursorPosition(self.prline, self.prcol) - self.setSelection(self.prline, self.prcol,\ - self.prline, self.lineLength(self.prline)) - self.removeSelectedText() - self.__insertText(cmd) - - def __searchHistory(self, txt, startIdx=-1): - """ - Private method used to search the history. - - @param txt text to match at the beginning (string) - @param startIdx index to start search from (integer) - @return index of found entry (integer) - """ - if startIdx == -1: - idx = 0 - else: - idx = startIdx + 1 - while idx < len(self.history) and \ - not self.history[idx].startswith(txt): - idx += 1 - return idx - - def __rsearchHistory(self, txt, startIdx=-1): - """ - Private method used to reverse search the history. - - @param txt text to match at the beginning (string) - @param startIdx index to start search from (integer) - @return index of found entry (integer) - """ - if startIdx == -1: - idx = len(self.history) - 1 - else: - idx = startIdx - 1 - while idx >= 0 and \ - not self.history[idx].startswith(txt): - idx -= 1 - return idx - - def contextMenuEvent(self, ev): - """ - Reimplemented to show our own context menu. - - @param ev context menu event (QContextMenuEvent) - """ - self.menu.popup(ev.globalPos()) - ev.accept() - - def clear(self): - """ - Public slot to clear the display. - """ - super().clear() - self.__send("\n") - - def __reset(self): - """ - Private slot to handle the 'reset' context menu entry. - """ - self.__stopShell() - self.__startShell() - - def __startShell(self): - """ - Private slot to start the shell process. - """ - args = [] - if Utilities.isWindowsPlatform(): - args.append("/Q") - self.__process.start("cmd.exe", args) - else: - shell = Preferences.getTerminal("Shell") - if not shell: - shell = os.environ.get('SHELL') - if shell is None: - self.__insertText(self.trUtf8("No shell has been configured.")) - return - if Preferences.getTerminal("ShellInteractive"): - args.append("-i") - self.__process.start(shell, args) - - def __stopShell(self): - """ - Private slot to stop the shell process. - """ - self.__process.kill() - self.__process.waitForFinished(3000) - - def handlePreferencesChanged(self): - """ - Public slot to handle the preferencesChanged signal. - """ - # rebind the lexer - self.__bindLexer() - self.recolor() - - # set margin 0 configuration - self.__setTextDisplay() - self.__setMargin0() - - # do the history related stuff - self.maxHistoryEntries = Preferences.getTerminal("MaxHistoryEntries") - self.history = self.history[-self.maxHistoryEntries:] - - # do the I/O encoding - self.__ioEncoding = Preferences.getSystem("IOEncoding") - - def focusInEvent(self, event): - """ - Public method called when the shell receives focus. - - @param event the event object (QFocusEvent) - """ - if not self.__actionsAdded: - self.addActions(self.vm.editorActGrp.actions()) - self.addActions(self.vm.copyActGrp.actions()) - self.addActions(self.vm.viewActGrp.actions()) - self.__searchShortcut = QShortcut(self.vm.searchAct.shortcut(), self, - self.__find, self.__find) - self.__searchNextShortcut = QShortcut(self.vm.searchNextAct.shortcut(), self, - self.__searchNext, self.__searchNext) - self.__searchPrevShortcut = QShortcut(self.vm.searchPrevAct.shortcut(), self, - self.__searchPrev, self.__searchPrev) - - try: - self.vm.editActGrp.setEnabled(False) - self.vm.editorActGrp.setEnabled(True) - self.vm.copyActGrp.setEnabled(True) - self.vm.viewActGrp.setEnabled(True) - self.vm.searchActGrp.setEnabled(False) - except AttributeError: - pass - self.__searchShortcut.setEnabled(True) - self.__searchNextShortcut.setEnabled(True) - self.__searchPrevShortcut.setEnabled(True) - self.setCaretWidth(self.caretWidth) - self.setCursorFlashTime(QApplication.cursorFlashTime()) - - super().focusInEvent(event) - - def focusOutEvent(self, event): - """ - Public method called when the shell loses focus. - - @param event the event object (QFocusEvent) - """ - try: - self.vm.editorActGrp.setEnabled(False) - except AttributeError: - pass - self.__searchShortcut.setEnabled(False) - self.__searchNextShortcut.setEnabled(False) - self.__searchPrevShortcut.setEnabled(False) - self.setCaretWidth(0) - super().focusOutEvent(event) - - def insert(self, txt): - """ - Public slot to insert text at the current cursor position. - - The cursor is advanced to the end of the inserted text. - - @param txt text to be inserted (string) - """ - l = len(txt) - line, col = self.getCursorPosition() - self.insertAt(txt, line, col) - if re.search(self.linesepRegExp, txt) is not None: - line += 1 - self.setCursorPosition(line, col + l) - - def __configure(self): - """ - Private method to open the configuration dialog. - """ - e5App().getObject("UserInterface").showPreferences("terminalPage") - - def __find(self): - """ - Private slot to show the find widget. - """ - txt = self.selectedText() - self.__mainWindow.showFind(txt) - - def __searchNext(self): - """ - Private method to search for the next occurrence. - """ - if self.__lastSearch: - self.searchNext(*self.__lastSearch) - - def searchNext(self, txt, caseSensitive, wholeWord): - """ - Public method to search the next occurrence of the given text. - - @param txt text to search for (string) - @param caseSensitive flag indicating to perform a case sensitive - search (boolean) - @param wholeWord flag indicating to search for whole words - only (boolean) - """ - self.__lastSearch = (txt, caseSensitive, wholeWord) - ok = self.findFirst(txt, False, caseSensitive, wholeWord, False, forward=True) - self.searchStringFound.emit(ok) - - def __searchPrev(self): - """ - Private method to search for the next occurrence. - """ - if self.__lastSearch: - self.searchPrev(*self.__lastSearch) - - def searchPrev(self, txt, caseSensitive, wholeWord): - """ - Public method to search the previous occurrence of the given text. - - @param txt text to search for (string) - @param caseSensitive flag indicating to perform a case sensitive - search (boolean) - @param wholeWord flag indicating to search for whole words - only (boolean) - """ - self.__lastSearch = (txt, caseSensitive, wholeWord) - if self.hasSelectedText(): - line, index = self.getSelection()[:2] - else: - line, index = -1, -1 - ok = self.findFirst(txt, False, caseSensitive, wholeWord, False, forward=False, - line=line, index=index) - self.searchStringFound.emit(ok)