Strange Eons

Script Debugger

Send Feedback      Home Page > Strange Eons > Miriam's Basement > Debugger

Contents

Enabling the Debugger
The Debugger Interface
An Example
Other Ways to Trigger Breakpoints
Notes and Suggestions

Starting with version 2.00.9, SE includes a built-in source-level debugger for script files. This is a tool that helps you solve problems in your script by stepping through them one line at a time. You can set breakpoints (lines where the normal execution of the script will be interrupted so you can start stepping through it), or set options that will cause breaks automatically when certain events occur. By entering watch expressions, you can monitor important variables in your script and observe how they change as the script runs.

You can also remotely debug a script by pointing a browser on the remote computer to the special URL. With most network setups, you can only debug scripts on other computers in the local network.

The new debugger replaces the old "Basic Debugger" plug-in. Interaction is through a Web interface: you point your Web browser at a special local URL, and click on links in the resulting Web page to issue debugging commands. The special local URL is actually serviced by a miniature Web server built into SE; it will perform the debugging commands that you choose, and then send your browser a Web page to inform you of the results.

Enabling the Debugger

Open the Preferences dialog and then check the Enable Debugger option under the Plug-in Scripts section. You will need to restart SE for this change to take effect. All scripts will run more slowly when debugging is enabled, because the debugging system has to observe each script while it runs.

Preferences dialog showing location of debugger option

