<div dir="ltr">Hello folks!<br>I include some code to add an option to debug the action of <font face="monospace">MenuItemMorph</font>s and <font face="monospace">PluggableButtonMorph</font>s. See <a href="https://drive.google.com/file/d/1cVMwcMS56EgpYOiQg5MawVF6W_RaEzX3/view">demo video</a> and screenshot below:<div><br></div><div style="text-align:center"><img src="cid:ii_lox0ucvk0" alt="image.png" width="395" height="178" class="gmail-CToWUd gmail-a6T" tabindex="0" style="cursor: pointer; outline: 0px; margin-right: 0px;"><br></div><div>Cheers!<br>Facu.<br><br>PS: I leave additional details about the implementation, that could be useful during code-review 👇<br><br></div><div><hr style="color:rgb(0,0,0);font-family:"Times New Roman";font-size:medium"></div><div>📝 The changes include support for <font face="monospace">MenuItemMorph</font>s and <font face="monospace">PluggableButtonMorph</font>s (for convenience, in this email, I'll refer to both of them as "buttons").<br>It'd be nice to have a more general implementation¹, but I started only with those because I usually debug the actions of those kinds of morph types (manually, until now :P).<br><br>The way it's implemented is by opening a debugger on the morph's action, and making it go forward² until it reaches the appropriate method on the morph's target/model (see <font face="monospace">#debugAction</font>).<br>Notice that it also shows a confirmation message in case you try to debug —and therefore run— the action of a disabled button³.<br><br>To execute the button's action, I reused some code from <font face="monospace">PluggableButtonMorph>>#performAction</font> and <font face="monospace">MenuItemMorph>>#invokeWithEvent:</font>.<br>To do that, I extracted a couple of methods; I include here the reasons that motivated the way I chose to do it:<br><ol><li style="margin-left:15px">To be able to skip the check to see if the button was enabled or not, I had to extract the code that runs the action without making any precondition checks.</li><li style="margin-left:15px">In the case of <font face="monospace">MenuItemMorph</font><span style="font-family:monospace">>>#invokeWithEvent:</span>, the <font face="monospace">#numArgs</font> message is sent to the corresponding selector. During manual testing, I discovered that this caused the <font face="monospace">String>>#numArgs</font> method to run in the debugger (stepping through it as part of the mechanism mentioned before), and it was <i>very slow</i>. So, to avoid running that part of the code in the debugger, I extracted a method that does all the pre-processing and returns a block that's ready to run the action (<font face="monospace">MenuItemMorph>>#actionBlockForEvent:</font>). Then, I run <i>that</i> block on the debugger.</li><li style="margin-left:15px">The issue mentioned in point (2) did not happen for <font face="monospace">PluggableButtonMorph</font><span style="font-family:monospace">>>#performAction</span>. Nonetheless, I made a similar implementation, just for consistency's sake (<font face="monospace">PluggableButtonMorph>>#actionBlock</font>). The different name has to do with the different vocabulary used for the <font face="monospace">PluggableButtonMorph</font> vs. the <font face="monospace">MenuItemMorph</font>, and with the fact that the <font face="monospace">MenuItemMorph</font> needs an event parameter.</li><li style="margin-left:15px">As the <font face="monospace">MenuItemMorph</font> needs an event, we have to simulate it. I wasn't sure what was the best way to do it, so I'm currently passing <font face="monospace">nil</font>. While trying it out, I noticed that all of the menu items I tested the option with were <i>not</i> using the event object. At any rate, if there's some menu option that uses it, it'll fail with a "does not understand" error.</li></ol>Additionally, as a refactor, to be able to open the debugger on a block without doing anything else, I extracted the method <font face="monospace">Debugger class>>#openDebugging:label:</font> from <font face="monospace">Debugger class>>#openDebugging:to:label:</font>.</div><div>_____<br>¹ e.g. detecting the events supported by any morph and letting you simulate and debug the one of your choosing.<br>² i.e. "step into", by sending the #send message.<br>³ Since the action is not run by a normal interaction with the button, and if it's disabled maybe running the action could leave the system in an unexpected state. It does, though, let you debug the action if you really want to do it.</div></div>