Serious First Steps In UserTalk Scripting
Prev | Table Of Contents | Next


10. Running, Debugging, and Getting Help

We are almost ready to put our knowledge to work for us, developing a serious and useful UserTalk program. But before we do this, we should know how to enlarge our knowledge independently of this tutorial. Clearly a tutorial like this can't come close to covering every UserTalk verb; so how will you know, as you develop your own programs, what verbs exist and what can be done with them? Also, in this chapter we will say something about working with scripts in general, since they have a number of features we have not yet studied explicitly.

The primary reference source for information about built-in UserTalk keywords and verbs remains DocServer, which comes with Frontier. Unfortunately, DocServer has not always been kept up to date (some important verbs aren't described in DocServer at all). But it is still a definitive compendium, explaining what each parameter of a verb needs to be, and often giving valuable examples and warnings. Most important, DocServer is driven by Frontier in a way that makes it easy to get to a verb's DocServer documentation quickly.

There are two ways to leap to a verb's DocServer page from Frontier. One is to hit command-= (or choose Main: DocServer), which brings up a dialog into which you can type a verb name. The other, even more convenient, is by way of the mechanism implemented at system.misc.control2click; if you can see the name of a verb (for example, in a script), you just control-double-click on the name and the DocServer page appears before you. Or, if you control-option-double-click the name of a verb, Frontier fetches the names of its parameters from DocServer and inserts them in the script right after the name.

However, DocServer has some limitations, of which the most significant is that it simply lists the verbs in what amounts to alphabetical order. This is great if you know the name of a verb in advance and want to know some details about it, but if you have in mind an action and want to know what verb you might use to make it happen, chasing around through DocServer can be very frustrating. To help with this problem, I've recently written ALittleHelp, a Frontier outline which provides a general reference arranged in how-to order.

There is also a large body of official Frontier documentation in the form of Web pages. These are somewhat oddly ordered, and in spots are incomplete or outdated, but they are also extremely useful. You can download the Web pages and read them from your hard disk with a browser; also, it's a good idea to grab a shareware utility such as UltraFind from the nets so that you can quickly search the Web pages (as textfiles). If you're persistent, you'll find that a great many of your questions are answered in the documentation.

Another important place to get information about UserTalk verbs is from the database itself - naturally enough, since a verb is a database entry. Again, there's a shortcut for finding out more about a database entry whose name you see in front of you: command-double-click the name of a database entry to jump to it. Looking directly in the database becomes more important when you're dealing with suites, whose verbs are not usually documented in DocServer. Suites not infrequently contain readme files and a table of examples that instruct you in their use. You can learn quite a bit, too, by browsing the database generally and just reading scripts, trying to understand them. For example, in the last chapter we saw that there's a utility routine in the database for creating an outline which maps the structure of a folder, and earlier we learned of a utility routine for writing a string to textfile; utility routines of this sort exemplify important techniques that provide the reader with valuable training.

Part of what helps you in studying a script is its use of comments which explain what it is doing. Use of comments is an art, but it is widely agreed among programmers that it is important to provide comments, both for others and for yourself, later, when you are trying to reconstruct why you wrote a program the way you did. In UserTalk, comments are of two types: either the whole line is a comment, or the line starts out as UserTalk code and then has a comment appended to it. To append a comment to a line of UserTalk, type option-backslash (the left guillemot or "chevron" character); this character and everything after it will be considered a comment. To make a whole line a comment, select the line or any text within it and hit command-backslash; this toggles the status of the line between comment and code. Or, when you create a new line, instead of hitting return, hit shift-return and the new line will be a comment. One of the advantages of having a whole line be a comment is that all lines in the bundle indented from it will also be comments, so a multi-line comment can be collapsed into one.

As you develop a program, you are sure to make mistakes, or to have areas of doubt where you're not sure the program is doing what you expect it to. One technique for dealing with this situation is to insert at key locations calls to verbs that display information, such as "msg" or the various dialog verbs, to give you an indication of what part of the program is executing at any given moment. But you can also watch the movement of the program in detailed slow-motion, and obtain information about the value of any variable at any given moment, by running the program in Debug mode.

To learn about Debug mode, let's use it with workspace.FileLister. Bring the workspace.FileLister window to the front and press the Debug button. The window enters Debug state, with a new set of buttons across the top; and the first executable line (the call to the FileLister handler, namely the last line of the script) is selected, ready to execute. (Lines are selected before they have actually executed.) Now, if you hit the Go button, the whole script will execute. Try it; the script executes to the end, and the window leaves Debug state. The Go button executes until the end of the script or until a line previously marked as a "breakpoint" is encountered. To mark a line as a breakpoint, command-click its triangle. You don't have to be in Debug mode to do this. Command-click on the triangle of the "fileloop" line: the triangle turns into a hand indicating that this is a place to stop. Press the Debug button and then the Go button; the script executes normally until it reaches the "fileloop" line, at which point it stops with that line selected.

We are now paused in the middle of executing our script. Any time you're stopped in a script in Debug mode, you can examine (and, if you wish, change) the value of local variables. There are several ways to do this, but the simplest is to select the name of the variable and then hit the Lookup button. Try this with the variable "whatFolder": select its name, perhaps by double-clicking the occurrence of its name in the "local" line where it is declared, and hit the Lookup button. A window opens that looks something like this:

compilerStack picture

This window comes from inside Frontier's compiler stack. What it actually shows is all the variables being tracked at this level of execution, which, as the title tells us, is level 2. Why is it level 2? Because level 1, the top level of our script, is simply the call to the FileLister handler; once we start performing that call and are inside the FileLister handler, we are a level deeper than previously. If you like, you can also look at the level 1 variables now; to do so, hit command-shift-Enter to bring up the window's parent, the stack table, and then double-click the level 1 stack entry to open and examine it. At first you may not understand everything you see in these stack windows, but you can see that the stuff in the level 2 window makes sense: the variable "whatFolder" has received the name of whatever folder you selected when the dialog came up, and the other variables have no values because at this point in the script nothing has happened to give them one.

Now do this: adjust the windows so you can see both the level 2 stack window and workspace.FileLister. Bring workspace.FileLister to the front and hit the Go button. At first, it seems nothing has happened; but look at the level 2 window and you'll see it has changed: "theFile" now has a value. When you pressed Go, the "fileloop" was executed once; thus, "theFile" was assigned its first file pathname, and this now appears in the compiler stack window. Press Go repeatedly to see "theFile" change until the routine ends; or, if you like, command-click the "fileloop" line to remove the breakpoint, and press Go to continue execution to the end of the routine. (Or, if you're sick of the whole thing, hit the Kill button to abort execution and leave Debug mode.) So now we've seen that you can use the compiler stack windows not only to examine variable values but also to watch them change as the script proceeds. (By the way, it does no harm to leave breakpoints in your scripts; they have no effect when the script is run in the ordinary way. Breakpoints are meaningful only when you're in Debug mode.)

