eric6/Debugger/DebugUI.py

changeset 6942
2602857055c5
parent 6904
3f35037a08d4
child 6984
e6a4784cab5e
child 6995
ee314cf3b1c9
equal deleted inserted replaced
6941:f99d60d6b59b 6942:2602857055c5
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2002 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the debugger UI.
8 """
9
10 from __future__ import unicode_literals
11
12 import os
13
14 from PyQt5.QtCore import pyqtSignal, QObject, Qt
15 from PyQt5.QtGui import QKeySequence
16 from PyQt5.QtWidgets import QMenu, QToolBar, QApplication, QDialog
17
18 from UI.Info import Program
19
20 from .DebugClientCapabilities import HasDebugger, HasInterpreter, \
21 HasProfiler, HasCoverage
22 import Preferences
23 import Utilities
24 import UI.PixmapCache
25 import UI.Config
26
27 from E5Gui.E5Action import E5Action, createActionGroup
28 from E5Gui import E5MessageBox
29
30 from eric6config import getConfig
31
32
33 class DebugUI(QObject):
34 """
35 Class implementing the debugger part of the UI.
36
37 @signal clientStack(stack) emitted at breaking after a reported exception
38 @signal compileForms() emitted if changed project forms should be compiled
39 @signal compileResources() emitted if changed project resources should be
40 compiled
41 @signal executeMake() emitted if a project specific make run should be
42 performed
43 @signal debuggingStarted(filename) emitted when a debugging session was
44 started
45 @signal resetUI() emitted to reset the UI
46 @signal exceptionInterrupt() emitted after the execution was interrupted
47 by an exception and acknowledged by the user
48 @signal appendStdout(msg) emitted when the client program has terminated
49 and the display of the termination dialog is suppressed
50 """
51 clientStack = pyqtSignal(list)
52 resetUI = pyqtSignal()
53 exceptionInterrupt = pyqtSignal()
54 compileForms = pyqtSignal()
55 compileResources = pyqtSignal()
56 executeMake = pyqtSignal()
57 debuggingStarted = pyqtSignal(str)
58 appendStdout = pyqtSignal(str)
59
60 def __init__(self, ui, vm, debugServer, debugViewer, project):
61 """
62 Constructor
63
64 @param ui reference to the main UI
65 @param vm reference to the viewmanager
66 @param debugServer reference to the debug server
67 @param debugViewer reference to the debug viewer widget
68 @param project reference to the project object
69 """
70 super(DebugUI, self).__init__(ui)
71
72 self.ui = ui
73 self.viewmanager = vm
74 self.debugServer = debugServer
75 self.debugViewer = debugViewer
76 self.project = project
77
78 # Clear some variables
79 self.projectOpen = False
80 self.editorOpen = False
81
82 # read the saved debug info values
83 self.lastUsedVenvName = Preferences.Prefs.settings.value(
84 'DebugInfo/VirtualEnvironment', '')
85 self.argvHistory = Preferences.toList(
86 Preferences.Prefs.settings.value('DebugInfo/ArgumentsHistory'))
87 self.wdHistory = Preferences.toList(
88 Preferences.Prefs.settings.value(
89 'DebugInfo/WorkingDirectoryHistory'))
90 self.envHistory = Preferences.toList(
91 Preferences.Prefs.settings.value('DebugInfo/EnvironmentHistory'))
92 self.excList = Preferences.toList(
93 Preferences.Prefs.settings.value('DebugInfo/Exceptions'))
94 self.excIgnoreList = Preferences.toList(
95 Preferences.Prefs.settings.value('DebugInfo/IgnoredExceptions'))
96 self.exceptions = Preferences.toBool(
97 Preferences.Prefs.settings.value(
98 'DebugInfo/ReportExceptions', True))
99 self.autoClearShell = Preferences.toBool(
100 Preferences.Prefs.settings.value('DebugInfo/AutoClearShell', True))
101 self.tracePython = Preferences.toBool(
102 Preferences.Prefs.settings.value('DebugInfo/TracePython', False))
103 self.autoContinue = Preferences.toBool(
104 Preferences.Prefs.settings.value('DebugInfo/AutoContinue', True))
105 self.forkAutomatically = Preferences.toBool(
106 Preferences.Prefs.settings.value(
107 'DebugInfo/ForkAutomatically', False))
108 self.forkIntoChild = Preferences.toBool(
109 Preferences.Prefs.settings.value('DebugInfo/ForkIntoChild', False))
110
111 self.lastDebuggedFile = None
112 self.lastStartAction = 0 # 0=None, 1=Script, 2=Project
113 self.clientType = ""
114 self.lastAction = -1
115 self.debugActions = [
116 self.__continue, self.__step, self.__stepOver, self.__stepOut,
117 self.__stepQuit, self.__runToCursor, self.__moveInstructionPointer
118 ]
119 self.localsVarFilter, self.globalsVarFilter = \
120 Preferences.getVarFilters()
121 self.debugViewer.setVariablesFilter(
122 self.globalsVarFilter, self.localsVarFilter)
123
124 # Connect the signals emitted by the debug-server
125 debugServer.clientGone.connect(self.__clientGone)
126 debugServer.clientLine.connect(self.__clientLine)
127 debugServer.clientExit.connect(self.__clientExit)
128 debugServer.clientSyntaxError.connect(self.__clientSyntaxError)
129 debugServer.clientException.connect(self.__clientException)
130 debugServer.clientSignal.connect(self.__clientSignal)
131 debugServer.clientVariables.connect(self.__clientVariables)
132 debugServer.clientVariable.connect(self.__clientVariable)
133 debugServer.clientBreakConditionError.connect(
134 self.__clientBreakConditionError)
135 debugServer.clientWatchConditionError.connect(
136 self.__clientWatchConditionError)
137 debugServer.passiveDebugStarted.connect(self.__passiveDebugStarted)
138 debugServer.clientThreadSet.connect(self.__clientThreadSet)
139
140 debugServer.clientThreadList.connect(debugViewer.showThreadList)
141
142 # Connect the signals emitted by the viewmanager
143 vm.editorOpened.connect(self.__editorOpened)
144 vm.lastEditorClosed.connect(self.__lastEditorClosed)
145 vm.checkActions.connect(self.__checkActions)
146 vm.cursorChanged.connect(self.__cursorChanged)
147 vm.breakpointToggled.connect(self.__cursorChanged)
148
149 # Connect the signals emitted by the project
150 project.projectOpened.connect(self.__projectOpened)
151 project.newProject.connect(self.__projectOpened)
152 project.projectClosed.connect(self.__projectClosed)
153
154 # Set a flag for the passive debug mode
155 self.passive = Preferences.getDebugger("PassiveDbgEnabled")
156
157 def variablesFilter(self, scope):
158 """
159 Public method to get the variables filter for a scope.
160
161 @param scope flag indicating global (True) or local (False) scope
162 @return filters list (list of integers)
163 """
164 if scope:
165 return self.globalsVarFilter[:]
166 else:
167 return self.localsVarFilter[:]
168
169 def initActions(self):
170 """
171 Public method defining the user interface actions.
172 """
173 self.actions = []
174
175 self.runAct = E5Action(
176 self.tr('Run Script'),
177 UI.PixmapCache.getIcon("runScript.png"),
178 self.tr('&Run Script...'),
179 Qt.Key_F2, 0, self, 'dbg_run_script')
180 self.runAct.setStatusTip(self.tr('Run the current Script'))
181 self.runAct.setWhatsThis(self.tr(
182 """<b>Run Script</b>"""
183 """<p>Set the command line arguments and run the script outside"""
184 """ the debugger. If the file has unsaved changes it may be"""
185 """ saved first.</p>"""
186 ))
187 self.runAct.triggered.connect(self.__runScript)
188 self.actions.append(self.runAct)
189
190 self.runProjectAct = E5Action(
191 self.tr('Run Project'),
192 UI.PixmapCache.getIcon("runProject.png"),
193 self.tr('Run &Project...'), Qt.SHIFT + Qt.Key_F2, 0, self,
194 'dbg_run_project')
195 self.runProjectAct.setStatusTip(self.tr('Run the current Project'))
196 self.runProjectAct.setWhatsThis(self.tr(
197 """<b>Run Project</b>"""
198 """<p>Set the command line arguments and run the current project"""
199 """ outside the debugger."""
200 """ If files of the current project have unsaved changes they"""
201 """ may be saved first.</p>"""
202 ))
203 self.runProjectAct.triggered.connect(self.__runProject)
204 self.actions.append(self.runProjectAct)
205
206 self.coverageAct = E5Action(
207 self.tr('Coverage run of Script'),
208 UI.PixmapCache.getIcon("coverageScript.png"),
209 self.tr('Coverage run of Script...'), 0, 0, self,
210 'dbg_coverage_script')
211 self.coverageAct.setStatusTip(
212 self.tr('Perform a coverage run of the current Script'))
213 self.coverageAct.setWhatsThis(self.tr(
214 """<b>Coverage run of Script</b>"""
215 """<p>Set the command line arguments and run the script under"""
216 """ the control of a coverage analysis tool. If the file has"""
217 """ unsaved changes it may be saved first.</p>"""
218 ))
219 self.coverageAct.triggered.connect(self.__coverageScript)
220 self.actions.append(self.coverageAct)
221
222 self.coverageProjectAct = E5Action(
223 self.tr('Coverage run of Project'),
224 UI.PixmapCache.getIcon("coverageProject.png"),
225 self.tr('Coverage run of Project...'), 0, 0, self,
226 'dbg_coverage_project')
227 self.coverageProjectAct.setStatusTip(
228 self.tr('Perform a coverage run of the current Project'))
229 self.coverageProjectAct.setWhatsThis(self.tr(
230 """<b>Coverage run of Project</b>"""
231 """<p>Set the command line arguments and run the current project"""
232 """ under the control of a coverage analysis tool."""
233 """ If files of the current project have unsaved changes"""
234 """ they may be saved first.</p>"""
235 ))
236 self.coverageProjectAct.triggered.connect(self.__coverageProject)
237 self.actions.append(self.coverageProjectAct)
238
239 self.profileAct = E5Action(
240 self.tr('Profile Script'),
241 UI.PixmapCache.getIcon("profileScript.png"),
242 self.tr('Profile Script...'), 0, 0, self, 'dbg_profile_script')
243 self.profileAct.setStatusTip(self.tr('Profile the current Script'))
244 self.profileAct.setWhatsThis(self.tr(
245 """<b>Profile Script</b>"""
246 """<p>Set the command line arguments and profile the script."""
247 """ If the file has unsaved changes it may be saved first.</p>"""
248 ))
249 self.profileAct.triggered.connect(self.__profileScript)
250 self.actions.append(self.profileAct)
251
252 self.profileProjectAct = E5Action(
253 self.tr('Profile Project'),
254 UI.PixmapCache.getIcon("profileProject.png"),
255 self.tr('Profile Project...'), 0, 0, self,
256 'dbg_profile_project')
257 self.profileProjectAct.setStatusTip(
258 self.tr('Profile the current Project'))
259 self.profileProjectAct.setWhatsThis(self.tr(
260 """<b>Profile Project</b>"""
261 """<p>Set the command line arguments and profile the current"""
262 """ project. If files of the current project have unsaved"""
263 """ changes they may be saved first.</p>"""
264 ))
265 self.profileProjectAct.triggered.connect(self.__profileProject)
266 self.actions.append(self.profileProjectAct)
267
268 self.debugAct = E5Action(
269 self.tr('Debug Script'),
270 UI.PixmapCache.getIcon("debugScript.png"),
271 self.tr('&Debug Script...'), Qt.Key_F5, 0, self,
272 'dbg_debug_script')
273 self.debugAct.setStatusTip(self.tr('Debug the current Script'))
274 self.debugAct.setWhatsThis(self.tr(
275 """<b>Debug Script</b>"""
276 """<p>Set the command line arguments and set the current line"""
277 """ to be the first executable Python statement of the current"""
278 """ editor window. If the file has unsaved changes it may be"""
279 """ saved first.</p>"""
280 ))
281 self.debugAct.triggered.connect(self.__debugScript)
282 self.actions.append(self.debugAct)
283
284 self.debugProjectAct = E5Action(
285 self.tr('Debug Project'),
286 UI.PixmapCache.getIcon("debugProject.png"),
287 self.tr('Debug &Project...'), Qt.SHIFT + Qt.Key_F5, 0, self,
288 'dbg_debug_project')
289 self.debugProjectAct.setStatusTip(self.tr(
290 'Debug the current Project'))
291 self.debugProjectAct.setWhatsThis(self.tr(
292 """<b>Debug Project</b>"""
293 """<p>Set the command line arguments and set the current line"""
294 """ to be the first executable Python statement of the main"""
295 """ script of the current project. If files of the current"""
296 """ project have unsaved changes they may be saved first.</p>"""
297 ))
298 self.debugProjectAct.triggered.connect(self.__debugProject)
299 self.actions.append(self.debugProjectAct)
300
301 self.restartAct = E5Action(
302 self.tr('Restart'),
303 UI.PixmapCache.getIcon("restart.png"),
304 self.tr('Restart'), Qt.Key_F4, 0, self, 'dbg_restart_script')
305 self.restartAct.setStatusTip(self.tr(
306 'Restart the last debugged script'))
307 self.restartAct.setWhatsThis(self.tr(
308 """<b>Restart</b>"""
309 """<p>Set the command line arguments and set the current line"""
310 """ to be the first executable Python statement of the script"""
311 """ that was debugged last. If there are unsaved changes, they"""
312 """ may be saved first.</p>"""
313 ))
314 self.restartAct.triggered.connect(self.__doRestart)
315 self.actions.append(self.restartAct)
316
317 self.stopAct = E5Action(
318 self.tr('Stop'),
319 UI.PixmapCache.getIcon("stopScript.png"),
320 self.tr('Stop'), Qt.SHIFT + Qt.Key_F10, 0,
321 self, 'dbg_stop_script')
322 self.stopAct.setStatusTip(self.tr("""Stop the running script."""))
323 self.stopAct.setWhatsThis(self.tr(
324 """<b>Stop</b>"""
325 """<p>This stops the script running in the debugger backend.</p>"""
326 ))
327 self.stopAct.triggered.connect(self.__stopScript)
328 self.actions.append(self.stopAct)
329
330 self.debugActGrp = createActionGroup(self)
331
332 act = E5Action(
333 self.tr('Continue'),
334 UI.PixmapCache.getIcon("continue.png"),
335 self.tr('&Continue'), Qt.Key_F6, 0,
336 self.debugActGrp, 'dbg_continue')
337 act.setStatusTip(
338 self.tr('Continue running the program from the current line'))
339 act.setWhatsThis(self.tr(
340 """<b>Continue</b>"""
341 """<p>Continue running the program from the current line. The"""
342 """ program will stop when it terminates or when a breakpoint"""
343 """ is reached.</p>"""
344 ))
345 act.triggered.connect(self.__continue)
346 self.actions.append(act)
347
348 act = E5Action(
349 self.tr('Continue to Cursor'),
350 UI.PixmapCache.getIcon("continueToCursor.png"),
351 self.tr('Continue &To Cursor'), Qt.SHIFT + Qt.Key_F6, 0,
352 self.debugActGrp, 'dbg_continue_to_cursor')
353 act.setStatusTip(self.tr(
354 """Continue running the program from the"""
355 """ current line to the current cursor position"""))
356 act.setWhatsThis(self.tr(
357 """<b>Continue To Cursor</b>"""
358 """<p>Continue running the program from the current line to the"""
359 """ current cursor position.</p>"""
360 ))
361 act.triggered.connect(self.__runToCursor)
362 self.actions.append(act)
363
364 act = E5Action(
365 self.tr('Move Instruction Pointer to Cursor'),
366 UI.PixmapCache.getIcon("moveInstructionPointer.png"),
367 self.tr('&Jump To Cursor'), Qt.Key_F12, 0,
368 self.debugActGrp, 'dbg_jump_to_cursor')
369 act.setStatusTip(self.tr(
370 """Skip the code from the"""
371 """ current line to the current cursor position"""))
372 act.setWhatsThis(self.tr(
373 """<b>Move Instruction Pointer to Cursor</b>"""
374 """<p>Move the Python internal instruction pointer to the"""
375 """ current cursor position without executing the code in"""
376 """ between.</p>"""
377 """<p>It's not possible to jump out of a function or jump"""
378 """ in a code block, e.g. a loop. In these cases, a error"""
379 """ message is printed to the log window.</p>"""
380 ))
381 act.triggered.connect(self.__moveInstructionPointer)
382 self.actions.append(act)
383
384 act = E5Action(
385 self.tr('Single Step'),
386 UI.PixmapCache.getIcon("step.png"),
387 self.tr('Sin&gle Step'), Qt.Key_F7, 0,
388 self.debugActGrp, 'dbg_single_step')
389 act.setStatusTip(self.tr('Execute a single Python statement'))
390 act.setWhatsThis(self.tr(
391 """<b>Single Step</b>"""
392 """<p>Execute a single Python statement. If the statement"""
393 """ is an <tt>import</tt> statement, a class constructor, or a"""
394 """ method or function call then control is returned to the"""
395 """ debugger at the next statement.</p>"""
396 ))
397 act.triggered.connect(self.__step)
398 self.actions.append(act)
399
400 act = E5Action(
401 self.tr('Step Over'),
402 UI.PixmapCache.getIcon("stepOver.png"),
403 self.tr('Step &Over'), Qt.Key_F8, 0,
404 self.debugActGrp, 'dbg_step_over')
405 act.setStatusTip(self.tr(
406 """Execute a single Python statement staying"""
407 """ in the current frame"""))
408 act.setWhatsThis(self.tr(
409 """<b>Step Over</b>"""
410 """<p>Execute a single Python statement staying in the same"""
411 """ frame. If the statement is an <tt>import</tt> statement,"""
412 """ a class constructor, or a method or function call then"""
413 """ control is returned to the debugger after the statement"""
414 """ has completed.</p>"""
415 ))
416 act.triggered.connect(self.__stepOver)
417 self.actions.append(act)
418
419 act = E5Action(
420 self.tr('Step Out'),
421 UI.PixmapCache.getIcon("stepOut.png"),
422 self.tr('Step Ou&t'), Qt.Key_F9, 0,
423 self.debugActGrp, 'dbg_step_out')
424 act.setStatusTip(self.tr(
425 """Execute Python statements until leaving"""
426 """ the current frame"""))
427 act.setWhatsThis(self.tr(
428 """<b>Step Out</b>"""
429 """<p>Execute Python statements until leaving the current"""
430 """ frame. If the statements are inside an <tt>import</tt>"""
431 """ statement, a class constructor, or a method or function"""
432 """ call then control is returned to the debugger after the"""
433 """ current frame has been left.</p>"""
434 ))
435 act.triggered.connect(self.__stepOut)
436 self.actions.append(act)
437
438 act = E5Action(
439 self.tr('Stop'),
440 UI.PixmapCache.getIcon("stepQuit.png"),
441 self.tr('&Stop'), Qt.Key_F10, 0,
442 self.debugActGrp, 'dbg_stop')
443 act.setStatusTip(self.tr('Stop debugging'))
444 act.setWhatsThis(self.tr(
445 """<b>Stop</b>"""
446 """<p>Stop the running debugging session.</p>"""
447 ))
448 act.triggered.connect(self.__stepQuit)
449 self.actions.append(act)
450
451 self.dbgFilterAct = E5Action(
452 self.tr('Variables Type Filter'),
453 self.tr('Varia&bles Type Filter...'), 0, 0, self,
454 'dbg_variables_filter')
455 self.dbgFilterAct.setStatusTip(self.tr(
456 'Configure variables type filter'))
457 self.dbgFilterAct.setWhatsThis(self.tr(
458 """<b>Variables Type Filter</b>"""
459 """<p>Configure the variables type filter. Only variable types"""
460 """ that are not selected are displayed in the global or local"""
461 """ variables window during a debugging session.</p>"""
462 ))
463 self.dbgFilterAct.triggered.connect(
464 self.__configureVariablesFilters)
465 self.actions.append(self.dbgFilterAct)
466
467 self.excFilterAct = E5Action(
468 self.tr('Exceptions Filter'),
469 self.tr('&Exceptions Filter...'), 0, 0, self,
470 'dbg_exceptions_filter')
471 self.excFilterAct.setStatusTip(self.tr(
472 'Configure exceptions filter'))
473 self.excFilterAct.setWhatsThis(self.tr(
474 """<b>Exceptions Filter</b>"""
475 """<p>Configure the exceptions filter. Only exception types"""
476 """ that are listed are highlighted during a debugging"""
477 """ session.</p><p>Please note, that all unhandled exceptions"""
478 """ are highlighted indepent from the filter list.</p>"""
479 ))
480 self.excFilterAct.triggered.connect(
481 self.__configureExceptionsFilter)
482 self.actions.append(self.excFilterAct)
483
484 self.excIgnoreFilterAct = E5Action(
485 self.tr('Ignored Exceptions'),
486 self.tr('&Ignored Exceptions...'), 0, 0,
487 self, 'dbg_ignored_exceptions')
488 self.excIgnoreFilterAct.setStatusTip(self.tr(
489 'Configure ignored exceptions'))
490 self.excIgnoreFilterAct.setWhatsThis(self.tr(
491 """<b>Ignored Exceptions</b>"""
492 """<p>Configure the ignored exceptions. Only exception types"""
493 """ that are not listed are highlighted during a debugging"""
494 """ session.</p><p>Please note, that unhandled exceptions"""
495 """ cannot be ignored.</p>"""
496 ))
497 self.excIgnoreFilterAct.triggered.connect(
498 self.__configureIgnoredExceptions)
499 self.actions.append(self.excIgnoreFilterAct)
500
501 self.dbgSetBpActGrp = createActionGroup(self)
502
503 self.dbgToggleBpAct = E5Action(
504 self.tr('Toggle Breakpoint'),
505 UI.PixmapCache.getIcon("breakpointToggle.png"),
506 self.tr('Toggle Breakpoint'),
507 QKeySequence(self.tr("Shift+F11", "Debug|Toggle Breakpoint")),
508 0, self.dbgSetBpActGrp, 'dbg_toggle_breakpoint')
509 self.dbgToggleBpAct.setStatusTip(self.tr('Toggle Breakpoint'))
510 self.dbgToggleBpAct.setWhatsThis(self.tr(
511 """<b>Toggle Breakpoint</b>"""
512 """<p>Toggles a breakpoint at the current line of the"""
513 """ current editor.</p>"""
514 ))
515 self.dbgToggleBpAct.triggered.connect(self.__toggleBreakpoint)
516 self.actions.append(self.dbgToggleBpAct)
517
518 self.dbgEditBpAct = E5Action(
519 self.tr('Edit Breakpoint'),
520 UI.PixmapCache.getIcon("cBreakpointToggle.png"),
521 self.tr('Edit Breakpoint...'),
522 QKeySequence(self.tr("Shift+F12", "Debug|Edit Breakpoint")), 0,
523 self.dbgSetBpActGrp, 'dbg_edit_breakpoint')
524 self.dbgEditBpAct.setStatusTip(self.tr('Edit Breakpoint'))
525 self.dbgEditBpAct.setWhatsThis(self.tr(
526 """<b>Edit Breakpoint</b>"""
527 """<p>Opens a dialog to edit the breakpoints properties."""
528 """ It works at the current line of the current editor.</p>"""
529 ))
530 self.dbgEditBpAct.triggered.connect(self.__editBreakpoint)
531 self.actions.append(self.dbgEditBpAct)
532
533 self.dbgNextBpAct = E5Action(
534 self.tr('Next Breakpoint'),
535 UI.PixmapCache.getIcon("breakpointNext.png"),
536 self.tr('Next Breakpoint'),
537 QKeySequence(
538 self.tr("Ctrl+Shift+PgDown", "Debug|Next Breakpoint")), 0,
539 self.dbgSetBpActGrp, 'dbg_next_breakpoint')
540 self.dbgNextBpAct.setStatusTip(self.tr('Next Breakpoint'))
541 self.dbgNextBpAct.setWhatsThis(self.tr(
542 """<b>Next Breakpoint</b>"""
543 """<p>Go to next breakpoint of the current editor.</p>"""
544 ))
545 self.dbgNextBpAct.triggered.connect(self.__nextBreakpoint)
546 self.actions.append(self.dbgNextBpAct)
547
548 self.dbgPrevBpAct = E5Action(
549 self.tr('Previous Breakpoint'),
550 UI.PixmapCache.getIcon("breakpointPrevious.png"),
551 self.tr('Previous Breakpoint'),
552 QKeySequence(
553 self.tr("Ctrl+Shift+PgUp", "Debug|Previous Breakpoint")),
554 0, self.dbgSetBpActGrp, 'dbg_previous_breakpoint')
555 self.dbgPrevBpAct.setStatusTip(self.tr('Previous Breakpoint'))
556 self.dbgPrevBpAct.setWhatsThis(self.tr(
557 """<b>Previous Breakpoint</b>"""
558 """<p>Go to previous breakpoint of the current editor.</p>"""
559 ))
560 self.dbgPrevBpAct.triggered.connect(self.__previousBreakpoint)
561 self.actions.append(self.dbgPrevBpAct)
562
563 act = E5Action(
564 self.tr('Clear Breakpoints'),
565 self.tr('Clear Breakpoints'),
566 QKeySequence(
567 self.tr("Ctrl+Shift+C", "Debug|Clear Breakpoints")), 0,
568 self.dbgSetBpActGrp, 'dbg_clear_breakpoint')
569 act.setStatusTip(self.tr('Clear Breakpoints'))
570 act.setWhatsThis(self.tr(
571 """<b>Clear Breakpoints</b>"""
572 """<p>Clear breakpoints of all editors.</p>"""
573 ))
574 act.triggered.connect(self.__clearBreakpoints)
575 self.actions.append(act)
576
577 self.debugActGrp.setEnabled(False)
578 self.dbgSetBpActGrp.setEnabled(False)
579 self.runAct.setEnabled(False)
580 self.runProjectAct.setEnabled(False)
581 self.profileAct.setEnabled(False)
582 self.profileProjectAct.setEnabled(False)
583 self.coverageAct.setEnabled(False)
584 self.coverageProjectAct.setEnabled(False)
585 self.debugAct.setEnabled(False)
586 self.debugProjectAct.setEnabled(False)
587 self.restartAct.setEnabled(False)
588 self.stopAct.setEnabled(False)
589
590 def initMenus(self):
591 """
592 Public slot to initialize the project menu.
593
594 @return the generated menu
595 """
596 dmenu = QMenu(self.tr('&Debug'), self.parent())
597 dmenu.setTearOffEnabled(True)
598 smenu = QMenu(self.tr('&Start'), self.parent())
599 smenu.setTearOffEnabled(True)
600 self.breakpointsMenu = QMenu(self.tr('&Breakpoints'), dmenu)
601
602 smenu.addAction(self.restartAct)
603 smenu.addAction(self.stopAct)
604 smenu.addSeparator()
605 smenu.addAction(self.runAct)
606 smenu.addAction(self.runProjectAct)
607 smenu.addSeparator()
608 smenu.addAction(self.debugAct)
609 smenu.addAction(self.debugProjectAct)
610 smenu.addSeparator()
611 smenu.addAction(self.profileAct)
612 smenu.addAction(self.profileProjectAct)
613 smenu.addSeparator()
614 smenu.addAction(self.coverageAct)
615 smenu.addAction(self.coverageProjectAct)
616
617 dmenu.addActions(self.debugActGrp.actions())
618 dmenu.addSeparator()
619 dmenu.addActions(self.dbgSetBpActGrp.actions())
620 self.menuBreakpointsAct = dmenu.addMenu(self.breakpointsMenu)
621 dmenu.addSeparator()
622 dmenu.addAction(self.dbgFilterAct)
623 dmenu.addAction(self.excFilterAct)
624 dmenu.addAction(self.excIgnoreFilterAct)
625
626 self.breakpointsMenu.aboutToShow.connect(self.__showBreakpointsMenu)
627 self.breakpointsMenu.triggered.connect(self.__breakpointSelected)
628 dmenu.aboutToShow.connect(self.__showDebugMenu)
629
630 return smenu, dmenu
631
632 def initToolbars(self, toolbarManager):
633 """
634 Public slot to initialize the debug toolbars.
635
636 @param toolbarManager reference to a toolbar manager object
637 (E5ToolBarManager)
638 @return the generated toolbars (list of QToolBar)
639 """
640 starttb = QToolBar(self.tr("Start"), self.ui)
641 starttb.setIconSize(UI.Config.ToolBarIconSize)
642 starttb.setObjectName("StartToolbar")
643 starttb.setToolTip(self.tr('Start'))
644
645 starttb.addAction(self.restartAct)
646 starttb.addAction(self.stopAct)
647 starttb.addSeparator()
648 starttb.addAction(self.runAct)
649 starttb.addAction(self.runProjectAct)
650 starttb.addSeparator()
651 starttb.addAction(self.debugAct)
652 starttb.addAction(self.debugProjectAct)
653
654 debugtb = QToolBar(self.tr("Debug"), self.ui)
655 debugtb.setIconSize(UI.Config.ToolBarIconSize)
656 debugtb.setObjectName("DebugToolbar")
657 debugtb.setToolTip(self.tr('Debug'))
658
659 debugtb.addActions(self.debugActGrp.actions())
660 debugtb.addSeparator()
661 debugtb.addAction(self.dbgToggleBpAct)
662 debugtb.addAction(self.dbgEditBpAct)
663 debugtb.addAction(self.dbgNextBpAct)
664 debugtb.addAction(self.dbgPrevBpAct)
665
666 toolbarManager.addToolBar(starttb, starttb.windowTitle())
667 toolbarManager.addToolBar(debugtb, debugtb.windowTitle())
668 toolbarManager.addAction(self.profileAct, starttb.windowTitle())
669 toolbarManager.addAction(self.profileProjectAct, starttb.windowTitle())
670 toolbarManager.addAction(self.coverageAct, starttb.windowTitle())
671 toolbarManager.addAction(self.coverageProjectAct,
672 starttb.windowTitle())
673
674 return [starttb, debugtb]
675
676 def setArgvHistory(self, argsStr, clearHistories=False, history=None):
677 """
678 Public slot to initialize the argv history.
679
680 @param argsStr the commandline arguments (string)
681 @param clearHistories flag indicating, that the list should
682 be cleared (boolean)
683 @param history list of history entries to be set (list of strings)
684 """
685 if clearHistories:
686 del self.argvHistory[1:]
687 elif history is not None:
688 self.argvHistory = history[:]
689 else:
690 if argsStr in self.argvHistory:
691 self.argvHistory.remove(argsStr)
692 self.argvHistory.insert(0, argsStr)
693
694 def setWdHistory(self, wdStr, clearHistories=False, history=None):
695 """
696 Public slot to initialize the wd history.
697
698 @param wdStr the working directory (string)
699 @param clearHistories flag indicating, that the list should
700 be cleared (boolean)
701 @param history list of history entries to be set (list of strings)
702 """
703 if clearHistories:
704 del self.wdHistory[1:]
705 elif history is not None:
706 self.wdHistory = history[:]
707 else:
708 if wdStr in self.wdHistory:
709 self.wdHistory.remove(wdStr)
710 self.wdHistory.insert(0, wdStr)
711
712 def setEnvHistory(self, envStr, clearHistories=False, history=None):
713 """
714 Public slot to initialize the env history.
715
716 @param envStr the environment settings (string)
717 @param clearHistories flag indicating, that the list should
718 be cleared (boolean)
719 @param history list of history entries to be set (list of strings)
720 """
721 if clearHistories:
722 del self.envHistory[1:]
723 elif history is not None:
724 self.envHistory = history[:]
725 else:
726 if envStr in self.envHistory:
727 self.envHistory.remove(envStr)
728 self.envHistory.insert(0, envStr)
729
730 def setExceptionReporting(self, exceptions):
731 """
732 Public slot to initialize the exception reporting flag.
733
734 @param exceptions flag indicating exception reporting status (boolean)
735 """
736 self.exceptions = exceptions
737
738 def setExcList(self, excList):
739 """
740 Public slot to initialize the exceptions type list.
741
742 @param excList list of exception types (list of strings)
743 """
744 self.excList = excList[:] # keep a copy
745
746 def setExcIgnoreList(self, excIgnoreList):
747 """
748 Public slot to initialize the ignored exceptions type list.
749
750 @param excIgnoreList list of ignored exception types (list of strings)
751 """
752 self.excIgnoreList = excIgnoreList[:] # keep a copy
753
754 def setAutoClearShell(self, autoClearShell):
755 """
756 Public slot to initialize the autoClearShell flag.
757
758 @param autoClearShell flag indicating, that the interpreter window
759 should be cleared (boolean)
760 """
761 self.autoClearShell = autoClearShell
762
763 def setTracePython(self, tracePython):
764 """
765 Public slot to initialize the trace Python flag.
766
767 @param tracePython flag indicating if the Python library should be
768 traced as well (boolean)
769 """
770 self.tracePython = tracePython
771
772 def setAutoContinue(self, autoContinue):
773 """
774 Public slot to initialize the autoContinue flag.
775
776 @param autoContinue flag indicating, that the debugger should not
777 stop at the first executable line (boolean)
778 """
779 self.autoContinue = autoContinue
780
781 def __editorOpened(self, fn):
782 """
783 Private slot to handle the editorOpened signal.
784
785 @param fn filename of the opened editor
786 """
787 self.editorOpen = True
788
789 if fn:
790 editor = self.viewmanager.getOpenEditor(fn)
791 else:
792 editor = None
793 self.__checkActions(editor)
794
795 def __lastEditorClosed(self):
796 """
797 Private slot to handle the closeProgram signal.
798 """
799 self.editorOpen = False
800 self.debugAct.setEnabled(False)
801 self.runAct.setEnabled(False)
802 self.profileAct.setEnabled(False)
803 self.coverageAct.setEnabled(False)
804 self.debugActGrp.setEnabled(False)
805 self.dbgSetBpActGrp.setEnabled(False)
806 self.lastAction = -1
807 if not self.projectOpen:
808 self.restartAct.setEnabled(False)
809 self.lastDebuggedFile = None
810 self.lastStartAction = 0
811 self.clientType = ""
812
813 def __checkActions(self, editor):
814 """
815 Private slot to check some actions for their enable/disable status.
816
817 @param editor editor window
818 """
819 if editor:
820 fn = editor.getFileName()
821 else:
822 fn = None
823
824 cap = 0
825 if fn:
826 for language in self.debugServer.getSupportedLanguages():
827 exts = self.debugServer.getExtensions(language)
828 if fn.endswith(exts):
829 cap = self.debugServer.getClientCapabilities(language)
830 break
831 else:
832 if editor.isPy2File():
833 cap = self.debugServer.getClientCapabilities('Python2')
834 elif editor.isPy3File():
835 cap = self.debugServer.getClientCapabilities('Python3')
836 elif editor.isRubyFile():
837 cap = self.debugServer.getClientCapabilities('Ruby')
838
839 if not self.passive:
840 self.runAct.setEnabled(cap & HasInterpreter)
841 self.coverageAct.setEnabled(cap & HasCoverage)
842 self.profileAct.setEnabled(cap & HasProfiler)
843 self.debugAct.setEnabled(cap & HasDebugger)
844 self.dbgSetBpActGrp.setEnabled(cap & HasDebugger)
845 if editor.curLineHasBreakpoint():
846 self.dbgEditBpAct.setEnabled(True)
847 else:
848 self.dbgEditBpAct.setEnabled(False)
849 if editor.hasBreakpoints():
850 self.dbgNextBpAct.setEnabled(True)
851 self.dbgPrevBpAct.setEnabled(True)
852 else:
853 self.dbgNextBpAct.setEnabled(False)
854 self.dbgPrevBpAct.setEnabled(False)
855 else:
856 self.runAct.setEnabled(False)
857 self.coverageAct.setEnabled(False)
858 self.profileAct.setEnabled(False)
859 self.debugAct.setEnabled(False)
860 self.dbgSetBpActGrp.setEnabled(False)
861
862 def __cursorChanged(self, editor):
863 """
864 Private slot handling the cursorChanged signal of the viewmanager.
865
866 @param editor editor window
867 """
868 if editor is None:
869 return
870
871 if editor.isPyFile() or editor.isRubyFile():
872 if editor.curLineHasBreakpoint():
873 self.dbgEditBpAct.setEnabled(True)
874 else:
875 self.dbgEditBpAct.setEnabled(False)
876 if editor.hasBreakpoints():
877 self.dbgNextBpAct.setEnabled(True)
878 self.dbgPrevBpAct.setEnabled(True)
879 else:
880 self.dbgNextBpAct.setEnabled(False)
881 self.dbgPrevBpAct.setEnabled(False)
882
883 def __projectOpened(self):
884 """
885 Private slot to handle the projectOpened signal.
886 """
887 self.projectOpen = True
888 cap = self.debugServer.getClientCapabilities(
889 self.project.getProjectLanguage())
890 if not self.passive:
891 self.debugProjectAct.setEnabled(cap & HasDebugger)
892 self.runProjectAct.setEnabled(cap & HasInterpreter)
893 self.profileProjectAct.setEnabled(cap & HasProfiler)
894 self.coverageProjectAct.setEnabled(cap & HasCoverage)
895
896 def __projectClosed(self):
897 """
898 Private slot to handle the projectClosed signal.
899 """
900 self.projectOpen = False
901 self.runProjectAct.setEnabled(False)
902 self.profileProjectAct.setEnabled(False)
903 self.coverageProjectAct.setEnabled(False)
904 self.debugProjectAct.setEnabled(False)
905
906 if not self.editorOpen:
907 self.restartAct.setEnabled(False)
908 self.lastDebuggedFile = None
909 self.lastStartAction = 0
910 self.clientType = ""
911
912 def clearHistories(self):
913 """
914 Public method to clear the various debug histories.
915 """
916 self.argvHistory = []
917 self.wdHistory = []
918 self.envHistory = []
919
920 Preferences.Prefs.settings.setValue(
921 'DebugInfo/ArgumentsHistory', self.argvHistory)
922 Preferences.Prefs.settings.setValue(
923 'DebugInfo/WorkingDirectoryHistory', self.wdHistory)
924 Preferences.Prefs.settings.setValue(
925 'DebugInfo/EnvironmentHistory', self.envHistory)
926
927 def shutdown(self):
928 """
929 Public method to perform shutdown actions.
930 """
931 # Just save the 10 most recent entries
932 del self.argvHistory[10:]
933 del self.wdHistory[10:]
934 del self.envHistory[10:]
935
936 Preferences.Prefs.settings.setValue(
937 'DebugInfo/VirtualEnvironment', self.lastUsedVenvName)
938 Preferences.Prefs.settings.setValue(
939 'DebugInfo/ArgumentsHistory', self.argvHistory)
940 Preferences.Prefs.settings.setValue(
941 'DebugInfo/WorkingDirectoryHistory', self.wdHistory)
942 Preferences.Prefs.settings.setValue(
943 'DebugInfo/EnvironmentHistory', self.envHistory)
944 Preferences.Prefs.settings.setValue(
945 'DebugInfo/Exceptions', self.excList)
946 Preferences.Prefs.settings.setValue(
947 'DebugInfo/IgnoredExceptions', self.excIgnoreList)
948 Preferences.Prefs.settings.setValue(
949 'DebugInfo/ReportExceptions', self.exceptions)
950 Preferences.Prefs.settings.setValue(
951 'DebugInfo/AutoClearShell', self.autoClearShell)
952 Preferences.Prefs.settings.setValue(
953 'DebugInfo/TracePython', self.tracePython)
954 Preferences.Prefs.settings.setValue(
955 'DebugInfo/AutoContinue', self.autoContinue)
956 Preferences.Prefs.settings.setValue(
957 'DebugInfo/ForkAutomatically', self.forkAutomatically)
958 Preferences.Prefs.settings.setValue(
959 'DebugInfo/ForkIntoChild', self.forkIntoChild)
960
961 def shutdownServer(self):
962 """
963 Public method to shut down the debug server.
964
965 This is needed to cleanly close the sockets on Win OS.
966
967 @return always true
968 """
969 self.debugServer.shutdownServer()
970 return True
971
972 def __resetUI(self):
973 """
974 Private slot to reset the user interface.
975 """
976 self.lastAction = -1
977 self.debugActGrp.setEnabled(False)
978 if not self.passive:
979 if self.editorOpen:
980 editor = self.viewmanager.activeWindow()
981 else:
982 editor = None
983 self.__checkActions(editor)
984
985 self.debugProjectAct.setEnabled(self.projectOpen)
986 self.runProjectAct.setEnabled(self.projectOpen)
987 self.profileProjectAct.setEnabled(self.projectOpen)
988 self.coverageProjectAct.setEnabled(self.projectOpen)
989 if self.lastDebuggedFile is not None and \
990 (self.editorOpen or self.projectOpen):
991 self.restartAct.setEnabled(True)
992 else:
993 self.restartAct.setEnabled(False)
994 self.stopAct.setEnabled(False)
995 self.resetUI.emit()
996
997 def __clientLine(self, fn, line, forStack):
998 """
999 Private method to handle a change to the current line.
1000
1001 @param fn filename (string)
1002 @param line linenumber (int)
1003 @param forStack flag indicating this is for a stack dump (boolean)
1004 """
1005 self.ui.raise_()
1006 self.ui.activateWindow()
1007 if self.ui.getViewProfile() != "debug":
1008 self.ui.setDebugProfile()
1009 self.viewmanager.setFileLine(fn, line)
1010 if not forStack:
1011 self.__getThreadList()
1012 self.__getClientVariables()
1013
1014 self.debugActGrp.setEnabled(True)
1015
1016 def __clientExit(self, status, message, quiet):
1017 """
1018 Private method to handle the debugged program terminating.
1019
1020 @param status exit code of the debugged program
1021 @type int
1022 @param message exit message of the debugged program
1023 @type str
1024 @param quiet flag indicating to suppress exit info display
1025 @type bool
1026 """
1027 self.viewmanager.exit()
1028
1029 self.__resetUI()
1030
1031 if not quiet:
1032 if not Preferences.getDebugger("SuppressClientExit") or \
1033 status != 0:
1034 if message:
1035 info = self.tr("<p>Message: {0}</p>").format(
1036 Utilities.html_uencode(message))
1037 else:
1038 info = ""
1039 if self.ui.currentProg is None:
1040 E5MessageBox.information(
1041 self.ui, Program,
1042 self.tr('<p>The program has terminated with an exit'
1043 ' status of {0}.</p>{1}').format(status, info))
1044 else:
1045 E5MessageBox.information(
1046 self.ui, Program,
1047 self.tr('<p><b>{0}</b> has terminated with an exit'
1048 ' status of {1}.</p>{2}')
1049 .format(Utilities.normabspath(self.ui.currentProg),
1050 status, info))
1051 else:
1052 if message:
1053 info = self.tr("Message: {0}").format(
1054 Utilities.html_uencode(message))
1055 else:
1056 info = ""
1057 if self.ui.notificationsEnabled():
1058 if self.ui.currentProg is None:
1059 msg = self.tr(
1060 'The program has terminated with an exit status of'
1061 ' {0}.\n{1}').format(status, info)
1062 else:
1063 msg = self.tr(
1064 '"{0}" has terminated with an exit status of'
1065 ' {1}.\n{2}').format(
1066 os.path.basename(self.ui.currentProg), status,
1067 info)
1068 self.ui.showNotification(
1069 UI.PixmapCache.getPixmap("debug48.png"),
1070 self.tr("Program terminated"), msg)
1071 else:
1072 if self.ui.currentProg is None:
1073 self.appendStdout.emit(self.tr(
1074 'The program has terminated with an exit status'
1075 ' of {0}.\n{1}\n').format(status, info))
1076 else:
1077 self.appendStdout.emit(self.tr(
1078 '"{0}" has terminated with an exit status of'
1079 ' {1}.\n{2}\n').format(
1080 Utilities.normabspath(self.ui.currentProg), status,
1081 info))
1082
1083 def __clientSyntaxError(self, message, filename, lineNo, characterNo):
1084 """
1085 Private method to handle a syntax error in the debugged program.
1086
1087 @param message message of the syntax error (string)
1088 @param filename translated filename of the syntax error position
1089 (string)
1090 @param lineNo line number of the syntax error position (integer)
1091 @param characterNo character number of the syntax error position
1092 (integer)
1093 """
1094 self.__resetUI()
1095 self.ui.raise_()
1096 self.ui.activateWindow()
1097
1098 if message is None:
1099 E5MessageBox.critical(
1100 self.ui, Program,
1101 self.tr(
1102 'The program being debugged contains an unspecified'
1103 ' syntax error.'))
1104 return
1105
1106 if not os.path.isabs(filename):
1107 if os.path.exists(os.path.join(self.project.getProjectPath(),
1108 filename)):
1109 filename = os.path.join(self.project.getProjectPath(),
1110 filename)
1111 else:
1112 ms = self.project.getMainScript(normalized=True)
1113 if ms is not None:
1114 d = os.path.dirname(ms)
1115 if os.path.exists(os.path.join(d, filename)):
1116 filename = os.path.join(d, filename)
1117 self.viewmanager.setFileLine(filename, lineNo, True, True)
1118 E5MessageBox.critical(
1119 self.ui, Program,
1120 self.tr('<p>The file <b>{0}</b> contains the syntax error'
1121 ' <b>{1}</b> at line <b>{2}</b>, character <b>{3}</b>.'
1122 '</p>')
1123 .format(filename, message, lineNo, characterNo))
1124
1125 def __clientException(self, exceptionType, exceptionMessage, stackTrace):
1126 """
1127 Private method to handle an exception of the debugged program.
1128
1129 @param exceptionType type of exception raised (string)
1130 @param exceptionMessage message given by the exception (string)
1131 @param stackTrace list of stack entries (list of string)
1132 """
1133 self.ui.raise_()
1134 QApplication.processEvents()
1135 if not exceptionType:
1136 E5MessageBox.critical(
1137 self.ui, Program,
1138 self.tr('An unhandled exception occured.'
1139 ' See the shell window for details.'))
1140 return
1141
1142 if (self.exceptions and
1143 exceptionType not in self.excIgnoreList and
1144 (not len(self.excList) or
1145 (len(self.excList) and exceptionType in self.excList)))\
1146 or exceptionType.startswith('unhandled'):
1147 res = None
1148 if stackTrace:
1149 try:
1150 file, line = stackTrace[0][:2]
1151 source, encoding = Utilities.readEncodedFile(file)
1152 source = source.splitlines(True)
1153 if len(source) >= line:
1154 lineFlags = Utilities.extractLineFlags(
1155 source[line - 1].strip())
1156 try:
1157 lineFlags += Utilities.extractLineFlags(
1158 source[line].strip(), flagsLine=True)
1159 except IndexError:
1160 pass
1161 if "__IGNORE_EXCEPTION__" in lineFlags:
1162 res = E5MessageBox.No
1163 except (UnicodeError, IOError):
1164 pass
1165 if res != E5MessageBox.No:
1166 self.viewmanager.setFileLine(
1167 stackTrace[0][0], stackTrace[0][1], True)
1168 if res != E5MessageBox.No:
1169 self.ui.activateWindow()
1170 if Preferences.getDebugger("BreakAlways"):
1171 res = E5MessageBox.Yes
1172 else:
1173 if stackTrace:
1174 if exceptionType.startswith('unhandled'):
1175 buttons = E5MessageBox.StandardButtons(
1176 E5MessageBox.No |
1177 E5MessageBox.Yes)
1178 else:
1179 buttons = E5MessageBox.StandardButtons(
1180 E5MessageBox.No |
1181 E5MessageBox.Yes |
1182 E5MessageBox.Ignore)
1183 res = E5MessageBox.critical(
1184 self.ui, Program,
1185 self.tr(
1186 '<p>The debugged program raised the exception'
1187 ' <b>{0}</b><br>"<b>{1}</b>"<br>'
1188 'File: <b>{2}</b>, Line: <b>{3}</b></p>'
1189 '<p>Break here?</p>')
1190 .format(
1191 exceptionType,
1192 Utilities.html_encode(exceptionMessage),
1193 stackTrace[0][0],
1194 stackTrace[0][1]),
1195 buttons,
1196 E5MessageBox.No)
1197 else:
1198 res = E5MessageBox.critical(
1199 self.ui, Program,
1200 self.tr(
1201 '<p>The debugged program raised the exception'
1202 ' <b>{0}</b><br>"<b>{1}</b>"</p>')
1203 .format(
1204 exceptionType,
1205 Utilities.html_encode(exceptionMessage)))
1206 if res == E5MessageBox.Yes:
1207 self.debugServer.setDebugging(True)
1208 self.exceptionInterrupt.emit()
1209 stack = []
1210 for fn, ln, func, args in stackTrace:
1211 stack.append((fn, ln, func, args))
1212 self.clientStack.emit(stack)
1213 self.__getClientVariables()
1214 self.ui.setDebugProfile()
1215 self.debugActGrp.setEnabled(True)
1216 return
1217 elif res == E5MessageBox.Ignore:
1218 if exceptionType not in self.excIgnoreList:
1219 self.excIgnoreList.append(exceptionType)
1220
1221 if self.lastAction != -1:
1222 if self.lastAction == 2:
1223 self.__specialContinue()
1224 else:
1225 self.debugActions[self.lastAction]()
1226 else:
1227 self.__continue()
1228
1229 def __clientSignal(self, message, filename, lineNo, funcName, funcArgs):
1230 """
1231 Private method to handle a signal generated on the client side.
1232
1233 @param message message of the syntax error
1234 @type str
1235 @param filename translated filename of the syntax error position
1236 @type str
1237 @param lineNo line number of the syntax error position
1238 @type int
1239 @param funcName name of the function causing the signal
1240 @type str
1241 @param funcArgs function arguments
1242 @type str
1243 """
1244 self.ui.raise_()
1245 self.ui.activateWindow()
1246 QApplication.processEvents()
1247 self.viewmanager.setFileLine(filename, lineNo, True)
1248 E5MessageBox.critical(
1249 self.ui, Program,
1250 self.tr("""<p>The program generate the signal "{0}".<br/>"""
1251 """File: <b>{1}</b>, Line: <b>{2}</b></p>""").format(
1252 message, filename, lineNo))
1253
1254 def __clientGone(self, unplanned):
1255 """
1256 Private method to handle the disconnection of the debugger client.
1257
1258 @param unplanned True if the client died, False otherwise
1259 """
1260 self.__resetUI()
1261 if unplanned:
1262 E5MessageBox.information(
1263 self.ui, Program,
1264 self.tr('The program being debugged has terminated'
1265 ' unexpectedly.'))
1266
1267 def __getThreadList(self):
1268 """
1269 Private method to get the list of threads from the client.
1270 """
1271 self.debugServer.remoteThreadList()
1272
1273 def __clientThreadSet(self):
1274 """
1275 Private method to handle a change of the client's current thread.
1276 """
1277 self.debugServer.remoteClientVariables(0, self.localsVarFilter)
1278
1279 def __getClientVariables(self):
1280 """
1281 Private method to request the global and local variables.
1282
1283 In the first step, the global variables are requested from the client.
1284 Once these have been received, the local variables are requested.
1285 This happens in the method '__clientVariables'.
1286 """
1287 # get globals first
1288 self.debugServer.remoteClientVariables(1, self.globalsVarFilter)
1289 # the local variables are requested once we have received the globals
1290
1291 def __clientVariables(self, scope, variables):
1292 """
1293 Private method to write the clients variables to the user interface.
1294
1295 @param scope scope of the variables (-1 = empty global, 1 = global,
1296 0 = local)
1297 @param variables the list of variables from the client
1298 """
1299 self.ui.activateDebugViewer()
1300 if scope > 0:
1301 self.debugViewer.showVariables(variables, True)
1302 if scope == 1:
1303 # now get the local variables
1304 self.debugServer.remoteClientVariables(0, self.localsVarFilter)
1305 elif scope == 0:
1306 self.debugViewer.showVariables(variables, False)
1307 elif scope == -1:
1308 vlist = [('None', '', '')]
1309 self.debugViewer.showVariables(vlist, False)
1310
1311 def __clientVariable(self, scope, variables):
1312 """
1313 Private method to write the contents of a clients classvariable to
1314 the user interface.
1315
1316 @param scope scope of the variables (-1 = empty global, 1 = global,
1317 0 = local)
1318 @param variables the list of members of a classvariable from the client
1319 """
1320 self.ui.activateDebugViewer()
1321 if scope == 1:
1322 self.debugViewer.showVariable(variables, True)
1323 elif scope == 0:
1324 self.debugViewer.showVariable(variables, False)
1325
1326 def __clientBreakConditionError(self, filename, lineno):
1327 """
1328 Private method to handle a condition error of a breakpoint.
1329
1330 @param filename filename of the breakpoint (string)
1331 @param lineno linenumber of the breakpoint (integer)
1332 """
1333 E5MessageBox.critical(
1334 self.ui,
1335 self.tr("Breakpoint Condition Error"),
1336 self.tr(
1337 """<p>The condition of the breakpoint <b>{0}, {1}</b>"""
1338 """ contains a syntax error.</p>""")
1339 .format(filename, lineno))
1340
1341 model = self.debugServer.getBreakPointModel()
1342 index = model.getBreakPointIndex(filename, lineno)
1343 if not index.isValid():
1344 return
1345
1346 bp = model.getBreakPointByIndex(index)
1347 if not bp:
1348 return
1349
1350 fn, line, cond, temp, enabled, count = bp[:6]
1351
1352 from .EditBreakpointDialog import EditBreakpointDialog
1353 dlg = EditBreakpointDialog(
1354 (fn, line), (cond, temp, enabled, count),
1355 [], self.ui, modal=True)
1356 if dlg.exec_() == QDialog.Accepted:
1357 cond, temp, enabled, count = dlg.getData()
1358 model.setBreakPointByIndex(index, fn, line,
1359 (cond, temp, enabled, count))
1360
1361 def __clientWatchConditionError(self, cond):
1362 """
1363 Private method to handle a expression error of a watch expression.
1364
1365 Note: This can only happen for normal watch expressions
1366
1367 @param cond expression of the watch expression (string)
1368 """
1369 E5MessageBox.critical(
1370 self.ui,
1371 self.tr("Watch Expression Error"),
1372 self.tr("""<p>The watch expression <b>{0}</b>"""
1373 """ contains a syntax error.</p>""")
1374 .format(cond))
1375
1376 model = self.debugServer.getWatchPointModel()
1377 index = model.getWatchPointIndex(cond)
1378 if not index.isValid():
1379 return
1380
1381 wp = model.getWatchPointByIndex(index)
1382 if not wp:
1383 return
1384
1385 cond, special, temp, enabled, count = wp[:5]
1386
1387 from .EditWatchpointDialog import EditWatchpointDialog
1388 dlg = EditWatchpointDialog(
1389 (cond, temp, enabled, count, special), self.ui)
1390 if dlg.exec_() == QDialog.Accepted:
1391 cond, temp, enabled, count, special = dlg.getData()
1392
1393 # check for duplicates
1394 idx = self.__model.getWatchPointIndex(cond, special)
1395 duplicate = idx.isValid() and \
1396 idx.internalPointer() != index.internalPointer()
1397 if duplicate:
1398 if not special:
1399 msg = self.tr("""<p>A watch expression '<b>{0}</b>'"""
1400 """ already exists.</p>""")\
1401 .format(Utilities.html_encode(cond))
1402 else:
1403 msg = self.tr(
1404 """<p>A watch expression '<b>{0}</b>'"""
1405 """ for the variable <b>{1}</b> already"""
1406 """ exists.</p>""")\
1407 .format(special,
1408 Utilities.html_encode(cond))
1409 E5MessageBox.warning(
1410 self.ui,
1411 self.tr("Watch expression already exists"),
1412 msg)
1413 model.deleteWatchPointByIndex(index)
1414 else:
1415 model.setWatchPointByIndex(index, cond, special,
1416 (temp, enabled, count))
1417
1418 def __configureVariablesFilters(self):
1419 """
1420 Private slot for displaying the variables filter configuration dialog.
1421 """
1422 from .VariablesFilterDialog import VariablesFilterDialog
1423 dlg = VariablesFilterDialog(self.ui, 'Filter Dialog', True)
1424 dlg.setSelection(self.localsVarFilter, self.globalsVarFilter)
1425 if dlg.exec_() == QDialog.Accepted:
1426 self.localsVarFilter, self.globalsVarFilter = dlg.getSelection()
1427 self.debugViewer.setVariablesFilter(
1428 self.globalsVarFilter, self.localsVarFilter)
1429
1430 def __configureExceptionsFilter(self):
1431 """
1432 Private slot for displaying the exception filter dialog.
1433 """
1434 from .ExceptionsFilterDialog import ExceptionsFilterDialog
1435 dlg = ExceptionsFilterDialog(self.excList, ignore=False)
1436 if dlg.exec_() == QDialog.Accepted:
1437 self.excList = dlg.getExceptionsList()[:] # keep a copy
1438
1439 def __configureIgnoredExceptions(self):
1440 """
1441 Private slot for displaying the ignored exceptions dialog.
1442 """
1443 from .ExceptionsFilterDialog import ExceptionsFilterDialog
1444 dlg = ExceptionsFilterDialog(self.excIgnoreList, ignore=True)
1445 if dlg.exec_() == QDialog.Accepted:
1446 self.excIgnoreList = dlg.getExceptionsList()[:] # keep a copy
1447
1448 def __toggleBreakpoint(self):
1449 """
1450 Private slot to handle the 'Set/Reset breakpoint' action.
1451 """
1452 self.viewmanager.activeWindow().menuToggleBreakpoint()
1453
1454 def __editBreakpoint(self):
1455 """
1456 Private slot to handle the 'Edit breakpoint' action.
1457 """
1458 self.viewmanager.activeWindow().menuEditBreakpoint()
1459
1460 def __nextBreakpoint(self):
1461 """
1462 Private slot to handle the 'Next breakpoint' action.
1463 """
1464 self.viewmanager.activeWindow().menuNextBreakpoint()
1465
1466 def __previousBreakpoint(self):
1467 """
1468 Private slot to handle the 'Previous breakpoint' action.
1469 """
1470 self.viewmanager.activeWindow().menuPreviousBreakpoint()
1471
1472 def __clearBreakpoints(self):
1473 """
1474 Private slot to handle the 'Clear breakpoints' action.
1475 """
1476 self.debugServer.getBreakPointModel().deleteAll()
1477
1478 def __showDebugMenu(self):
1479 """
1480 Private method to set up the debug menu.
1481 """
1482 bpCount = self.debugServer.getBreakPointModel().rowCount()
1483 self.menuBreakpointsAct.setEnabled(bpCount > 0)
1484
1485 def __showBreakpointsMenu(self):
1486 """
1487 Private method to handle the show breakpoints menu signal.
1488 """
1489 self.breakpointsMenu.clear()
1490
1491 model = self.debugServer.getBreakPointModel()
1492 for row in range(model.rowCount()):
1493 index = model.index(row, 0)
1494 filename, line, cond = model.getBreakPointByIndex(index)[:3]
1495 if not cond:
1496 formattedCond = ""
1497 else:
1498 formattedCond = " : {0}".format(cond[:20])
1499 bpSuffix = " : {0:d}{1}".format(line, formattedCond)
1500 act = self.breakpointsMenu.addAction(
1501 "{0}{1}".format(
1502 Utilities.compactPath(
1503 filename,
1504 self.ui.maxMenuFilePathLen - len(bpSuffix)),
1505 bpSuffix))
1506 act.setData([filename, line])
1507
1508 def __breakpointSelected(self, act):
1509 """
1510 Private method to handle the breakpoint selected signal.
1511
1512 @param act reference to the action that triggered (QAction)
1513 """
1514 qvList = act.data()
1515 filename = qvList[0]
1516 line = qvList[1]
1517 self.viewmanager.openSourceFile(filename, line)
1518
1519 def __compileChangedProjectFiles(self):
1520 """
1521 Private method to signal compilation of changed forms and resources
1522 is wanted.
1523 """
1524 if Preferences.getProject("AutoCompileForms"):
1525 self.compileForms.emit()
1526 if Preferences.getProject("AutoCompileResources"):
1527 self.compileResources.emit()
1528 if Preferences.getProject("AutoExecuteMake"):
1529 self.executeMake.emit()
1530 QApplication.processEvents()
1531
1532 def __coverageScript(self):
1533 """
1534 Private slot to handle the coverage of script action.
1535 """
1536 self.__doCoverage(False)
1537
1538 def __coverageProject(self):
1539 """
1540 Private slot to handle the coverage of project action.
1541 """
1542 self.__compileChangedProjectFiles()
1543 self.__doCoverage(True)
1544
1545 def __doCoverage(self, runProject):
1546 """
1547 Private method to handle the coverage actions.
1548
1549 @param runProject flag indicating coverage of the current project
1550 (True) or script (false)
1551 """
1552 from .StartDialog import StartDialog
1553
1554 self.__resetUI()
1555 doNotStart = False
1556
1557 # Get the command line arguments, the working directory and the
1558 # exception reporting flag.
1559 if runProject:
1560 cap = self.tr("Coverage of Project")
1561 else:
1562 cap = self.tr("Coverage of Script")
1563 dlg = StartDialog(
1564 cap, self.lastUsedVenvName, self.argvHistory, self.wdHistory,
1565 self.envHistory, self.exceptions, self.ui, 2,
1566 autoClearShell=self.autoClearShell)
1567 if dlg.exec_() == QDialog.Accepted:
1568 (lastUsedVenvName, argv, wd, env, exceptions, clearShell,
1569 console) = dlg.getData()
1570 eraseCoverage = dlg.getCoverageData()
1571
1572 if runProject:
1573 fn = self.project.getMainScript(True)
1574 if fn is None:
1575 E5MessageBox.critical(
1576 self.ui,
1577 self.tr("Coverage of Project"),
1578 self.tr(
1579 "There is no main script defined for the"
1580 " current project. Aborting"))
1581 return
1582
1583 if Preferences.getDebugger("Autosave") and \
1584 not self.project.saveAllScripts(reportSyntaxErrors=True):
1585 doNotStart = True
1586
1587 # save the info for later use
1588 self.project.setDbgInfo(
1589 lastUsedVenvName, argv, wd, env, exceptions, self.excList,
1590 self.excIgnoreList, clearShell)
1591
1592 self.lastStartAction = 6
1593 self.clientType = self.project.getProjectLanguage()
1594 else:
1595 editor = self.viewmanager.activeWindow()
1596 if editor is None:
1597 return
1598
1599 if not self.viewmanager.checkDirty(
1600 editor,
1601 Preferences.getDebugger("Autosave")) or \
1602 editor.getFileName() is None:
1603 return
1604
1605 fn = editor.getFileName()
1606 self.lastStartAction = 5
1607 self.clientType = editor.determineFileType()
1608
1609 # save the filename for use by the restart method
1610 self.lastDebuggedFile = fn
1611 self.restartAct.setEnabled(True)
1612
1613 # save the most recently used virtual environment
1614 self.lastUsedVenvName = lastUsedVenvName
1615
1616 # This moves any previous occurrence of these arguments to the head
1617 # of the list.
1618 self.setArgvHistory(argv)
1619 self.setWdHistory(wd)
1620 self.setEnvHistory(env)
1621
1622 # Save the exception flags
1623 self.exceptions = exceptions
1624
1625 # Save the erase coverage flag
1626 self.eraseCoverage = eraseCoverage
1627
1628 # Save the clear interpreter flag
1629 self.autoClearShell = clearShell
1630
1631 # Save the run in console flag
1632 self.runInConsole = console
1633
1634 # Hide all error highlights
1635 self.viewmanager.unhighlight()
1636
1637 if not doNotStart:
1638 if runProject and self.project.getProjectType() in [
1639 "E6Plugin"]:
1640 argv = '--plugin="{0}" {1}'.format(fn, argv)
1641 fn = os.path.join(getConfig('ericDir'), "eric6.py")
1642
1643 self.debugViewer.initCallStackViewer(runProject)
1644
1645 # Ask the client to open the new program.
1646 self.debugServer.remoteCoverage(
1647 lastUsedVenvName, fn, argv, wd, env,
1648 autoClearShell=self.autoClearShell, erase=eraseCoverage,
1649 forProject=runProject, runInConsole=console,
1650 clientType=self.clientType)
1651
1652 self.stopAct.setEnabled(True)
1653
1654 if dlg.clearHistories():
1655 self.setArgvHistory("", clearHistories=True)
1656 self.setWdHistory("", clearHistories=True)
1657 self.setEnvHistory("", clearHistories=True)
1658 elif dlg.historiesModified():
1659 argvHistory, wdHistory, envHistory = dlg.getHistories()
1660 self.setArgvHistory("", history=argvHistory)
1661 self.setWdHistory("", history=wdHistory)
1662 self.setEnvHistory("", history=envHistory)
1663
1664 def __profileScript(self):
1665 """
1666 Private slot to handle the profile script action.
1667 """
1668 self.__doProfile(False)
1669
1670 def __profileProject(self):
1671 """
1672 Private slot to handle the profile project action.
1673 """
1674 self.__compileChangedProjectFiles()
1675 self.__doProfile(True)
1676
1677 def __doProfile(self, runProject):
1678 """
1679 Private method to handle the profile actions.
1680
1681 @param runProject flag indicating profiling of the current project
1682 (True) or script (False)
1683 """
1684 from .StartDialog import StartDialog
1685
1686 self.__resetUI()
1687 doNotStart = False
1688
1689 # Get the command line arguments, the working directory and the
1690 # exception reporting flag.
1691 if runProject:
1692 cap = self.tr("Profile of Project")
1693 else:
1694 cap = self.tr("Profile of Script")
1695 dlg = StartDialog(
1696 cap, self.lastUsedVenvName, self.argvHistory, self.wdHistory,
1697 self.envHistory, self.exceptions, self.ui, 3,
1698 autoClearShell=self.autoClearShell)
1699 if dlg.exec_() == QDialog.Accepted:
1700 (lastUsedVenvName, argv, wd, env, exceptions, clearShell,
1701 console) = dlg.getData()
1702 eraseTimings = dlg.getProfilingData()
1703
1704 if runProject:
1705 fn = self.project.getMainScript(True)
1706 if fn is None:
1707 E5MessageBox.critical(
1708 self.ui,
1709 self.tr("Profile of Project"),
1710 self.tr(
1711 "There is no main script defined for the"
1712 " current project. Aborting"))
1713 return
1714
1715 if Preferences.getDebugger("Autosave") and \
1716 not self.project.saveAllScripts(reportSyntaxErrors=True):
1717 doNotStart = True
1718
1719 # save the info for later use
1720 self.project.setDbgInfo(
1721 lastUsedVenvName, argv, wd, env, exceptions, self.excList,
1722 self.excIgnoreList, clearShell)
1723
1724 self.lastStartAction = 8
1725 self.clientType = self.project.getProjectLanguage()
1726 else:
1727 editor = self.viewmanager.activeWindow()
1728 if editor is None:
1729 return
1730
1731 if not self.viewmanager.checkDirty(
1732 editor,
1733 Preferences.getDebugger("Autosave")) or \
1734 editor.getFileName() is None:
1735 return
1736
1737 fn = editor.getFileName()
1738 self.lastStartAction = 7
1739 self.clientType = editor.determineFileType()
1740
1741 # save the filename for use by the restart method
1742 self.lastDebuggedFile = fn
1743 self.restartAct.setEnabled(True)
1744
1745 # save the most recently used virtual environment
1746 self.lastUsedVenvName = lastUsedVenvName
1747
1748 # This moves any previous occurrence of these arguments to the head
1749 # of the list.
1750 self.setArgvHistory(argv)
1751 self.setWdHistory(wd)
1752 self.setEnvHistory(env)
1753
1754 # Save the exception flags
1755 self.exceptions = exceptions
1756
1757 # Save the erase timing flag
1758 self.eraseTimings = eraseTimings
1759
1760 # Save the clear interpreter flag
1761 self.autoClearShell = clearShell
1762
1763 # Save the run in console flag
1764 self.runInConsole = console
1765
1766 # Hide all error highlights
1767 self.viewmanager.unhighlight()
1768
1769 if not doNotStart:
1770 if runProject and self.project.getProjectType() in [
1771 "E6Plugin"]:
1772 argv = '--plugin="{0}" {1}'.format(fn, argv)
1773 fn = os.path.join(getConfig('ericDir'), "eric6.py")
1774
1775 self.debugViewer.initCallStackViewer(runProject)
1776
1777 # Ask the client to open the new program.
1778 self.debugServer.remoteProfile(
1779 lastUsedVenvName, fn, argv, wd, env,
1780 autoClearShell=self.autoClearShell, erase=eraseTimings,
1781 forProject=runProject, runInConsole=console,
1782 clientType=self.clientType)
1783
1784 self.stopAct.setEnabled(True)
1785
1786 if dlg.clearHistories():
1787 self.setArgvHistory("", clearHistories=True)
1788 self.setWdHistory("", clearHistories=True)
1789 self.setEnvHistory("", clearHistories=True)
1790 elif dlg.historiesModified():
1791 argvHistory, wdHistory, envHistory = dlg.getHistories()
1792 self.setArgvHistory("", history=argvHistory)
1793 self.setWdHistory("", history=wdHistory)
1794 self.setEnvHistory("", history=envHistory)
1795
1796 def __runScript(self):
1797 """
1798 Private slot to handle the run script action.
1799 """
1800 self.__doRun(False)
1801
1802 def __runProject(self):
1803 """
1804 Private slot to handle the run project action.
1805 """
1806 self.__compileChangedProjectFiles()
1807 self.__doRun(True)
1808
1809 def __doRun(self, runProject):
1810 """
1811 Private method to handle the run actions.
1812
1813 @param runProject flag indicating running the current project (True)
1814 or script (False)
1815 """
1816 from .StartDialog import StartDialog
1817
1818 self.__resetUI()
1819 doNotStart = False
1820
1821 # Get the command line arguments, the working directory and the
1822 # exception reporting flag.
1823 if runProject:
1824 cap = self.tr("Run Project")
1825 else:
1826 cap = self.tr("Run Script")
1827 dlg = StartDialog(
1828 cap, self.lastUsedVenvName, self.argvHistory, self.wdHistory,
1829 self.envHistory, self.exceptions, self.ui, 1,
1830 autoClearShell=self.autoClearShell,
1831 autoFork=self.forkAutomatically,
1832 forkChild=self.forkIntoChild)
1833 if dlg.exec_() == QDialog.Accepted:
1834 (lastUsedVenvName, argv, wd, env, exceptions, clearShell,
1835 console) = dlg.getData()
1836 forkAutomatically, forkIntoChild = dlg.getRunData()
1837
1838 if runProject:
1839 fn = self.project.getMainScript(True)
1840 if fn is None:
1841 E5MessageBox.critical(
1842 self.ui,
1843 self.tr("Run Project"),
1844 self.tr(
1845 "There is no main script defined for the"
1846 " current project. Aborting"))
1847 return
1848
1849 if Preferences.getDebugger("Autosave") and \
1850 not self.project.saveAllScripts(reportSyntaxErrors=True):
1851 doNotStart = True
1852
1853 # save the info for later use
1854 self.project.setDbgInfo(
1855 lastUsedVenvName, argv, wd, env, exceptions, self.excList,
1856 self.excIgnoreList, clearShell)
1857
1858 self.lastStartAction = 4
1859 self.clientType = self.project.getProjectLanguage()
1860 else:
1861 editor = self.viewmanager.activeWindow()
1862 if editor is None:
1863 return
1864
1865 if not self.viewmanager.checkDirty(
1866 editor,
1867 Preferences.getDebugger("Autosave")) or \
1868 editor.getFileName() is None:
1869 return
1870
1871 fn = editor.getFileName()
1872 self.lastStartAction = 3
1873 self.clientType = editor.determineFileType()
1874
1875 # save the filename for use by the restart method
1876 self.lastDebuggedFile = fn
1877 self.restartAct.setEnabled(True)
1878
1879 # save the most recently used virtual environment
1880 self.lastUsedVenvName = lastUsedVenvName
1881
1882 # This moves any previous occurrence of these arguments to the head
1883 # of the list.
1884 self.setArgvHistory(argv)
1885 self.setWdHistory(wd)
1886 self.setEnvHistory(env)
1887
1888 # Save the exception flags
1889 self.exceptions = exceptions
1890
1891 # Save the clear interpreter flag
1892 self.autoClearShell = clearShell
1893
1894 # Save the run in console flag
1895 self.runInConsole = console
1896
1897 # Save the forking flags
1898 self.forkAutomatically = forkAutomatically
1899 self.forkIntoChild = forkIntoChild
1900
1901 # Hide all error highlights
1902 self.viewmanager.unhighlight()
1903
1904 if not doNotStart:
1905 if runProject and self.project.getProjectType() in [
1906 "E6Plugin"]:
1907 argv = '--plugin="{0}" {1}'.format(fn, argv)
1908 fn = os.path.join(getConfig('ericDir'), "eric6.py")
1909
1910 self.debugViewer.initCallStackViewer(runProject)
1911
1912 # Ask the client to open the new program.
1913 self.debugServer.remoteRun(
1914 lastUsedVenvName, fn, argv, wd, env,
1915 autoClearShell=self.autoClearShell, forProject=runProject,
1916 runInConsole=console, autoFork=forkAutomatically,
1917 forkChild=forkIntoChild, clientType=self.clientType)
1918
1919 self.stopAct.setEnabled(True)
1920
1921 if dlg.clearHistories():
1922 self.setArgvHistory("", clearHistories=True)
1923 self.setWdHistory("", clearHistories=True)
1924 self.setEnvHistory("", clearHistories=True)
1925 elif dlg.historiesModified():
1926 argvHistory, wdHistory, envHistory = dlg.getHistories()
1927 self.setArgvHistory("", history=argvHistory)
1928 self.setWdHistory("", history=wdHistory)
1929 self.setEnvHistory("", history=envHistory)
1930
1931 def __debugScript(self):
1932 """
1933 Private slot to handle the debug script action.
1934 """
1935 self.__doDebug(False)
1936
1937 def __debugProject(self):
1938 """
1939 Private slot to handle the debug project action.
1940 """
1941 self.__compileChangedProjectFiles()
1942 self.__doDebug(True)
1943
1944 def __doDebug(self, debugProject):
1945 """
1946 Private method to handle the debug actions.
1947
1948 @param debugProject flag indicating debugging the current project
1949 (True) or script (False)
1950 """
1951 from .StartDialog import StartDialog
1952
1953 self.__resetUI()
1954 doNotStart = False
1955
1956 # Get the command line arguments, the working directory and the
1957 # exception reporting flag.
1958 if debugProject:
1959 cap = self.tr("Debug Project")
1960 else:
1961 cap = self.tr("Debug Script")
1962 dlg = StartDialog(
1963 cap, self.lastUsedVenvName, self.argvHistory, self.wdHistory,
1964 self.envHistory, self.exceptions, self.ui, 0,
1965 tracePython=self.tracePython, autoClearShell=self.autoClearShell,
1966 autoContinue=self.autoContinue, autoFork=self.forkAutomatically,
1967 forkChild=self.forkIntoChild)
1968 if dlg.exec_() == QDialog.Accepted:
1969 (lastUsedVenvName, argv, wd, env, exceptions, clearShell,
1970 console) = dlg.getData()
1971 tracePython, autoContinue, forkAutomatically, forkIntoChild = \
1972 dlg.getDebugData()
1973
1974 if debugProject:
1975 fn = self.project.getMainScript(True)
1976 if fn is None:
1977 E5MessageBox.critical(
1978 self.ui,
1979 self.tr("Debug Project"),
1980 self.tr(
1981 "There is no main script defined for the"
1982 " current project. No debugging possible."))
1983 return
1984
1985 if Preferences.getDebugger("Autosave") and \
1986 not self.project.saveAllScripts(reportSyntaxErrors=True):
1987 doNotStart = True
1988
1989 # save the info for later use
1990 self.project.setDbgInfo(
1991 lastUsedVenvName, argv, wd, env, exceptions, self.excList,
1992 self.excIgnoreList, clearShell, tracePython=tracePython,
1993 autoContinue=self.autoContinue)
1994
1995 self.lastStartAction = 2
1996 self.clientType = self.project.getProjectLanguage()
1997 else:
1998 editor = self.viewmanager.activeWindow()
1999 if editor is None:
2000 return
2001
2002 if not self.viewmanager.checkDirty(
2003 editor,
2004 Preferences.getDebugger("Autosave")) or \
2005 editor.getFileName() is None:
2006 return
2007
2008 fn = editor.getFileName()
2009 self.lastStartAction = 1
2010 self.clientType = editor.determineFileType()
2011
2012 # save the filename for use by the restart method
2013 self.lastDebuggedFile = fn
2014 self.restartAct.setEnabled(True)
2015
2016 # save the most recently used virtual environment
2017 self.lastUsedVenvName = lastUsedVenvName
2018
2019 # This moves any previous occurrence of these arguments to the head
2020 # of the list.
2021 self.setArgvHistory(argv)
2022 self.setWdHistory(wd)
2023 self.setEnvHistory(env)
2024
2025 # Save the exception flags
2026 self.exceptions = exceptions
2027
2028 # Save the tracePython flag
2029 self.tracePython = tracePython
2030
2031 # Save the clear interpreter flag
2032 self.autoClearShell = clearShell
2033
2034 # Save the run in console flag
2035 self.runInConsole = console
2036
2037 # Save the auto continue flag
2038 self.autoContinue = autoContinue
2039
2040 # Save the forking flags
2041 self.forkAutomatically = forkAutomatically
2042 self.forkIntoChild = forkIntoChild
2043
2044 # Hide all error highlights
2045 self.viewmanager.unhighlight()
2046
2047 if not doNotStart:
2048 if debugProject and self.project.getProjectType() in [
2049 "E6Plugin"]:
2050 argv = '--plugin="{0}" {1}'.format(fn, argv)
2051 fn = os.path.join(getConfig('ericDir'), "eric6.py")
2052 tracePython = True # override flag because it must be true
2053
2054 self.debugViewer.initCallStackViewer(debugProject)
2055
2056 # Ask the client to send call trace info
2057 enableCallTrace = self.debugViewer.isCallTraceEnabled()
2058 self.debugViewer.clearCallTrace()
2059 self.debugViewer.setCallTraceToProjectMode(debugProject)
2060
2061 # Ask the client to open the new program.
2062 self.debugServer.remoteLoad(
2063 lastUsedVenvName, fn, argv, wd, env,
2064 autoClearShell=self.autoClearShell,
2065 tracePython=tracePython,
2066 autoContinue=autoContinue, forProject=debugProject,
2067 runInConsole=console, autoFork=forkAutomatically,
2068 forkChild=forkIntoChild, clientType=self.clientType,
2069 enableCallTrace=enableCallTrace)
2070
2071 if self.debugServer.isClientProcessUp() and \
2072 self.debugServer.getClientType() == self.clientType:
2073 # Signal that we have started a debugging session
2074 self.debuggingStarted.emit(fn)
2075
2076 self.stopAct.setEnabled(True)
2077
2078 if dlg.clearHistories():
2079 self.setArgvHistory("", clearHistories=True)
2080 self.setWdHistory("", clearHistories=True)
2081 self.setEnvHistory("", clearHistories=True)
2082 elif dlg.historiesModified():
2083 argvHistory, wdHistory, envHistory = dlg.getHistories()
2084 self.setArgvHistory("", history=argvHistory)
2085 self.setWdHistory("", history=wdHistory)
2086 self.setEnvHistory("", history=envHistory)
2087
2088 def __doRestart(self):
2089 """
2090 Private slot to handle the restart action to restart the last
2091 debugged file.
2092 """
2093 self.__resetUI()
2094 doNotStart = False
2095
2096 # first save any changes
2097 if self.lastStartAction in [1, 3, 5, 7, 9]:
2098 editor = self.viewmanager.getOpenEditor(self.lastDebuggedFile)
2099 if editor and \
2100 not self.viewmanager.checkDirty(
2101 editor, Preferences.getDebugger("Autosave")):
2102 return
2103 forProject = False
2104 elif self.lastStartAction in [2, 4, 6, 8, 10]:
2105 if Preferences.getDebugger("Autosave") and \
2106 not self.project.saveAllScripts(reportSyntaxErrors=True):
2107 doNotStart = True
2108 self.__compileChangedProjectFiles()
2109 forProject = True
2110 else:
2111 return # should not happen
2112
2113 # get the saved stuff
2114 venvName = self.lastUsedVenvName
2115 wd = self.wdHistory[0]
2116 argv = self.argvHistory[0]
2117 fn = self.lastDebuggedFile
2118 env = self.envHistory[0]
2119
2120 # Hide all error highlights
2121 self.viewmanager.unhighlight()
2122
2123 if not doNotStart:
2124 if forProject and self.project.getProjectType() in [
2125 "E6Plugin"]:
2126 argv = '--plugin="{0}" {1}'.format(fn, argv)
2127 fn = os.path.join(getConfig('ericDir'), "eric6.py")
2128
2129 self.debugViewer.initCallStackViewer(forProject)
2130
2131 if self.lastStartAction in [1, 2]:
2132 # Ask the client to send call trace info
2133 enableCallTrace = self.debugViewer.isCallTraceEnabled()
2134 self.debugViewer.clearCallTrace()
2135 self.debugViewer.setCallTraceToProjectMode(forProject)
2136
2137 # Ask the client to debug the new program.
2138 self.debugServer.remoteLoad(
2139 venvName, fn, argv, wd, env,
2140 autoClearShell=self.autoClearShell,
2141 tracePython=self.tracePython,
2142 autoContinue=self.autoContinue,
2143 forProject=forProject,
2144 runInConsole=self.runInConsole,
2145 autoFork=self.forkAutomatically,
2146 forkChild=self.forkIntoChild,
2147 clientType=self.clientType,
2148 enableCallTrace=enableCallTrace)
2149
2150 # Signal that we have started a debugging session
2151 self.debuggingStarted.emit(fn)
2152
2153 elif self.lastStartAction in [3, 4]:
2154 # Ask the client to run the new program.
2155 self.debugServer.remoteRun(
2156 venvName, fn, argv, wd, env,
2157 autoClearShell=self.autoClearShell,
2158 forProject=forProject,
2159 runInConsole=self.runInConsole,
2160 autoFork=self.forkAutomatically,
2161 forkChild=self.forkIntoChild,
2162 clientType=self.clientType)
2163
2164 elif self.lastStartAction in [5, 6]:
2165 # Ask the client to coverage run the new program.
2166 self.debugServer.remoteCoverage(
2167 venvName, fn, argv, wd, env,
2168 autoClearShell=self.autoClearShell,
2169 erase=self.eraseCoverage,
2170 forProject=forProject,
2171 runInConsole=self.runInConsole,
2172 clientType=self.clientType)
2173
2174 elif self.lastStartAction in [7, 8]:
2175 # Ask the client to profile run the new program.
2176 self.debugServer.remoteProfile(
2177 venvName, fn, argv, wd, env,
2178 autoClearShell=self.autoClearShell,
2179 erase=self.eraseTimings,
2180 forProject=forProject,
2181 runInConsole=self.runInConsole,
2182 clientType=self.clientType)
2183
2184 self.stopAct.setEnabled(True)
2185
2186 def __stopScript(self):
2187 """
2188 Private slot to stop the running script.
2189 """
2190 self.debugServer.startClient(False)
2191
2192 def __passiveDebugStarted(self, fn, exc):
2193 """
2194 Private slot to handle a passive debug session start.
2195
2196 @param fn filename of the debugged script
2197 @param exc flag to enable exception reporting of the IDE (boolean)
2198 """
2199 # Hide all error highlights
2200 self.viewmanager.unhighlight()
2201
2202 # Set filename of script being debugged
2203 self.ui.currentProg = fn
2204
2205 # Set exception reporting
2206 self.setExceptionReporting(exc)
2207
2208 # Signal that we have started a debugging session
2209 self.debuggingStarted.emit(fn)
2210
2211 # Initialize the call stack viewer
2212 self.debugViewer.initCallStackViewer(False)
2213
2214 def __continue(self):
2215 """
2216 Private method to handle the Continue action.
2217 """
2218 self.lastAction = 0
2219 self.__enterRemote()
2220 self.debugServer.remoteContinue()
2221
2222 def __specialContinue(self):
2223 """
2224 Private method to handle the Special Continue action.
2225 """
2226 self.lastAction = 2
2227 self.__enterRemote()
2228 self.debugServer.remoteContinue(1)
2229
2230 def __step(self):
2231 """
2232 Private method to handle the Step action.
2233 """
2234 self.lastAction = 1
2235 self.__enterRemote()
2236 self.debugServer.remoteStep()
2237
2238 def __stepOver(self):
2239 """
2240 Private method to handle the Step Over action.
2241 """
2242 self.lastAction = 2
2243 self.__enterRemote()
2244 self.debugServer.remoteStepOver()
2245
2246 def __stepOut(self):
2247 """
2248 Private method to handle the Step Out action.
2249 """
2250 self.lastAction = 3
2251 self.__enterRemote()
2252 self.debugServer.remoteStepOut()
2253
2254 def __stepQuit(self):
2255 """
2256 Private method to handle the Step Quit action.
2257 """
2258 self.lastAction = 4
2259 self.__enterRemote()
2260 self.debugServer.remoteStepQuit()
2261 self.__resetUI()
2262
2263 def __runToCursor(self):
2264 """
2265 Private method to handle the Run to Cursor action.
2266 """
2267 self.lastAction = 0
2268 aw = self.viewmanager.activeWindow()
2269 line = aw.getCursorPosition()[0] + 1
2270 self.__enterRemote()
2271 self.debugServer.remoteBreakpoint(
2272 aw.getFileName(), line, 1, None, 1)
2273 self.debugServer.remoteContinue()
2274
2275 def __moveInstructionPointer(self):
2276 """
2277 Private method to move the instruction pointer to a different line.
2278 """
2279 self.lastAction = 0
2280 aw = self.viewmanager.activeWindow()
2281 line = aw.getCursorPosition()[0] + 1
2282 self.debugServer.remoteMoveIP(line)
2283
2284 def __enterRemote(self):
2285 """
2286 Private method to update the user interface.
2287
2288 This method is called just prior to executing some of
2289 the program being debugged.
2290 """
2291 # Disable further debug commands from the user.
2292 self.debugActGrp.setEnabled(False)
2293
2294 self.viewmanager.unhighlight(True)
2295
2296 def getActions(self):
2297 """
2298 Public method to get a list of all actions.
2299
2300 @return list of all actions (list of E5Action)
2301 """
2302 return self.actions[:]

eric ide

mercurial