eric6/QScintilla/Shell.py

changeset 6942
2602857055c5
parent 6858
9d962e654978
child 6987
3371a03ed0a7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/QScintilla/Shell.py	Sun Apr 14 15:09:21 2019 +0200
@@ -0,0 +1,2324 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2002 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a graphical Python shell.
+"""
+
+from __future__ import unicode_literals
+
+import sys
+import re
+
+try:
+    from enum import Enum
+except ImportError:
+    from ThirdParty.enum import Enum
+
+from PyQt5.QtCore import pyqtSignal, QFileInfo, Qt, QEvent
+from PyQt5.QtGui import QClipboard, QPalette, QFont
+from PyQt5.QtWidgets import QDialog, QInputDialog, QApplication, QMenu, \
+    QWidget, QHBoxLayout, QVBoxLayout, QShortcut, QSizePolicy
+from PyQt5.Qsci import QsciScintilla
+
+from E5Gui.E5Application import e5App
+from E5Gui import E5MessageBox
+
+from .QsciScintillaCompat import QsciScintillaCompat
+
+import Preferences
+import Utilities
+from Globals import qVersionTuple
+
+import UI.PixmapCache
+
+from Debugger.DebugClientCapabilities import HasCompleter
+
+
+class ShellAssembly(QWidget):
+    """
+    Class implementing the containing widget for the shell.
+    """
+    def __init__(self, dbs, vm, project, horizontal=True, parent=None):
+        """
+        Constructor
+        
+        @param dbs reference to the debug server object
+        @type DebugServer
+        @param vm reference to the viewmanager object
+        @type ViewManager
+        @param project reference to the project object
+        @type Project
+        @param horizontal flag indicating a horizontal layout
+        @type bool
+        @param parent parent widget
+        @type QWidget
+        """
+        super(ShellAssembly, self).__init__(parent)
+        
+        self.__shell = Shell(dbs, vm, project, False, self)
+        
+        from UI.SearchWidget import SearchWidget
+        self.__searchWidget = SearchWidget(self.__shell, self, horizontal)
+        self.__searchWidget.setSizePolicy(QSizePolicy.Fixed,
+                                          QSizePolicy.Preferred)
+        self.__searchWidget.hide()
+        
+        if horizontal:
+            self.__layout = QHBoxLayout(self)
+        else:
+            self.__layout = QVBoxLayout(self)
+        self.__layout.setContentsMargins(1, 1, 1, 1)
+        self.__layout.addWidget(self.__shell)
+        self.__layout.addWidget(self.__searchWidget)
+        
+        self.__searchWidget.searchNext.connect(self.__shell.searchNext)
+        self.__searchWidget.searchPrevious.connect(self.__shell.searchPrev)
+        self.__shell.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 shell(self):
+        """
+        Public method to get a reference to the terminal widget.
+        
+        @return reference to the shell widget (Shell)
+        """
+        return self.__shell
+
+
+class ShellHistoryStyle(Enum):
+    """
+    Class defining the shell history styles.
+    """
+    Disabled = 0
+    LinuxStyle = 1
+    WindowsStyle = 2
+
+
+class Shell(QsciScintillaCompat):
+    """
+    Class implementing a graphical Python shell.
+    
+    A user can enter commands that are executed in the remote
+    Python interpreter.
+    
+    @signal searchStringFound(bool) emitted to indicate the search
+        result
+    @signal historyStyleChanged(ShellHistoryStyle) emitted to indicate a
+        change of the history style
+    @signal queueText(str) emitted to queue some text for processing
+    @signal virtualEnvironmentChanged(str) emitted to signal the new virtual
+        environment of the shell
+    """
+    searchStringFound = pyqtSignal(bool)
+    historyStyleChanged = pyqtSignal(ShellHistoryStyle)
+    queueText = pyqtSignal(str)
+    virtualEnvironmentChanged = pyqtSignal(str)
+    
+    def __init__(self, dbs, vm, project, windowedVariant, parent=None):
+        """
+        Constructor
+        
+        @param dbs reference to the debug server object
+        @type DebugServer
+        @param vm reference to the viewmanager object
+        @type ViewManager
+        @param project reference to the project object
+        @type Project
+        @param windowedVariant flag indicating the shell window variant
+        @type bool
+        @param parent parent widget
+        @type QWidget
+        """
+        super(Shell, self).__init__(parent)
+        self.setUtf8(True)
+        
+        self.vm = vm
+        self.__mainWindow = parent
+        self.__lastSearch = ()
+        self.__windowed = windowedVariant
+        self.__currentVenv = ""
+        self.__currentWorkingDirectory = ""
+        
+        self.linesepRegExp = r"\r\n|\n|\r"
+        
+        self.passive = ((not self.__windowed) and
+                        Preferences.getDebugger("PassiveDbgEnabled"))
+        if self.passive:
+            self.setWindowTitle(self.tr('Shell - Passive'))
+        else:
+            self.setWindowTitle(self.tr('Shell'))
+        
+        if self.__windowed:
+            self.setWhatsThis(self.tr(
+                """<b>The Shell Window</b>"""
+                """<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 while holding down the"""
+                """ Ctrl-key. This can be switched to just the up and down"""
+                """ cursor keys on the Shell page of the configuration"""
+                """ dialog. Pressing these keys after some text has been"""
+                """ entered will start an incremental search.</p>"""
+                """<p>The shell has some special commands. 'restart' kills"""
+                """ the shell and starts a new one. 'clear' clears the"""
+                """ display of the shell window. 'start' is used to start a"""
+                """ shell for a virtual environment and should be followed"""
+                """ by a virtual environment name. start' without a virtual"""
+                """ environment name starts the default shell. Available"""
+                """ virtual environments may be listed with the 'envs' or"""
+                """ 'environments' commands. The active virtual environment"""
+                """ can be questioned by the 'which' command. 'quit' or"""
+                """ 'exit' is used to exit the application. These commands"""
+                """ (except environments', 'envs' and 'which') are available"""
+                """ through the window menus as well.</p>"""
+                """<p>Pressing the Tab key after some text has been entered"""
+                """ will show a list of possible completions. The relevant"""
+                """ entry may be selected from this list. If only one entry"""
+                """ is available, this will be inserted automatically.</p>"""
+            ))
+        else:
+            self.setWhatsThis(self.tr(
+                """<b>The Shell Window</b>"""
+                """<p>This is simply an interpreter running in a window. The"""
+                """ interpreter is the one that is used to run the program"""
+                """ being debugged. This means that you can execute any"""
+                """ command while the program being debugged is running.</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 while holding down the"""
+                """ Ctrl-key. This can be switched to just the up and down"""
+                """ cursor keys on the Shell page of the configuration"""
+                """ dialog. Pressing these keys after some text has been"""
+                """ entered will start an incremental search.</p>"""
+                """<p>The shell has some special commands. 'restart' kills"""
+                """ the shell and starts a new one. 'clear' clears the"""
+                """ display of the shell window. 'start' is used to start a"""
+                """ shell for a virtual environment and should be followed"""
+                """ by a virtual environment name. start' without a virtual"""
+                """ environment name starts the default shell. Available"""
+                """ virtual environments may be listed with the 'envs' or"""
+                """ 'environments' commands. The active virtual environment"""
+                """ can be questioned by the 'which' command. These commands"""
+                """ (except environments' and 'envs') are available through"""
+                """ the context menu as well.</p>"""
+                """<p>Pressing the Tab key after some text has been entered"""
+                """ will show a list of possible completions. The relevant"""
+                """ entry may be selected from this list. If only one entry"""
+                """ is available, this will be inserted automatically.</p>"""
+                """<p>In passive debugging mode the shell is only available"""
+                """ after the program to be debugged has connected to the"""
+                """ IDE until it has finished. This is indicated by a"""
+                """ different prompt and by an indication in the window"""
+                """ caption.</p>"""
+            ))
+        
+        self.userListActivated.connect(self.__completionListSelected)
+        self.linesChanged.connect(self.__resizeLinenoMargin)
+        
+        if self.__windowed:
+            self.__showStdOutErr = True
+        else:
+            self.__showStdOutErr = Preferences.getShell("ShowStdOutErr")
+        if self.__showStdOutErr:
+            dbs.clientProcessStdout.connect(self.__writeStdOut)
+            dbs.clientProcessStderr.connect(self.__writeStdErr)
+        dbs.clientOutput.connect(self.__writeQueued)
+        dbs.clientStatement.connect(self.__clientStatement)
+        dbs.clientGone.connect(self.__initialise)
+        dbs.clientRawInput.connect(self.__raw_input)
+        dbs.clientBanner.connect(self.__writeBanner)
+        dbs.clientCompletionList.connect(self.__showCompletions)
+        dbs.clientCapabilities.connect(self.__clientCapabilities)
+        dbs.clientException.connect(self.__clientException)
+        dbs.clientSyntaxError.connect(self.__clientSyntaxError)
+        dbs.clientSignal.connect(self.__clientSignal)
+        self.dbs = dbs
+        
+        # Initialize instance variables.
+        self.__initialise()
+        self.prline = 0
+        self.prcol = 0
+        self.inDragDrop = False
+        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)
+        
+        # clear QScintilla defined keyboard commands
+        # we do our own handling through the view manager
+        self.clearAlternateKeys()
+        self.clearKeys()
+        self.__actionsAdded = False
+        
+        # Make sure we have prompts.
+        if self.passive:
+            sys.ps1 = self.tr("Passive >>> ")
+        else:
+            try:
+                sys.ps1
+            except AttributeError:
+                sys.ps1 = ">>> "
+        try:
+            sys.ps2
+        except AttributeError:
+            sys.ps2 = "... "
+        
+        if self.passive:
+            self.__getBanner()
+        
+        if not self.__windowed:
+            # Create a little language context menu
+            self.lmenu = QMenu(self.tr('Start'))
+            self.lmenu.aboutToShow.connect(self.__showStartMenu)
+            self.lmenu.triggered.connect(self.__startDebugClient)
+            
+            # Create the history context menu
+            self.hmenu = QMenu(self.tr('History'))
+            self.hmenu.addAction(self.tr('Select entry'), self.selectHistory)
+            self.hmenu.addAction(self.tr('Show'), self.showHistory)
+            self.hmenu.addAction(self.tr('Clear'), self.clearHistory)
+            
+            # Create a little context menu
+            self.menu = QMenu(self)
+            self.menu.addAction(self.tr('Cut'), self.cut)
+            self.menu.addAction(self.tr('Copy'), self.copy)
+            self.menu.addAction(self.tr('Paste'), self.paste)
+            self.menu.addMenu(self.hmenu).setEnabled(self.isHistoryEnabled())
+            
+            self.menu.addSeparator()
+            self.menu.addAction(self.tr('Find'), self.__find)
+            self.menu.addSeparator()
+            self.menu.addAction(self.tr('Clear'), self.clear)
+            self.menu.addAction(self.tr('Restart'), self.doRestart)
+            self.menu.addAction(
+                self.tr('Restart and Clear'), self.doClearRestart)
+            self.menu.addSeparator()
+            self.menu.addMenu(self.lmenu)
+            self.menu.addAction(self.tr('Active Name'), self.__showVenvName)
+            self.menu.addSeparator()
+            self.menu.addAction(self.tr("Configure..."), self.__configure)
+        
+        self.__bindLexer()
+        self.__setTextDisplay()
+        self.__setMargin0()
+        
+        # set the autocompletion and calltips function
+        self.__setAutoCompletion()
+        self.__setCallTips()
+        
+        self.setWindowIcon(UI.PixmapCache.getIcon("eric.png"))
+        
+        self.incrementalSearchString = ""
+        self.incrementalSearchActive = False
+        
+        self.supportedEditorCommands = {
+            QsciScintilla.SCI_LINEDELETE: self.__clearCurrentLine,
+            QsciScintilla.SCI_TAB: self.__QScintillaTab,
+            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.__QScintillaCursorCommand,
+            QsciScintilla.SCI_LINEDOWN: self.__QScintillaCursorCommand,
+            QsciScintilla.SCI_LINESCROLLUP: self.__QScintillaCursorCommand,
+            QsciScintilla.SCI_LINESCROLLDOWN: self.__QScintillaCursorCommand,
+            
+            QsciScintilla.SCI_PAGEUP: self.__QScintillaAutoCompletionCommand,
+            QsciScintilla.SCI_PAGEDOWN: self.__QScintillaAutoCompletionCommand,
+            
+            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,
+            
+            QsciScintilla.SCI_CANCEL: self.__QScintillaCancel,
+        }
+        
+        self.__historyNavigateByCursor = \
+            Preferences.getShell("HistoryNavigateByCursor")
+        
+        self.__queuedText = ''
+        self.__blockTextProcessing = False
+        self.queueText.connect(self.__concatenateText, Qt.QueuedConnection)
+        
+        self.__project = project
+        if self.__project:
+            self.__project.projectOpened.connect(self.__projectOpened)
+            self.__project.projectClosed.connect(self.__projectClosed)
+        
+        self.grabGesture(Qt.PinchGesture)
+    
+    def __showStartMenu(self):
+        """
+        Private slot to prepare the start submenu.
+        """
+        self.lmenu.clear()
+        venvManager = e5App().getObject("VirtualEnvManager")
+        for venvName in sorted(venvManager.getVirtualenvNames()):
+            self.lmenu.addAction(venvName)
+        if self.__project.isOpen():
+            self.lmenu.addSeparator()
+            self.lmenu.addAction(self.tr("Project"))
+        
+    def __resizeLinenoMargin(self):
+        """
+        Private slot to resize the line numbers margin.
+        """
+        linenoMargin = Preferences.getShell("LinenoMargin")
+        if linenoMargin:
+            self.setMarginWidth(0, '8' * (len(str(self.lines())) + 1))
+        
+    def closeShell(self):
+        """
+        Public method to shutdown the shell.
+        """
+        for clientType in self.__historyLists:
+            self.saveHistory(clientType)
+        
+    def __bindLexer(self, language='Python3'):
+        """
+        Private slot to set the lexer.
+        
+        @param language lexer language to set (string)
+        """
+        self.language = language
+        if Preferences.getShell("SyntaxHighlightingEnabled"):
+            from . import Lexers
+            self.lexer_ = Lexers.getLexer(self.language, self)
+        else:
+            self.lexer_ = None
+        
+        if self.lexer_ is None:
+            self.setLexer(None)
+            font = Preferences.getShell("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")
+        if self.lexer_.hasSubstyles():
+            self.lexer_.readSubstyles(self)
+        
+        # initialize the lexer APIs settings
+        api = self.vm.getAPIsManager().getAPIs(self.language)
+        if api is not None:
+            api = api.getQsciAPIs()
+            if api is not None:
+                self.lexer_.setAPIs(api)
+        
+        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.getShell("MarginsFont"))
+        self.setMarginsForegroundColor(
+            Preferences.getEditorColour("MarginsForeground"))
+        self.setMarginsBackgroundColor(
+            Preferences.getEditorColour("MarginsBackground"))
+        
+        # set margin 0 settings
+        linenoMargin = Preferences.getShell("LinenoMargin")
+        self.setMarginLineNumbers(0, linenoMargin)
+        if linenoMargin:
+            self.__resizeLinenoMargin()
+        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.setCaretLineVisible(False)
+        self.caretWidth = Preferences.getEditor("CaretWidth")
+        self.setCaretWidth(self.caretWidth)
+        if Preferences.getShell("WrapEnabled"):
+            self.setWrapMode(QsciScintilla.WrapWord)
+        else:
+            self.setWrapMode(QsciScintilla.WrapNone)
+        self.useMonospaced = Preferences.getShell("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:
+            if not self.lexer_:
+                f = Preferences.getShell("MonospacedFont")
+                self.monospacedStyles(f)
+        else:
+            if not self.lexer_:
+                self.clearStyles()
+                self.__setMargin0()
+            self.setFont(Preferences.getShell("MonospacedFont"))
+        
+        self.useMonospaced = on
+        
+    def __setAutoCompletion(self, language='Python'):
+        """
+        Private method to configure the autocompletion function.
+        
+        @param language of the autocompletion set to set (string)
+        """
+        self.setAutoCompletionCaseSensitivity(
+            Preferences.getEditor("AutoCompletionCaseSensitivity"))
+        self.setAutoCompletionThreshold(-1)
+        
+        self.racEnabled = Preferences.getShell("AutoCompletionEnabled")
+        
+        self.maxLines = Preferences.getEditor("AutoCompletionMaxLines")
+        self.maxChars = Preferences.getEditor("AutoCompletionMaxChars")
+        
+    def __setCallTips(self, language='Python'):
+        """
+        Private method to configure the calltips function.
+        
+        @param language of the calltips set to set (string)
+        """
+        if Preferences.getShell("CallTipsEnabled"):
+            self.setCallTipsBackgroundColor(
+                Preferences.getEditorColour("CallTipsBackground"))
+            self.setCallTipsVisible(Preferences.getEditor("CallTipsVisible"))
+            calltipsStyle = Preferences.getEditor("CallTipsStyle")
+            if calltipsStyle == QsciScintilla.CallTipsNoContext:
+                self.setCallTipsStyle(QsciScintilla.CallTipsNoContext)
+            elif calltipsStyle == \
+                    QsciScintilla.CallTipsNoAutoCompletionContext:
+                self.setCallTipsStyle(
+                    QsciScintilla.CallTipsNoAutoCompletionContext)
+            else:
+                self.setCallTipsStyle(QsciScintilla.CallTipsContext)
+        else:
+            self.setCallTipsStyle(QsciScintilla.CallTipsNone)
+        
+    def setDebuggerUI(self, ui):
+        """
+        Public method to set the debugger UI.
+        
+        @param ui reference to the debugger UI object (DebugUI)
+        """
+        ui.exceptionInterrupt.connect(self.__writePrompt)
+        
+    def __initialise(self):
+        """
+        Private method to get ready for a new remote interpreter.
+        """
+        self.buff = ""
+        self.inContinue = False
+        self.inRawMode = False
+        self.echoInput = True
+        self.clientCapabilities = 0
+        self.inCommandExecution = False
+        self.interruptCommandExecution = False
+        
+    def __clientCapabilities(self, cap, clType, venvName):
+        """
+        Private slot to handle the reporting of the clients capabilities.
+        
+        @param cap client capabilities
+        @type int
+        @param clType type of the debug client
+        @type str
+        @param venvName name of the virtual environment
+        @type str
+        """
+        self.clientCapabilities = cap
+        self.__currentVenv = venvName
+        if clType != self.clientType:
+            self.clientType = clType
+            self.__bindLexer(self.clientType)
+            self.__setTextDisplay()
+            self.__setMargin0()
+            self.__setAutoCompletion(self.clientType)
+            self.__setCallTips(self.clientType)
+            self.racEnabled = \
+                Preferences.getShell("AutoCompletionEnabled") and \
+                (cap & HasCompleter) > 0
+            
+            if self.clientType not in self.__historyLists:
+                # load history list
+                self.loadHistory(self.clientType)
+            self.__history = self.__historyLists[self.clientType]
+            self.__setHistoryIndex()
+        
+        self.virtualEnvironmentChanged.emit(venvName)
+        Preferences.setShell("LastVirtualEnvironment", venvName)
+    
+    def __setHistoryIndex(self, index=None):
+        """
+        Private method to set the initial history index.
+        
+        @param index index value to be set
+        @type int or None
+        """
+        if index is None:
+            # determine based on history style
+            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
+        else:
+            self.__histidx = index
+            if self.__histidx >= len(self.__history):
+                self.__histidx = -1
+            if self.clientType and \
+                    self.__historyStyle == ShellHistoryStyle.WindowsStyle:
+                Preferences.Prefs.settings.setValue(
+                    "Shell/HistoryIndexes/" + self.clientType, self.__histidx)
+    
+    def __isHistoryIndexValid(self):
+        """
+        Private method to test, if the history index is valid.
+        
+        @return flag indicating validity
+        @rtype bool
+        """
+        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.
+        
+        @param clientType type of the debug client (string)
+        """
+        hl = Preferences.Prefs.settings.value("Shell/Histories/" + clientType)
+        if hl is not None:
+            self.__historyLists[clientType] = hl[-self.__maxHistoryEntries:]
+        else:
+            self.__historyLists[clientType] = []
+        
+    def reloadHistory(self):
+        """
+        Public method to reload the history of the currently selected client
+        type.
+        """
+        self.loadHistory(self.clientType)
+        self.__history = self.__historyLists[self.clientType]
+        self.__setHistoryIndex()
+        
+    def saveHistory(self, clientType):
+        """
+        Public method to save the history for the given client type.
+        
+        @param clientType type of the debug client (string)
+        """
+        if clientType in self.__historyLists:
+            Preferences.Prefs.settings.setValue(
+                "Shell/Histories/" + clientType,
+                self.__historyLists[clientType])
+        
+    def getHistory(self, clientType):
+        """
+        Public method to get the history for the given client type.
+        
+        @param clientType type of the debug client (string).
+            If it is None, the current history is returned.
+        @return reference to the history list (list of strings)
+        """
+        if clientType is None:
+            return self.__history
+        elif clientType in self.__historyLists:
+            return self.__historyLists[clientType]
+        else:
+            return []
+        
+    def clearHistory(self):
+        """
+        Public slot to clear the current history.
+        """
+        if self.clientType:
+            self.__historyLists[self.clientType] = []
+            self.__history = self.__historyLists[self.clientType]
+        else:
+            self.__history = []
+        self.__setHistoryIndex(index=-1)
+        
+    def selectHistory(self):
+        """
+        Public slot to select a history entry to execute.
+        """
+        current = self.__histidx
+        if current == -1:
+            current = len(self.__history) - 1
+        cmd, ok = QInputDialog.getItem(
+            self,
+            self.tr("Select History"),
+            self.tr("Select the history entry to execute"
+                    " (most recent shown last)."),
+            self.__history,
+            current, False)
+        if ok:
+            self.__insertHistory(cmd)
+        
+    def showHistory(self):
+        """
+        Public slot to show the shell history dialog.
+        """
+        from .ShellHistoryDialog import ShellHistoryDialog
+        dlg = ShellHistoryDialog(self.__history, self.vm, self)
+        if dlg.exec_() == QDialog.Accepted:
+            self.__historyLists[self.clientType], idx = dlg.getHistory()
+            self.__history = self.__historyLists[self.clientType]
+            self.__setHistoryIndex(index=idx)
+        
+    def clearAllHistories(self):
+        """
+        Public method to clear all available histories and sync them.
+        """
+        Preferences.Prefs.settings.beginGroup("Shell/Histories")
+        for clientType in Preferences.Prefs.settings.childKeys():
+            self.__historyLists[clientType] = []
+            self.saveHistory(clientType)
+        Preferences.Prefs.settings.endGroup()
+        
+        self.clearHistory()
+        
+    def getClientType(self):
+        """
+        Public slot to get the clients type.
+        
+        @return client type (string)
+        """
+        return self.clientType
+        
+    def __getBanner(self):
+        """
+        Private method to get the banner for the remote interpreter.
+        
+        It requests the interpreter version and platform running on the
+        debug client side.
+        """
+        if self.passive:
+            self.__writeBanner('', '', '', '')
+        else:
+            self.dbs.remoteBanner()
+        
+    def __writeBanner(self, version, platform, dbgclient, venvName):
+        """
+        Private method to write a banner with info from the debug client.
+        
+        @param version interpreter version string
+        @type str
+        @param platform platform of the remote interpreter
+        @type str
+        @param dbgclient debug client variant used
+        @type str
+        @param venvName name of the virtual environment
+        @type str
+        """
+        super(Shell, self).clear()
+        if self.passive and not self.dbs.isConnected():
+            self.__write(self.tr('Passive Debug Mode'))
+            self.__write(self.tr('\nNot connected'))
+        else:
+            self.__currentVenv = venvName
+            version = version.replace("#", self.tr("No."))
+            if platform != "" and dbgclient != "":
+                self.__write(
+                    self.tr('{0} on {1}, {2}')
+                        .format(version, platform, dbgclient))
+            else:
+                self.__write(version)
+            if venvName:
+                self.__write("\n[{0}]".format(venvName))
+            
+            self.virtualEnvironmentChanged.emit(venvName)
+            Preferences.setShell("LastVirtualEnvironment", venvName)
+        self.__write('\n')
+        
+        self.__write(sys.ps1)
+        
+    def __writePrompt(self):
+        """
+        Private method to write the prompt using a write queue.
+        """
+        self.queueText.emit(self.inContinue and sys.ps2 or sys.ps1)
+    
+    def __clientStatement(self, more):
+        """
+        Private method to handle the response from the debugger client.
+        
+        @param more flag indicating that more user input is required (boolean)
+        """
+        if not self.inRawMode:
+            self.inContinue = more
+            self.__writePrompt()
+        self.inCommandExecution = False
+    
+    def __clientException(self, exceptionType, exceptionMessage, stackTrace):
+        """
+        Private method to handle an exception of the client.
+        
+        @param exceptionType type of exception raised (string)
+        @param exceptionMessage message given by the exception (string)
+        @param stackTrace list of stack entries (list of string)
+        """
+        self .__clientError()
+        
+        if not self.__windowed and \
+           Preferences.getDebugger("ShowExceptionInShell"):
+            if exceptionType:
+                if stackTrace:
+                    self.__write(
+                        self.tr('Exception "{0}"\n{1}\nFile: {2}, Line: {3}\n')
+                        .format(
+                            exceptionType,
+                            exceptionMessage,
+                            stackTrace[0][0],
+                            stackTrace[0][1]
+                        )
+                    )
+                else:
+                    self.__write(
+                        self.tr('Exception "{0}"\n{1}\n')
+                        .format(
+                            exceptionType,
+                            exceptionMessage)
+                    )
+        
+    def __clientSyntaxError(self, message, filename, lineNo, characterNo):
+        """
+        Private method to handle a syntax error in the debugged program.
+        
+        @param message message of the syntax error (string)
+        @param filename translated filename of the syntax error position
+            (string)
+        @param lineNo line number of the syntax error position (integer)
+        @param characterNo character number of the syntax error position
+            (integer)
+        """
+        self .__clientError()
+        
+        if not self.__windowed and \
+           Preferences.getDebugger("ShowExceptionInShell"):
+            if message is None:
+                self.__write(self.tr("Unspecified syntax error.\n"))
+            else:
+                self.__write(
+                    self.tr('Syntax error "{1}" in file {0} at line {2},'
+                            ' character {3}.\n')
+                        .format(filename, message, lineNo, characterNo)
+                )
+        
+    def __clientSignal(self, message, filename, lineNo, funcName, funcArgs):
+        """
+        Private method to handle a signal generated on the client side.
+        
+        @param message message of the syntax error
+        @type str
+        @param filename translated filename of the syntax error position
+        @type str
+        @param lineNo line number of the syntax error position
+        @type int
+        @param funcName name of the function causing the signal
+        @type str
+        @param funcArgs function arguments
+        @type str
+        """
+        self.__clientError()
+        
+        self.__write(
+            self.tr("""Signal "{0}" generated in file {1} at line {2}.\n"""
+                    """Function: {3}({4})""")
+                .format(message, filename, lineNo, funcName, funcArgs)
+        )
+        
+    def __clientError(self):
+        """
+        Private method to handle an error in the client.
+        """
+        self.inCommandExecution = False
+        self.interruptCommandExecution = True
+        self.inContinue = False
+        
+    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 __writeQueued(self, s):
+        """
+        Private method to display some text using a write queue.
+        
+        @param s text to be displayed (string)
+        """
+        self.queueText.emit(s)
+
+    def __concatenateText(self, text):
+        """
+        Private slot to queue text and process it in one step.
+        
+        @param text text to be appended
+        @type str
+        """
+        self.__queuedText += text
+        if self.__blockTextProcessing:
+            return
+        
+        self.__blockTextProcessing = True
+        # Get all text which is still waiting for output
+        QApplication.processEvents()
+        
+        # Finally process the accumulated text
+        self.__write(self.__queuedText)
+        
+        self.__queuedText = ''
+        self.__blockTextProcessing = False
+        
+        # little trick to get the cursor position registered within QScintilla
+        self.SendScintilla(QsciScintilla.SCI_CHARLEFT)
+        self.SendScintilla(QsciScintilla.SCI_CHARRIGHT)
+
+    def __write(self, s):
+        """
+        Private method to display some text without queuing.
+        
+        @param s text to be displayed
+        @type str
+        """
+        line, col = self.__getEndPos()
+        self.setCursorPosition(line, col)
+        self.insert(Utilities.filterAnsiSequences(s))
+        self.prline, self.prcol = self.getCursorPosition()
+        self.ensureCursorVisible()
+        self.ensureLineVisible(self.prline)
+        
+    def __writeStdOut(self, s):
+        """
+        Private method to display some text with StdOut label.
+        
+        @param s text to be displayed (string)
+        """
+        self.__write(self.tr("StdOut: {0}").format(s))
+        
+    def __writeStdErr(self, s):
+        """
+        Private method to display some text with StdErr label.
+        
+        @param s text to be displayed (string)
+        """
+        self.__write(self.tr("StdErr: {0}").format(s))
+        
+    def __raw_input(self, s, echo):
+        """
+        Private method to handle raw input.
+        
+        @param s prompt to be displayed (string)
+        @param echo Flag indicating echoing of the input (boolean)
+        """
+        # Get all text which is still waiting for output
+        QApplication.processEvents()
+        
+        self.setFocus()
+        self.inRawMode = True
+        self.echoInput = echo
+        self.__write(s)
+        line, col = self.__getEndPos()
+        self.setCursorPosition(line, col)
+        buf = self.text(line)
+        if buf.startswith(sys.ps1):
+            buf = buf.replace(sys.ps1, "")
+        if buf.startswith(sys.ps2):
+            buf = buf.replace(sys.ps2, "")
+        self.prompt = buf
+        # move cursor to end of line
+        self.moveCursorToEOL()
+        
+    def paste(self):
+        """
+        Public slot to handle the paste action.
+        """
+        if self.__isCursorOnLastLine():
+            line, col = self.getCursorPosition()
+            lastLine = self.text(line)
+            if lastLine.startswith(sys.ps1):
+                lastLine = lastLine[len(sys.ps1):]
+                col -= len(sys.ps1)
+                prompt = sys.ps1
+            elif lastLine.startswith(sys.ps2):
+                lastLine = lastLine[len(sys.ps2):]
+                col -= len(sys.ps2)
+                prompt = sys.ps2
+            else:
+                prompt = ""
+            if col < 0:
+                col = 0
+                prompt = ""
+            
+            # Remove if text is selected
+            if self.hasSelectedText():
+                lineFrom, indexFrom, lineTo, indexTo = self.getSelection()
+                if self.text(lineFrom).startswith(sys.ps1):
+                    indexFrom -= len(sys.ps1)
+                    indexTo -= len(sys.ps1)
+                elif self.text(lineFrom).startswith(sys.ps2):
+                    indexFrom -= len(sys.ps2)
+                    indexTo -= len(sys.ps2)
+                if indexFrom < 0:
+                    indexFrom = 0
+                lastLine = lastLine[:indexFrom] + lastLine[indexTo:]
+                col = indexFrom
+
+            self.setCursorPosition(line, len(prompt))
+            self.deleteLineRight()
+            
+            lines = QApplication.clipboard().text()
+            lines = lastLine[:col] + lines + lastLine[col:]
+            self.executeLines(lines)
+            line, _ = self.getCursorPosition()
+            pos = len(self.text(line)) - (len(lastLine) - col)
+            self.setCursorPosition(line, pos)
+        
+    def __middleMouseButton(self):
+        """
+        Private method to handle the middle mouse button press.
+        """
+        lines = QApplication.clipboard().text(QClipboard.Selection)
+        self.executeLines(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
+        @type str
+        @param historyIndex history index to be set
+        @type int
+        """
+        lines = lines.splitlines(True)
+        if not lines:
+            return
+        
+        indentLen = self.__indentLength(lines[0])
+        for line in lines:
+            if line.startswith(sys.ps1):
+                line = line[len(sys.ps1) + indentLen:]
+            elif line.startswith(sys.ps2):
+                line = line[len(sys.ps2) + indentLen:]
+            else:
+                line = line[indentLen:]
+            
+            if line.endswith("\r\n"):
+                fullline = True
+                cmd = line[:-2]
+            elif line.endswith("\r") or line.endswith("\n"):
+                fullline = True
+                cmd = line[:-1]
+            else:
+                fullline = False
+            
+            self.incrementalSearchActive = True
+            self.__insertTextAtEnd(line)
+            if fullline:
+                self.incrementalSearchActive = False
+                
+                self.__executeCommand(cmd, historyIndex=historyIndex)
+                if self.interruptCommandExecution:
+                    self.__executeCommand("")
+                    break
+    
+    def __indentLength(self, line):
+        """
+        Private method to determine the indentation length of the given line.
+        
+        @param line line to determine the indentation length for
+        @type str
+        @return indentation length
+        @rtype int
+        """
+        if line.startswith(sys.ps1):
+            line = line[len(sys.ps1):]
+        # If line starts with sys.ps2 or neither don't manipulate the line.
+        indentLen = len(line) - len(line.lstrip())
+        return indentLen
+    
+    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(Utilities.filterAnsiSequences(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(Utilities.filterAnsiSequences(s))
+        self.prline, _ = self.getCursorPosition()
+        
+    def __insertTextNoEcho(self, s):
+        """
+        Private method to insert some text at the end of the buffer without
+        echoing it.
+        
+        @param s text to be inserted (string)
+        """
+        self.buff += 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()
+        if event.button() == Qt.MidButton:
+            self.__middleMouseButton()
+        else:
+            super(Shell, self).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 qVersionTuple() >= (5, 0, 0):
+                delta = evt.angleDelta().y()
+            else:
+                delta = evt.delta()
+            if delta < 0:
+                self.zoomOut()
+            elif delta > 0:
+                self.zoomIn()
+            evt.accept()
+            return
+        
+        super(Shell, self).wheelEvent(evt)
+    
+    def event(self, evt):
+        """
+        Public 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(Shell, self).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.setTotalScaleFactor(zoom)
+            elif pinch.state() == Qt.GestureUpdated:
+                zoom = int(pinch.totalScaleFactor() * 10) - 10
+                if zoom <= -9:
+                    zoom = -9
+                    pinch.setTotalScaleFactor(0.1)
+                elif zoom >= 20:
+                    zoom = 20
+                    pinch.setTotalScaleFactor(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.
+        
+        @return flag indicating that the cursor is on the last line (boolean)
+        """
+        cline, ccol = self.getCursorPosition()
+        return cline == self.lines() - 1
+        
+    def keyPressEvent(self, ev):
+        """
+        Protected method 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()
+            if self.echoInput:
+                ac = self.isListActive()
+                super(Shell, self).keyPressEvent(ev)
+                self.incrementalSearchActive = True
+                if ac and \
+                   self.racEnabled:
+                    self.dbs.remoteCompletion(self.completionText + txt)
+            else:
+                self.__insertTextNoEcho(txt)
+        else:
+            ev.ignore()
+        
+    def __QScintillaCommand(self, cmd):
+        """
+        Private method to send the command to QScintilla.
+        
+        @param cmd QScintilla command
+        """
+        self.SendScintilla(cmd)
+        
+    def __QScintillaTab(self, cmd):
+        """
+        Private method to handle the Tab key.
+        
+        @param cmd QScintilla command
+        """
+        if self.isListActive():
+            self.SendScintilla(cmd)
+        elif self.__isCursorOnLastLine():
+            line, index = self.getCursorPosition()
+            buf = self.text(line)
+            if buf.startswith(sys.ps1):
+                buf = buf.replace(sys.ps1, "")
+            if buf.startswith(sys.ps2):
+                buf = buf.replace(sys.ps2, "")
+            if self.inContinue and not buf[:index - len(sys.ps2)].strip():
+                self.SendScintilla(cmd)
+            elif self.racEnabled:
+                self.dbs.remoteCompletion(buf)
+        
+    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()
+            db = 0
+            ac = self.isListActive()
+            oldLength = len(self.text(line))
+            
+            if self.text(line).startswith(sys.ps1):
+                if col > len(sys.ps1):
+                    method()
+                    db = 1
+            elif self.text(line).startswith(sys.ps2):
+                if col > len(sys.ps2):
+                    method()
+                    db = 1
+            elif col > 0:
+                method()
+                db = 1
+            if db and ac and self.racEnabled and self.completionText:
+                delta = len(self.text(line)) - oldLength
+                self.dbs.remoteCompletion(self.completionText[:delta])
+        
+    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 self.text(lineFrom).startswith(sys.ps1):
+                    if indexFrom >= len(sys.ps1):
+                        self.delete()
+                elif self.text(lineFrom).startswith(sys.ps2):
+                    if indexFrom >= len(sys.ps2):
+                        self.delete()
+                elif indexFrom >= 0:
+                    self.delete()
+            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()
+            if self.text(line).startswith(sys.ps1):
+                prompt = sys.ps1
+            elif self.text(line).startswith(sys.ps2):
+                prompt = sys.ps2
+            else:
+                prompt = ""
+            
+            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():
+            if self.isListActive():
+                self.SendScintilla(cmd)
+            else:
+                self.incrementalSearchString = ""
+                self.incrementalSearchActive = False
+                line, col = self.__getEndPos()
+                self.setCursorPosition(line, col)
+                buf = self.text(line)
+                if buf.startswith(sys.ps1):
+                    buf = buf.replace(sys.ps1, "")
+                if buf.startswith(sys.ps2):
+                    buf = buf.replace(sys.ps2, "")
+                self.insert('\n')
+                self.__executeCommand(buf)
+        else:
+            txt = ""
+            line, col = self.getCursorPosition()
+            if self.hasSelectedText():
+                lineFrom, indexFrom, lineTo, indexTo = self.getSelection()
+                if line == lineFrom:
+                    txt = self.text(line)[indexFrom:].rstrip()
+                elif line == lineTo:
+                    txt = self.text(line)[:indexTo]
+            else:
+                txt = self.text(line)[col:].rstrip()
+            
+            if txt:
+                line, col = self.__getEndPos()
+                self.setCursorPosition(line, col)
+                self.insert(txt)
+        
+    def __QScintillaLeftCommand(self, method, allLinesAllowed=False):
+        """
+        Private method to handle a QScintilla command working to the left.
+        
+        @param method shell method to execute
+        @param allLinesAllowed flag indicating that the command may be executed
+            on any line (boolean)
+        """
+        if self.__isCursorOnLastLine() or allLinesAllowed:
+            line, col = self.getCursorPosition()
+            if self.text(line).startswith(sys.ps1):
+                if col > len(sys.ps1):
+                    method()
+            elif self.text(line).startswith(sys.ps2):
+                if col > len(sys.ps2):
+                    method()
+            elif col > 0:
+                method()
+        else:
+            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()
+        else:
+            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
+        """
+        if self.isListActive():
+            self.SendScintilla(cmd)
+        elif self.__isCursorOnLastLine():
+            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)
+        
+    def __QScintillaLineEnd(self, cmd):
+        """
+        Private method to handle the End key.
+        
+        @param cmd QScintilla command
+        """
+        if self.isListActive():
+            self.SendScintilla(cmd)
+        elif self.__isCursorOnLastLine():
+            self.moveCursorToEOL()
+    
+    def __QScintillaCursorCommand(self, cmd):
+        """
+        Private method to handle the cursor commands.
+        
+        @param cmd QScintilla command
+        """
+        if self.isListActive() or self.isCallTipActive():
+            if cmd in (QsciScintilla.SCI_LINEUP, QsciScintilla.SCI_LINEDOWN):
+                self.SendScintilla(cmd)
+        else:
+            if self.__historyNavigateByCursor:
+                if cmd == QsciScintilla.SCI_LINEUP:
+                    self.__QScintillaHistoryUp(cmd)
+                elif cmd == QsciScintilla.SCI_LINEDOWN:
+                    self.__QScintillaHistoryDown(cmd)
+                elif cmd == QsciScintilla.SCI_LINESCROLLUP:
+                    self.__QScintillaLineUp(cmd)
+                elif cmd == QsciScintilla.SCI_LINESCROLLDOWN:
+                    self.__QScintillaLineDown(cmd)
+            else:
+                if cmd == QsciScintilla.SCI_LINEUP:
+                    self.__QScintillaLineUp(cmd)
+                elif cmd == QsciScintilla.SCI_LINEDOWN:
+                    self.__QScintillaLineDown(cmd)
+                elif cmd == QsciScintilla.SCI_LINESCROLLUP:
+                    self.__QScintillaHistoryUp(cmd)
+                elif cmd == QsciScintilla.SCI_LINESCROLLDOWN:
+                    self.__QScintillaHistoryDown(cmd)
+    
+    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 history up command.
+        
+        @param cmd QScintilla command
+        """
+        if self.isHistoryEnabled():
+            line, col = self.__getEndPos()
+            buf = self.text(line)
+            if buf.startswith(sys.ps1):
+                buf = buf.replace(sys.ps1, "")
+            if buf.startswith(sys.ps2):
+                buf = buf.replace(sys.ps2, "")
+            if buf and self.incrementalSearchActive:
+                if self.incrementalSearchString and \
+                   buf.startswith(self.incrementalSearchString):
+                    idx, found = self.__rsearchHistory(
+                        self.incrementalSearchString, self.__histidx)
+                    if found and idx >= 0:
+                        self.__setHistoryIndex(index=idx)
+                        self.__useHistory()
+                else:
+                    idx, found = self.__rsearchHistory(buf)
+                    if found and idx >= 0:
+                        self.__setHistoryIndex(index=idx)
+                        self.incrementalSearchString = buf
+                        self.__useHistory()
+            else:
+                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:
+                    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 history down command.
+        
+        @param cmd QScintilla command
+        """
+        if self.isHistoryEnabled():
+            line, col = self.__getEndPos()
+            buf = self.text(line)
+            if buf.startswith(sys.ps1):
+                buf = buf.replace(sys.ps1, "")
+            if buf.startswith(sys.ps2):
+                buf = buf.replace(sys.ps2, "")
+            if buf and self.incrementalSearchActive:
+                if self.incrementalSearchString and \
+                   buf.startswith(self.incrementalSearchString):
+                    idx, found = self.__searchHistory(
+                        self.incrementalSearchString, self.__histidx)
+                    if found and idx >= 0:
+                        self.__setHistoryIndex(index=idx)
+                        self.__useHistory()
+                else:
+                    idx, found = self.__searchHistory(buf)
+                    if found and idx >= 0:
+                        self.__setHistoryIndex(index=idx)
+                        self.incrementalSearchString = buf
+                        self.__useHistory()
+            else:
+                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:
+                    if self.__isHistoryIndexValid():
+                        self.__setHistoryIndex(index=self.__histidx + 1)
+                        self.__useHistory()
+    
+    def __QScintillaCancel(self):
+        """
+        Private method to handle the ESC command.
+        """
+        if self.isListActive() or self.isCallTipActive():
+            self.SendScintilla(QsciScintilla.SCI_CANCEL)
+        else:
+            if self.incrementalSearchActive:
+                self.__resetIncrementalHistorySearch()
+            self.__insertHistory("")
+    
+    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.
+        """
+        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.extendSelectionToBOL()
+        while col > 0:
+            self.extendSelectionRight()
+            col -= 1
+        
+    def __QScintillaAutoCompletionCommand(self, cmd):
+        """
+        Private method to handle a command for autocompletion only.
+        
+        @param cmd QScintilla command
+        """
+        if self.isListActive() or self.isCallTipActive():
+            self.SendScintilla(cmd)
+        
+    def __executeCommand(self, cmd, historyIndex=None):
+        """
+        Private slot to execute a command.
+        
+        @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
+            self.interruptCommandExecution = False
+            if not cmd:
+                # make sure cmd is a string
+                cmd = ''
+            
+            # 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)
+                if self.__historyStyle == ShellHistoryStyle.LinuxStyle:
+                    self.__setHistoryIndex(index=-1)
+                elif self.__historyStyle == ShellHistoryStyle.WindowsStyle:
+                    if historyIndex is None:
+                        if self.__histidx - 1 > 0 and \
+                           cmd != self.__history[self.__histidx - 1]:
+                            self.__setHistoryIndex(index=-1)
+                    else:
+                        self.__setHistoryIndex(historyIndex)
+            
+            if cmd == 'start' or cmd.startswith('start '):
+                if not self.passive:
+                    cmdList = cmd.split(None, 1)
+                    if len(cmdList) < 2:
+                        self.dbs.startClient(False)  # start default backend
+                    else:
+                        venvName = cmdList[1]
+                        if venvName == self.tr("Project"):
+                            if self.__project.isOpen():
+                                self.dbs.startClient(
+                                    False, forProject=True,
+                                    workingDir=self.__project.getProjectPath())
+                                self.__currentWorkingDirectory = \
+                                    self.__project.getProjectPath()
+                            else:
+                                self.dbs.startClient(
+                                    False, venvName=self.__currentVenv,
+                                    workingDir=self.__currentWorkingDirectory)
+                                # same as reset
+                        else:
+                            self.dbs.startClient(False, venvName=venvName)
+                            self.__currentWorkingDirectory = ""
+                    self.__getBanner()
+                    return
+            elif cmd == 'clear':
+                # Display the banner.
+                self.__getBanner()
+                if not self.passive:
+                    return
+                else:
+                    cmd = ''
+            elif cmd in ['reset', 'restart']:
+                self.dbs.startClient(False, venvName=self.__currentVenv,
+                                     workingDir=self.__currentWorkingDirectory)
+                if self.passive:
+                    return
+                else:
+                    cmd = ''
+            elif cmd in ['envs', 'environments']:
+                venvs = e5App().getObject("VirtualEnvManager")\
+                    .getVirtualenvNames()
+                s = self.tr('Available Virtual Environments:\n{0}\n').format(
+                    '\n'.join("- {0}".format(venv) for venv in sorted(venvs))
+                )
+                self.__write(s)
+                self.__clientStatement(False)
+                return
+            elif cmd == 'which':
+                s = self.tr("Current Virtual Environment: '{0}'\n").format(
+                    self.__currentVenv)
+                self.__write(s)
+                self.__clientStatement(False)
+                return
+            elif cmd in ["quit", "quit()", "exit", "exit()"] and \
+                    self.__windowed:
+                # call main window quit()
+                self.vm.quit()
+                return
+            
+            self.dbs.remoteStatement(cmd)
+            while self.inCommandExecution:
+                try:
+                    QApplication.processEvents()
+                except KeyboardInterrupt:
+                    pass
+        else:
+            if not self.echoInput:
+                cmd = self.buff
+                self.buff = ""
+            elif cmd:
+                cmd = cmd[len(self.prompt):]
+            self.inRawMode = False
+            self.echoInput = True
+            
+            self.dbs.remoteRawInput(cmd)
+    
+    def __showVenvName(self):
+        """
+        Private method to show the name of the active virtual environment.
+        """
+        s = "\n" + self.tr("Current Virtual Environment: '{0}'\n").format(
+            self.__currentVenv)
+        self.__write(s)
+        self.__clientStatement(False)
+    
+    def __useHistory(self):
+        """
+        Private method to display a command from the history.
+        """
+        if self.__isHistoryIndexValid():
+            cmd = self.__history[self.__histidx]
+        else:
+            cmd = ""
+            self.__resetIncrementalHistorySearch()
+        
+        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 __resetIncrementalHistorySearch(self):
+        """
+        Private method to reset the incremental history search.
+        """
+        self.incrementalSearchString = ""
+        self.incrementalSearchActive = False
+    
+    def __searchHistory(self, txt, startIdx=-1):
+        """
+        Private method used to search the history.
+        
+        @param txt text to match at the beginning
+        @type str
+        @param startIdx index to start search from
+        @type int
+        @return tuple containing the index of found entry and a flag indicating
+            that something was found
+        @rtype tuple of (int, bool)
+        """
+        if startIdx == -1:
+            idx = 0
+        else:
+            idx = startIdx + 1
+        while idx < len(self.__history) and \
+                not self.__history[idx].startswith(txt):
+            idx += 1
+        found = (idx < len(self.__history) and
+                 self.__history[idx].startswith(txt))
+        return idx, found
+        
+    def __rsearchHistory(self, txt, startIdx=-1):
+        """
+        Private method used to reverse search the history.
+        
+        @param txt text to match at the beginning
+        @type str
+        @param startIdx index to start search from
+        @type int
+        @return tuple containing the index of found entry and a flag indicating
+            that something was found
+        @rtype tuple of (int, bool)
+        """
+        if startIdx == -1:
+            idx = len(self.__history) - 1
+        else:
+            idx = startIdx - 1
+        while idx >= 0 and \
+                not self.__history[idx].startswith(txt):
+            idx -= 1
+        found = idx >= 0 and self.__history[idx].startswith(txt)
+        return idx, found
+        
+    def focusNextPrevChild(self, nextChild):
+        """
+        Public method to stop Tab moving to the next window.
+        
+        While the user is entering a multi-line command, the movement to
+        the next window by the Tab key being pressed is suppressed.
+        
+        @param nextChild next window
+        @return flag indicating the movement
+        """
+        if nextChild and self.inContinue:
+            return False
+        
+        return QsciScintillaCompat.focusNextPrevChild(self, nextChild)
+        
+    def contextMenuEvent(self, ev):
+        """
+        Protected method to show our own context menu.
+        
+        @param ev context menu event (QContextMenuEvent)
+        """
+        if not self.__windowed:
+            self.menu.popup(ev.globalPos())
+            ev.accept()
+        
+    def clear(self):
+        """
+        Public slot to clear the display.
+        """
+        # Display the banner.
+        self.__getBanner()
+        
+    def doClearRestart(self):
+        """
+        Public slot to handle the 'restart and clear' context menu entry.
+        """
+        self.doRestart()
+        self.clear()
+        
+    def doRestart(self):
+        """
+        Public slot to handle the 'restart' context menu entry.
+        """
+        self.dbs.startClient(False, venvName=self.__currentVenv,
+                             workingDir=self.__currentWorkingDirectory)
+        
+    def __startDebugClient(self, action):
+        """
+        Private slot to start a debug client according to the action
+        triggered.
+        
+        @param action context menu action that was triggered (QAction)
+        """
+        venvName = action.text()
+        if venvName == self.tr("Project"):
+            if self.__project.isOpen():
+                self.__currentWorkingDirectory = \
+                    self.__project.getProjectPath()
+            self.dbs.startClient(False, forProject=True,
+                                 workingDir=self.__currentWorkingDirectory)
+        else:
+            self.dbs.startClient(False, venvName=venvName)
+        self.__getBanner()
+        
+    def handlePreferencesChanged(self):
+        """
+        Public slot to handle the preferencesChanged signal.
+        """
+        # rebind the lexer
+        self.__bindLexer(self.language)
+        self.recolor()
+        
+        # set margin 0 configuration
+        self.__setTextDisplay()
+        self.__setMargin0()
+        
+        # set the autocompletion and calltips function
+        self.__setAutoCompletion()
+        self.__setCallTips()
+        
+        # do the history related stuff
+        self.__maxHistoryEntries = Preferences.getShell("MaxHistoryEntries")
+        for key in list(self.__historyLists.keys()):
+            self.__historyLists[key] = \
+                self.__historyLists[key][-self.__maxHistoryEntries:]
+        self.__historyStyle = Preferences.getShell("HistoryStyle")
+        self.__historyWrap = Preferences.getShell("HistoryWrap")
+        self.__setHistoryIndex()
+        if not self.__windowed:
+            self.hmenu.menuAction().setEnabled(self.isHistoryEnabled())
+        self.__historyNavigateByCursor = \
+            Preferences.getShell("HistoryNavigateByCursor")
+        self.historyStyleChanged.emit(self.__historyStyle)
+        
+        # do stdout /stderr stuff
+        showStdOutErr = Preferences.getShell("ShowStdOutErr")
+        if self.__showStdOutErr != showStdOutErr:
+            if showStdOutErr:
+                self.dbs.clientProcessStdout.connect(self.__writeStdOut)
+                self.dbs.clientProcessStderr.connect(self.__writeStdErr)
+            else:
+                self.dbs.clientProcessStdout.disconnect(self.__writeStdOut)
+                self.dbs.clientProcessStderr.disconnect(self.__writeStdErr)
+            self.__showStdOutErr = showStdOutErr
+        
+    def __showCompletions(self, completions, text):
+        """
+        Private method to display the possible completions.
+        
+        @param completions list of possible completions (list of strings)
+        @param text text that is about to be completed (string)
+        """
+        if len(completions) == 0:
+            return
+        
+        if len(completions) > 1:
+            completions.sort()
+            self.showUserList(1, completions)
+            self.completionText = text
+        else:
+            txt = completions[0]
+            if text != "":
+                txt = txt.replace(text, "")
+            self.__insertText(txt)
+            self.completionText = ""
+        
+    def __completionListSelected(self, listId, txt):
+        """
+        Private slot to handle the selection from the completion list.
+        
+        @param listId the ID of the user list (should be 1) (integer)
+        @param txt the selected text (string)
+        """
+        if listId == 1:
+            if self.completionText != "":
+                txt = txt.replace(self.completionText, "")
+            self.__insertText(txt)
+            self.completionText = ""
+    
+    #################################################################
+    ## Drag and Drop Support
+    #################################################################
+    
+    def dragEnterEvent(self, event):
+        """
+        Protected method to handle the drag enter event.
+        
+        @param event the drag enter event (QDragEnterEvent)
+        """
+        self.inDragDrop = event.mimeData().hasUrls() or \
+            event.mimeData().hasText()
+        if self.inDragDrop:
+            event.acceptProposedAction()
+        else:
+            super(Shell, self).dragEnterEvent(event)
+        
+    def dragMoveEvent(self, event):
+        """
+        Protected method to handle the drag move event.
+        
+        @param event the drag move event (QDragMoveEvent)
+        """
+        if self.inDragDrop:
+            event.accept()
+        else:
+            super(Shell, self).dragMoveEvent(event)
+        
+    def dragLeaveEvent(self, event):
+        """
+        Protected method to handle the drag leave event.
+        
+        @param event the drag leave event (QDragLeaveEvent)
+        """
+        if self.inDragDrop:
+            self.inDragDrop = False
+            event.accept()
+        else:
+            super(Shell, self).dragLeaveEvent(event)
+        
+    def dropEvent(self, event):
+        """
+        Protected method to handle the drop event.
+        
+        @param event the drop event (QDropEvent)
+        """
+        if event.mimeData().hasUrls() and not self.__windowed:
+            for url in event.mimeData().urls():
+                fname = url.toLocalFile()
+                if fname:
+                    if not QFileInfo(fname).isDir():
+                        self.vm.openSourceFile(fname)
+                    else:
+                        E5MessageBox.information(
+                            self,
+                            self.tr("Drop Error"),
+                            self.tr("""<p><b>{0}</b> is not a file.</p>""")
+                            .format(fname))
+            event.acceptProposedAction()
+        elif event.mimeData().hasText():
+            s = event.mimeData().text()
+            if s:
+                event.acceptProposedAction()
+                self.executeLines(s)
+            del s
+        else:
+            super(Shell, self).dropEvent(event)
+        
+        self.inDragDrop = False
+        
+    def focusInEvent(self, event):
+        """
+        Protected 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())
+            if not self.__windowed:
+                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
+        if not self.__windowed:
+            self.__searchShortcut.setEnabled(True)
+            self.__searchNextShortcut.setEnabled(True)
+            self.__searchPrevShortcut.setEnabled(True)
+        self.setCaretWidth(self.caretWidth)
+        self.setCursorFlashTime(QApplication.cursorFlashTime())
+        
+        super(Shell, self).focusInEvent(event)
+        
+    def focusOutEvent(self, event):
+        """
+        Protected method called when the shell loses focus.
+        
+        @param event the event object (QFocusEvent)
+        """
+        try:
+            self.vm.editorActGrp.setEnabled(False)
+        except AttributeError:
+            pass
+        if not self.__windowed:
+            self.__searchShortcut.setEnabled(False)
+            self.__searchNextShortcut.setEnabled(False)
+            self.__searchPrevShortcut.setEnabled(False)
+        self.setCaretWidth(0)
+        super(Shell, self).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)
+        """
+        txt = Utilities.filterAnsiSequences(txt)
+        length = 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 + length)
+        
+    def __configure(self):
+        """
+        Private method to open the configuration dialog.
+        """
+        e5App().getObject("UserInterface").showPreferences("shellPage")
+    
+    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, regexp):
+        """
+        Public method to search the next occurrence of the given text.
+        
+        @param txt text to search for
+        @type str
+        @param caseSensitive flag indicating to perform a case sensitive
+            search
+        @type bool
+        @param wholeWord flag indicating to search for whole words
+            only
+        @type bool
+        @param regexp flag indicating a regular expression search
+        @type bool
+        """
+        self.__lastSearch = (txt, caseSensitive, wholeWord, regexp)
+        posixMode = Preferences.getEditor("SearchRegexpMode") == 0 and regexp
+        cxx11Mode = Preferences.getEditor("SearchRegexpMode") == 1 and regexp
+        ok = self.findFirst(
+            txt, regexp, caseSensitive, wholeWord, True, forward=True,
+            posix=posixMode, cxx11=cxx11Mode)
+        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, regexp):
+        """
+        Public method to search the previous occurrence of the given text.
+        
+        @param txt text to search for
+        @type str
+        @param caseSensitive flag indicating to perform a case sensitive
+            search
+        @type bool
+        @param wholeWord flag indicating to search for whole words
+            only
+        @type bool
+        @param regexp flag indicating a regular expression search
+        @type bool
+        """
+        self.__lastSearch = (txt, caseSensitive, wholeWord, regexp)
+        if self.hasSelectedText():
+            line, index = self.getSelection()[:2]
+        else:
+            line, index = -1, -1
+        posixMode = Preferences.getEditor("SearchRegexpMode") == 0 and regexp
+        cxx11Mode = Preferences.getEditor("SearchRegexpMode") == 1 and regexp
+        ok = self.findFirst(
+            txt, regexp, caseSensitive, wholeWord, True,
+            forward=False, line=line, index=index, posix=posixMode,
+            cxx11=cxx11Mode)
+        self.searchStringFound.emit(ok)
+    
+    def historyStyle(self):
+        """
+        Public method to get the shell history style.
+        
+        @return shell history style
+        @rtype ShellHistoryStyle
+        """
+        return self.__historyStyle
+    
+    def isHistoryEnabled(self):
+        """
+        Public method to check, if the history is enabled.
+        
+        @return flag indicating if history is enabled
+        @rtype bool
+        """
+        return self.__historyStyle != ShellHistoryStyle.Disabled
+    
+    #################################################################
+    ## Project Support
+    #################################################################
+    
+    def __projectOpened(self):
+        """
+        Private slot to start the shell for the opened project.
+        """
+        if Preferences.getProject("RestartShellForProject"):
+            self.dbs.startClient(False, forProject=True,
+                                 workingDir=self.__project.getProjectPath())
+            self.__currentWorkingDirectory = self.__project.getProjectPath()
+            self.__getBanner()
+    
+    def __projectClosed(self):
+        """
+        Private slot to restart the default shell when the project is closed.
+        """
+        if Preferences.getProject("RestartShellForProject"):
+            self.dbs.startClient(False)
+            self.__getBanner()

eric ide

mercurial