"Fossies" - the Fresh Open Source Software Archive

Member "eric6-20.9/eric/eric6/QScintilla/Shell.py" (2 May 2020, 87521 Bytes) of package /linux/misc/eric6-20.9.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "Shell.py" see the Fossies "Dox" file reference documentation.

    1 # -*- coding: utf-8 -*-
    2 
    3 # Copyright (c) 2002 - 2020 Detlev Offenbach <detlev@die-offenbachs.de>
    4 #
    5 
    6 """
    7 Module implementing a graphical Python shell.
    8 """
    9 
   10 
   11 import sys
   12 import re
   13 
   14 try:
   15     from enum import Enum
   16 except ImportError:
   17     from ThirdParty.enum import Enum
   18 
   19 from PyQt5.QtCore import pyqtSignal, QFileInfo, Qt, QEvent
   20 from PyQt5.QtGui import QClipboard, QPalette, QFont
   21 from PyQt5.QtWidgets import (
   22     QDialog, QInputDialog, QApplication, QMenu, QWidget, QHBoxLayout,
   23     QVBoxLayout, QShortcut, QSizePolicy
   24 )
   25 from PyQt5.Qsci import QsciScintilla
   26 
   27 from E5Gui.E5Application import e5App
   28 from E5Gui import E5MessageBox
   29 
   30 from .QsciScintillaCompat import QsciScintillaCompat
   31 
   32 import Preferences
   33 import Utilities
   34 
   35 import UI.PixmapCache
   36 
   37 from Debugger.DebugClientCapabilities import HasCompleter
   38 
   39 
   40 class ShellAssembly(QWidget):
   41     """
   42     Class implementing the containing widget for the shell.
   43     """
   44     def __init__(self, dbs, vm, project, horizontal=True, parent=None):
   45         """
   46         Constructor
   47         
   48         @param dbs reference to the debug server object
   49         @type DebugServer
   50         @param vm reference to the viewmanager object
   51         @type ViewManager
   52         @param project reference to the project object
   53         @type Project
   54         @param horizontal flag indicating a horizontal layout
   55         @type bool
   56         @param parent parent widget
   57         @type QWidget
   58         """
   59         super(ShellAssembly, self).__init__(parent)
   60         
   61         self.__shell = Shell(dbs, vm, project, False, self)
   62         
   63         from UI.SearchWidget import SearchWidget
   64         self.__searchWidget = SearchWidget(self.__shell, self, horizontal)
   65         self.__searchWidget.setSizePolicy(QSizePolicy.Fixed,
   66                                           QSizePolicy.Preferred)
   67         self.__searchWidget.hide()
   68         
   69         if horizontal:
   70             self.__layout = QHBoxLayout(self)
   71         else:
   72             self.__layout = QVBoxLayout(self)
   73         self.__layout.setContentsMargins(1, 1, 1, 1)
   74         self.__layout.addWidget(self.__shell)
   75         self.__layout.addWidget(self.__searchWidget)
   76         
   77         self.__searchWidget.searchNext.connect(self.__shell.searchNext)
   78         self.__searchWidget.searchPrevious.connect(self.__shell.searchPrev)
   79         self.__shell.searchStringFound.connect(
   80             self.__searchWidget.searchStringFound)
   81     
   82     def showFind(self, txt=""):
   83         """
   84         Public method to display the search widget.
   85         
   86         @param txt text to be shown in the combo (string)
   87         """
   88         self.__searchWidget.showFind(txt)
   89     
   90     def shell(self):
   91         """
   92         Public method to get a reference to the shell widget.
   93         
   94         @return reference to the shell widget (Shell)
   95         """
   96         return self.__shell
   97 
   98 
   99 class ShellHistoryStyle(Enum):
  100     """
  101     Class defining the shell history styles.
  102     """
  103     Disabled = 0
  104     LinuxStyle = 1
  105     WindowsStyle = 2
  106 
  107 
  108 class Shell(QsciScintillaCompat):
  109     """
  110     Class implementing a graphical Python shell.
  111     
  112     A user can enter commands that are executed in the remote
  113     Python interpreter.
  114     
  115     @signal searchStringFound(bool) emitted to indicate the search
  116         result
  117     @signal historyStyleChanged(ShellHistoryStyle) emitted to indicate a
  118         change of the history style
  119     @signal queueText(str) emitted to queue some text for processing
  120     @signal virtualEnvironmentChanged(str) emitted to signal the new virtual
  121         environment of the shell
  122     """
  123     searchStringFound = pyqtSignal(bool)
  124     historyStyleChanged = pyqtSignal(ShellHistoryStyle)
  125     queueText = pyqtSignal(str)
  126     virtualEnvironmentChanged = pyqtSignal(str)
  127     
  128     def __init__(self, dbs, vm, project, windowedVariant, parent=None):
  129         """
  130         Constructor
  131         
  132         @param dbs reference to the debug server object
  133         @type DebugServer
  134         @param vm reference to the viewmanager object
  135         @type ViewManager
  136         @param project reference to the project object
  137         @type Project
  138         @param windowedVariant flag indicating the shell window variant
  139         @type bool
  140         @param parent parent widget
  141         @type QWidget
  142         """
  143         super(Shell, self).__init__(parent)
  144         self.setUtf8(True)
  145         
  146         self.vm = vm
  147         self.__mainWindow = parent
  148         self.__lastSearch = ()
  149         self.__windowed = windowedVariant
  150         self.__currentVenv = ""
  151         self.__currentWorkingDirectory = ""
  152         
  153         self.linesepRegExp = r"\r\n|\n|\r"
  154         
  155         self.passive = ((not self.__windowed) and
  156                         Preferences.getDebugger("PassiveDbgEnabled"))
  157         if self.passive:
  158             self.setWindowTitle(self.tr('Shell - Passive'))
  159         else:
  160             self.setWindowTitle(self.tr('Shell'))
  161         
  162         if self.__windowed:
  163             self.setWhatsThis(self.tr(
  164                 """<b>The Shell Window</b>"""
  165                 """<p>You can use the cursor keys while entering commands."""
  166                 """ There is also a history of commands that can be recalled"""
  167                 """ using the up and down cursor keys while holding down the"""
  168                 """ Ctrl-key. This can be switched to just the up and down"""
  169                 """ cursor keys on the Shell page of the configuration"""
  170                 """ dialog. Pressing these keys after some text has been"""
  171                 """ entered will start an incremental search.</p>"""
  172                 """<p>The shell has some special commands. 'restart' kills"""
  173                 """ the shell and starts a new one. 'clear' clears the"""
  174                 """ display of the shell window. 'start' is used to start a"""
  175                 """ shell for a virtual environment and should be followed"""
  176                 """ by a virtual environment name. start' without a virtual"""
  177                 """ environment name starts the default shell. Available"""
  178                 """ virtual environments may be listed with the 'envs' or"""
  179                 """ 'environments' commands. The active virtual environment"""
  180                 """ can be questioned by the 'which' command. 'quit' or"""
  181                 """ 'exit' is used to exit the application. These commands"""
  182                 """ (except environments', 'envs' and 'which') are available"""
  183                 """ through the window menus as well.</p>"""
  184                 """<p>Pressing the Tab key after some text has been entered"""
  185                 """ will show a list of possible completions. The relevant"""
  186                 """ entry may be selected from this list. If only one entry"""
  187                 """ is available, this will be inserted automatically.</p>"""
  188             ))
  189         else:
  190             self.setWhatsThis(self.tr(
  191                 """<b>The Shell Window</b>"""
  192                 """<p>This is simply an interpreter running in a window. The"""
  193                 """ interpreter is the one that is used to run the program"""
  194                 """ being debugged. This means that you can execute any"""
  195                 """ command while the program being debugged is running.</p>"""
  196                 """<p>You can use the cursor keys while entering commands."""
  197                 """ There is also a history of commands that can be recalled"""
  198                 """ using the up and down cursor keys while holding down the"""
  199                 """ Ctrl-key. This can be switched to just the up and down"""
  200                 """ cursor keys on the Shell page of the configuration"""
  201                 """ dialog. Pressing these keys after some text has been"""
  202                 """ entered will start an incremental search.</p>"""
  203                 """<p>The shell has some special commands. 'restart' kills"""
  204                 """ the shell and starts a new one. 'clear' clears the"""
  205                 """ display of the shell window. 'start' is used to start a"""
  206                 """ shell for a virtual environment and should be followed"""
  207                 """ by a virtual environment name. start' without a virtual"""
  208                 """ environment name starts the default shell. Available"""
  209                 """ virtual environments may be listed with the 'envs' or"""
  210                 """ 'environments' commands. The active virtual environment"""
  211                 """ can be questioned by the 'which' command. These commands"""
  212                 """ (except environments' and 'envs') are available through"""
  213                 """ the context menu as well.</p>"""
  214                 """<p>Pressing the Tab key after some text has been entered"""
  215                 """ will show a list of possible completions. The relevant"""
  216                 """ entry may be selected from this list. If only one entry"""
  217                 """ is available, this will be inserted automatically.</p>"""
  218                 """<p>In passive debugging mode the shell is only available"""
  219                 """ after the program to be debugged has connected to the"""
  220                 """ IDE until it has finished. This is indicated by a"""
  221                 """ different prompt and by an indication in the window"""
  222                 """ caption.</p>"""
  223             ))
  224         
  225         self.userListActivated.connect(self.__completionListSelected)
  226         self.linesChanged.connect(self.__resizeLinenoMargin)
  227         
  228         if self.__windowed:
  229             self.__showStdOutErr = True
  230         else:
  231             self.__showStdOutErr = Preferences.getShell("ShowStdOutErr")
  232         if self.__showStdOutErr:
  233             dbs.clientProcessStdout.connect(self.__writeStdOut)
  234             dbs.clientProcessStderr.connect(self.__writeStdErr)
  235         dbs.clientOutput.connect(self.__writeQueued)
  236         dbs.clientStatement.connect(self.__clientStatement)
  237         dbs.clientGone.connect(self.__initialise)
  238         dbs.clientRawInput.connect(self.__raw_input)
  239         dbs.clientBanner.connect(self.__writeBanner)
  240         dbs.clientCompletionList.connect(self.__showCompletions)
  241         dbs.clientCapabilities.connect(self.__clientCapabilities)
  242         dbs.clientException.connect(self.__clientException)
  243         dbs.clientSyntaxError.connect(self.__clientSyntaxError)
  244         dbs.clientSignal.connect(self.__clientSignal)
  245         self.dbs = dbs
  246         
  247         # Initialize instance variables.
  248         self.__initialise()
  249         self.prline = 0
  250         self.prcol = 0
  251         self.inDragDrop = False
  252         self.lexer_ = None
  253         self.completionText = ""
  254         
  255         self.clientType = ''
  256         
  257         # Initialize history
  258         self.__historyLists = {}
  259         self.__maxHistoryEntries = Preferences.getShell("MaxHistoryEntries")
  260         self.__historyStyle = Preferences.getShell("HistoryStyle")
  261         self.__historyWrap = Preferences.getShell("HistoryWrap")
  262         self.__history = []
  263         self.__setHistoryIndex()
  264         # remove obsolete shell histories (Python and Ruby)
  265         for clientType in ["Python", "Ruby"]:
  266             Preferences.Prefs.settings.remove("Shell/Histories/" + clientType)
  267         
  268         # clear QScintilla defined keyboard commands
  269         # we do our own handling through the view manager
  270         self.clearAlternateKeys()
  271         self.clearKeys()
  272         self.__actionsAdded = False
  273         
  274         # Make sure we have prompts.
  275         if self.passive:
  276             sys.ps1 = self.tr("Passive >>> ")
  277         else:
  278             try:
  279                 sys.ps1
  280             except AttributeError:
  281                 sys.ps1 = ">>> "
  282         try:
  283             sys.ps2
  284         except AttributeError:
  285             sys.ps2 = "... "
  286         
  287         if self.passive:
  288             self.__getBanner()
  289         
  290         if not self.__windowed:
  291             # Create a little language context menu
  292             self.lmenu = QMenu(self.tr('Start'))
  293             self.lmenu.aboutToShow.connect(self.__showStartMenu)
  294             self.lmenu.triggered.connect(self.__startDebugClient)
  295             
  296             # Create the history context menu
  297             self.hmenu = QMenu(self.tr('History'))
  298             self.hmenu.addAction(self.tr('Select entry'), self.selectHistory)
  299             self.hmenu.addAction(self.tr('Show'), self.showHistory)
  300             self.hmenu.addAction(self.tr('Clear'), self.clearHistory)
  301             
  302             # Create a little context menu
  303             self.menu = QMenu(self)
  304             self.menu.addAction(self.tr('Cut'), self.cut)
  305             self.menu.addAction(self.tr('Copy'), self.copy)
  306             self.menu.addAction(self.tr('Paste'), self.paste)
  307             self.menu.addMenu(self.hmenu).setEnabled(self.isHistoryEnabled())
  308             
  309             self.menu.addSeparator()
  310             self.menu.addAction(self.tr('Find'), self.__find)
  311             self.menu.addSeparator()
  312             self.menu.addAction(self.tr('Clear'), self.clear)
  313             self.menu.addAction(self.tr('Restart'), self.doRestart)
  314             self.menu.addAction(
  315                 self.tr('Restart and Clear'), self.doClearRestart)
  316             self.menu.addSeparator()
  317             self.menu.addMenu(self.lmenu)
  318             self.menu.addAction(self.tr('Active Name'), self.__showVenvName)
  319             self.menu.addSeparator()
  320             self.menu.addAction(self.tr("Configure..."), self.__configure)
  321         
  322         self.__bindLexer()
  323         self.__setTextDisplay()
  324         self.__setMargin0()
  325         
  326         # set the autocompletion and calltips function
  327         self.__setAutoCompletion()
  328         self.__setCallTips()
  329         
  330         self.setWindowIcon(UI.PixmapCache.getIcon("eric"))
  331         
  332         self.incrementalSearchString = ""
  333         self.incrementalSearchActive = False
  334         
  335         self.supportedEditorCommands = {
  336             QsciScintilla.SCI_LINEDELETE: self.__clearCurrentLine,
  337             QsciScintilla.SCI_TAB: self.__QScintillaTab,
  338             QsciScintilla.SCI_NEWLINE: self.__QScintillaNewline,
  339             
  340             QsciScintilla.SCI_DELETEBACK: self.__QScintillaDeleteBack,
  341             QsciScintilla.SCI_CLEAR: self.__QScintillaDelete,
  342             QsciScintilla.SCI_DELWORDLEFT: self.__QScintillaDeleteWordLeft,
  343             QsciScintilla.SCI_DELWORDRIGHT: self.__QScintillaDeleteWordRight,
  344             QsciScintilla.SCI_DELLINELEFT: self.__QScintillaDeleteLineLeft,
  345             QsciScintilla.SCI_DELLINERIGHT: self.__QScintillaDeleteLineRight,
  346             
  347             QsciScintilla.SCI_CHARLEFT: self.__QScintillaCharLeft,
  348             QsciScintilla.SCI_CHARRIGHT: self.__QScintillaCharRight,
  349             QsciScintilla.SCI_WORDLEFT: self.__QScintillaWordLeft,
  350             QsciScintilla.SCI_WORDRIGHT: self.__QScintillaWordRight,
  351             QsciScintilla.SCI_VCHOME: self.__QScintillaVCHome,
  352             QsciScintilla.SCI_LINEEND: self.__QScintillaLineEnd,
  353             
  354             QsciScintilla.SCI_LINEUP: self.__QScintillaCursorCommand,
  355             QsciScintilla.SCI_LINEDOWN: self.__QScintillaCursorCommand,
  356             QsciScintilla.SCI_LINESCROLLUP: self.__QScintillaCursorCommand,
  357             QsciScintilla.SCI_LINESCROLLDOWN: self.__QScintillaCursorCommand,
  358             
  359             QsciScintilla.SCI_PAGEUP: self.__QScintillaAutoCompletionCommand,
  360             QsciScintilla.SCI_PAGEDOWN: self.__QScintillaAutoCompletionCommand,
  361             
  362             QsciScintilla.SCI_CHARLEFTEXTEND: self.__QScintillaCharLeftExtend,
  363             QsciScintilla.SCI_CHARRIGHTEXTEND: self.extendSelectionRight,
  364             QsciScintilla.SCI_WORDLEFTEXTEND: self.__QScintillaWordLeftExtend,
  365             QsciScintilla.SCI_WORDRIGHTEXTEND: self.extendSelectionWordRight,
  366             QsciScintilla.SCI_VCHOMEEXTEND: self.__QScintillaVCHomeExtend,
  367             QsciScintilla.SCI_LINEENDEXTEND: self.extendSelectionToEOL,
  368             
  369             QsciScintilla.SCI_CANCEL: self.__QScintillaCancel,
  370         }
  371         
  372         self.__historyNavigateByCursor = (
  373             Preferences.getShell("HistoryNavigateByCursor")
  374         )
  375         
  376         self.__queuedText = ''
  377         self.__blockTextProcessing = False
  378         self.queueText.connect(self.__concatenateText, Qt.QueuedConnection)
  379         
  380         self.__project = project
  381         if self.__project:
  382             self.__project.projectOpened.connect(self.__projectOpened)
  383             self.__project.projectClosed.connect(self.__projectClosed)
  384         
  385         self.grabGesture(Qt.PinchGesture)
  386     
  387     def __showStartMenu(self):
  388         """
  389         Private slot to prepare the start submenu.
  390         """
  391         self.lmenu.clear()
  392         venvManager = e5App().getObject("VirtualEnvManager")
  393         for venvName in sorted(venvManager.getVirtualenvNames()):
  394             self.lmenu.addAction(venvName)
  395         if self.__project.isOpen():
  396             self.lmenu.addSeparator()
  397             self.lmenu.addAction(self.tr("Project"))
  398         
  399     def __resizeLinenoMargin(self):
  400         """
  401         Private slot to resize the line numbers margin.
  402         """
  403         linenoMargin = Preferences.getShell("LinenoMargin")
  404         if linenoMargin:
  405             self.setMarginWidth(0, '8' * (len(str(self.lines())) + 1))
  406         
  407     def closeShell(self):
  408         """
  409         Public method to shutdown the shell.
  410         """
  411         for clientType in self.__historyLists:
  412             self.saveHistory(clientType)
  413         
  414     def __bindLexer(self, language='Python3'):
  415         """
  416         Private slot to set the lexer.
  417         
  418         @param language lexer language to set (string)
  419         """
  420         self.language = language
  421         if Preferences.getShell("SyntaxHighlightingEnabled"):
  422             from . import Lexers
  423             self.lexer_ = Lexers.getLexer(self.language, self)
  424         else:
  425             self.lexer_ = None
  426         
  427         if self.lexer_ is None:
  428             self.setLexer(None)
  429             font = Preferences.getShell("MonospacedFont")
  430             self.monospacedStyles(font)
  431             return
  432         
  433         # get the font for style 0 and set it as the default font
  434         key = 'Scintilla/{0}/style0/font'.format(self.lexer_.language())
  435         fdesc = Preferences.Prefs.settings.value(key)
  436         if fdesc is not None:
  437             font = QFont(fdesc[0], int(fdesc[1]))
  438             self.lexer_.setDefaultFont(font)
  439         self.setLexer(self.lexer_)
  440         self.lexer_.readSettings(Preferences.Prefs.settings, "Scintilla")
  441         if self.lexer_.hasSubstyles():
  442             self.lexer_.readSubstyles(self)
  443         
  444         # initialize the lexer APIs settings
  445         api = self.vm.getAPIsManager().getAPIs(self.language)
  446         if api is not None:
  447             api = api.getQsciAPIs()
  448             if api is not None:
  449                 self.lexer_.setAPIs(api)
  450         
  451         self.lexer_.setDefaultColor(self.lexer_.color(0))
  452         self.lexer_.setDefaultPaper(self.lexer_.paper(0))
  453         
  454     def __setMargin0(self):
  455         """
  456         Private method to configure margin 0.
  457         """
  458         # set the settings for all margins
  459         self.setMarginsFont(Preferences.getShell("MarginsFont"))
  460         self.setMarginsForegroundColor(
  461             Preferences.getEditorColour("MarginsForeground"))
  462         self.setMarginsBackgroundColor(
  463             Preferences.getEditorColour("MarginsBackground"))
  464         
  465         # set margin 0 settings
  466         linenoMargin = Preferences.getShell("LinenoMargin")
  467         self.setMarginLineNumbers(0, linenoMargin)
  468         if linenoMargin:
  469             self.__resizeLinenoMargin()
  470         else:
  471             self.setMarginWidth(0, 0)
  472         
  473         # disable margins 1 and 2
  474         self.setMarginWidth(1, 0)
  475         self.setMarginWidth(2, 0)
  476         
  477     def __setTextDisplay(self):
  478         """
  479         Private method to configure the text display.
  480         """
  481         self.setTabWidth(Preferences.getEditor("TabWidth"))
  482         if Preferences.getEditor("ShowWhitespace"):
  483             self.setWhitespaceVisibility(QsciScintilla.WsVisible)
  484             try:
  485                 self.setWhitespaceForegroundColor(
  486                     Preferences.getEditorColour("WhitespaceForeground"))
  487                 self.setWhitespaceBackgroundColor(
  488                     Preferences.getEditorColour("WhitespaceBackground"))
  489                 self.setWhitespaceSize(
  490                     Preferences.getEditor("WhitespaceSize"))
  491             except AttributeError:
  492                 # QScintilla before 2.5 doesn't support this
  493                 pass
  494         else:
  495             self.setWhitespaceVisibility(QsciScintilla.WsInvisible)
  496         self.setEolVisibility(Preferences.getEditor("ShowEOL"))
  497         if Preferences.getEditor("BraceHighlighting"):
  498             self.setBraceMatching(QsciScintilla.SloppyBraceMatch)
  499         else:
  500             self.setBraceMatching(QsciScintilla.NoBraceMatch)
  501         self.setMatchedBraceForegroundColor(
  502             Preferences.getEditorColour("MatchingBrace"))
  503         self.setMatchedBraceBackgroundColor(
  504             Preferences.getEditorColour("MatchingBraceBack"))
  505         self.setUnmatchedBraceForegroundColor(
  506             Preferences.getEditorColour("NonmatchingBrace"))
  507         self.setUnmatchedBraceBackgroundColor(
  508             Preferences.getEditorColour("NonmatchingBraceBack"))
  509         if Preferences.getEditor("CustomSelectionColours"):
  510             self.setSelectionBackgroundColor(
  511                 Preferences.getEditorColour("SelectionBackground"))
  512         else:
  513             self.setSelectionBackgroundColor(
  514                 QApplication.palette().color(QPalette.Highlight))
  515         if Preferences.getEditor("ColourizeSelText"):
  516             self.resetSelectionForegroundColor()
  517         elif Preferences.getEditor("CustomSelectionColours"):
  518             self.setSelectionForegroundColor(
  519                 Preferences.getEditorColour("SelectionForeground"))
  520         else:
  521             self.setSelectionForegroundColor(
  522                 QApplication.palette().color(QPalette.HighlightedText))
  523         self.setSelectionToEol(Preferences.getEditor("ExtendSelectionToEol"))
  524         self.setCaretForegroundColor(
  525             Preferences.getEditorColour("CaretForeground"))
  526         self.setCaretLineVisible(False)
  527         self.caretWidth = Preferences.getEditor("CaretWidth")
  528         self.setCaretWidth(self.caretWidth)
  529         if Preferences.getShell("WrapEnabled"):
  530             self.setWrapMode(QsciScintilla.WrapWord)
  531         else:
  532             self.setWrapMode(QsciScintilla.WrapNone)
  533         self.useMonospaced = Preferences.getShell("UseMonospacedFont")
  534         self.__setMonospaced(self.useMonospaced)
  535         
  536         self.setCursorFlashTime(QApplication.cursorFlashTime())
  537         
  538         if Preferences.getEditor("OverrideEditAreaColours"):
  539             self.setColor(Preferences.getEditorColour("EditAreaForeground"))
  540             self.setPaper(Preferences.getEditorColour("EditAreaBackground"))
  541         
  542     def __setMonospaced(self, on):
  543         """
  544         Private method to set/reset a monospaced font.
  545         
  546         @param on flag to indicate usage of a monospace font (boolean)
  547         """
  548         if on:
  549             if not self.lexer_:
  550                 f = Preferences.getShell("MonospacedFont")
  551                 self.monospacedStyles(f)
  552         else:
  553             if not self.lexer_:
  554                 self.clearStyles()
  555                 self.__setMargin0()
  556             self.setFont(Preferences.getShell("MonospacedFont"))
  557         
  558         self.useMonospaced = on
  559         
  560     def __setAutoCompletion(self, language='Python'):
  561         """
  562         Private method to configure the autocompletion function.
  563         
  564         @param language of the autocompletion set to set (string)
  565         """
  566         self.setAutoCompletionCaseSensitivity(
  567             Preferences.getEditor("AutoCompletionCaseSensitivity"))
  568         self.setAutoCompletionThreshold(-1)
  569         
  570         self.racEnabled = Preferences.getShell("AutoCompletionEnabled")
  571         
  572         self.maxLines = Preferences.getEditor("AutoCompletionMaxLines")
  573         self.maxChars = Preferences.getEditor("AutoCompletionMaxChars")
  574         
  575     def __setCallTips(self, language='Python'):
  576         """
  577         Private method to configure the calltips function.
  578         
  579         @param language of the calltips set to set (string)
  580         """
  581         if Preferences.getShell("CallTipsEnabled"):
  582             self.setCallTipsBackgroundColor(
  583                 Preferences.getEditorColour("CallTipsBackground"))
  584             self.setCallTipsForegroundColor(
  585                 Preferences.getEditorColour("CallTipsForeground"))
  586             self.setCallTipsHighlightColor(
  587                 Preferences.getEditorColour("CallTipsHighlight"))
  588             self.setCallTipsVisible(Preferences.getEditor("CallTipsVisible"))
  589             calltipsStyle = Preferences.getEditor("CallTipsStyle")
  590             if calltipsStyle == QsciScintilla.CallTipsNoContext:
  591                 self.setCallTipsStyle(QsciScintilla.CallTipsNoContext)
  592             elif (
  593                 calltipsStyle ==
  594                     QsciScintilla.CallTipsNoAutoCompletionContext
  595             ):
  596                 self.setCallTipsStyle(
  597                     QsciScintilla.CallTipsNoAutoCompletionContext)
  598             else:
  599                 self.setCallTipsStyle(QsciScintilla.CallTipsContext)
  600         else:
  601             self.setCallTipsStyle(QsciScintilla.CallTipsNone)
  602         
  603     def setDebuggerUI(self, ui):
  604         """
  605         Public method to set the debugger UI.
  606         
  607         @param ui reference to the debugger UI object (DebugUI)
  608         """
  609         ui.exceptionInterrupt.connect(self.__writePrompt)
  610         
  611     def __initialise(self):
  612         """
  613         Private method to get ready for a new remote interpreter.
  614         """
  615         self.buff = ""
  616         self.inContinue = False
  617         self.inRawMode = False
  618         self.echoInput = True
  619         self.clientCapabilities = 0
  620         self.inCommandExecution = False
  621         self.interruptCommandExecution = False
  622         
  623     def __clientCapabilities(self, cap, clType, venvName):
  624         """
  625         Private slot to handle the reporting of the clients capabilities.
  626         
  627         @param cap client capabilities
  628         @type int
  629         @param clType type of the debug client
  630         @type str
  631         @param venvName name of the virtual environment
  632         @type str
  633         """
  634         self.clientCapabilities = cap
  635         self.__currentVenv = venvName
  636         if clType != self.clientType:
  637             self.clientType = clType
  638             self.__bindLexer(self.clientType)
  639             self.__setTextDisplay()
  640             self.__setMargin0()
  641             self.__setAutoCompletion(self.clientType)
  642             self.__setCallTips(self.clientType)
  643             self.racEnabled = (
  644                 Preferences.getShell("AutoCompletionEnabled") and
  645                 (cap & HasCompleter) > 0
  646             )
  647             
  648             if self.clientType not in self.__historyLists:
  649                 # load history list
  650                 self.loadHistory(self.clientType)
  651             self.__history = self.__historyLists[self.clientType]
  652             self.__setHistoryIndex()
  653         
  654         self.virtualEnvironmentChanged.emit(venvName)
  655         Preferences.setShell("LastVirtualEnvironment", venvName)
  656     
  657     def __setHistoryIndex(self, index=None):
  658         """
  659         Private method to set the initial history index.
  660         
  661         @param index index value to be set
  662         @type int or None
  663         """
  664         if index is None:
  665             # determine based on history style
  666             if (
  667                 self.clientType and
  668                 self.__historyStyle == ShellHistoryStyle.WindowsStyle
  669             ):
  670                 idx = int(Preferences.Prefs.settings.value(
  671                     "Shell/HistoryIndexes/" + self.clientType, -1))
  672                 if idx >= len(self.__history):
  673                     idx = -1
  674                 self.__histidx = idx
  675             else:
  676                 self.__histidx = -1
  677         else:
  678             self.__histidx = index
  679             if self.__histidx >= len(self.__history):
  680                 self.__histidx = -1
  681             if (
  682                 self.clientType and
  683                 self.__historyStyle == ShellHistoryStyle.WindowsStyle
  684             ):
  685                 Preferences.Prefs.settings.setValue(
  686                     "Shell/HistoryIndexes/" + self.clientType, self.__histidx)
  687     
  688     def __isHistoryIndexValid(self):
  689         """
  690         Private method to test, if the history index is valid.
  691         
  692         @return flag indicating validity
  693         @rtype bool
  694         """
  695         return (0 <= self.__histidx < len(self.__history))
  696     
  697     def getHistoryIndex(self):
  698         """
  699         Public method to get the current value of the history index.
  700         
  701         @return history index
  702         @rtype int
  703         """
  704         return self.__histidx
  705     
  706     def loadHistory(self, clientType):
  707         """
  708         Public method to load the history for the given client type.
  709         
  710         @param clientType type of the debug client (string)
  711         """
  712         hl = Preferences.Prefs.settings.value("Shell/Histories/" + clientType)
  713         if hl is not None:
  714             self.__historyLists[clientType] = hl[-self.__maxHistoryEntries:]
  715         else:
  716             self.__historyLists[clientType] = []
  717         
  718     def reloadHistory(self):
  719         """
  720         Public method to reload the history of the currently selected client
  721         type.
  722         """
  723         self.loadHistory(self.clientType)
  724         self.__history = self.__historyLists[self.clientType]
  725         self.__setHistoryIndex()
  726         
  727     def saveHistory(self, clientType):
  728         """
  729         Public method to save the history for the given client type.
  730         
  731         @param clientType type of the debug client (string)
  732         """
  733         if clientType in self.__historyLists:
  734             Preferences.Prefs.settings.setValue(
  735                 "Shell/Histories/" + clientType,
  736                 self.__historyLists[clientType])
  737         
  738     def getHistory(self, clientType):
  739         """
  740         Public method to get the history for the given client type.
  741         
  742         @param clientType type of the debug client (string).
  743             If it is None, the current history is returned.
  744         @return reference to the history list (list of strings)
  745         """
  746         if clientType is None:
  747             return self.__history
  748         elif clientType in self.__historyLists:
  749             return self.__historyLists[clientType]
  750         else:
  751             return []
  752         
  753     def clearHistory(self):
  754         """
  755         Public slot to clear the current history.
  756         """
  757         if self.clientType:
  758             self.__historyLists[self.clientType] = []
  759             self.__history = self.__historyLists[self.clientType]
  760         else:
  761             self.__history = []
  762         self.__setHistoryIndex(index=-1)
  763         
  764     def selectHistory(self):
  765         """
  766         Public slot to select a history entry to execute.
  767         """
  768         current = self.__histidx
  769         if current == -1:
  770             current = len(self.__history) - 1
  771         cmd, ok = QInputDialog.getItem(
  772             self,
  773             self.tr("Select History"),
  774             self.tr("Select the history entry to execute"
  775                     " (most recent shown last)."),
  776             self.__history,
  777             current, False)
  778         if ok:
  779             self.__insertHistory(cmd)
  780         
  781     def showHistory(self):
  782         """
  783         Public slot to show the shell history dialog.
  784         """
  785         from .ShellHistoryDialog import ShellHistoryDialog
  786         dlg = ShellHistoryDialog(self.__history, self.vm, self)
  787         if dlg.exec_() == QDialog.Accepted:
  788             self.__historyLists[self.clientType], idx = dlg.getHistory()
  789             self.__history = self.__historyLists[self.clientType]
  790             self.__setHistoryIndex(index=idx)
  791         
  792     def clearAllHistories(self):
  793         """
  794         Public method to clear all available histories and sync them.
  795         """
  796         Preferences.Prefs.settings.beginGroup("Shell/Histories")
  797         for clientType in Preferences.Prefs.settings.childKeys():
  798             self.__historyLists[clientType] = []
  799             self.saveHistory(clientType)
  800         Preferences.Prefs.settings.endGroup()
  801         
  802         self.clearHistory()
  803         
  804     def getClientType(self):
  805         """
  806         Public slot to get the clients type.
  807         
  808         @return client type (string)
  809         """
  810         return self.clientType
  811         
  812     def __getBanner(self):
  813         """
  814         Private method to get the banner for the remote interpreter.
  815         
  816         It requests the interpreter version and platform running on the
  817         debug client side.
  818         """
  819         if self.passive:
  820             self.__writeBanner('', '', '', '')
  821         else:
  822             self.dbs.remoteBanner()
  823         
  824     def __writeBanner(self, version, platform, dbgclient, venvName):
  825         """
  826         Private method to write a banner with info from the debug client.
  827         
  828         @param version interpreter version string
  829         @type str
  830         @param platform platform of the remote interpreter
  831         @type str
  832         @param dbgclient debug client variant used
  833         @type str
  834         @param venvName name of the virtual environment
  835         @type str
  836         """
  837         super(Shell, self).clear()
  838         if self.passive and not self.dbs.isConnected():
  839             self.__write(self.tr('Passive Debug Mode'))
  840             self.__write(self.tr('\nNot connected'))
  841         else:
  842             self.__currentVenv = venvName
  843             version = version.replace("#", self.tr("No."))
  844             if platform != "" and dbgclient != "":
  845                 self.__write(
  846                     self.tr('{0} on {1}, {2}')
  847                         .format(version, platform, dbgclient))
  848             else:
  849                 self.__write(version)
  850             if venvName:
  851                 self.__write("\n[{0}]".format(venvName))
  852             
  853             self.virtualEnvironmentChanged.emit(venvName)
  854             Preferences.setShell("LastVirtualEnvironment", venvName)
  855         self.__write('\n')
  856         
  857         self.__write(sys.ps1)
  858         
  859     def __writePrompt(self):
  860         """
  861         Private method to write the prompt using a write queue.
  862         """
  863         self.queueText.emit(self.inContinue and sys.ps2 or sys.ps1)
  864     
  865     def __clientStatement(self, more):
  866         """
  867         Private method to handle the response from the debugger client.
  868         
  869         @param more flag indicating that more user input is required (boolean)
  870         """
  871         if not self.inRawMode:
  872             self.inContinue = more
  873             self.__writePrompt()
  874         self.inCommandExecution = False
  875     
  876     def __clientException(self, exceptionType, exceptionMessage, stackTrace):
  877         """
  878         Private method to handle an exception of the client.
  879         
  880         @param exceptionType type of exception raised (string)
  881         @param exceptionMessage message given by the exception (string)
  882         @param stackTrace list of stack entries (list of string)
  883         """
  884         self .__clientError()
  885         
  886         if (
  887             not self.__windowed and
  888             Preferences.getDebugger("ShowExceptionInShell")
  889         ):
  890             if exceptionType:
  891                 if stackTrace:
  892                     self.__write(
  893                         self.tr('Exception "{0}"\n{1}\nFile: {2}, Line: {3}\n')
  894                         .format(
  895                             exceptionType,
  896                             exceptionMessage,
  897                             stackTrace[0][0],
  898                             stackTrace[0][1]
  899                         )
  900                     )
  901                 else:
  902                     self.__write(
  903                         self.tr('Exception "{0}"\n{1}\n')
  904                         .format(
  905                             exceptionType,
  906                             exceptionMessage)
  907                     )
  908         
  909     def __clientSyntaxError(self, message, filename, lineNo, characterNo):
  910         """
  911         Private method to handle a syntax error in the debugged program.
  912         
  913         @param message message of the syntax error (string)
  914         @param filename translated filename of the syntax error position
  915             (string)
  916         @param lineNo line number of the syntax error position (integer)
  917         @param characterNo character number of the syntax error position
  918             (integer)
  919         """
  920         self .__clientError()
  921         
  922         if (
  923             not self.__windowed and
  924             Preferences.getDebugger("ShowExceptionInShell")
  925         ):
  926             if message is None:
  927                 self.__write(self.tr("Unspecified syntax error.\n"))
  928             else:
  929                 self.__write(
  930                     self.tr('Syntax error "{1}" in file {0} at line {2},'
  931                             ' character {3}.\n')
  932                         .format(filename, message, lineNo, characterNo)
  933                 )
  934         
  935     def __clientSignal(self, message, filename, lineNo, funcName, funcArgs):
  936         """
  937         Private method to handle a signal generated on the client side.
  938         
  939         @param message message of the syntax error
  940         @type str
  941         @param filename translated filename of the syntax error position
  942         @type str
  943         @param lineNo line number of the syntax error position
  944         @type int
  945         @param funcName name of the function causing the signal
  946         @type str
  947         @param funcArgs function arguments
  948         @type str
  949         """
  950         self.__clientError()
  951         
  952         self.__write(
  953             self.tr("""Signal "{0}" generated in file {1} at line {2}.\n"""
  954                     """Function: {3}({4})""")
  955                 .format(message, filename, lineNo, funcName, funcArgs)
  956         )
  957         
  958     def __clientError(self):
  959         """
  960         Private method to handle an error in the client.
  961         """
  962         self.inCommandExecution = False
  963         self.interruptCommandExecution = True
  964         self.inContinue = False
  965         
  966     def __getEndPos(self):
  967         """
  968         Private method to return the line and column of the last character.
  969         
  970         @return tuple of two values (int, int) giving the line and column
  971         """
  972         line = self.lines() - 1
  973         return (line, len(self.text(line)))
  974         
  975     def __writeQueued(self, s):
  976         """
  977         Private method to display some text using a write queue.
  978         
  979         @param s text to be displayed (string)
  980         """
  981         self.queueText.emit(s)
  982 
  983     def __concatenateText(self, text):
  984         """
  985         Private slot to queue text and process it in one step.
  986         
  987         @param text text to be appended
  988         @type str
  989         """
  990         self.__queuedText += text
  991         if self.__blockTextProcessing:
  992             return
  993         
  994         self.__blockTextProcessing = True
  995         # Get all text which is still waiting for output
  996         QApplication.processEvents()
  997         
  998         # Finally process the accumulated text
  999         self.__flushQueuedText()
 1000     
 1001     def __flushQueuedText(self):
 1002         """
 1003         Private slot to flush the accumulated text output.
 1004         """
 1005         self.__write(self.__queuedText)
 1006         
 1007         self.__queuedText = ''
 1008         self.__blockTextProcessing = False
 1009         
 1010         # little trick to get the cursor position registered within QScintilla
 1011         self.SendScintilla(QsciScintilla.SCI_CHARLEFT)
 1012         self.SendScintilla(QsciScintilla.SCI_CHARRIGHT)
 1013     
 1014     def __write(self, s):
 1015         """
 1016         Private method to display some text without queuing.
 1017         
 1018         @param s text to be displayed
 1019         @type str
 1020         """
 1021         line, col = self.__getEndPos()
 1022         self.setCursorPosition(line, col)
 1023         self.insert(Utilities.filterAnsiSequences(s))
 1024         self.prline, self.prcol = self.getCursorPosition()
 1025         self.ensureCursorVisible()
 1026         self.ensureLineVisible(self.prline)
 1027         
 1028     def __writeStdOut(self, s):
 1029         """
 1030         Private method to display some text with StdOut label.
 1031         
 1032         @param s text to be displayed (string)
 1033         """
 1034         self.__write(self.tr("StdOut: {0}").format(s))
 1035         
 1036     def __writeStdErr(self, s):
 1037         """
 1038         Private method to display some text with StdErr label.
 1039         
 1040         @param s text to be displayed (string)
 1041         """
 1042         self.__write(self.tr("StdErr: {0}").format(s))
 1043         
 1044     def __raw_input(self, prompt, echo):
 1045         """
 1046         Private method to handle raw input.
 1047         
 1048         @param prompt prompt to be displayed
 1049         @type str
 1050         @param echo Flag indicating echoing of the input
 1051         @type bool
 1052         """
 1053         self.setFocus()
 1054         self.inRawMode = True
 1055         self.echoInput = echo
 1056         
 1057         # Get all text which is still waiting for output
 1058         QApplication.processEvents()
 1059         self.__flushQueuedText()
 1060         
 1061         self.__write(prompt)
 1062         line, col = self.__getEndPos()
 1063         self.setCursorPosition(line, col)
 1064         buf = self.text(line)
 1065         if buf.startswith(sys.ps1):
 1066             buf = buf.replace(sys.ps1, "")
 1067         if buf.startswith(sys.ps2):
 1068             buf = buf.replace(sys.ps2, "")
 1069         self.prompt = buf
 1070         # move cursor to end of line
 1071         self.moveCursorToEOL()
 1072         
 1073     def paste(self):
 1074         """
 1075         Public slot to handle the paste action.
 1076         """
 1077         if self.__isCursorOnLastLine():
 1078             line, col = self.getCursorPosition()
 1079             lastLine = self.text(line)
 1080             if lastLine.startswith(sys.ps1):
 1081                 lastLine = lastLine[len(sys.ps1):]
 1082                 col -= len(sys.ps1)
 1083                 prompt = sys.ps1
 1084             elif lastLine.startswith(sys.ps2):
 1085                 lastLine = lastLine[len(sys.ps2):]
 1086                 col -= len(sys.ps2)
 1087                 prompt = sys.ps2
 1088             else:
 1089                 prompt = ""
 1090             if col < 0:
 1091                 col = 0
 1092                 prompt = ""
 1093             
 1094             # Remove if text is selected
 1095             if self.hasSelectedText():
 1096                 lineFrom, indexFrom, lineTo, indexTo = self.getSelection()
 1097                 if self.text(lineFrom).startswith(sys.ps1):
 1098                     indexFrom -= len(sys.ps1)
 1099                     indexTo -= len(sys.ps1)
 1100                 elif self.text(lineFrom).startswith(sys.ps2):
 1101                     indexFrom -= len(sys.ps2)
 1102                     indexTo -= len(sys.ps2)
 1103                 if indexFrom < 0:
 1104                     indexFrom = 0
 1105                 lastLine = lastLine[:indexFrom] + lastLine[indexTo:]
 1106                 col = indexFrom
 1107 
 1108             self.setCursorPosition(line, len(prompt))
 1109             self.deleteLineRight()
 1110             
 1111             lines = QApplication.clipboard().text()
 1112             lines = lastLine[:col] + lines + lastLine[col:]
 1113             self.executeLines(lines)
 1114             line, _ = self.getCursorPosition()
 1115             pos = len(self.text(line)) - (len(lastLine) - col)
 1116             self.setCursorPosition(line, pos)
 1117         
 1118     def __middleMouseButton(self):
 1119         """
 1120         Private method to handle the middle mouse button press.
 1121         """
 1122         lines = QApplication.clipboard().text(QClipboard.Selection)
 1123         self.executeLines(lines)
 1124         
 1125     def executeLines(self, lines, historyIndex=None):
 1126         """
 1127         Public method to execute a set of lines as multiple commands.
 1128         
 1129         @param lines multiple lines of text to be executed as
 1130             single commands
 1131         @type str
 1132         @param historyIndex history index to be set
 1133         @type int
 1134         """
 1135         lines = lines.splitlines(True)
 1136         if not lines:
 1137             return
 1138         
 1139         indentLen = self.__indentLength(lines[0])
 1140         for line in lines:
 1141             if line.startswith(sys.ps1):
 1142                 line = line[len(sys.ps1) + indentLen:]
 1143             elif line.startswith(sys.ps2):
 1144                 line = line[len(sys.ps2) + indentLen:]
 1145             else:
 1146                 line = line[indentLen:]
 1147             
 1148             if line.endswith("\r\n"):
 1149                 fullline = True
 1150                 cmd = line[:-2]
 1151             elif line.endswith("\r") or line.endswith("\n"):
 1152                 fullline = True
 1153                 cmd = line[:-1]
 1154             else:
 1155                 fullline = False
 1156             
 1157             self.incrementalSearchActive = True
 1158             self.__insertTextAtEnd(line)
 1159             if fullline:
 1160                 self.incrementalSearchActive = False
 1161                 
 1162                 self.__executeCommand(cmd, historyIndex=historyIndex)
 1163                 if self.interruptCommandExecution:
 1164                     self.__executeCommand("")
 1165                     break
 1166     
 1167     def __indentLength(self, line):
 1168         """
 1169         Private method to determine the indentation length of the given line.
 1170         
 1171         @param line line to determine the indentation length for
 1172         @type str
 1173         @return indentation length
 1174         @rtype int
 1175         """
 1176         if line.startswith(sys.ps1):
 1177             line = line[len(sys.ps1):]
 1178         # If line starts with sys.ps2 or neither don't manipulate the line.
 1179         indentLen = len(line) - len(line.lstrip())
 1180         return indentLen
 1181     
 1182     def __clearCurrentLine(self):
 1183         """
 1184         Private method to clear the line containing the cursor.
 1185         """
 1186         line, col = self.getCursorPosition()
 1187         if self.text(line).startswith(sys.ps1):
 1188             col = len(sys.ps1)
 1189         elif self.text(line).startswith(sys.ps2):
 1190             col = len(sys.ps2)
 1191         else:
 1192             col = 0
 1193         self.setCursorPosition(line, col)
 1194         self.deleteLineRight()
 1195         
 1196     def __insertText(self, s):
 1197         """
 1198         Private method to insert some text at the current cursor position.
 1199         
 1200         @param s text to be inserted (string)
 1201         """
 1202         line, col = self.getCursorPosition()
 1203         self.insertAt(Utilities.filterAnsiSequences(s), line, col)
 1204         self.setCursorPosition(line, col + len(s))
 1205         
 1206     def __insertTextAtEnd(self, s):
 1207         """
 1208         Private method to insert some text at the end of the command line.
 1209         
 1210         @param s text to be inserted (string)
 1211         """
 1212         line, col = self.__getEndPos()
 1213         self.setCursorPosition(line, col)
 1214         self.insert(Utilities.filterAnsiSequences(s))
 1215         self.prline, _ = self.getCursorPosition()
 1216         
 1217     def __insertTextNoEcho(self, s):
 1218         """
 1219         Private method to insert some text at the end of the buffer without
 1220         echoing it.
 1221         
 1222         @param s text to be inserted (string)
 1223         """
 1224         self.buff += s
 1225         self.prline, self.prcol = self.getCursorPosition()
 1226         
 1227     def mousePressEvent(self, event):
 1228         """
 1229         Protected method to handle the mouse press event.
 1230         
 1231         @param event the mouse press event (QMouseEvent)
 1232         """
 1233         self.setFocus()
 1234         if event.button() == Qt.MidButton:
 1235             self.__middleMouseButton()
 1236         else:
 1237             super(Shell, self).mousePressEvent(event)
 1238         
 1239     def wheelEvent(self, evt):
 1240         """
 1241         Protected method to handle wheel events.
 1242         
 1243         @param evt reference to the wheel event (QWheelEvent)
 1244         """
 1245         if evt.modifiers() & Qt.ControlModifier:
 1246             delta = evt.angleDelta().y()
 1247             if delta < 0:
 1248                 self.zoomOut()
 1249             elif delta > 0:
 1250                 self.zoomIn()
 1251             evt.accept()
 1252             return
 1253         
 1254         super(Shell, self).wheelEvent(evt)
 1255     
 1256     def event(self, evt):
 1257         """
 1258         Public method handling events.
 1259         
 1260         @param evt reference to the event (QEvent)
 1261         @return flag indicating, if the event was handled (boolean)
 1262         """
 1263         if evt.type() == QEvent.Gesture:
 1264             self.gestureEvent(evt)
 1265             return True
 1266         
 1267         return super(Shell, self).event(evt)
 1268     
 1269     def gestureEvent(self, evt):
 1270         """
 1271         Protected method handling gesture events.
 1272         
 1273         @param evt reference to the gesture event (QGestureEvent
 1274         """
 1275         pinch = evt.gesture(Qt.PinchGesture)
 1276         if pinch:
 1277             if pinch.state() == Qt.GestureStarted:
 1278                 zoom = (self.getZoom() + 10) / 10.0
 1279                 pinch.setTotalScaleFactor(zoom)
 1280             elif pinch.state() == Qt.GestureUpdated:
 1281                 zoom = int(pinch.totalScaleFactor() * 10) - 10
 1282                 if zoom <= -9:
 1283                     zoom = -9
 1284                     pinch.setTotalScaleFactor(0.1)
 1285                 elif zoom >= 20:
 1286                     zoom = 20
 1287                     pinch.setTotalScaleFactor(3.0)
 1288                 self.zoomTo(zoom)
 1289             evt.accept()
 1290     
 1291     def editorCommand(self, cmd):
 1292         """
 1293         Public method to perform an editor command.
 1294         
 1295         @param cmd the scintilla command to be performed
 1296         """
 1297         try:
 1298             self.supportedEditorCommands[cmd]()
 1299         except TypeError:
 1300             self.supportedEditorCommands[cmd](cmd)
 1301         except KeyError:
 1302             pass
 1303         
 1304     def __isCursorOnLastLine(self):
 1305         """
 1306         Private method to check, if the cursor is on the last line.
 1307         
 1308         @return flag indicating that the cursor is on the last line (boolean)
 1309         """
 1310         cline, ccol = self.getCursorPosition()
 1311         return cline == self.lines() - 1
 1312         
 1313     def keyPressEvent(self, ev):
 1314         """
 1315         Protected method to handle the user input a key at a time.
 1316         
 1317         @param ev key event (QKeyEvent)
 1318         """
 1319         txt = ev.text()
 1320         
 1321         # See it is text to insert.
 1322         if len(txt) and txt >= " ":
 1323             if not self.__isCursorOnLastLine():
 1324                 line, col = self.__getEndPos()
 1325                 self.setCursorPosition(line, col)
 1326                 self.prline, self.prcol = self.getCursorPosition()
 1327             if self.echoInput:
 1328                 ac = self.isListActive()
 1329                 super(Shell, self).keyPressEvent(ev)
 1330                 self.incrementalSearchActive = True
 1331                 if ac and self.racEnabled:
 1332                     self.dbs.remoteCompletion(self.completionText + txt)
 1333             else:
 1334                 self.__insertTextNoEcho(txt)
 1335         else:
 1336             ev.ignore()
 1337         
 1338     def __QScintillaCommand(self, cmd):
 1339         """
 1340         Private method to send the command to QScintilla.
 1341         
 1342         @param cmd QScintilla command
 1343         """
 1344         self.SendScintilla(cmd)
 1345         
 1346     def __QScintillaTab(self, cmd):
 1347         """
 1348         Private method to handle the Tab key.
 1349         
 1350         @param cmd QScintilla command
 1351         """
 1352         if self.isListActive():
 1353             self.SendScintilla(cmd)
 1354         elif self.__isCursorOnLastLine():
 1355             line, index = self.getCursorPosition()
 1356             buf = self.text(line)
 1357             if buf.startswith(sys.ps1):
 1358                 buf = buf.replace(sys.ps1, "")
 1359             if buf.startswith(sys.ps2):
 1360                 buf = buf.replace(sys.ps2, "")
 1361             if self.inContinue and not buf[:index - len(sys.ps2)].strip():
 1362                 self.SendScintilla(cmd)
 1363             elif self.racEnabled:
 1364                 self.dbs.remoteCompletion(buf)
 1365         
 1366     def __QScintillaLeftDeleteCommand(self, method):
 1367         """
 1368         Private method to handle a QScintilla delete command working to
 1369         the left.
 1370         
 1371         @param method shell method to execute
 1372         """
 1373         if self.__isCursorOnLastLine():
 1374             line, col = self.getCursorPosition()
 1375             db = 0
 1376             ac = self.isListActive()
 1377             oldLength = len(self.text(line))
 1378             
 1379             if self.text(line).startswith(sys.ps1):
 1380                 if col > len(sys.ps1):
 1381                     method()
 1382                     db = 1
 1383             elif self.text(line).startswith(sys.ps2):
 1384                 if col > len(sys.ps2):
 1385                     method()
 1386                     db = 1
 1387             elif col > 0:
 1388                 method()
 1389                 db = 1
 1390             if db and ac and self.racEnabled and self.completionText:
 1391                 delta = len(self.text(line)) - oldLength
 1392                 self.dbs.remoteCompletion(self.completionText[:delta])
 1393         
 1394     def __QScintillaDeleteBack(self):
 1395         """
 1396         Private method to handle the Backspace key.
 1397         """
 1398         self.__QScintillaLeftDeleteCommand(self.deleteBack)
 1399         
 1400     def __QScintillaDeleteWordLeft(self):
 1401         """
 1402         Private method to handle the Delete Word Left command.
 1403         """
 1404         self.__QScintillaLeftDeleteCommand(self.deleteWordLeft)
 1405         
 1406     def __QScintillaDelete(self):
 1407         """
 1408         Private method to handle the delete command.
 1409         """
 1410         if self.__isCursorOnLastLine():
 1411             if self.hasSelectedText():
 1412                 lineFrom, indexFrom, lineTo, indexTo = self.getSelection()
 1413                 if self.text(lineFrom).startswith(sys.ps1):
 1414                     if indexFrom >= len(sys.ps1):
 1415                         self.delete()
 1416                 elif self.text(lineFrom).startswith(sys.ps2):
 1417                     if indexFrom >= len(sys.ps2):
 1418                         self.delete()
 1419                 elif indexFrom >= 0:
 1420                     self.delete()
 1421             else:
 1422                 self.delete()
 1423         
 1424     def __QScintillaDeleteLineLeft(self):
 1425         """
 1426         Private method to handle the Delete Line Left command.
 1427         """
 1428         if self.__isCursorOnLastLine():
 1429             if self.isListActive():
 1430                 self.cancelList()
 1431             
 1432             line, col = self.getCursorPosition()
 1433             if self.text(line).startswith(sys.ps1):
 1434                 prompt = sys.ps1
 1435             elif self.text(line).startswith(sys.ps2):
 1436                 prompt = sys.ps2
 1437             else:
 1438                 prompt = ""
 1439             
 1440             self.deleteLineLeft()
 1441             self.insertAt(prompt, line, 0)
 1442             self.setCursorPosition(line, len(prompt))
 1443         
 1444     def __QScintillaNewline(self, cmd):
 1445         """
 1446         Private method to handle the Return key.
 1447         
 1448         @param cmd QScintilla command
 1449         """
 1450         if self.__isCursorOnLastLine():
 1451             if self.isListActive():
 1452                 self.SendScintilla(cmd)
 1453             else:
 1454                 self.incrementalSearchString = ""
 1455                 self.incrementalSearchActive = False
 1456                 line, col = self.__getEndPos()
 1457                 self.setCursorPosition(line, col)
 1458                 buf = self.text(line)
 1459                 if buf.startswith(sys.ps1):
 1460                     buf = buf.replace(sys.ps1, "")
 1461                 if buf.startswith(sys.ps2):
 1462                     buf = buf.replace(sys.ps2, "")
 1463                 self.insert('\n')
 1464                 self.__executeCommand(buf)
 1465         else:
 1466             txt = ""
 1467             line, col = self.getCursorPosition()
 1468             if self.hasSelectedText():
 1469                 lineFrom, indexFrom, lineTo, indexTo = self.getSelection()
 1470                 if line == lineFrom:
 1471                     txt = self.text(line)[indexFrom:].rstrip()
 1472                 elif line == lineTo:
 1473                     txt = self.text(line)[:indexTo]
 1474             else:
 1475                 txt = self.text(line)[col:].rstrip()
 1476             
 1477             if txt:
 1478                 line, col = self.__getEndPos()
 1479                 self.setCursorPosition(line, col)
 1480                 self.insert(txt)
 1481         
 1482     def __QScintillaLeftCommand(self, method, allLinesAllowed=False):
 1483         """
 1484         Private method to handle a QScintilla command working to the left.
 1485         
 1486         @param method shell method to execute
 1487         @param allLinesAllowed flag indicating that the command may be executed
 1488             on any line (boolean)
 1489         """
 1490         if self.__isCursorOnLastLine() or allLinesAllowed:
 1491             line, col = self.getCursorPosition()
 1492             if self.text(line).startswith(sys.ps1):
 1493                 if col > len(sys.ps1):
 1494                     method()
 1495             elif self.text(line).startswith(sys.ps2):
 1496                 if col > len(sys.ps2):
 1497                     method()
 1498             elif col > 0:
 1499                 method()
 1500         else:
 1501             method()
 1502         
 1503     def __QScintillaCharLeft(self):
 1504         """
 1505         Private method to handle the Cursor Left command.
 1506         """
 1507         self.__QScintillaLeftCommand(self.moveCursorLeft)
 1508         
 1509     def __QScintillaWordLeft(self):
 1510         """
 1511         Private method to handle the Cursor Word Left command.
 1512         """
 1513         self.__QScintillaLeftCommand(self.moveCursorWordLeft)
 1514         
 1515     def __QScintillaRightCommand(self, method):
 1516         """
 1517         Private method to handle a QScintilla command working to the right.
 1518         
 1519         @param method shell method to execute
 1520         """
 1521         if self.__isCursorOnLastLine():
 1522             method()
 1523         else:
 1524             method()
 1525         
 1526     def __QScintillaCharRight(self):
 1527         """
 1528         Private method to handle the Cursor Right command.
 1529         """
 1530         self.__QScintillaRightCommand(self.moveCursorRight)
 1531         
 1532     def __QScintillaWordRight(self):
 1533         """
 1534         Private method to handle the Cursor Word Right command.
 1535         """
 1536         self.__QScintillaRightCommand(self.moveCursorWordRight)
 1537         
 1538     def __QScintillaDeleteWordRight(self):
 1539         """
 1540         Private method to handle the Delete Word Right command.
 1541         """
 1542         self.__QScintillaRightCommand(self.deleteWordRight)
 1543         
 1544     def __QScintillaDeleteLineRight(self):
 1545         """
 1546         Private method to handle the Delete Line Right command.
 1547         """
 1548         self.__QScintillaRightCommand(self.deleteLineRight)
 1549         
 1550     def __QScintillaVCHome(self, cmd):
 1551         """
 1552         Private method to handle the Home key.
 1553         
 1554         @param cmd QScintilla command
 1555         """
 1556         if self.isListActive():
 1557             self.SendScintilla(cmd)
 1558         elif self.__isCursorOnLastLine():
 1559             line, col = self.getCursorPosition()
 1560             if self.text(line).startswith(sys.ps1):
 1561                 col = len(sys.ps1)
 1562             elif self.text(line).startswith(sys.ps2):
 1563                 col = len(sys.ps2)
 1564             else:
 1565                 col = 0
 1566             self.setCursorPosition(line, col)
 1567         
 1568     def __QScintillaLineEnd(self, cmd):
 1569         """
 1570         Private method to handle the End key.
 1571         
 1572         @param cmd QScintilla command
 1573         """
 1574         if self.isListActive():
 1575             self.SendScintilla(cmd)
 1576         elif self.__isCursorOnLastLine():
 1577             self.moveCursorToEOL()
 1578     
 1579     def __QScintillaCursorCommand(self, cmd):
 1580         """
 1581         Private method to handle the cursor commands.
 1582         
 1583         @param cmd QScintilla command
 1584         """
 1585         if self.isListActive() or self.isCallTipActive():
 1586             if cmd in (QsciScintilla.SCI_LINEUP, QsciScintilla.SCI_LINEDOWN):
 1587                 self.SendScintilla(cmd)
 1588         else:
 1589             if self.__historyNavigateByCursor:
 1590                 if cmd == QsciScintilla.SCI_LINEUP:
 1591                     self.__QScintillaHistoryUp(cmd)
 1592                 elif cmd == QsciScintilla.SCI_LINEDOWN:
 1593                     self.__QScintillaHistoryDown(cmd)
 1594                 elif cmd == QsciScintilla.SCI_LINESCROLLUP:
 1595                     self.__QScintillaLineUp(cmd)
 1596                 elif cmd == QsciScintilla.SCI_LINESCROLLDOWN:
 1597                     self.__QScintillaLineDown(cmd)
 1598             else:
 1599                 if cmd == QsciScintilla.SCI_LINEUP:
 1600                     self.__QScintillaLineUp(cmd)
 1601                 elif cmd == QsciScintilla.SCI_LINEDOWN:
 1602                     self.__QScintillaLineDown(cmd)
 1603                 elif cmd == QsciScintilla.SCI_LINESCROLLUP:
 1604                     self.__QScintillaHistoryUp(cmd)
 1605                 elif cmd == QsciScintilla.SCI_LINESCROLLDOWN:
 1606                     self.__QScintillaHistoryDown(cmd)
 1607     
 1608     def __QScintillaLineUp(self, cmd):
 1609         """
 1610         Private method to handle the cursor up command.
 1611         
 1612         @param cmd QScintilla command
 1613         """
 1614         self.SendScintilla(QsciScintilla.SCI_LINEUP)
 1615     
 1616     def __QScintillaLineDown(self, cmd):
 1617         """
 1618         Private method to handle the cursor down command.
 1619         
 1620         @param cmd QScintilla command
 1621         """
 1622         self.SendScintilla(QsciScintilla.SCI_LINEDOWN)
 1623     
 1624     def __QScintillaHistoryUp(self, cmd):
 1625         """
 1626         Private method to handle the history up command.
 1627         
 1628         @param cmd QScintilla command
 1629         """
 1630         if self.isHistoryEnabled():
 1631             line, col = self.__getEndPos()
 1632             buf = self.text(line)
 1633             if buf.startswith(sys.ps1):
 1634                 buf = buf.replace(sys.ps1, "")
 1635             if buf.startswith(sys.ps2):
 1636                 buf = buf.replace(sys.ps2, "")
 1637             if buf and self.incrementalSearchActive:
 1638                 if (
 1639                     self.incrementalSearchString and
 1640                     buf.startswith(self.incrementalSearchString)
 1641                 ):
 1642                     idx, found = self.__rsearchHistory(
 1643                         self.incrementalSearchString, self.__histidx)
 1644                     if found and idx >= 0:
 1645                         self.__setHistoryIndex(index=idx)
 1646                         self.__useHistory()
 1647                 else:
 1648                     idx, found = self.__rsearchHistory(buf)
 1649                     if found and idx >= 0:
 1650                         self.__setHistoryIndex(index=idx)
 1651                         self.incrementalSearchString = buf
 1652                         self.__useHistory()
 1653             else:
 1654                 if self.__historyWrap:
 1655                     if self.__histidx < 0:
 1656                         # wrap around
 1657                         self.__setHistoryIndex(index=len(self.__history) - 1)
 1658                     else:
 1659                         self.__setHistoryIndex(index=self.__histidx - 1)
 1660                     self.__useHistory()
 1661                 else:
 1662                     if self.__histidx < 0:
 1663                         self.__setHistoryIndex(index=len(self.__history) - 1)
 1664                         self.__useHistory()
 1665                     elif self.__histidx > 0:
 1666                         self.__setHistoryIndex(index=self.__histidx - 1)
 1667                         self.__useHistory()
 1668     
 1669     def __QScintillaHistoryDown(self, cmd):
 1670         """
 1671         Private method to handle the history down command.
 1672         
 1673         @param cmd QScintilla command
 1674         """
 1675         if self.isHistoryEnabled():
 1676             line, col = self.__getEndPos()
 1677             buf = self.text(line)
 1678             if buf.startswith(sys.ps1):
 1679                 buf = buf.replace(sys.ps1, "")
 1680             if buf.startswith(sys.ps2):
 1681                 buf = buf.replace(sys.ps2, "")
 1682             if buf and self.incrementalSearchActive:
 1683                 if (
 1684                     self.incrementalSearchString and
 1685                     buf.startswith(self.incrementalSearchString)
 1686                 ):
 1687                     idx, found = self.__searchHistory(
 1688                         self.incrementalSearchString, self.__histidx)
 1689                     if found and idx >= 0:
 1690                         self.__setHistoryIndex(index=idx)
 1691                         self.__useHistory()
 1692                 else:
 1693                     idx, found = self.__searchHistory(buf)
 1694                     if found and idx >= 0:
 1695                         self.__setHistoryIndex(index=idx)
 1696                         self.incrementalSearchString = buf
 1697                         self.__useHistory()
 1698             else:
 1699                 if self.__historyWrap:
 1700                     if self.__histidx >= len(self.__history) - 1:
 1701                         # wrap around
 1702                         self.__setHistoryIndex(index=0)
 1703                     else:
 1704                         self.__setHistoryIndex(index=self.__histidx + 1)
 1705                     self.__useHistory()
 1706                 else:
 1707                     if self.__isHistoryIndexValid():
 1708                         self.__setHistoryIndex(index=self.__histidx + 1)
 1709                         self.__useHistory()
 1710     
 1711     def __QScintillaCancel(self):
 1712         """
 1713         Private method to handle the ESC command.
 1714         """
 1715         if self.isListActive() or self.isCallTipActive():
 1716             self.SendScintilla(QsciScintilla.SCI_CANCEL)
 1717         else:
 1718             if self.incrementalSearchActive:
 1719                 self.__resetIncrementalHistorySearch()
 1720             self.__insertHistory("")
 1721     
 1722     def __QScintillaCharLeftExtend(self):
 1723         """
 1724         Private method to handle the Extend Selection Left command.
 1725         """
 1726         self.__QScintillaLeftCommand(self.extendSelectionLeft, True)
 1727         
 1728     def __QScintillaWordLeftExtend(self):
 1729         """
 1730         Private method to handle the Extend Selection Left one word command.
 1731         """
 1732         self.__QScintillaLeftCommand(self.extendSelectionWordLeft, True)
 1733         
 1734     def __QScintillaVCHomeExtend(self):
 1735         """
 1736         Private method to handle the Extend Selection to start of line command.
 1737         """
 1738         line, col = self.getCursorPosition()
 1739         if self.text(line).startswith(sys.ps1):
 1740             col = len(sys.ps1)
 1741         elif self.text(line).startswith(sys.ps2):
 1742             col = len(sys.ps2)
 1743         else:
 1744             col = 0
 1745         
 1746         self.extendSelectionToBOL()
 1747         while col > 0:
 1748             self.extendSelectionRight()
 1749             col -= 1
 1750         
 1751     def __QScintillaAutoCompletionCommand(self, cmd):
 1752         """
 1753         Private method to handle a command for autocompletion only.
 1754         
 1755         @param cmd QScintilla command
 1756         """
 1757         if self.isListActive() or self.isCallTipActive():
 1758             self.SendScintilla(cmd)
 1759         
 1760     def __executeCommand(self, cmd, historyIndex=None):
 1761         """
 1762         Private slot to execute a command.
 1763         
 1764         @param cmd command to be executed by debug client
 1765         @type str
 1766         @param historyIndex history index to be set
 1767         @type int
 1768         """
 1769         if not self.inRawMode:
 1770             self.inCommandExecution = True
 1771             self.interruptCommandExecution = False
 1772             if not cmd:
 1773                 # make sure cmd is a string
 1774                 cmd = ''
 1775             
 1776             # History Handling
 1777             if self.isHistoryEnabled():
 1778                 if cmd != "" and (
 1779                         len(self.__history) == 0 or self.__history[-1] != cmd):
 1780                     if len(self.__history) == self.__maxHistoryEntries:
 1781                         del self.__history[0]
 1782                     self.__history.append(cmd)
 1783                 if self.__historyStyle == ShellHistoryStyle.LinuxStyle:
 1784                     self.__setHistoryIndex(index=-1)
 1785                 elif self.__historyStyle == ShellHistoryStyle.WindowsStyle:
 1786                     if historyIndex is None:
 1787                         if (
 1788                             self.__histidx - 1 > 0 and
 1789                             cmd != self.__history[self.__histidx - 1]
 1790                         ):
 1791                             self.__setHistoryIndex(index=-1)
 1792                     else:
 1793                         self.__setHistoryIndex(historyIndex)
 1794             
 1795             if cmd == 'start' or cmd.startswith('start '):
 1796                 if not self.passive:
 1797                     cmdList = cmd.split(None, 1)
 1798                     if len(cmdList) < 2:
 1799                         self.dbs.startClient(False)  # start default backend
 1800                     else:
 1801                         venvName = cmdList[1]
 1802                         if venvName == self.tr("Project"):
 1803                             if self.__project.isOpen():
 1804                                 self.dbs.startClient(
 1805                                     False, forProject=True,
 1806                                     workingDir=self.__project.getProjectPath())
 1807                                 self.__currentWorkingDirectory = (
 1808                                     self.__project.getProjectPath()
 1809                                 )
 1810                             else:
 1811                                 self.dbs.startClient(
 1812                                     False, venvName=self.__currentVenv,
 1813                                     workingDir=self.__currentWorkingDirectory)
 1814                                 # same as reset
 1815                         else:
 1816                             self.dbs.startClient(False, venvName=venvName)
 1817                             self.__currentWorkingDirectory = ""
 1818                     self.__getBanner()
 1819                     return
 1820             elif cmd == 'clear':
 1821                 # Display the banner.
 1822                 self.__getBanner()
 1823                 if not self.passive:
 1824                     return
 1825                 else:
 1826                     cmd = ''
 1827             elif cmd in ['reset', 'restart']:
 1828                 self.dbs.startClient(False, venvName=self.__currentVenv,
 1829                                      workingDir=self.__currentWorkingDirectory)
 1830                 if self.passive:
 1831                     return
 1832                 else:
 1833                     cmd = ''
 1834             elif cmd in ['envs', 'environments']:
 1835                 venvs = (
 1836                     e5App().getObject("VirtualEnvManager")
 1837                     .getVirtualenvNames()
 1838                 )
 1839                 s = self.tr('Available Virtual Environments:\n{0}\n').format(
 1840                     '\n'.join("- {0}".format(venv) for venv in sorted(venvs))
 1841                 )
 1842                 self.__write(s)
 1843                 self.__clientStatement(False)
 1844                 return
 1845             elif cmd == 'which':
 1846                 s = self.tr("Current Virtual Environment: '{0}'\n").format(
 1847                     self.__currentVenv)
 1848                 self.__write(s)
 1849                 self.__clientStatement(False)
 1850                 return
 1851             elif (
 1852                 cmd in ["quit", "quit()", "exit", "exit()"] and
 1853                 self.__windowed
 1854             ):
 1855                 # call main window quit()
 1856                 self.vm.quit()
 1857                 return
 1858             
 1859             self.dbs.remoteStatement(cmd)
 1860             while self.inCommandExecution:
 1861                 try:
 1862                     QApplication.processEvents()
 1863                 except KeyboardInterrupt:
 1864                     pass
 1865         else:
 1866             if not self.echoInput:
 1867                 cmd = self.buff
 1868                 self.buff = ""
 1869             elif cmd:
 1870                 cmd = cmd[len(self.prompt):]
 1871             self.inRawMode = False
 1872             self.echoInput = True
 1873             
 1874             self.dbs.remoteRawInput(cmd)
 1875     
 1876     def __showVenvName(self):
 1877         """
 1878         Private method to show the name of the active virtual environment.
 1879         """
 1880         s = "\n" + self.tr("Current Virtual Environment: '{0}'\n").format(
 1881             self.__currentVenv)
 1882         self.__write(s)
 1883         self.__clientStatement(False)
 1884     
 1885     def __useHistory(self):
 1886         """
 1887         Private method to display a command from the history.
 1888         """
 1889         if self.__isHistoryIndexValid():
 1890             cmd = self.__history[self.__histidx]
 1891         else:
 1892             cmd = ""
 1893             self.__resetIncrementalHistorySearch()
 1894         
 1895         self.__insertHistory(cmd)
 1896 
 1897     def __insertHistory(self, cmd):
 1898         """
 1899         Private method to insert a command selected from the history.
 1900         
 1901         @param cmd history entry to be inserted (string)
 1902         """
 1903         self.setCursorPosition(self.prline, self.prcol)
 1904         self.setSelection(self.prline, self.prcol,
 1905                           self.prline, self.lineLength(self.prline))
 1906         self.removeSelectedText()
 1907         self.__insertText(cmd)
 1908     
 1909     def __resetIncrementalHistorySearch(self):
 1910         """
 1911         Private method to reset the incremental history search.
 1912         """
 1913         self.incrementalSearchString = ""
 1914         self.incrementalSearchActive = False
 1915     
 1916     def __searchHistory(self, txt, startIdx=-1):
 1917         """
 1918         Private method used to search the history.
 1919         
 1920         @param txt text to match at the beginning
 1921         @type str
 1922         @param startIdx index to start search from
 1923         @type int
 1924         @return tuple containing the index of found entry and a flag indicating
 1925             that something was found
 1926         @rtype tuple of (int, bool)
 1927         """
 1928         if startIdx == -1:
 1929             idx = 0
 1930         else:
 1931             idx = startIdx + 1
 1932         while (
 1933             idx < len(self.__history) and
 1934             not self.__history[idx].startswith(txt)
 1935         ):
 1936             idx += 1
 1937         found = (idx < len(self.__history) and
 1938                  self.__history[idx].startswith(txt))
 1939         return idx, found
 1940         
 1941     def __rsearchHistory(self, txt, startIdx=-1):
 1942         """
 1943         Private method used to reverse search the history.
 1944         
 1945         @param txt text to match at the beginning
 1946         @type str
 1947         @param startIdx index to start search from
 1948         @type int
 1949         @return tuple containing the index of found entry and a flag indicating
 1950             that something was found
 1951         @rtype tuple of (int, bool)
 1952         """
 1953         if startIdx == -1:
 1954             idx = len(self.__history) - 1
 1955         else:
 1956             idx = startIdx - 1
 1957         while (
 1958             idx >= 0 and
 1959             not self.__history[idx].startswith(txt)
 1960         ):
 1961             idx -= 1
 1962         found = idx >= 0 and self.__history[idx].startswith(txt)
 1963         return idx, found
 1964         
 1965     def focusNextPrevChild(self, nextChild):
 1966         """
 1967         Public method to stop Tab moving to the next window.
 1968         
 1969         While the user is entering a multi-line command, the movement to
 1970         the next window by the Tab key being pressed is suppressed.
 1971         
 1972         @param nextChild next window
 1973         @return flag indicating the movement
 1974         """
 1975         if nextChild and self.inContinue:
 1976             return False
 1977         
 1978         return QsciScintillaCompat.focusNextPrevChild(self, nextChild)
 1979         
 1980     def contextMenuEvent(self, ev):
 1981         """
 1982         Protected method to show our own context menu.
 1983         
 1984         @param ev context menu event (QContextMenuEvent)
 1985         """
 1986         if not self.__windowed:
 1987             self.menu.popup(ev.globalPos())
 1988             ev.accept()
 1989         
 1990     def clear(self):
 1991         """
 1992         Public slot to clear the display.
 1993         """
 1994         # Display the banner.
 1995         self.__getBanner()
 1996         
 1997     def doClearRestart(self):
 1998         """
 1999         Public slot to handle the 'restart and clear' context menu entry.
 2000         """
 2001         self.doRestart()
 2002         self.clear()
 2003         
 2004     def doRestart(self):
 2005         """
 2006         Public slot to handle the 'restart' context menu entry.
 2007         """
 2008         self.dbs.startClient(False, venvName=self.__currentVenv,
 2009                              workingDir=self.__currentWorkingDirectory)
 2010         
 2011     def __startDebugClient(self, action):
 2012         """
 2013         Private slot to start a debug client according to the action
 2014         triggered.
 2015         
 2016         @param action context menu action that was triggered (QAction)
 2017         """
 2018         venvName = action.text()
 2019         if venvName == self.tr("Project"):
 2020             if self.__project.isOpen():
 2021                 self.__currentWorkingDirectory = (
 2022                     self.__project.getProjectPath()
 2023                 )
 2024             self.dbs.startClient(False, forProject=True,
 2025                                  workingDir=self.__currentWorkingDirectory)
 2026         else:
 2027             self.dbs.startClient(False, venvName=venvName)
 2028         self.__getBanner()
 2029         
 2030     def handlePreferencesChanged(self):
 2031         """
 2032         Public slot to handle the preferencesChanged signal.
 2033         """
 2034         # rebind the lexer
 2035         self.__bindLexer(self.language)
 2036         self.recolor()
 2037         
 2038         # set margin 0 configuration
 2039         self.__setTextDisplay()
 2040         self.__setMargin0()
 2041         
 2042         # set the autocompletion and calltips function
 2043         self.__setAutoCompletion()
 2044         self.__setCallTips()
 2045         
 2046         # do the history related stuff
 2047         self.__maxHistoryEntries = Preferences.getShell("MaxHistoryEntries")
 2048         for key in list(self.__historyLists.keys()):
 2049             self.__historyLists[key] = (
 2050                 self.__historyLists[key][-self.__maxHistoryEntries:]
 2051             )
 2052         self.__historyStyle = Preferences.getShell("HistoryStyle")
 2053         self.__historyWrap = Preferences.getShell("HistoryWrap")
 2054         self.__setHistoryIndex()
 2055         if not self.__windowed:
 2056             self.hmenu.menuAction().setEnabled(self.isHistoryEnabled())
 2057         self.__historyNavigateByCursor = Preferences.getShell(
 2058             "HistoryNavigateByCursor")
 2059         self.historyStyleChanged.emit(self.__historyStyle)
 2060         
 2061         # do stdout /stderr stuff
 2062         showStdOutErr = Preferences.getShell("ShowStdOutErr")
 2063         if self.__showStdOutErr != showStdOutErr:
 2064             if showStdOutErr:
 2065                 self.dbs.clientProcessStdout.connect(self.__writeStdOut)
 2066                 self.dbs.clientProcessStderr.connect(self.__writeStdErr)
 2067             else:
 2068                 self.dbs.clientProcessStdout.disconnect(self.__writeStdOut)
 2069                 self.dbs.clientProcessStderr.disconnect(self.__writeStdErr)
 2070             self.__showStdOutErr = showStdOutErr
 2071         
 2072     def __showCompletions(self, completions, text):
 2073         """
 2074         Private method to display the possible completions.
 2075         
 2076         @param completions list of possible completions (list of strings)
 2077         @param text text that is about to be completed (string)
 2078         """
 2079         if len(completions) == 0:
 2080             return
 2081         
 2082         if len(completions) > 1:
 2083             completions.sort()
 2084             self.showUserList(1, completions)
 2085             self.completionText = text
 2086         else:
 2087             txt = completions[0]
 2088             if text != "":
 2089                 txt = txt.replace(text, "")
 2090             self.__insertText(txt)
 2091             self.completionText = ""
 2092         
 2093     def __completionListSelected(self, listId, txt):
 2094         """
 2095         Private slot to handle the selection from the completion list.
 2096         
 2097         @param listId the ID of the user list (should be 1) (integer)
 2098         @param txt the selected text (string)
 2099         """
 2100         if listId == 1:
 2101             if self.completionText != "":
 2102                 txt = txt.replace(self.completionText, "")
 2103             self.__insertText(txt)
 2104             self.completionText = ""
 2105     
 2106     #################################################################
 2107     ## Drag and Drop Support
 2108     #################################################################
 2109     
 2110     def dragEnterEvent(self, event):
 2111         """
 2112         Protected method to handle the drag enter event.
 2113         
 2114         @param event the drag enter event (QDragEnterEvent)
 2115         """
 2116         self.inDragDrop = (
 2117             event.mimeData().hasUrls() or
 2118             event.mimeData().hasText()
 2119         )
 2120         if self.inDragDrop:
 2121             event.acceptProposedAction()
 2122         else:
 2123             super(Shell, self).dragEnterEvent(event)
 2124         
 2125     def dragMoveEvent(self, event):
 2126         """
 2127         Protected method to handle the drag move event.
 2128         
 2129         @param event the drag move event (QDragMoveEvent)
 2130         """
 2131         if self.inDragDrop:
 2132             event.accept()
 2133         else:
 2134             super(Shell, self).dragMoveEvent(event)
 2135         
 2136     def dragLeaveEvent(self, event):
 2137         """
 2138         Protected method to handle the drag leave event.
 2139         
 2140         @param event the drag leave event (QDragLeaveEvent)
 2141         """
 2142         if self.inDragDrop:
 2143             self.inDragDrop = False
 2144             event.accept()
 2145         else:
 2146             super(Shell, self).dragLeaveEvent(event)
 2147         
 2148     def dropEvent(self, event):
 2149         """
 2150         Protected method to handle the drop event.
 2151         
 2152         @param event the drop event (QDropEvent)
 2153         """
 2154         if event.mimeData().hasUrls() and not self.__windowed:
 2155             for url in event.mimeData().urls():
 2156                 fname = url.toLocalFile()
 2157                 if fname:
 2158                     if not QFileInfo(fname).isDir():
 2159                         self.vm.openSourceFile(fname)
 2160                     else:
 2161                         E5MessageBox.information(
 2162                             self,
 2163                             self.tr("Drop Error"),
 2164                             self.tr("""<p><b>{0}</b> is not a file.</p>""")
 2165                             .format(fname))
 2166             event.acceptProposedAction()
 2167         elif event.mimeData().hasText():
 2168             s = event.mimeData().text()
 2169             if s:
 2170                 event.acceptProposedAction()
 2171                 self.executeLines(s)
 2172             del s
 2173         else:
 2174             super(Shell, self).dropEvent(event)
 2175         
 2176         self.inDragDrop = False
 2177         
 2178     def focusInEvent(self, event):
 2179         """
 2180         Protected method called when the shell receives focus.
 2181         
 2182         @param event the event object (QFocusEvent)
 2183         """
 2184         if not self.__actionsAdded:
 2185             self.addActions(self.vm.editorActGrp.actions())
 2186             self.addActions(self.vm.copyActGrp.actions())
 2187             self.addActions(self.vm.viewActGrp.actions())
 2188             if not self.__windowed:
 2189                 self.__searchShortcut = QShortcut(
 2190                     self.vm.searchAct.shortcut(), self,
 2191                     self.__find, self.__find)
 2192                 self.__searchNextShortcut = QShortcut(
 2193                     self.vm.searchNextAct.shortcut(), self,
 2194                     self.__searchNext, self.__searchNext)
 2195                 self.__searchPrevShortcut = QShortcut(
 2196                     self.vm.searchPrevAct.shortcut(), self,
 2197                     self.__searchPrev, self.__searchPrev)
 2198         
 2199         try:
 2200             self.vm.editActGrp.setEnabled(False)
 2201             self.vm.editorActGrp.setEnabled(True)
 2202             self.vm.copyActGrp.setEnabled(True)
 2203             self.vm.viewActGrp.setEnabled(True)
 2204             self.vm.searchActGrp.setEnabled(False)
 2205         except AttributeError:
 2206             pass
 2207         if not self.__windowed:
 2208             self.__searchShortcut.setEnabled(True)
 2209             self.__searchNextShortcut.setEnabled(True)
 2210             self.__searchPrevShortcut.setEnabled(True)
 2211         self.setCaretWidth(self.caretWidth)
 2212         self.setCursorFlashTime(QApplication.cursorFlashTime())
 2213         
 2214         super(Shell, self).focusInEvent(event)
 2215         
 2216     def focusOutEvent(self, event):
 2217         """
 2218         Protected method called when the shell loses focus.
 2219         
 2220         @param event the event object (QFocusEvent)
 2221         """
 2222         try:
 2223             self.vm.editorActGrp.setEnabled(False)
 2224         except AttributeError:
 2225             pass
 2226         if not self.__windowed:
 2227             self.__searchShortcut.setEnabled(False)
 2228             self.__searchNextShortcut.setEnabled(False)
 2229             self.__searchPrevShortcut.setEnabled(False)
 2230         self.setCaretWidth(0)
 2231         super(Shell, self).focusOutEvent(event)
 2232         
 2233     def insert(self, txt):
 2234         """
 2235         Public slot to insert text at the current cursor position.
 2236         
 2237         The cursor is advanced to the end of the inserted text.
 2238         
 2239         @param txt text to be inserted (string)
 2240         """
 2241         txt = Utilities.filterAnsiSequences(txt)
 2242         length = len(txt)
 2243         line, col = self.getCursorPosition()
 2244         self.insertAt(txt, line, col)
 2245         if re.search(self.linesepRegExp, txt) is not None:
 2246             line += 1
 2247         self.setCursorPosition(line, col + length)
 2248         
 2249     def __configure(self):
 2250         """
 2251         Private method to open the configuration dialog.
 2252         """
 2253         e5App().getObject("UserInterface").showPreferences("shellPage")
 2254     
 2255     def __find(self):
 2256         """
 2257         Private slot to show the find widget.
 2258         """
 2259         txt = self.selectedText()
 2260         self.__mainWindow.showFind(txt)
 2261     
 2262     def __searchNext(self):
 2263         """
 2264         Private method to search for the next occurrence.
 2265         """
 2266         if self.__lastSearch:
 2267             self.searchNext(*self.__lastSearch)
 2268     
 2269     def searchNext(self, txt, caseSensitive, wholeWord, regexp):
 2270         """
 2271         Public method to search the next occurrence of the given text.
 2272         
 2273         @param txt text to search for
 2274         @type str
 2275         @param caseSensitive flag indicating to perform a case sensitive
 2276             search
 2277         @type bool
 2278         @param wholeWord flag indicating to search for whole words
 2279             only
 2280         @type bool
 2281         @param regexp flag indicating a regular expression search
 2282         @type bool
 2283         """
 2284         self.__lastSearch = (txt, caseSensitive, wholeWord, regexp)
 2285         posixMode = Preferences.getEditor("SearchRegexpMode") == 0 and regexp
 2286         cxx11Mode = Preferences.getEditor("SearchRegexpMode") == 1 and regexp
 2287         ok = self.findFirst(
 2288             txt, regexp, caseSensitive, wholeWord, True, forward=True,
 2289             posix=posixMode, cxx11=cxx11Mode)
 2290         self.searchStringFound.emit(ok)
 2291     
 2292     def __searchPrev(self):
 2293         """
 2294         Private method to search for the next occurrence.
 2295         """
 2296         if self.__lastSearch:
 2297             self.searchPrev(*self.__lastSearch)
 2298     
 2299     def searchPrev(self, txt, caseSensitive, wholeWord, regexp):
 2300         """
 2301         Public method to search the previous occurrence of the given text.
 2302         
 2303         @param txt text to search for
 2304         @type str
 2305         @param caseSensitive flag indicating to perform a case sensitive
 2306             search
 2307         @type bool
 2308         @param wholeWord flag indicating to search for whole words
 2309             only
 2310         @type bool
 2311         @param regexp flag indicating a regular expression search
 2312         @type bool
 2313         """
 2314         self.__lastSearch = (txt, caseSensitive, wholeWord, regexp)
 2315         if self.hasSelectedText():
 2316             line, index = self.getSelection()[:2]
 2317         else:
 2318             line, index = -1, -1
 2319         posixMode = Preferences.getEditor("SearchRegexpMode") == 0 and regexp
 2320         cxx11Mode = Preferences.getEditor("SearchRegexpMode") == 1 and regexp
 2321         ok = self.findFirst(
 2322             txt, regexp, caseSensitive, wholeWord, True,
 2323             forward=False, line=line, index=index, posix=posixMode,
 2324             cxx11=cxx11Mode)
 2325         self.searchStringFound.emit(ok)
 2326     
 2327     def historyStyle(self):
 2328         """
 2329         Public method to get the shell history style.
 2330         
 2331         @return shell history style
 2332         @rtype ShellHistoryStyle
 2333         """
 2334         return self.__historyStyle
 2335     
 2336     def isHistoryEnabled(self):
 2337         """
 2338         Public method to check, if the history is enabled.
 2339         
 2340         @return flag indicating if history is enabled
 2341         @rtype bool
 2342         """
 2343         return self.__historyStyle != ShellHistoryStyle.Disabled
 2344     
 2345     #################################################################
 2346     ## Project Support
 2347     #################################################################
 2348     
 2349     def __projectOpened(self):
 2350         """
 2351         Private slot to start the shell for the opened project.
 2352         """
 2353         if Preferences.getProject("RestartShellForProject"):
 2354             self.dbs.startClient(False, forProject=True,
 2355                                  workingDir=self.__project.getProjectPath())
 2356             self.__currentWorkingDirectory = self.__project.getProjectPath()
 2357             self.__getBanner()
 2358     
 2359     def __projectClosed(self):
 2360         """
 2361         Private slot to restart the default shell when the project is closed.
 2362         """
 2363         if Preferences.getProject("RestartShellForProject"):
 2364             self.dbs.startClient(False)
 2365             self.__getBanner()