Friday, November 29, 2013

Making Thor Even More Useful

I’ve been using Thor since day one. In case you haven’t heard of it, Thor is the most crazily–useful tool ever invented for VFP developers. Created by a few developers (mostly Jim Nelson) and available as a VFPX project, Thor is described as “a tool for managing add-on tools in the IDE, managing menus and hot key assignments for IDE Tools.” While that’s true, it’s the wide array of add-ons for Thor that makes it the incredible productivity booster it is.

One tool I use a dozen times a day is one originally created by Andy Kramek and Marcia Akins that adds a variable name to the LOCAL statement if it isn’t already there. The cool thing about this tool is that it picks up the variable name from the text where the cursor is located. So, I can type something like “lcMyVariable”, hit Alt-6 (the hotkey I assigned to the tool in Thor), and voila: lcMyVariable is added to the LOCAL statement. No more scrolling to the top of the code, manually adding the variable name, then scrolling back down to where I was (or more likely, forgetting to add it to LOCAL so now it’s a PRIVATE variable by default). Even more interesting is that Andy and Marcia didn’t create this tool for Thor. Instead, I simply took their code and added a little wrapper to it so it’s now a Thor tool.

One tool I knew Thor has had for a while is called Create LOCALs. It’s similar to Andy and Marcia’s tool except it goes through an entire block of code, finds all variables, and adds them all to the LOCAL statement. I thought this would be a cool tool but when I tried it, one thing it did was a deal-breaker for me: it sorts the variables alphabetically rather than listing them in the order they’re first used. I know some of you are probably thinking, “Wow, how anally retentive do you have to be to care about the order variables are listed in”, and the answer is “You know how anal I am if you’ve ever seen my code”. However, it turns out that there’s a practical reason why variables should be listed in the order used: in an error log created with LIST MEMORY, variables appear in the order declared, which can be very useful in determining where in a routine an error occurred. (To learn how to do that, you’ll have to come to Southwest Fox next year and attend my “Fix Problems Fast with Advanced Error Handling and Instrumentation Techniques” session.) So, I continued to use the “one variable at a time” tool.

Earlier this month, I sat in on Tamar Granor’s Make Thor Your Own session. In this session, she explained how to create your own Thor tools and work with plugins for existing tools. She used the Create LOCALs tool as an example, showing how its behavior is controlled with a plugin and how she modified the plugin to work the way she wanted. That turned on a light bulb for me; maybe I could do something similar so that tool would work the way I want.

This turned out to be incredibly easy to do. First, I opened the Thor Configuration utility by choosing Configure from the Thor menu. I selected the Tool Definitions page and chose the Create LOCALs tool, then clicked the Plug-Ins link:


The Manage Plug-in PRGs dialog appeared:


I clicked Create to create PEME_CreateLocalsStatements.PRG in the Thor\Tools\My Tools folder of the directory where Thor is installed. This is my copy of the plugin code for the Create LOCALs tool that supersedes the one that comes with Thor. Looking over the code, I quickly found this:

Asort (laLocals, 1, -1, 0, 0)

Commenting out that line was all that was needed to make this tool work the way I want. However, it occurred to me that perhaps the tool would be more useful generically if sorting was user-configurable. Another thing Tamar showed in her session was how some tools have an options page and how to create your own.

To see the options for this tool, click the Options link when Create LOCALs is selected in the Tool Definitions page or select the Options page and choose Create Locals:


As you can see, Create LOCALs already has a few options that configure the behavior of the tool, but not one for sorting. After a bit of digging, I found that the options for the tool are defined in the clsCreateLocals class in Thor_Options_Createlocals.VCX in the Thor\Tools\Procs folder. It turns out if you copy the VCX and VCT files to the My Tools folder, Thor uses that copy rather than the original. So, it was a simple matter to modify that class and add a “Sort variables alphabetically” checkbox.


I put the following code into the Init method of the checkbox to retrieve the existing value of the option, which defaults to true the first time:

llValue = execscript(_screen.cThorDispatcher, 'Get Option=', 'lSort', ;
This.Value = nvl(llValue, .T.)

The InteractiveChange method saves the setting:

execscript(_screen.cThorDispatcher, 'Set Option=', 'lSort', ;
    'CreateLocalStatement', This.Value)

Because I used a BaseCheckbox from the same VCX as the class for the checkbox, and the Refresh method of that class expects the cControlSource property to be filled in, which it isn’t here, I added a comment to that method in the checkbox to override the default behavior.

I then made this change in PEME_CreateLocalsStatements.PRG:

*** DH 11/29/2013: don't sort variables unless we're supposed to
*Asort (laLocals, 1, -1, 0, 0)
llSort = nvl(execscript(_screen.cThorDispatcher, 'Get Option=', ;
    'lSort', 'CreateLocalStatement'), .T.)
if llSort
    Asort (laLocals, 1, -1, 0, 0)
endif llSort

Now variables are only sorted if the “Sort variables alphabetically” option is turned on.

As you can see in the first screen shot above, I defined Alt-9 as the hotkey for the Create LOCALs tool. So now, I don’t have to worry about creating local variables as I type code. I just press Alt-9 before I close the editor window and like magic, all the variables appear in the LOCAL statement at the top of the code. This saves me even more time that before.

If you haven’t started exploring Thor, I strongly suggest you do so. Its rich set of tools are guaranteed to have something that will increase your productivity.