202 (self canCreateOrToggleBreakpointAtLine:nil) ifFalse:[ |
202 (self canCreateOrToggleBreakpointAtLine:nil) ifFalse:[ |
203 ((topView := codeView topView) class == DebugView) ifTrue:[ |
203 ((topView := codeView topView) class == DebugView) ifTrue:[ |
204 self hasBreakpoints ifFalse:[ |
204 self hasBreakpoints ifFalse:[ |
205 ^ 'Sorry - cannot add breakpoint in the debugger (would need recompilation)\(can only add breakpoints if stopped at a method breakpoint)' withCRs |
205 ^ 'Sorry - cannot add breakpoint in the debugger (would need recompilation)\(can only add breakpoints if stopped at a method breakpoint)' withCRs |
206 ]. |
206 ]. |
207 ^ 'Click to toggle existing breakpoint. Shift-Click to toggle tracepoint.\Sorry - cannot add new breakpoint if method is already entered\(i.e. if not stopped at a method breakpoint).' withCRs |
207 ^ 'Sorry - cannot add new breakpoint if method is already entered\(i.e. if not stopped at a breakpoint).' withCRs |
208 ]. |
208 ]. |
209 ^ 'Cannot add breakpoint when modified. Please accept first.' |
209 ^ 'Cannot add breakpoint when modified. Please accept first.' |
210 ]. |
210 ]. |
211 |
211 |
212 ^ 'Click to toggle breakpoint. Shift-Click to toggle tracepoint.' |
212 ^ 'Click to toggle breakpoint. Shift-Click to toggle tracepoint.' |
361 "Modified: / 18-07-2012 / 10:53:22 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
361 "Modified: / 18-07-2012 / 10:53:22 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
362 "Modified: / 22-07-2013 / 16:00:13 / cg" |
362 "Modified: / 22-07-2013 / 16:00:13 / cg" |
363 ! |
363 ! |
364 |
364 |
365 setOrToggleBreakpointAtLine:line |
365 setOrToggleBreakpointAtLine:line |
366 |pos bpnt prepareFullBreakSupport mClass| |
366 |pos bpnt prepareFullBreakSupport mClass ok| |
367 |
367 |
368 "/ if true, setting a single breakpoint in a method will create |
368 "/ if true, setting a single breakpoint in a method will create |
369 "/ a whole set of invisible (and disabled) breakpoints in that method, |
369 "/ a whole set of invisible (and disabled) breakpoints in that method, |
370 "/ one for each line. |
370 "/ one for each line. |
371 "/ These can later be enabled in the debugger |
371 "/ These can later be enabled in the debugger |
386 ^ self |
386 ^ self |
387 ]. |
387 ]. |
388 |
388 |
389 bpnt := self breakpointAtLine:line. |
389 bpnt := self breakpointAtLine:line. |
390 bpnt isNil ifTrue:[ |
390 bpnt isNil ifTrue:[ |
391 "/ no breakpoint there - add as required |
391 "/ no breakpoint there - create a new one as required (i.e. recompile) |
392 (self canCreateOrToggleBreakpointAtLine:line) ifTrue:[ |
392 ok := (self canCreateOrToggleBreakpointAtLine:line). |
|
393 ok ifFalse:[ |
|
394 codeView topView class == DebugView ifTrue:[ |
|
395 (Dialog |
|
396 confirm:'Sorry, in an active method, I can only add new breakpoints in an already breakpointed method. |
|
397 (i.e. a method stopped at a method breakpoint or one which already has statement breakpoints) |
|
398 The reason is that the method needs to be recompiled for the breakpoint, which would not affect the method being currently executed. |
|
399 |
|
400 You can proceed to set the breakpoint, but it will only affect the next call into this method, not the current invocation.' |
|
401 yesLabel:'Set Breakpoint for Next Call' noLabel:'Ok') ifTrue:[ |
|
402 self halt. |
|
403 ok := true. |
|
404 ] |
|
405 ] ifFalse:[ |
|
406 Dialog warn:'Sorry, cannot add a new breakpoint here.'. |
|
407 ]. |
|
408 ]. |
|
409 ok ifTrue:[ |
393 prepareFullBreakSupport ifTrue:[ |
410 prepareFullBreakSupport ifTrue:[ |
394 "/ add a (disabled) breakpoint for every source line. This |
411 "/ add a (disabled) breakpoint for every source line. This |
395 "/ allows for breakpoints to be enabled/disabled in the debugger... |
412 "/ allows for breakpoints to be enabled/disabled in the debugger... |
396 1 to:textView numberOfLines do:[:eachLine | |
413 1 to:textView numberOfLines do:[:eachLine | |
397 |oldBPnt eachPos otherBpnt| |
414 |oldBPnt eachPos otherBpnt| |
415 Display shiftDown ifTrue:[ |
432 Display shiftDown ifTrue:[ |
416 "/ trace |
433 "/ trace |
417 bpnt beTracepoint |
434 bpnt beTracepoint |
418 ]. |
435 ]. |
419 self assert: breakpoints notEmptyOrNil. |
436 self assert: breakpoints notEmptyOrNil. |
|
437 |
|
438 "/ recompile the method with breakpoints |
420 self recompile. |
439 self recompile. |
421 ] ifFalse:[ |
|
422 codeView topView class == DebugView ifTrue:[ |
|
423 Dialog warn:'Sorry, in an active method, I can only add new breakpoints in an already breakpointed method. |
|
424 (i.e. a method stopped at a method breakpoint or one which already has statement breakpoints) |
|
425 The reason is that the method needs to be recompiled for the breakpoint, which would not affect the method being currently executed.'. |
|
426 "/ Dialog warn:'Sorry, can only add a new breakpoint in a wrapped method which has not yet started.'. |
|
427 ] ifFalse:[ |
|
428 Dialog warn:'Sorry, cannot add a new breakpoint here.'. |
|
429 ]. |
|
430 ] |
440 ] |
431 ] ifFalse:[ |
441 ] ifFalse:[ |
432 "/ breakpoint already there - just enable/disable |
442 "/ breakpoint already there - just enable/disable |
433 Display shiftDown ifTrue:[ |
443 Display shiftDown ifTrue:[ |
434 bpnt toggleTracing |
444 bpnt toggleTracing |
437 ]. |
447 ]. |
438 (mClass := currentMethod mclass) isNil ifTrue:[ |
448 (mClass := currentMethod mclass) isNil ifTrue:[ |
439 "/ hack: ouch - was wrapped in the meantime; |
449 "/ hack: ouch - was wrapped in the meantime; |
440 "/ hurry up and update. Should be done elsewhere (in codeView) |
450 "/ hurry up and update. Should be done elsewhere (in codeView) |
441 self updateCurrentMethod. |
451 self updateCurrentMethod. |
442 mClass := currentMethod mclass. |
452 currentMethod notNil ifTrue:[ mClass := currentMethod mclass ]. |
443 ]. |
453 ]. |
444 mClass notNil ifTrue:[ |
454 mClass notNil ifTrue:[ |
445 Smalltalk changed:#methodTrap with:(MethodTrapChangeNotificationParameter changeClass:mClass changeSelector:currentMethod selector). |
455 Smalltalk changed:#methodTrap with:(MethodTrapChangeNotificationParameter changeClass:mClass changeSelector:currentMethod selector). |
446 ]. |
456 ]. |
447 ]. |
457 ]. |
448 |
458 |
449 gutterView redrawLine:line. |
459 gutterView redrawLine:line. |
450 |
460 |
451 "Created: / 17-06-2011 / 13:45:22 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
461 "Created: / 17-06-2011 / 13:45:22 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
452 "Modified: / 27-07-2011 / 13:27:55 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
462 "Modified: / 27-07-2011 / 13:27:55 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
453 "Modified: / 22-07-2013 / 13:33:18 / cg" |
463 "Modified: / 28-08-2013 / 14:45:36 / cg" |
454 ! ! |
464 ! ! |
455 |
465 |
456 !BreakpointService methodsFor:'queries'! |
466 !BreakpointService methodsFor:'queries'! |
457 |
467 |
458 canCreateOrToggleBreakpointAtLine:lineOrNilForAnywhere |
468 canCreateOrToggleBreakpointAtLine:lineOrNilForAnywhere |
|
469 "is it possible to place a breakpoint here and now?" |
|
470 |
459 |bpnt topView| |
471 |bpnt topView| |
460 |
472 |
461 textView reallyModified ifTrue:[ |
473 textView reallyModified ifTrue:[ |
|
474 "/ this is not really true - we could keep track of where the breakpoints |
|
475 "/ are while editing and shift them as required. |
|
476 "/ (another idea worth a try would be |
|
477 "/ to match the original parsetree (enumerating nodes with the breakpoints) |
|
478 "/ against the new parsetree (walking in sync?) when finally compiling, |
|
479 "/ and placing new breakpoints on matching tree nodes. |
|
480 "/ (too much work, for a quick solution, I guess) |
462 ^ false |
481 ^ false |
463 ]. |
482 ]. |
|
483 |
464 "/ can always toggle existing breakpoints... |
484 "/ can always toggle existing breakpoints... |
465 lineOrNilForAnywhere notNil ifTrue:[ |
485 lineOrNilForAnywhere notNil ifTrue:[ |
466 bpnt := self breakpointAtLine:lineOrNilForAnywhere. |
486 bpnt := self breakpointAtLine:lineOrNilForAnywhere. |
467 bpnt notNil ifTrue:[ |
487 bpnt notNil ifTrue:[ |
468 ^ true. |
488 ^ true. |
469 ] |
489 ] |
470 ]. |
490 ] ifFalse:[ |
471 |
491 (currentMethod notNil and:[currentMethod isMethodWithBreakpoints]) ifTrue:[ |
|
492 ^ true. |
|
493 ] |
|
494 ]. |
|
495 |
|
496 "/ ok, the method has no breakpoints yet. |
|
497 |
|
498 "/ this is a bad hack - looking into the debugger's state here. |
|
499 "/ I guess, we have to move code around a bit... |
472 ((topView := codeView topView) class == DebugView) ifTrue:[ |
500 ((topView := codeView topView) class == DebugView) ifTrue:[ |
473 "/ can only create new breakpoints in the debugger, |
501 "/ can only create new breakpoints in the debugger, |
474 "/ iff we are in a wrapped method's prolog |
502 "/ iff we are in a wrapped method's prolog |
475 topView selectedContextIsWrapped ifTrue:[ |
503 topView selectedContextIsWrapped ifTrue:[ |
476 topView selectedContext lineNumber == 1 ifTrue:[ |
504 topView selectedContext lineNumber == 1 ifTrue:[ |
477 ^ true |
505 ^ true |
478 ]. |
506 ]. |
479 ]. |
507 ]. |
|
508 |
|
509 "/ well, if the debugger's code has already been modified, |
|
510 "/ we will accept the new code anyway. So there's no problem in adding |
|
511 "/ a breakpoint on the fly... |
|
512 topView showingAlreadyModifiedCode ifTrue:[^ true]. |
480 ^ false. |
513 ^ false. |
481 ]. |
514 ]. |
|
515 |
|
516 "/ in a non-debugger, we can do it. |
482 ^ true. |
517 ^ true. |
483 ! |
518 ! |
484 |
519 |
485 hasBreakpoints |
520 hasBreakpoints |
486 ^ breakpoints notEmptyOrNil |
521 ^ breakpoints notEmptyOrNil |