J3STER
J3STER

Reputation: 1075

Change the way an object is displayed in debugger/inspector variable-value table

I would like to know if there is a message I can override in Pharo so that my custom classes display more descriptive information in the inspector/debuger much like simple variable types do, like Integers or Strings. For instance:

enter image description here

Instead of that, I would like it to show a more custom and informative description consisting of its internal variales so as to have a tighter/tidier view of the variables instead of having to click on it and open another chart (therefore losing sight of the information on the previous chart). I know you can increase the amount of charts shown below, but that is not the point of the question. I would like to achieve something like this:

enter image description here

I have browsed the pharo forums and found nothing, I have also tried overriding over 30 methods hoping that one of them changed the output. Only the class message seemed to change the output, but I could only return an instance of Metaclass and besides messing with this message would break a lot of stuff. Finally I tried to reverse engineer the debugger and then the inspector to see at which point is the table constructed and what values are used or which messages are sent to build said values, but it was just too much for me, the callstack kept growing and I couldn't even scratch the surface.

Upvotes: 3

Views: 244

Answers (3)

EstebanLM
EstebanLM

Reputation: 4357

Overriding printOn: will work for simple cases where you want to just change description.
Pharo allows a lot more than that!
Due the extensible (moldable) nature of our inspector, you do not need to override a method to get your own visualisation of the object.
For example, look this array visualisation:

inspector

This is obtained adding this method to Collection:

gtInspectorItemsIn: composite
    <gtInspectorPresentationOrder: 0>

    ^ composite fastList
        title: 'Items';
        display: [ self asOrderedCollection ];
        beMultiple;
        format: [ :each | GTObjectPrinter asTruncatedTextFrom: each ];
        send: [ :result | 
            result
                ifNil: [ nil ]
                ifNotNil: [ result size = 1
                        ifTrue: [ result anyOne ]
                        ifFalse: [ self species withAll: result ]
                    ]
            ]

if you browse for senders of gtInspectorPresentationOrder: you will see there are already a lot of special visualisations in the image.
You can take those as an example on how to create your own, adapted exactly to what you need :)

Upvotes: 3

Leandro Caniglia
Leandro Caniglia

Reputation: 14843

In Smalltalk, every time you observe something you don't like or understand, you ask the question: Which message is doing this?

In your case, the question would be: Which message creates the string a MyPoint that I see everywhere?

Next, to answer your question you need to find a good place for inserting a halt and then debug from there until you find the culprit. To do this just find the simplest expression that would reproduce the issue and debug it. In your case the right-click command in the Playground will do. So,

  1. Write and select (MyPoint on: 14 and: -5) halt in a Playground.
  2. Right-click and issue the Print it command (I'm assuming you already checked that this command produces the string 'a MyPoint').
  3. Debug
  4. Go over the evaluation of #DoIt, which answers the result
  5. Continue this way alternating between Into and Over to make sure you follow the result to where it's being taken
  6. Eventually you will reach the implementation of Object >> #printString. Bingo!

Now you can open a System Browser and take a look at this method, study how it's been implemented in different classes, etc. Your investigation should show you that the most basic message for printing is #printOn:. You may also want to take a look at other implementors so to better understand what people usually do. (Bear in mind that writing good #printOn:s is a minimalist art)

Upvotes: 4

melkyades
melkyades

Reputation: 1796

Luckily, doing this in any Smalltalk is very easy. Types inherited from Object are expected to answer to the message printString, and ultimately printOn: aStream. Those messages are expected to give a description of the object. So, you should just override printOn: in your class (printString uses printOn:) and all the browsers and inspectors will automatically use it. There other possibilities in Pharo, if you want to provide more complex information in different tabs, but I think printOn: will suffice for you.

An example would be:

MyPoint>>printOn: aStream
    aStream nextPut: ${.
    x printOn: aStream.
    aStream nextPutAll: ', '
    y printOn: aStream.
    aStream nextPut: $}

Upvotes: 5

Related Questions