Alpha |
Version: | 9.2.3 - "Suhail" |
Last update: | 2021-05-21 14:43:30 |
This document explains some debugging techniques with Alpha.
See the Bug Reporting file for advice on how to
write and send bug reports. In the Help menu, there is a submenu
with commands related to bug reporting.
Troubleshooting
The problem you are experiencing most likely came with the version of Alpha
you installed, and therefore affects also other people having installed this
version. This is the sort of bug it is in the interest of the community to
have reported and fixed.
However, there are two other possibilities: one is that your particular
installation of Alpha got corrupted somehow. Preferences files and certain
index files can sometimes get corrupted (whereas it is highly unlikely that
the program itself get corrupted, so it is almost never a solution to
reinstall the whole program).
The other possibility is that some of Alpha's numerous preferences got set in
some way that make the program behave in a way that seems buggy, but which in
reality is an intended feature, appreciated by certain users.
This short section gives some advice on how to rule out these two
possibilities: you can try to start up Alpha from a fresh Prefs folder to see
if the problem goes away, and you can instruct Alpha to rebuild all the
indices it relies on.
The Alpha Developer Menu and The Debugging Palette
For troubleshooting and debugging, it is recommended to activate the
Alpha Developer Menu (click here to open the Menus Preferences dialog
accessible via Alpha ↣ Global Setup ↣ Menus).
This menu contains many facilities for debugging, in particular the Debugging
Palette. This is a small floating window which provides easy access to many
of the debugging related tools described in this document, such as
Obtaining 'errorInfo',
Rebuilding Tcl indices and Package Info, and
Tracing.
Click here to see the
palette. More information is available in the Debugging Palette Help window.
Rebuilding Tcl indices and Package Info
AlphaTcl relies on two systems of indices to find the Tcl files in which
procedures and packages are defined: one are the tclIndex files found in each
folder inside AlphaTcl. (This is the standard Tcl way of finding
procedures.) The other system consists of index files kept in a Cache
folder inside the application bundle and serves to keep track of package
definitions without having to source those files as long as they are not
needed.
In normal usage of Alpha, it should never be necessary to rebuild any of
these indices, but if the Tcl files are modified, for example a new procedure
is defined in some file, or some package definition is modified, the indices
may need to be rebuilt. The symptom is typically an error telling that some
proc is not defined. It is easy to rebuild the indices: select the
Alpha ↣ Rebuild AlphaTcl Indices
command in the Alpha Developer Menu. This
lets you specify which indices or Package Infos you want to rebuild, and
after rebuilding indices, quit and restart Alpha, to see if it helps.
Removing preference files
One of the most common problems in any software is a corrupted preferences
file. A different problem, which is sometimes encountered in Alpha is that
the user sets some exotic setting by accident, leading to unexpected
behaviour. Restarting Alpha with a virgin Prefs folder is of course the
proper first experiment to confirm these hypotheses. If the problem goes
away, then the bug has been localised to the prefs, and some further
debugging is then due in order to reconstruct a usable prefs configuration.
If the bug is still experienced with a virgin prefs folder, then certainly
the bug is of more global nature, and the developers will be very interested
in the fact that the bug can be reproduced with a pristine Alpha
installation.
Alpha stores all of its preferences in a special folder on your hard drive,
which by default is
~/Library/Preferences/Alpha-v9.0
To locate your preferences folder right now, click here.
If the files are not present, a rather minimal set of files will be created
automatically at start-up, so that it is present while Alpha runs.
So in order to start up with fresh preference files, do the following:
- Quit Alpha.
- Locate and rename your preferences folder, say to Alpha-v9.0-suspended
- Restart Alpha.
Since Alpha doesn't recognise the old folder's name as its prefs folder, it
will create a new one.
You can now test whether the problem has gone away or if it persists.
If the problem persists, your prefs are innocent, and you will want to
reinstall them. So do this:
- Quit Alpha.
- Delete the new preferences folder created by the test.
- Rename your original prefs folder Alpha-v9.0-suspended to
its original name Alpha-v9.0.
- Restart Alpha.
It is possible that this restart will trigger a rebuilding of indices
(which you are informed about in the status bar).
IMPORTANT: only move or restore prefs files while Alpha is not running.
Otherwise Alpha may overwrite the files with current values, and either the
experiment or your old precious prefs file may be ruined.
If the problem went away with the clean-prefs relaunch, surely there is
something wrong with the original prefs. You now have two options: either
you can stick with the new prefs, and from within Alpha reconfigure all the
settings you had made. If you had not made many changes to the default
configuration, perhaps making them once again is not so difficult. On the
other hand, if you had spent a lot of time configuring, and possibly made
many tweaks in you prefs.tcl file, then of course
you will rather go into the trouble of restoring these files little by
little to see where the problem lies. In other words, you'll have to figure
out exactly which file causes the problem.
Here is a list of the most common prefs files, which you may look into, to
see if you can detect some anomaly, or guess which is most likely to be
related to the problem:
prefs.tcl | the prefs you wrote yourself in Tcl |
arrdefs.tcl | holding many of the prefs you set in dialogues, including filesets information |
defs.tcl | ditto |
earlydefs.tcl | mostly more internal prefs that Alpha defines itself |
In addition, there may be mode specific prefs files like for example
TeXprefs.tcl | TeX-mode specific prefs (that you wrote yourself) |
Starting from the clean prefs, you can try to
- Quit
- Copy one of the original prefs files into the
current experimental prefs folder
- Restart
- Test
If you detect that one specific prefs file causes the problem, you can either
leave it out, hoping that the settings it contains can be restored manually
from within Alpha, or you can try to look into the file and restore it in
pieces. If you try this, beware that if you edit it in Alpha, then Alpha is
already open, and then when it quits it may overwrite the changes you made!
You might consider editing in another editor, or you should edit the file
outside the prefs folder and only copy it in after Alpha has quit.
Note: outside the Alpha-v9.0 folder there is also a .plist
file net.sourceforge.alphacocoa.plist. At present, none of your
user settings are stored there; it is used only for caching some values. It
won't hurt to delete this file, but it is also quite unlikely that it will
address any problem.
Removing single preference settings
Sometimes one of your preferences has a faulty value that prevents the proper
operation of some routine. If the error message (or a note from an AlphaTcl
developer) suggests that this might be the case, you can try selecting the
menu command Alpha ↣ Preferences ↣ Remove Saved Setting to restore a
preference value to the default value. You must immediately restart Alpha
after selecting this command in order for the default value to be restored.
Debugging
The AlphaTcl library is huge: more than 160000 lines of code in over 500 Tcl
files. How to figure out where the wrong code is? Of course this requires
some familiarity with the layout of AlphaTcl, but here are some tricks to
narrow it down.
Most scripts and code snippets are bundled into procedures, often just called
procs. Each proc takes certain arguments, does some things to the content of
some window, modifies the state of some global variables, and finally returns
some value. The expected behaviour of each proc is specified in comments
before the actual Tcl code.
The tclMode.tcl file is one example of an installed .tcl file that defines
AlphaTcl's Tcl mode. Click here
to locate this collection of files in your local disk. AlphaTcl's Tcl mode
and the package Alpha Developer Menu are used extensively by developers to
improve Alpha.
Which proc to debug?
Identifying the faulty proc is already a substantial part of the debugging.
If there is an error, the first step is to look into 'errorInfo', as
described below. (Be aware that this info can sometimes be misleading, as
it can contain older irrelevant "errors".)
If a menu-selection causes a problem, then there are three ways you may be
able to determine which procedure to investigate:
- Ask on the alphatcl-developers mailing list; see the information in the
Internet Resources section
for more information.
- If the menu item has a Keyboard Shortcut (or if the problem occurs
with a given key-press), then use Alpha ↣ Global Setup ↣ Keyboard Shortcuts ↣ Describe Shortcut menu item (which
is bound to
F7
) to find the procedure. For example, ⌘I
might be bound to menu::textEditProc Text fillParagraph. In this
case, [menu::textEditProc] is the first procedure that you might want to
debug.
- If the menu item is called Line To Paragraph, then the procedure might
be named
lineToParagraph
(i.e. scrunch everything together and make the first character lower case).
Click here to open a dialogue listing
all defined procedures in the various Tcl namespaces -- selecting
one will open the file in which the procedure is defined.
Obtaining 'errorInfo'
Whenever an AlphaTcl procedure encounters a true error in the code, the error
info is recorded in a global 'errorInfo' variable, which can be easily
displayed in a new window. There are several ways to achieve this:
If the error has just occurred, and you still do not know whether you will be
able to reproduce it, the best is to try to get the 'errorInfo' immediately.
(The more operations you do before getting the 'errorInfo', the higher is the
risk that the error will be overwritten by some irrelevant info.) The most
direct methods is
METHOD 1: press Escape-X
and then type this command into the status bar:
putScrap $errorInfo
followed by return
. This will place the value of 'errorInfo' into the
Clipboard. Now open a new window and do Paste.
Alternatively, you can use the shell:
METHOD 2: Open the Alpha Tcl Shell (⌘Y
), and write
set errorInfo
in the prompt, followed by return
. This will display the error message
directly in the shell.
METHOD 3: if the Alpha Developer Menu is active, select in it
Alpha Testing ↣ Display Error Info.
You can also find this item in the Debugging Palette, which is activated through the Alpha Developer Menu, or by
clicking here.
Finally the item Display Error Info is also available from the Tcl Menu,
should that be active.
If the bug is reproducible, then you have time to prepare all these tools:
open the Tcl Shell, turn the Alpha Developer Menu on, create the Debugging
Palette. And then, once all this is active, go back to the original window
and reproduce the bug, and immediately select Display Error Info from the
Debugging Palette.
Having the shell open while reproducing a bug is also useful because certain
errors are displayed here automatically if it is open.
Finally, it is very useful, while you are debugging, to adjust the
preference variable Display Errors In (in the Errors Preferences panel) to the
value new window. This will make all errors be displayed immediately in
a new window.
We assume now that you got hold of the 'errorInfo'. Even if you don't
understand it -- it is a rather technical message -- you might at least
figure out from it in which proc the error occurs: typically it will say
something like error, unknown variable bla in proc alpha::foo. Then of
course the proc alpha::foo has to be investigated.
If you don't feel like debugging yourself, you can attach the 'errorInfo'
to your bug report, or ask for help on one of the mailing lists,
described in the Readme file.
Looking into Tcl procs
Once you know the name of the AlphaTcl procedure causing the problem, you
wish to have a look at the file where this proc is defined. To find the proc
definition, there are tools in the Tcl Menu (see Tcl Procedures ↣ Find Proc Definition), or in the
Alpha Developer Menu.
Another way which is useful is to use the AlphaTcl Shell: write the
name of the proc here and press F6 (Shift-Command-double-click). This
will open the file containing the proc definition, and move to it.
Shift-Command-Double-Clicking on the name of a proc works in any window in Tcl
mode, like for example an error window.
From now on, some rudimentary knowledge of programming is required,
in order to understand what the proc is supposed to do. The first step is
to read the description in the comments surrounding the proc definition, to
learn how it is supposed to work and which arguments the proc takes. If you
have the 'errorInfo' available, you can probably spot the exact line of
code that throws the error.
Is it an undefined variable? A missing argument to a function call?
In any case, the task now consists in figuring out why the variables are not
as expected.
Creating debugging windows
One useful way of figuring out where exactly inside a proc an error occurs
(and which in any case can help understanding how the proc works) is to
modify the code temporarily. Doing this directly in the .tcl file is
possible, but not recommended. It is much more convenient to work on a
temporary copy. To get one, highlight the name of the proc (in the Tcl file
the proc is defined in, or in an error window, or in the Shell), and select
Tcl Menu ↣ Tcl Procedures ↣ Debug Proc to create a debugging window. (If
there is no proc name highlighted, you will get instead a listpick dialogue
to navigate to the desired proc. If the name contains :: (the namespace
separator), as in 'text::isInComment', you'll have to choose the namespaces
successively in the listpicks, i.e. first ::text, then isInComment.)
Alternatively, you can demand the debugging window directly from the Shell
by giving the command
procs::debug <procName>
where <procName> could be for example 'text::isInComment'.
In any case, the result will be a new editable window containing the
definition of the procedure. In this window you can make modifications to
the proc. To see how the change affects the functioning, the proc has to be
evaluated again, so that Alpha's tcl interpreter knows the proc has been
modified. You do this with ⌃⌘L
. See the Tcl Menu for many other
features.
Now we are ready to experiment with modifications of the proc.
Alertnote debugging
If the given proc throws an error before it reaches the end of its script, we
want to know where the error happens. You can now modify the proc to make it
give extra feedback when running. One common method for this is with
alertnotes. The command
alertnote "hello"
will simply display an alertnote saying hello, and wait until the
user presses OK. The idea is to sprinkle some [alertnote] commands over the code of the proc. For a simple example, if the proc
looks like this
proc testProc {args} {
set value [lindex $args end]
incr value
...
return $value
}
modify it to
proc testProc {args} {
set myvar [lindex $args end]
alertnote "beginning value: $myvar"
incr myvar
alertnote "new value: $myvar"
...
return $myvar
}
For the modification to take effect, you need to reload the proc. You do
this with ⌃⌘L
. Now when you call the proc, in the Shell or in the
status bar, or by performing the malfunctioning operation, you can see from
the alertnotes displayed how far you got before you ran into a problem, and
what happens to the variables.
Tip: if the error results in a freeze/crash, you should save
the file containing the debugging [alertnote] dialogue
calls before you evaluate it, so that it is easier to remember which step
caused the bug when restarting Alpha.
Recording info in global variables
If it is too intrusive with the alertnotes, you may prefer to write the
interesting values to a global variable which can be examined afterwards.
You can do this by inserting a line like this in the proc
set ::XXX1 $pos
This creates a variable XXX1
in the global namespace (that's what
the ::
do), so that it is still accessible after the proc has
terminated or aborted with an error. You can then inspect it in the Shell
by doing
set XXX1
If the proc is actually called more than once during the operation, only the
last value of XXX1
will be available afterwards. In this case, it may be
appropriate to use instead a list: in the Tcl Shell (⌘Y
) do
set ::LLL [list]
to create an empty list in the global namespace. Now inside the proc you
are debugging write
lappend ::LLL $pos
(if $pos
is the variable you are interested in). This will append this
value to the list, and once the proc returns, you can inspect the whole
list in the Tcl Shell.
Recording info in log files
Another method for recording information for later inspection is to send it
to a log file. AlphaTcl defines a proc called alpha::logFile for
this purpose. By default, it expects two arguments: the name of the log
file (any name chosen by you) and the text you want to write in this file.
When you are debugging a piece of code, you can insert calls to
alpha::logFile. This is useful for instance when you want to check some
values inside a loop because alertnotes are a nuisance in that case (since
they interrupt the process at each iteration). Here is an example:
for {set i 0} {$i < 100} {incr i} {
set value [getSomeValue]
alpha::logFile valuesInLoop "Step $i: $value"
}
In this example, the log file is named valuesInLoop: it will be located in
~/Library/Logs/AlphaTcl/.
Catching errors
The Tcl command [catch] is very useful for determining
if some other procedure that is called by one in question is causing the
error. Any [catch] script returns "1" if an error was
thrown, and "0" if the script was fine, and will optionally place the return value or error code into a variable. For example, you
can include
this:
proc testProc {args} {
set value [lindex $args end]
alertnote "beginning value: $value"
if {[catch {Tcl::MarkFile} result]} {
alertnote "caught: $result"
}
...
}
This can help you determine why a complicated procedure is failing.
Forced shell dumps
Another way to debug Tcl routines is to insert statements that print values
to another window. For example, one could use the proc [alpha::stderr] to insert the value of the args variable that is
created by the procedure in the previous example into an already opened
Tcl Shell window.
More Tcl Shell debugging tricks
When you want to get a handle on what a proc is doing, you can use a
combination of the source in one window and the shell in another.
- First, figure out what values the parameters of the proc would take on in
the case you want to investigate, (perhaps from a trace while running things
normally).
- Now go to the shell and set variables with the same names as the
parameters to the values you discovered through the trace.
- Now go to the tcl source file and select a subset of the proc's internal
code and just load it (with the Tcl Menu ↣ Evaluate menu item or the key
combo
⌘L
).
After each successive part is run you can pop over to the shell and use it
to check out the state of any variable with a simple [set] statement, or, even easier, just Shift-Command-Double-Click on a variable
name if you want to inspect the variable's value.
Tracing
Alertnote debugging and the like are really very ad hoc methods, but it can
be a quite efficient way of debugging average bugs. For more subtle
issues, a much more methodic technique is tracing: simply put, it amounts to
an instruction to the Tcl interpreter to dump ALL the information about a
function call to a window -- this info is equivalent of having all the
possible alertnotes in the code, so that every single instruction is
recorded. The result of this, called a stack trace, is usually huge, so it
can be a lot of work to dig out useful information from it.
If a bug you have reported cannot be reproduced by the developer looking
into it, he will typically ask you send him a stack trace of some specific
proc, so as to get all the information in one go, instead of bothering the
reporter to write alertnote commands all over the place.
Performing a trace
To create a stack trace of a specific proc, follow these steps:
- Click here to display the Debugging Palette.
- Select the Perform A Stack Trace command in the palette.
- Select the procedure you need to trace. If the name of the procedure
includes "::" in the middle, as in ::Tcl::MarkFile, then you need to first
select the ::Tcl namespace in a first listpick dialog, and then MarkFile should be included in the
list presented in the subsequent dialog.
- Perform the action that triggers the problem.
- Immediately select Display Trace Results in the Debugging Palette.
A new window should be opened with the trace information.
Tracing via the Tcl Menu
The tracing facilities are also available from the Tcl Menu, in the submenu
Tcl Tracing. (The Tcl Menu is activated for example when the Tcl Shell is
frontmost). To start the trace using the menu items, perform the
following steps:
- Select the Tcl Tracing ↣ Trace Tcl Proc menu item.
- From the listbox that appears, select the procedure you need to trace.
- Go back to a situation in which the bug occurs and repeat the action
that triggers the problem.
- Go back to the Tcl shell, and select Tcl Tracing ↣ Display Traces from
the Tcl Menu.
Tracing tips
- If the trace dump is empty, you probably traced the wrong procedure. In
this case ask for help on the Alpha-Developers List.
- If the stack trace is really long, check if it has calls to unknown in
it. If this is the case, then calling that procedure required the
auto_loading of various files. Try tracing the procedure again to see if
the size is then reduced.
- Don't send traces to the mailing lists, as traces are often very long, and
quite uninteresting to everybody except the person who is investigating the
error -- send it directly to him.
Applying AlphaTcl patches
Identifying the cause of a problem is only the first step towards resolving
it. If the errant code belonged to a file in the standard distribution, it
should be corrected for the next release. In most cases, the fix can also
be applied to your working version of Alpha as well.
If the fix was added to the AlphaTcl Subversion repository by a
developer, you could update your own AlphaTcl library (inside the
application bundle) to the latest development version. This Update AlphaTcl hyperlink will update your
AlphaTcl library right now. (Click on the More Info button in the
confirmation dialogue to learn more about the AlphaTcl Subversion
Repository.)
In some cases, the developer will supply you with some code to place in your
prefs.tcl file. Select
Alpha ↣ Preferences ↣ Edit Prefs File to open it
and insert the code as directed. Then save this file, select the command
Tcl Menu ↣ Evaluate to load it into the interpreter, and then test to see
if this solved your problem. Your prefs.tcl file will always be sourced
automatically whenever you restart Alpha. At this point the patch has been
added to your personal distribution and there is nothing more to do.
Otherwise, you might be instructed to modify an existing AlphaTcl file.
Assuming that you have been supplied with a patch from a helpful developer,
you can easily create an over-ride for the file in question. Your corrected
version will reside in an Alpha Support Folder, and will always be used
preferentially when the program is launched.
- If you know the name of the file that needs to be fixed and if the Support
Folders Tool package is activated, you can select the
Tools ↣ Support Folders ↣ Open AlphaTcl File command and navigate through the AlphaTcl
hierarchy to locate and open it for viewing.
- If you only know the name of the procedure which needs to be fixed, you can
click here to locate it. If the name
of the procedure includes "::" in the middle, as in ::Tcl::MarkFile, then
you need to first select the ::Tcl namespace, and then MarkFile should be
included in the list presented in the subsequent dialogue.
Once the installed AlphaTcl file has been opened, you need to select the
command Tools ↣ Support Folders ↣ Save In Support Folder to create the
over-ride version. Now you can modify this file to apply the patch. Save
this file when you are finished, select the Tcl Menu ↣ Evaluate command to
load the new code into the interpreter, and then perform the action which
caused the original bug to see if the fix actually worked. If so, you can
close this file. The next time you launch Alpha, your over-ride file will
automatically be used instead of the installed version.
See the Support Folders Help file for more information.
N.B. Any Support Folder over-ride file (or "prefs.tcl" code) will still be
used even after you update Alpha to the next release. To confirm that the
patch has been added to the standard distribution, temporarily remove the
over-ride file (or comment out the code in your preferences file), restart
Alpha, and test the operation that caused the original bug.
Credits and Copyright
Author: Joachim Kock, with many snippets from earlier help files.
This document has been placed in the public domain.