The other main thing Debug mode is most frequently used for is to step one command at a time through the script. This is a little tricky because the Step button alone may not do what you want. Try it: enter Debug mode, remove any breakpoints you've previously set, and hit the Step button. The script appears to execute normally, right to the end. That's because the Step button moves to the next command at the same level, and there is no next command at this level; once we've performed the call to the FileLister handler, we're done. To step from the call to the FileLister handler to the first command within the FileLister handler, you have to use the In button. So try it: enter Debug mode, and hit the In button. Now you can repeatedly hit the Step button to watch the routine progress one command at a time. It gets a little boring when it starts going round and round the "fileloop", so you can hit Go if you've had enough.

You don't have to be right on a call to a handler or verb in order to use the In button. The rule is: the In button works like the Go button, except that as soon as we come to a command at a deeper level, we pause there; similarly, the Out button works like the Go button, except that we pause as soon as we come to a command at a shallower level.

When you first attempt to run a script, Frontier will catch any linguistic ("syntax") errors in your use of UserTalk before starting to execute, and will put up a dialog telling you if it finds one. You can then press the Go To button to cause a spot near the error to be selected, though in a few cases it can still be hard to find. Once your script is running, there can still be errors (called "run-time" errors); again, Frontier will stop and put up an error dialog, and at this point you can press the Go To button to see the line where the error occurred. You can also hold down the Go To button to get a popup menu showing you the stack of embedded handler calls; this can be helpful in complex situations for understanding what the program was up to when the error happened.

So much for debugging. Let's now review the chief ways in which UserTalk commands can be caused to execute. We're already familiar with two: open a script and press the Run button; and, call a script from another script. What others are there? Here are some of the main ones.

You can select a script as an entry in the table it lives in and choose Main: Run Selection (command-slash). This is the same as opening the script and hitting the Run button.

You can type (or paste) a command into the Quick Script window and hit the Run button. (The Quick Script window can be summoned with command-semicolon.) In the Quick Script window, you have left the realm of outlines, so you can't enter a multi-line script in the same way as you do an outline. To see this, go into workspace.FileLister, select the "fileloop" line, and hit Copy. Now go to Quick Script and Paste. Notice the transformation. The lineation and indentation here are just for ease of reading; what actually shows the structure of the lines is the use of curly braces and semicolons. The rule is that every indented bundle must have curly braces around it, and every command that doesn't have a curly brace after it must have a semicolon after it. Bear this in mind if you write scripts of any length in the Quick Script window.

By the way, nothing stops you from using the same braces-and-semicolon notation here and there in an outline. For example, it would be perfectly legal, and in some ways it is rather clearer, to rewrite FileLister like this:

    on fileLister ()
        local (whatFolder)
        if not file.getFolderDialog("Pick a folder to list:", @whatFolder) { return }
        new (outlineType, @workspace.FileOutline)
        target.set (@workspace.FileOutline)
        editMenu.setFont ("Geneva"); editMenu.setFontSize (9)
        local (theFile)
        fileloop (theFile in whatFolder, 1)
            op.insert(theFile, down)
            rollbeachball()
        edit (@workspace.FileOutline)
    fileLister ()

Finally, you can attach a script to a menu item and choose the menu item. This technique is particularly valuable for utility scripts that you write. The menubar is just a special kind of outline, and you are free to modify it; indeed, there is a menu with your initials which you are actually expected to modify. The quickest way is to option-choose a menu-item; this opens the menubar for editing. When any menu item is selected, you can see its script by hitting the Script button.

Where should you put scripts that you write? What I do is develop them in the workspace table, but then keep finished utility scripts in my people.man table (the name of yours will depend on what your initials are). If I want to access a utility script from a menu item, I make that item's script a simple call to the utility script; that way, later editing of the utility script is easier because I don't have to open the menubar.


Prev | Table Of Contents | Next
Text © Matt Neuburg 1997 ALL RIGHTS RESERVED
You can download a copy of this tutorial.
This Web document scripted with Frontier. Last build at 4/18/97; 10:48:51 PM.