eric6/QScintilla/Shell.py

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

eric ide

mercurial