When you start SE with debugging enabled, a control will appear either in the notification area ("tray") of your desktop or near the top of the main SE window. The location depends on your platform. It will display a URL that you can use to connect your web browser to the debugger. Note that you should open this page before you start debugging, because when a script is interrupted SE is effectively frozen (so opening the page using by clicking the icon won't work):

Debugger notification icon in Windows 7

Alternatively, if you choose Debug Script in the Quickscript window, the URL will be opened in your browser automatically and the debugger will start out interrupted at the start of your Quickscript  code.

The Debugger Interface

The debugger Web page is divided into four areas. At the top is the main command panel. Just beneath that is the source panel. On the bottom left is the watch expression panel, and on the bottom right is the stack panel. I'll describe each of these in turn.

Command Panel

This panel consists of rows of commands that can be issued to the debugger. The first row toggles on or off various conditions that will interrupt a running script, such as entering a leaving a function. The next row consists of the main debugging commands:

Refresh
Because the debugger interface is not continuously connected to the debugger, it does not always know when the script is interrupted. To get around this, the break, continue, and step commands insert a short delay before they return. If a new breakpoint is reached during this delay, then the debugger window will display the new breakpoint immediately. Once this timeout has elapsed, however, the connection is broken and the debugger won't notice when the script is interrupted by a breakpoint. You will know, though, because SE will appear to stop responding as it pauses the execution of the script. In this case, go to the debugger page and choose Refresh to update the debugger display.

Break
Interrupts a running script at the next possible opportunity. If there is no script running at the moment, then the next script to start running will be immediately interrupted. (In the latter case, unless the script starts within a second or so, you will need to use Refresh once the interruption occurs.)

Continue
Resumes the normal execution of an interrupted script. The script will run until it ends, a breakpoint is reached, or you issue a Break command.

Step Over
If a script is interrupted, execute the next line (the highlighted line in the source display). If that line contains function calls, they will be called without interruption (unless a separate breakpoint causes the interruption).

Step Into
This works like Step Over, except that if the line contains a function call, execution will be interrupted at the start of the function.

Step Out
Resumes execution of an interrupted script until the current function returns.

Script List
Displays a list of the loaded script files. Clicking one of the files will display it in the source window, which lets you set or clear breakpoints in that script. Scripts will not appear in this list until they have been loaded by the script engine at least once. For example, if you define a class map file that refers to a script, that script won't appear in the list until you create the matching component.

The final row of commands allows you to review general information about the application; the last button in this list will forcibly exit Strange Eons without allowing you to save files and without performing its usual shutdown routines. This is meant to be used if the main application locks up (try clicking Refresh first to make sure you haven't just reached a breakpoint!).

Source Panel

This panel displays the current script file. If the script has just been interrupted, then it will display the source of the interrupted script, and highlight the interrupted line. The left column shows line numbers; line numbers with link underlines can have a breakpoint set on them (or cleared again) by clicking the link. Lines with a breakpoint set show their line number with a pink background instead of grey. Script execution will be interrupted when it reaches one of these lines.

Watch Expression Panel

This panel allows you to add one or more JavaScript expressions that you wish to watch. As you step through a script, watched expressions will be updated to display their current value. For example, you can add a variable name to watch the value of the variable change. In fact, you can enter any JavaScript expression, such as target.width + bias/2, and watch the results. Note that watch values can only be displayed when the script is interrupted. If the script is not interrupted (or no script is running), then the watch values will be listed as "undefined". To watch a new expression, type it in the text field and then click "Add Watch".

Stack Panel

This panel displays the current "call stack": a list of the locations of nested function calls have taken place. For example, if you define functions A and B and in your script you call A which then calls B and reaches a breakpoint, then the place where you called into A will appear at the top, followed by the location where you called B from A, and finally the location of the current line. Clicking the list entries will display that location in the source window.

A scope is really a graph, not a tree, but the debugger prevents you from forming a loop using the special value <self reference>.

At the bottom of the panel is a tree that represents the current scope: all of the variables and properties that you can "see" from your current location, so that you could refer to them by name at that point in the script. For example, if the script is interrupted inside of a function, all of the parameters passed to that function will be in scope, along with local variables that you have declared and any global variables that you have not "hidden" with local variables that have the same name.

An Example

To start experimenting with the debugger, here is a simple script that will take some time to run:

println( "START" );
function count( n ) {
    println( "START count()" );
    for( var i=0; i<n; ++i ) {
        var j = i*2;
        println( i );
        j--;
    }
    println( "END count()" );
}
println( "CALL count()" );
count( 3000 );
println( "RETURN FROM count()" );
println( "END" );

Copy this script into the Quickscript window, then choose Debug Script. (This option is only available if debugging has been enabled; see above for instructions.) When you use this button, the script will be interrupted immediately. In addition, the debugger interface will be opened for you in your default browser. We'll start poking at buttons in a moment. For now, choose Continue to allow the script to continue running. Close the debugger Web page and switch back to Strange Eons. Keep reading as you wait for the script to finish.

In  addition to choosing to debug the script when we run it, we can also "attach" the debugger to a running script even though it wasn't started with a special command. One way to do this is by choosing the script in the Script List and setting a breakpoint, but in this case we'll just get the script started and then interrupt it manually. Click the debugger link to open the debugger interface in your browser. Then run the Quickscript using Run Script. Wait until the script counts through a couple of hundred numbers and then switch to the debugger and choose Break. The script will be interrupted at the next possible opportunity. (Note that it will interrupt whatever script happens to run next, whether that is the Quickscript or not, but in this case that will almost certainly be the Quickscript.)

Try using Step Over to walk through the loop a few times. To get a better idea of what is going on, add i as a watch expression, and then step a few more times and watch the value of i change as you work through the loop. Add j too, if you'd like. When you are done, click Step Out. Unless you are already close to the end of the loop, the debugger page will reload before the function returns. The debugger won't know when the script is interrupted, but in this case we can tell for ourselves: wait for the numbers to stop scrolling in the script console, then click Refresh to update the debugger window.  Step through the rest of the script or choose Continue to let it finish on its own.

We've now covered the most commonly used commands when debugging a script. Why not take a few minutes to experiment with a script of your own, or with some scripts from the Plug-in Authoring Kit? (You can drag and drop a script file onto the Quickscript window to replace the current script with the one in the file.) In the rest of this article we'll describe some of the features of the debugger that can't be readily discovered by experimenting with the debugger interface.

More Ways of Triggering Breakpoints

Using a debugger efficiently means being able to quickly zero in on the relevant code by setting up breakpoints around the problem. A common tactic is to start by casting a wide net around the potentially buggy code, step through the debugger until you can narrow down the source of the problem, and work the breakpoints to a smaller and smaller segment of the script as needed until you develop a testable hypothesis as to the cause. In this section we'll look at some additional ways of creating breakpoints.

The breakpoint() Function

Sometimes we want to trigger a breakpoint from within a script. For example, when a script hasn't been loaded and you need to trigger a breakpoint when the script executes for the first time. In this case, the file won't be listed in the Script List yet, so you can't set a breakpoint on it from the script window. Sometimes you can simply issue a Break command right before running the script, but when that isn't feasible you can add a call to breakpoint() to the script to interrupt it at that point. (It has no effect if the debugger is not running.)

Stepping Into Component Creation

In the New Component dialog, you can step into a scripted component in the debugger by selecting it and then holding down Shift as you choose Create. (This has no effect if the selected component is a compiled class—as most of the standard SE components are.) A debugger window will be opened and the script interrupted, similar to using Debug Script. Try installing the Talisman example DIY extension and then creating a Talisman component with Shift held down.  Once the debugger loads, set breakpoints in some of the diy functions, such as create() and paintFront() , and then choose Continue.

Additional Notes

Browser Compatibility: The debugger interface has been tested in recent versions of Firefox, Google Chrome, Internet Explorer (version 8 only), and Safari. Other browsers, especially older versions of Internet Explorer, may not work correctly or may exhibit drawing problems.

Starting the Debugger in an Ongoing Session: It is possible to start the debugger without restarting the application, but only scripts that are compiled after the debugger starts will be available for debugging. To do this, paste and run arkham.plugins.debugging.ScriptDebugger.install(); in the Quickscript window. You can cause activated and injected (not extension) plug-ins to be recompiled by unloading and reloading plug-ins (open the Plug-in Manager and press OK).

Return to Home Page    Send Feedback

July 05, 2009  — Updated January 01, 2011