Extending the debugger through moldable exceptions

In Glamorous Toolkit exceptions are moldable. They can define custom debugging views and actions shown in a domain-specific debugger tailored to that exception.

To achieve this, exception can define debugging views simply by defining normal inspector views and annotating them with the pragma gtExceptionView. When an exception defines one or more such views, a domain-specific debugger is enabled that directly shows those views.

For more details on how to configure the domain-specific debugger attached to an exception see Configuring moldable exceptions.

Exception with a debugging view

The exception GtExampleExceptionWithDebuggingView Exception subclass: #GtExampleExceptionWithDebuggingView instanceVariableNames: 'actualString expectedString' classVariableNames: '' package: 'GToolkit-Debugger-Examples' defines a view in that method #selector gtViewDiffFor: aView <gtView> <gtExceptionView> ^ aView forward title: 'Diff'; priority: 1; object: [ self computeDiff ]; view: #gtTextView:; actionButtonIcon: BrGlamorousVectorIcons inspect tooltip: 'Inspect the comparator' action: [ :aButton | aButton phlow spawnObject: self computeDiff ] that shows a comparison betwen an expected and an obtained value.

The debugging view is defined as a normal inspector view attached to the exception object. This means that we can see the view also when inspecting the exception object.

Whenever the exception is not handled, a new domain-specific debugger is enabled that shows the debugging view defined by this exception.

The normal debugger is also available. Above, there is a tab labeled "GT Debugger" that switches to the default debugger.

Exception with multiple debugging view

We are not limited to a single debugging view within an exception. Exceptions can define multiple debugging views. The exception GtExampleComparisonExceptionWithDebuggingViews Error subclass: #GtExampleComparisonExceptionWithDebuggingViews instanceVariableNames: 'expectedString actualString targetSelector targetClass' classVariableNames: '' package: 'GToolkit-Debugger-Examples' defines two debugging views, #selector gtViewDiffFor: aView <gtView> <gtExceptionView> <gtEmbeddedDebuggerView> ^ aView forward title: 'Diff'; priority: 1; object: [ GtDiffBuilder computeDifferencesFrom: expectedString to: actualString using: GtCharacterGroupDiffSplitter words ignoreWhitespace ]; view: #gtTextView:; actionButtonIcon: BrGlamorousVectorIcons inspect tooltip: 'Inspect the comparator' action: [ :aButton | aButton phlow spawnObject: aButton phlow firstParentWithView content phlow firstChildWithView phlow entity viewObject wait object ] and #selector gtViewChangeViewFor: aView <gtView> <gtExceptionView> ^ aView forward title: 'Changes'; priority: 1.5; object: [ GtDiffBuilder computeDifferencesFrom: expectedString to: actualString using: GtCharacterGroupDiffSplitter words ]; view: #gtChangeViewFor: .

Both these views are then shown when we encounter this exception, by using a tab widget.