Extending Alpha
Alpha
Version:9.2.3 - "Suhail"
Last update:2021-05-21 14:43:29





Abstract

This file is a manual about extending the capacities of Alpha programmatically. If you need information about Alpha's interface and functionalities, please refer to the Alpha Manual.
This document serves three classes of readers: first of all it contains information for POWER USERS wanting to extend their Alpha by adding a few new keyboard shortcuts, menu items, and procedures they have written for personal use. This is covered in PART 1: TWEAKING ALPHA.
Gradually such users become PACKAGE DEVELOPERS contributing their advances to the Alpha Community. As explained in PART 2: WRITING PACKAGES, this means bundling the new functionality into packages (Features, Menus, Modes, etc.), and learning how these interact with AlphaTcl as a whole.
From here the step to becoming a CORE ALPHATCL DEVELOPER is not big: soon you will be interested in understanding Alpha's startup sequence, learn how to take advantage of event hooks and traced variables, minor modes, window attributes, and so on -- which is the subject matter of PART 3: ADVANCED TOPICS.
Other files that document technical details of AlphaTcl:

INTRODUCTION

This document explains how to write or modify code to add functionality to Alpha. At a first level, this may amount to defining some new keyboard shortcuts to existing functions, or to write some simple Tcl procedures to meet personal needs. Next, one may be interested in making such an added function available as a menu item. It also happens that one would like to modify one of Alpha's standard procedures to suit one's needs. All this is possible, and not very complicated, thanks to the fact that most of Alpha's functionality is implemented in Tcl scripts, stored as plain text files inside the application bundle, easily accessible, and which can be modified on the fly.
The library of these scripts, altogether called AlphaTcl, also provides a consistent API by which you can add new features to Alpha by bundling your scripts into so-called packages. This does not imply that your scripts cease to be plain text files or that they are frozen or stowed away: the wrapping merely consists in declaring the scripts as a unit or a module which can be referenced, turned on and off as a whole, and which links the script into global functionalities such as the preferences system, help facilities, dependency handling and so on. Furthermore, such a package comes with an installation mechanism so that it is easy to make it avaible to other users.
Examples of packages are new modes or menus, adding an item to an existing mode or menu, or simply adding some new functionality to existing actions.
This document also tells you how to make your package interact effectively with a few other commonly used packages which users might already be using, and some internal technologies in AlphaTcl which you don't have to reinvent. Finally, Part 3 covers additional technical documentation of AlphaTcl, mostly advanced topics, such as event hooks and window attributes.

Alpha and AlphaTcl

Under the hood, the application Alpha has three components, and you can actually see them if you open the application bundle by control-clicking on the Alpha icon in the Finder, and then select Show Package Contents: The script files in AlphaTcl are written in Tcl, but with additional commands provided by the core, as mentioned above. Of course, the scripts themselves define new commands (aka as procs), so in conclusion there are three kinds of commands available:
Alpha core commands
functions defined in the core, but made available to the Tcl interpreter. These are for example, position commands, commands for getting text in and out of a window, window and menu handling commands, but only low level such. The set of all core commands is documented in the help file Alpha Commands.
Tcl core commands
the standard commands of the scripting language Tcl. This includes fundamentals like [if] and [while] for conditionals, and [proc] for defining new procedures. See the documentation for the Core Tcl Commands.
AlphaTcl commands
the procedures defined in the library using the Tcl command [proc]. Almost all the functionality available in Alpha's graphical user interface, for example the commands corresponding to all the menu items, as well as definition of keyboard shortcuts and menus, is implemented in such procs. These procs are documented in comments inside the Tcl files, alongside with the proc definitions. Since there are thousands of commands, and since this library is a rather dynamical thing, it is not practical to have a man page describing them all. The Tcl files are really meant to be read also by humans.
Since the core is a black box, and Tcl is a scripting language which for our purposes can be considered immutable, what this Extending Alpha file is about is mainly AlphaTcl.

The Tcl Menu, the Tcl Shell, and the Alpha Developer Menu

Whenever you open a Tcl file in Alpha, Alpha enters Tcl Mode, and in particular activates the Tcl Menu. The Tcl Menu contains facilities for evalutating Tcl scripts in the Tcl interpreter. You should in particular remember the ⌘L keyboard shortcut for evaluating the whole file (or the current selection is there is one), and ⌃⌘L for evaluating only the proc surrounding the insertion point.
More direct and interactive access to the Tcl interpreter is to be had in the Alpha Tcl Shell, opened via Tools ↣ Tcl Shell (or ⌘Y): here you can type any command, and evaluate it by hitting Return. For example, you can inspect the value of some global variable:
«» set tabSize
«» set fillColumn
«» set errorInfo
or evaluate a command, like
«» listpick [list a b c]
Evaluating the commands in a Tcl file line by line with ⌘L, combined with inspecting variable values in the Tcl Shell is an invaluable tool in developing Tcl scripts, to run them and to debug them.
Tcl Mode is designed to work with Tcl projects in general, i.e. whatever you might be programming in Tcl. In the present manual we are concerned with AlphaTcl scripts. For this purpose, there is a second menu available, the Alpha Developer Menu, with tools more explicitly geared towards AlphaTcl development, like for example Unlike the Tcl Menu which is automatically activated whenever a Tcl window is frontmost, the Alpha Developer Menu must be turned on explicitly. It can be turned on either globally, in the Alpha ↣ Global Setup ↣ Menus dialog, or for Tcl mode only, via Alpha ↣ Tcl Mode Setup ↣ Menus.
One of the first things you may wish to do in the Alpha Developer Menu is to build the standard filesets for all the Tcl files in AlphaTcl. Select Alpha Developer Menu ↣ Create AlphaTcl Filesets. This provides really convenient access to the AlphaTcl files from the Fileset Menu.
For more information about debugging, see the help files Bug Reporting and Debugging Help, available from the Help Menu.

Editing Tcl files

We assume you have built the AlphaTcl filesets, as just decribed. Then all Alpha's Tcl files are easily accessible from the Filesets Menu, and you can browse around in them, experiment with them, learn from them, and copy code to base your own procs upon. Alpha automatically enters Tcl mode when editing a Tcl file, and then the Evaluate commands are available: ⌘L to evaluate the whole file or the selection if there is one, and ⌃⌘L for evaluating the proc surrounding the insertion point.
If you don't know where to look for a specific procedure, there are two options: one is to use the Tcl Menu ↣ Tcl Procedures ↣ Find Proc Definition menu item. If the proc is defined in a namespace (i.e. has :: inside its name, as in pos::lineStart), it is necessary, in the listpick, first to select the namespace ::pos (notice that there is a leading :: here) and then in the subsequent listpick find the proc lineStart. A somewhat easier method, if you know the exact name of the proc, is to type it in the Tcl Shell (without evaluating with Return), highlight its name, and then do Shift-Command-Double-Click (F6): this will open the Tcl file containing the definition of the proc, and move to it. This works in all Tcl files: while reading a proc foo which calls another proc bar, you can jump directly to the definition of bar with Shift-Command-Double-Click.
If you want to write a new proc based on a given one, it is helpful to experiment with it by editing it, to observe the effects of a modification. This is easy, just remember not to save. Simply evaluate without saving, discard changes when closing the window, and restart Alpha to bring it back to its normal state. However, to avoid saving by accident, and to allow you to save your experiments somewhere else, it is recommended to edit only a copy, instead of experimenting directly in the Tcl file inside the application. You can of course copy the file as you please, but copy it to a location outside Alpha. You can also get a temporary debugging window (not associated to a file on disk) by highlighting the name of the proc and selecting the Tcl Menu ↣ Tcl Procs ↣ Debug Proc menu item.
To understand a proc, it is helpful to experiment with it for example by sprinkling some alertnote commands all over it: if you are curious to know what is the value of the variable $pos at some places in the proc, insert alertnote commands like:
alertnote "first value: $pos"
... # more code
alertnote "second value: $pos"
... 
inside the body of the proc. After evaluation, this will display the values next time the proc is invoked, and you can follow how the variable changes value.

PART 1: TWEAKING ALPHA

This first part is for Alpha users who wish to modify or extend some part of the AlphaTcl code, mainly for personal use, without necessarily creating new packages.

Basics

An illustrative example

Suppose you want to write a proc that strips the trailing space of the current line. Such a proc would have the shape
proc stripTrailingSpaceOfCurrentLine {} {
    # body of proc
}
It takes no arguments, because the proc itself will determine the position and the text to operate on. So the body of the proc should implement the algorithm: (1) determine the positions; (2) acquire the text; (3) manipulate the text; (4) put the manipulated text back in. (In fact, this rough description applies to a great many procs in AlphaTcl!) Here goes:
proc stripTrailingSpaceOfCurrentLine {} {
    # Determine positions:
    set pos [getPos]
    set lineStartPos [linePos start $pos]
    set lineEndPos [linePos end $pos]
    # Acquire the text:
    set txt [text get $lineStartPos $lineEndPos]
    # Manipulate the text, if required:
    if { [regsub {\s+$} $txt "" txt] } {
        # Put the manipulated text back in, at the correct positions:
        text replace $lineStartPos $lineEndPos $txt
    }
}

binding create {z 'p'} stripTrailingSpaceOfCurrentLine
Now you can perform this operation with the keyboard shortcut ⌃P (this is what the last instruction means with the [binding create] command).
Perhaps you'll find it easy to read this proc and understand what it does, but how were you supposed to guess all those position procs, and how to come up with that cryptic [regsub] ? Well, you must start somewhere, and the good news is that you can get quite far just by looking at other code snippets, and that you don't have to read thick manuals. But of course there are places to look up things: all commands that relate to elementary operations in a window, like getting positions or reading and writing text, are typically Alpha core commands, and you can easily find them by perusing Alpha Commands, in which the commands are listed by subject. On the other hand, once you have a text string stored in a variable, and want to manipulate it, that's typically plain Tcl, in this case the command [regsub]. To read about those, look in the documentation for the Core Tcl Commands.
Once you feel comfortable with this proc, you may want more: why not a proc that strips the trailing space of every line in the entire document?
proc stripTrailingSpaceOfDocument {} {
	goto [minPos]
	while { [pos::compare [getPos] < [maxPos]] } {
		stripTrailingSpaceOfCurrentLine
		goto [linePos next]
	}
}
(Watch out! is this proc correct or will it go into an infinite loop if the document ends with a line without a linebreak? This depends on how [linePos next] is defined. One could fear that when it comes to the last line, since there is no next line it would go instead to the start of the current line. Well it doesn't. Either you could figure this out with a few experiments (carried out before writing the while loop), or you could look up the exact specifications in Alpha Commands. It turns out that the specifications are not clear on this point :-( So look up the definition itself, by Shift-Command-Double-Clicking on the name of the proc. This will take you to the file positions.tcl, where you can read some more info, and if needed, scrutinise the body of the proc itself.)
Now let's bind that to ⌃⇧P:
binding create {zs 'p'} stripTrailingSpaceOfDocument
Bad surprise: the binding doesn't work :-( In Tcl mode at least, ⌃⇧P is instead bound to Tcl::previousProc, or something like that. This is a typical Alpha frustration -- the mode-specific binding takes precedence over the global binding just introduced. A first solution is to remove the mode-specific binding with
binding delete -tag Tcl {zs 'p'} 
This will reveal that your binding was in fact correctly registered, but that it was just overruled by the mode-specific binding. Alternatively you could choose another key combination not already in use, e.g. ⌃⌥⇧P:
binding create {zos 'p'} stripTrailingSpaceOfDocument
Finally, suppose we want to create a new menu item at the bottom of the Text menu, after a separator line: this is accomplished by
menuItem append $menu::core(Text) -
menuItem append $menu::core(Text) "Strip Trailing Space Of Current Line"
In this case, that's all there is to it. Since the name of the menu item is matched by the name of the proc (modulo an obvious conversion), the menu itself figures out how to invoke this proc when the menu item is selected. However, a much better way of obtaining the link between the menu item and the proc is to supply it explicitly:
menuItem append $menu::core(Text) "Strip All Trailing Spaces" \
        -command stripTrailingSpaceOfDocument
Notice in the menu how this way has the additional benefit of automatically displaying the keyboard shortcut with the menu item!
All this is explained in more detail in the sections below.

Where to put new code? -- prefs files and smarter source

Where do you put your personal Tcl code so that Alpha can find it? Alpha has a set of preferences files for this purpose (see the section User defined preference files in the file Alpha Preferences). There is one global preferences file which is loaded when Alpha is launched. In this file you should put code which should be loaded regardless of which mode you're working in. This prefs.tcl file is opened / created by selecting the menu item Alpha ↣ Preferences ↣ Edit Prefs File.
Then there is one preferences file for each mode. The file for a mode is loaded as the last code to be loaded when a mode is used the first time. This preferences file can be opened / created using the menu item Alpha ↣ Mode Setup ↣ Edit Prefs File.
If you write many procs, and you prefs files start to become bloated, you may consider putting the procs in separate Tcl files, say myFootballProcs.tcl. You can put this file any safe place you like, but it is not recommended to put it inside the Alpha application bundle. In order for Alpha to load this file, add the following line to your prefs.tcl file:
source /complete/path/to/the/file/myFootbalProcs.tcl
You can also choose to use the User folders: one is the User Packages folder, which can be opened via Alpha ↣ Preferences ↣ Show User Packages, the other is the Application Support Folder, accessed via Alpha ↣ Preferences ↣ Show Support Folder. See the help file Application Support Help for more information.
If your tweaking of Alpha is concerned with modification of existing AlphaTcl procs rather than new procs, clearly you have to ensure that the tweaked version is sourced rather than the original. Modifying the original AlphaTcl file is an obvious way to ensure this, but it is not recommended. For one thing, it makes it difficult to revert to the original proc if required, for example if the development of the replacement proc goes astray. Second, if you update AlphaTcl at some point, either you risk that your precious modifications be overwritten by an update, or if you simply install a new version of Alpha, you'll have to dig out all your modifications from the old application.
The correct thing to do is to make a copy of the original file and place it in the Application Support Folder at the appropriate place (i.e inside the subfolder Modes if the original file was in the so-named folder. This is to be thought of as a user tree: whenever a file is found in this tree, it will be sourced instead of the one found in the application tree. So do all your editing in this copy. There are commands for making it easier to create and manage such smarter source files in the submenu Smarter Source of the Alpha Developer Menu. You should activate the package Smarter Source. See the help file Smarter Source Help for further information.
Finally, as your additions begin to take the form of some coherent unit, you should consider bundling them into a package. This is what Part 2 of this document will explain in great detail.

The User Menu

We shall shortly discuss how to define new menus and how to insert new menu items into existing menus. If we are talking merely about some personal procs that you would like to make available through a menu, for your own use, a very convenient method is to turn on the User Menu package, which you do in Alpha ↣ Global Setup ↣ Menus.
This inserts a new menu called User (represented by an icon showing an open menu and a user's head) whose main item is New item. Upon selecting this item, a dialog will ask the name of the item you want to add and the name of the procedure to be triggered by this item. You can also assign a keyboard shortcut. In this way, all the technical complication of menu creation is bypassed. For instance, you could make a menu item for the proc stripTrailingSpaceOfCurrentLine seen in the An illustrative example section. You could name the item Strip Trailing Space (or whatever) and the associated proc would be stripTrailingSpaceOfCurrentLine. Very handy.
See User Menu Help for more information.

Some background, general advice and tips

Tcl files and Tcl indices

The AlphaTcl library is too big for it to be practical to load entirely into the Tcl interpreter: a file is only loaded (sourced) when some procedure defined in it is needed for some operation. For this to be possible, AlphaTcl (like most Tcl programs) keeps a tclIndex file in each folder: this file lists all the procedures defined in the files present in the folder, and says which file they belong to. If you modify the files by adding or renaming procs, it is necessary to rebuild these index files. Typically, you have defined a new proc [myproc] in some Tcl file, and although it has been declared and loaded and tested, the next time you start Alpha you get instead the error message
invalid command name myproc
because the Tcl interpreter is not aware of where this proc is to be found.
It may also happen that the file in which it is defined actually has been sourced for some other reason, (i.e. another proc in it which is requested and which is in the old tclIndex file). When one proc is requested, naturally the whole file and all procs defined in it are loaded at the same time. But even if this happens, one cannot rely on this happening every time Alpha starts up, so it is important to rebuild the indices anyway.
It is easy to rebuild Tcl indices: select the Rebuild AlphaTcl Indices command in the Alpha Developer Menu, or for more fine-grained control, the commands in the submenu Tcl Menu ↣ Tcl Indices. After rebuilding indices, quit and restart Alpha. It is also possible to rebuild the indices manually just in one particular folder, by cd'ing to that directory in the AlphaTcl Shell (⌘Y), and issuing the command
 
auto_mkindex 
The Tcl indices should not be confused with the package info files (kept in the bundle's Cache folder) which store information about package definitions. Although a feature/mode/menu may be defined in a Tcl file that is properly indexed, this does not mean that it is sourced, because Alpha caches package information to avoid having to scan hundreds of files on startup: the definitions are cached in the package info files. So after a modification to a package definition, it is further necessary to rebuild the package info files. See the section on Package Indices, further below.
Note that AlphaTcl will always check whether the number of files/folders have changed between editing sessions and will perform an automatic rebuild of all indices when necessary.

Compatibility and portability issues

This section concerns respect for the past and protection against the future! Currently Alpha is the only application making use of the AlphaTcl library. In the past, the library has been shared by other members of the Alpha family, and this could be the case again in the future. For this reason it is important that the procs that make up AlphaTcl do not make too many assumptions about the outer circumstances, and that they make themselves robust by abstraction layers and by introspection. This section also has some information about how older code (created for AlphaTcl v 7.x or 8.0) should be adjusted in order to work with the current library.

Abstraction layers

Currently, the only use of the AlphaTcl library is in Alpha, the only member of the Alpha family currently being maintained and developed. Nevertheless, the AlphaTcl library continues to develop in such a way that other Alphas, old or new, could use it. The upshot is that the code, as much as possible should abstract from any particular features of the binary Alpha or of the circumstance that Alpha runs in Mac OS X.

Important path variables

The location of the prefs folder (or other folders that Alpha needs to reference) are never given explicitly as ~/Library/Preferences/Alpha-v9.0/, even if this would be the correct place in OS X. It is always referenced through the variable $PREFS which early, when Alpha starts up, is initialised to the above path. This is not only a question of consideration for future Alpha family members or ports to other platforms, but as much a very useful abstraction: if it is later on decided that the prefs should be kept in a different place, then this change can be made in one single line in Alpha, instead of making the change throughout the code base. Similarly there are variables holding the value of other paths that Alpha needs (like $HOME for the AlphaTcl library and $APPLICATION for the application bundle).

Directory delimiters

Although paths in unix and OS X both use a slash as directory separator, the slash should never be used literally in paths in AlphaTcl. Instead, the path should be built up or decomposed using the Tcl commands [file join] and [file split]. respectively so that you don't assume any particular delimiter, and your code works fine on all platforms.
If you really need the file separator, use [file separator] to get the correct value. In general, excessive manual tweaking of file separators is probably a sign your code isn't designed in the simplest way -- please ask on the Alpha's Mailing Lists if you run into problems like this.

Position procs

Alpha uses natural numbers to indicate positions in a window by counting from the beginning of the window. However, you should not rely on natural number arithmetic to perform operations on positions. Instead, AlphaTcl provides the following 5 functions, which provide all the functionality you need: See Alpha Commands for details, and the positions.tcl file for more position query procs that are available in AlphaTcl.

Environment introspection

Whenever an AlphaTcl script assumes some Alpha or OS X specific feature, such as AppleScript or a folder called /Applications, or whatever, the script ought to be wrapped in a conditional, testing whether we are really in OS X! This was daily practice in AlphaTcl development up until around 2005, but since then, the tendency has been to relax a little bit more, since currently the only actively maintained version of Alpha is the Alpha which runs only on OS X. However, it is still very much recommended for serious development to have an eye on this issue.
There are many other environment characteristics that code may need to test for: version of Alpha, AlphaTcl or Tcl, version of the operating system, processor type, etc. Although OS X is based on unix, it should not be assumed that all standard unix tools are available, because some might be installed only if the user installs Developer Tools, and it is also possible that the PATH has been tampered, so that even the most basic tools may not be readily available.
The basic advice is to try to avoid any dependence! For example, many unix tools for access to the file system have Tcl equivalents which should always be preferred. As a rule of thumb, all calls to [exec] should be wrapped in suitable exception handling.
The most important tests are probably against versions of Alpha and AlphaTcl: the present lines are written for Alpha 9.0, and at the point of its release, all the involved components are in perfect harmony. But soon there will be some beta version of 9.1 out, with marvelous new scripts depending on fancy new functionalities in the core. Any script making use of such new stuff should guard against suddenly being executed in an old binary -- it all too easily happens that someone updates from svn and gets new AlphaTcl scripts into his good old Alpha 9.0 ...
Of course it is not practical to wrap hundreds of lines of code in conditionals, and one of the big advantages of bundling code into packages is that the package can make the checks once and for all during its initialisation, so that all the scripts in the package don't have to bother about this.
For package requirement scripts, three of the most basic calls are something like:
alpha::package require Alpha 9.0
alpha::package require AlphaTcl 9.0
package require Tcl 8.6
See the section Package Requirements for more details.
Other useful variables, and the meaning of their possible values are the following:
VariableValueImplication
$tcl_platform(platform)macintoshClassic MacOS, but NOT Mac OS X.
$tcl_platform(platform)unixUnix, for example Mac OS X (hence command-line tools should be available)
$tcl_platform(platform)windowsMicrosoft Windows OS (any) -- also with command-line tools.
${alpha::macos}0Windows or Unix, but NOT Mac OS X.
${alpha::macos}1Classic MacOS (now obsolete)
${alpha::macos}2Mac OS X
${alpha::platform}alphaAlpha 7,8,X
${alpha::platform}tkAlphatk (on any platform)
[info tclversion]8.xTcl 8.x.
$alpha::windowingsystemalphaAlpha on Mac OS X
$alpha::windowingsystemaquaAlphatk on Aqua-Tk (Mac OS X)
$alpha::windowingsystemwindowsAlphatk on Windows
$alpha::windowingsystemclassicAlphatk on MacOS classic
$alpha::windowingsystemx11Alphatk on Unix with X-windows (could be Mac OS X with DarwinX)
Some further calls that may be needed in particular circumstances (listed with their current value as of this release, as illustration):
VariableCurrent ValueImplication
[exec sw_vers -productName]Mac OS Xsystem name
[exec sw_vers -productVersion]10.13.6system version
[exec arch]i386CPU architecture
[exec uname -s]Darwinoperating system name
[exec uname -r]17.7.0operating system release
msgcat::mclocaleccurrent locale

Line endings

Plain text files on OS X (and in unix) use \n for line endings (LF). Your code should never assume this, however, because there are still many Mac files around with line ending \r (CR), and on Windows the old DOS convention of \r\n (CRLF) is still used.
Whenever your code tests for a line ending, it should test for both \r and \n.

Error handling

Errors which are not caught in your code with a [catch] are bugs, unless they start with the string cancel (case doesn't matter here), when they are considered to be the result of the user cancelling an operation. This can make your code simpler, by allowing you to simply throw a cancel error, as in
error "cancel"
error "Cancelled -- this is not a valid option."
If the string cancel is present as in these two examples, then the error message will just be displayed in the status bar.
Any other error which is not caught is a bug, and may be shown to the user, depending on their error reporting settings (see the Errors Preferences panel).

Escaping infinite loops

Even the best programmers get themselves into infinite loops while experimenting with new code, and typically just when there are many open windows with unsaved changes! The following trick allows you, in many cases, to escape an infinite loop.
Step 0: write the following two lines in your prefs.tcl file:
    package require Tclx
    signal -restart error SIGINT
Do this now -- it has to be done beforehand! This will be done once for all (and this is why it's called Step 0!).
Step 1: in the advent of an infinite loop (or any task that takes too long to wait for), switch to the application Terminal, and from there send an interrupt signal to Alpha. To do this you first have to figure out the process identification number of Alpha, which you can do with the command
    ps aux | grep Alpha
This will list two processes -- one is Alpha and the other is the grep process itself.
Step 2: supposing Alpha has process identifier 4547, the interrupt signal is sent with the command
    kill -SIGINT 4547
This will provoke an error in Alpha, and in particular escape the loop. Then save all your work (and restart Alpha).

Defining keyboard shortcuts

Any command can be bound to any key combination, or to a menu item. If one command is bound to both a keyboard combination and a menu item, then the symbol for the key combination will automatically be displayed in the menu item. It is important to note that this displayed symbol is only a visual aid for the user to remember the shortcut; there is no direct link between the menu item and the keyboard shortcut. This means that anybody who wishes to change the shortcut (a developer, a user, or a script which dynamically assigns keyboard shortcuts), does not have to bother about menus (which could have been modified, turned off, or depend on modes). Conversely, anybody modifying the menus, doesn't have to bother about bindings. If there is one available, it will automatically be displayed.

Keyboard shortcuts

The main info concerning bindings is found in the help file Keyboard Shortcuts and the reference for the [binding] command.
Here is a minimal example to start with:
binding create {z 'p'} {alertnote hello}
You can evaluate this in the AlphaTcl Shell (⌘Y) to test it.
This will create a binding from the key combination ⌃P to the command alertnote hello. The z indicates that the Ctrl modifier key has to be pressed simultaneously with the P. The available modifier keys, which can be combined in any order, are
cCommand ()
oOption or Alt ()
zControl ()
sShift ()
More complex key combinations are possible, as explained further below.
To elaborate further on the example, consider
binding create -creator PAUL -tag TeX {z 'p'} {alertnote hello}
The TeX tag means that the binding is only available in TeX mode. The tag doesn't have to be the name of a mode, it can be any string, and then the binding only takes effect in windows whose bindtag attribute list contains this string as an element (cf. Defining minor modes and modifying window behaviours below). This allows bindings to be activated even on a window-by-window basis.
The creator tag (which has to be a four-letter creator code) does not have any effect on the binding per se, but it is highly recommended to put it in all binding declarations, so as to keep track of who defined which bindings. For example you can obtain a list of the bindings with a given creator:
binding list -creator PAUL
For the format of the return value of this command, see [binding list].
Typically a package will define all its bindings with some creator code, say SODA, so that the deactivation script of the package can turn them all off at once by doing
binding::deleteBindingsForCreator SODA
To turn off an individual binding, do
binding delete -tag TeX {z 'p'}
Note that a binding can be turned off without knowing what command it was bound to. If you want to know, do
binding info command -tag TeX {z 'p'}
Note that in the last two examples, the tag is important, since otherwise in the delete example other bindings might be deleted as well, and in the info example, the command of a different binding (a global one) might be returned.

Special keys

To bind to special keys, there are many possibilities, but the easiest is perhaps via virtual keycodes. For example, to bind to shift-return, do
binding create {vs Return} {alertnote hello}
Here the v indicates that the second element is a virtual keycode. For a list of all virtual keycodes, see the Symbolic key names section.

Composite bindings

Since there is a high risk of conflicts between competing bindings, it is often practical, and highly recommended, that a package -- or any user who is setting up his personal bindings -- defines all bindings as two-strokes bindings with the same first part, like for example ⌃P X, ⌃P Q, etc. In this way, from the global viewpoint only one binding is occupied, namely ⌃P, while inside this binding the package has complete freedom to choose the second letters (which themselves can be combinations), and can much more easily find nice mnemonic shortcuts. As an example of a package taking this principle rather far, see the package Embrace.
In a two-stroke key combination, the first stroke is called the prefix. The prefix must be declared separately. For instance:
binding create {z 'p'} {prefixBinding}
This will work as a composite binding precisely because the prefix is bound to the [prefixBinding] command.
Once this is in place, you can define all sorts of bindings for the second part of the composite binding, by doing for instance
binding create -prefix {z 'p'} {"" 'h'} {alertnote howdy}
This binds the combination ⌃P H. The command [prefixBinding] admits an optional argument to specify a prompt. For example one could do
binding create {z 'p'} {prefixBinding -prompt "Type letter of desired alert: "}
binding create -prefix {z 'p'} {"" 'h'} {alertnote howdy}
binding create -prefix {z 'p'} {"" 'b'} {alertnote bye}
The binding command allows several further variations, and support for character codes, glyph codes, and symbolic names. The definitive reference is the [i] command help page.

Creating new menus and menu items

Alpha's menu commands allow the user to build custom menus of the same sophistication as Alpha's standard menus, or to insert menu items into any existing menu. This includes nested submenus, dynamical menu items, automatically disabling menu items if the corresponding command is not applicable in the current situation, decorating the menu items with tickmarks, bullets or indeed any unicode character. It is also possible to create a menu which is rebuilt on the fly at the moment the user opens it, so as to reflect the current state of the application. For example, the Windows Menu contains a list of all open windows. This list is compiled on the fly when the user opens the menu.

Adding menu items (for example to Alpha's standard menus)

The main info concerning the menu handling commands is found in the reference pages of the [menuRef] and [menuItem] core commands.
There are two aspects of this: one is to insert the menu item into some existing menu. The second is to link this new menu item to the envisaged command.
The main difficulty of the first aspect is to correctly specify the place for the new menu item. Since in principle various menus can have the same name (for example, there are many menus called Help), every menu has a reference token. This token is a unique string which is returned when the menu is declared, via the command [menuRef]. For example, the Search Menu might have reference something like menu18. But even if this token is known, one should never refer to it explicitly, because it may vary from session to session (depending for example on the order in which some modes are sourced during the session), so it is necessary either to store the token in some global variable where it can always be looked up, or to search through all the defined menus to find the reference.
In the case of the Search Menu, as an example, the menu is actually declared in the file alphaMenus.tcl, inside the proc [menu::buildCoreMenus]. Here you see the declaration, inside a loop where at some point the variable $menuName has value Search:
set token [menuRef create -title $menuName -name $menuName]
set menu::core($menuName) $token
The first line creates the menu, and the second stores the token for later use. You can peruse the whole array menu::core to see which tokens are assigned to which menus, but the idea is never to use the tokens directly, but rather always refer to this array.
Other menus than the core menus are defined elsewhere, and you'll have to look around in the tcl files to find the global variables that store their identifier token. They are usually called menuToken but may be a simple variable or an array variable.
Alternatively, there is of course a way of querying. The command
menuRef list
will return a list of all existing menu tokens. For each item $token in this list you can ask for the name of the menu:
menuRef set $token -name
or perhaps better
menuRef set $token -title
Although there may be duplicate titles, most likely you can find the desired menu uniquely in this way.
Although we were really only interested in inserting an item into an existing menu, we see that it is necessary to know a little bit about how the whole menu was created! There is further info about this in the next section. You can also ask on the mailing lists, of course!
We assume now that we have got hold of the reference to the menu, and that it is stored as the value of the variable $token. Now we can insert a new menu item into this menu by the command
menuItem insert $token $index $text
here the variable $text contains the text the item will appear as. The variable $index is a natural number indicating the position within the menu. The first item has index 0, and the last can be referenced using the list idiom end, the second-to-last by end-1, etc. Note that these indices might not necessarily be the positions you see graphically in the menu, because it may have disabled or dynamical items which also count! So to figure out the correct index, you really need to look up the definition of the menu and see which items are there. Note also that if you wish to put the menu item last, the correct index is
menuItem insert $token end+1 $text
(because end refers to the last already existing item). There is an alternative, much simpler, syntax for this, namely
menuItem append $token $text
There are many options for configuring menu items. See section Further menu item possibilitites below.
Now the item has been inserted into the menu. But selecting it will only produce an error, because there is not yet any command associated to this new item. This should be done by giving a -command $cmd argument to the call to [menuItem]. As an example, we refine the above example to
menuItem insert $token $index -command $cmd
where $cmd is the desired command. As a concrete example, try
menuItem insert $menu::core(Search) 12 "Hi" -command {alertnote hello}
Go to the Search Menu and try it out. Luckily, the item will be gone next time you restart Alpha. If you can't wait that long, do
menuItem delete $menu::core(Search) 12

Creating new menus

Main info: [menuRef] command.
Creating a new menu involves three steps: first the menu is declared, then it is filled with menu items using the command [menuItem], and finally the menu is inserted somewhere, typically in the menu bar or as a submenu, but it could also be as a popup menu or as a contextual menu.
To create a new menu, do
set myMenuToken [menuRef create -title $name]
and refer to $myMenuToken in all future correspondence with the menu. Several variations and options are possible.

Icons

One possible option is to supply a
-icon $iconToken
argument instead of a -title argument, in order to have the menu displayed with the icon $iconToken instead of a name. The icon token is typically obtained with the command [imageRef create]. As an illustration:
set iconToken [imageRef create -file "/path/to/some/myIcon.icns"]
set myMenuToken [menuRef create -icon $iconToken]
Note that AlphaTcl provides convenience procs in the file icons.tcl. The proc [icon::createMenuIcon] will find an icns by name without specifying the complete path of the file: it looks in the appropriate folders. For instance, here is how the Filesets Menu package creates its main menu:
icon::createMenuIcon fileset
set menuToken(main) [menuRef create -icon [icon::getMenuIcon fileset] \
           -name $filesetMenu -command $menuProc]

Menu procs

Another possible option is the -command argument, like in
set myMenuToken [menuRef create -title $name -command "myMenuProc"]
Here myMenuProc is a callback proc which takes two arguments: the reference to the menu (i-e the token), and the name of a menu item. This proc is then required to take the appropriate action depending on the menu selection. So it will typically look something like this:
proc myMenuProc {menuToken itemName} {
	switch $itemName {
		"Hi" {
			alertnote "Hello"
		}
		...
		default {
			error "Not implemented yet"
		}       
	}
}
It should be noted that instead of supplying such a menu proc for the whole menu, it is also possible to supply a command for each menu item individually. This second method has some conceptual advantages, in that each menu item becomes more of an independent unit, a name associated with a command, without depending on features of a parent menu and its attendant menu proc. For example, a menu item with its own command can be moved to another menu without further administration overhead.

Dynamically built menus

Finally, an important possible option to the [menuRef] command is the -updateProc argument which lets you specify a Tcl procedure to evaluate before a menu is opened, typically to rebuild the whole menu in accordance with the situation. This is useful for menus whose content varies with the context. When the procedure declared by this option is invoked, the token of the menu is appended to its list of arguments. An example of a menu using this is the Windows Menu, the exact list of menu items is only calculated on demand at the moment the user opens the menu.

Inserting the new menu

Once the menu has been constructed, it has to be inserted somewhere. To insert it in the main menu bar, do
menuRef insert $token -before $otherToken
Here $token is the menu we are inserting, and $otherToken is the reference to another menu in the menu bar, before which we wish to insert the new menu. If unspecified, the menu is appended at the right of the menu bar (yet before the Help menu).

Nested submenus

To insert the new menu $myMenuToken as a submenu of another menu $parentMenu, say as the second item, do
menuItem set $parentMenu 1 -submenu $myMenuToken
Note that a same submenu can not be inserted in two different parents.

Further menu item possibilitites

The main info about menu items is found in the reference of the [menuItem] command.

Separators and static text

Separators are menu items on their own, and count in the index count. A separator may be defined in two different ways: Note that the name can contain other stuff than the dash. This can be useful for later use, if for example a futher item is to be inserted, then one can navigate by searching for the exact string naming that separator. Another solution is to set a tag (which is an integer value) on the item with the -tag option and then find it using the [menuItem index] command.
Headers or other static text can be indented with the -indent option:
menuItem append token "Section header" -header 1
There are many facilities for changing the layout of the text of an item, for example with the extra flags like -style
-style 2 -icon [icon::getNamed lightBlueDot]
which will set the item in italic and insert a light blue dot. See the [menuItem] reference page for all the options.

Dynamical menu items

Here is a typical example, taken from the Edit Menu:
menuItem insert 17 $menu::core(Edit) "Shift Left" -dynamic 1
menuItem insert 18 $menu::core(Edit) "Shift Left Space" -dynamic 1 -alternate 1 -modifiers "o"
Both menu items have the -dynamic flag, which means that their display depends on which modifier keys are pressed. The second item has the option -alternate 1, which means that it is an alternate item.The second item has also the -modifiers "o" option which means that it will only be displayed when the option key () is pressed.
It is important that the dynamic pair are adjacent in the order of the menu items. Otherwise both items will be shown.
Note that the modifier specified to trigger the alternate item is supposed to match the keyboard shortcut specified elsewhere for the command attached to the item. That is, if the keyboard shortcut defined with [binding create] is ⌘[ for Shift Left, then it should be ⌥⌘[ for Shift Left Space.

Disabling menu items

At any time, one can enable or disable a menu item with the command
menu::enableItem $token "Name Of The Item" 0
This is a convenience proc based on the -enabled option.
If the test to perform for deciding whether a menu item should be enabled or disabled is whether there is one (or two, three, etc) open window(s) which can be edited or not, then the enabling and disabling can be automatised by registering a dimThreshold hook for the menu item. If for example a menu item Copy in menu $token needs at least one open window to make sense, the enabling and disabling can be achieved by registering a hook in this way:
hook::register dimThreshold [list $token "Copy"] 1
See the section on Event Hooks for more information about hooks.

PART 2: WRITING PACKAGES

Alpha provides nice facilities for bundling your scripts into packages, be it extensions, features or modes; this helps them take advantage of global facilities such as preferences and help text, makes it easier to do dependency checking, and last but not least, makes it easy to distribute and install. The most advanced type of package, that of a Mode, provides functionalities like syntax colouring, comment handling, and function marking, which cannot be achieved without the alpha::mode declaration that defines a mode. This Part 2 describes those facilities for writing packages.
We strongly recommend that you look at some of the existing packages and base your code upon them. There are at least a dozen quite small, simple packages in AlphaTcl which would make good templates. Here's a partial list:
recentFiles.tcl
colors.tcl
macros.tcl
spellcheck.tcl
smartPaste.tcl
backup.tcl
autoSaveOnSwitch.tcl
fileUtils.tcl
changeLogHelper.tcl
These files are all found in either the CorePackages or Packages folders.

Package basics

There are two basic types of package which Alpha uses: modes and features.
A mode helps with editing a file for a particular purpose: web pages use HTML mode, C++ code uses C++ mode, LaTeX documents use TeX mode,... There are about 70 such modes currently available.
Features are of three types: menus, extensions and ordinary features. A feature adds functionality to Alpha either globally (a global feature) or just for particular modes (a mode feature). Menus are one type of feature used to extend Alpha, and aren't really much different from features which don't add menus: the only distinguishing difference is a couple of lines of code which do some menu creation/deletion.
For examples of existing menus and features which may be activated in Alpha, see the Menus Preferences dialog and the Features Preferences dialog.
All packages will contain a package identification and initialization command, called as appropriate. (One of the purposes of this part is to describe the minor, but important differences between them).
The following procs can be used to declare a new package: NOTE: Technically, menus, features and extensions are all treated in the same way by Alpha. However each will have different associated information which will determine whether/in what section it appears in a dialog box. All this information is stored in the index::feature array.
It is not actually necessary to place modes in Tcl/Modes, menus in Tcl/Menus or packages in Tcl/Packages inside the AlphaTcl library: they could go anywhere on the auto_path variable. The chosen layout has proved convenient though.

Examples

Here are some examples:
    alpha::library identities 0.5  { ...
	
    alpha::feature recentFiles 0.5.1 "global-only" { ...
The package Identities is an extension which allows you to create multiple identities when using Alpha. It installs an Alpha ↣ Preferences ↣ Identities submenu for the commands which allow you to create new and edit current identities. It is designed to be turned on globally, and there is no action to be taken if it is turned off. The number is the version of this package; in this case, version 0.5.
The package Recent Files, which creates a menu of recent files accessible from Alpha's File menu, is an global-only feature that is defined in the file recentFiles.tcl. Like extensions, global-only features are only designed to be turned on and off globally (so you can't arrange to use the recent files menu when in C++ mode but not when in HTML mode), which makes sense for this package, since a user will either want to have access to the menu all the time, or not at all. It is a feature so that we can also create a deactivation script to remove the menu when it is turned off. Notice this is declared as an feature, not as a menu.
The [alpha::menu] proc is reserved for menus which appear in Alpha's menubar, not submenus such as this.
In fact the Alpha ↣ Mode Setup ↣ Features dialog lets expert users turn such global extensions off for particular modes, but this might cause unforeseen problems. See the Text Mode Features Preferences.
Another example:
    alpha::feature latexAccents 1.0.5 {TeX Bib} ...
Some users of LaTeX find it easier to type accented characters 'éåü…' directly into their documents rather than somewhat esoteric control codes like \'{e}. The package Latex Accents makes that task a lot easier. It is only useful for LaTeX and BibTeX documents, so the author specifies this information in an extra argument to [alpha::feature] which is not allowed (or relevant) for [alpha::library].
Most modes add a menu which is automatically activated in that mode. Other menus are useful globally. It's up to the user to decide whether each feature/menu should be activated globally or only on a mode-by-mode basis, but each feature can specify its default. Mode authors can of course set the defaults for their mode. Examples of globally useful menus are the Filesets Menu, the Filters Menu and the Electric Menu
Finally, an extension is a simple form of feature which is either globally active or off (it either doesn't make sense or isn't particularly useful to turn extensions on and off in a mode-dependent way). Examples of extensions are the printer choices sub-menu, or the bib-engine (used to interact with BibTeX).
Note: a menu is something which sits in Alpha's menubar, at the top level. A feature or extension can create submenus which sit inside top level menus, but these are not menus in the same sense. The main distinction is that menus must be registered with the procs [alpha::menu] or [addMenu], whereas submenus need no special registration.

Quickstart

For the impatient reader: here's how to write a very simple feature which contains one new procedure and one new key-binding (to that procedure). Just create a file which looks like this:
alpha::feature myPackage 0.1 {C C++} {
	# no global initialization required
} {
	# activation script
	# bind Ctrl-P to my procedure, in those two modes:
	binding create -tag C {z 'p'} myProcedure
	binding create -tag C++ {z 'p'} myProcedure
} {
	# deactivation script
	binding delete -tag C {z 'p'}
	binding delete -tag C++ {z 'p'}
} requirements {
	# if your package has any particular requirements (such as 
	# particular versions of Alpha or it only runs on unix),
	# place code to test that here.  Otherwise omit this
	# section completely.
	if {[info tclversion] < 8.0} {
		error "My package requires Tcl 8"
	}
} uninstall {
	this-file
} maintainer {
	"My Name" my@email http://webpage..
} help {
	Binds the blah-key to 'myProcedure' which carries out...

	This package is only designed to do something useful in
	C and C++ modes.
}

proc myProcedure {} {
	# do some cool stuff
	alertnote "It works"
}
Save this file in the Packages subfolder of Alpha's Application Support Folder. The name of the file does not matter: it could be myPackage.tcl or anything else. Then quit Alpha: when you relaunch it, it detects the presence of the new file and automatically rebuilds the necessary indices in order to register the identity and characteristics of the new package myPackage.
By default this package declares it is useful for C and C++ modes, although the user could choose to activate the package globally or individually for any set of modes. You will find it in the Mode Features sub panel of the Alpha ↣ Global Setup ↣ Features dialog.

Package indices

There is one subtle and important point about packages: the commands [alpha::feature], [alpha::mode], etc. listed above, contrary to all other commands, are not meant for execution at runtime, and if you try to invoke one of them nothing will happen. They are not executed at startup either.
THE PACKAGE DECLARATION COMMANDS ARE ONLY EXECUTED WHEN ALPHA REBUILDS PACKAGE INDICES.
So while developing a package or modifying an existing one, any changes to the declaration will not take effect by evaluating, nor by restarting. It is necessary to request a Rebuild AlphaTcl Indices from the Alpha Developer Menu.
What happens is that Alpha, maintains a Cache of all package information, in order to avoid sourcing all the files defining packages, while still having all meta-data about them available. Avoiding to source all the files is simply for economy of memory, and to speed up the startup. The necessity of having the meta-data available is for example to display it in the prefs panes, and to know which other packages should be turned on first, if one package is requested.
While this system is practical in normal usage (and, for most users, it is never necessary to rebuild indices, and when it is, typically Alpha figures it out by itself), it is often a source of confusion for the developer and for package writers in particular. For example, it often happens in the development phase that you change the name of some variable, and next time Alpha starts up you get a start-up error complaining about an unknown variable. It is then because the old variable is still present (uninitialised) in the cached package script. Rebuilding indices then cures the problem. Or worse: your recently modified package continues to work fine, but when shipped to other users, unknown variable errors occur. It may then be that some component in the package is referencing an old variable that is still defined on your machine because it was defined in the old init script which is in the cache, but that on the foreign machine, a fresher cache will not have the old initialisation, hence causing the error. The upshot is to remember to rebuild package indices whenever you make changes to a package declaration.
Packages are rebuilt automatically for example whenever Alpha detects a new file in the AlphaTcl directory hierarchy, so when a user installs a package for the first time in Alpha's Application Support Folder.

Declaring your package to Alpha

A package must contain, preferably as its first non-comment line (this is important), a statement like this:
alpha::mode NAME VERSION ... 

alpha::menu NAME VERSION ... 

alpha::feature NAME VERSION ... 

alpha::extension NAME VERSION ... 
(The other parameters to these commands are explained below). The name will identify your package, and for modes must be at most 4 characters long. It should not contain any spaces (this limitation may be lifted in a future version of Alpha). The version is a string of the form 1.0.1, or 2.3b1 or 1.4.530.1.3a5. Modes, menus and extensions take different arguments for the remainder of the alpha:: declaration line, but each ends in a script which Alpha scans and stores for you (Alpha scans all installed files for package declaration lines and caches this information so that at startup, no files need be read). For modes and menus, this script is executed automatically at startup. For features, there are initialization and activation/deactivation scripts. An extension is a simpler form of a feature which only has a single initialization script (used the first time it is activated). Package initialization occurs in the order: modes, menus and finally extensions.
Important: The declaration command must not be wrapped in any [catch] statements. This is necessary to allow Alpha to rebuild package indices rapidly (note that it is no longer required to be at the beginning of the line). If you wish to write code which is able to run both inside AlphaTcl and with other Tcl interpreters, try something like:
if {[info commands alpha::extension] ne ""} {
	alpha::extension ...
} else {
	# initialize in some other way for other generic Tcl interpreters
}
Your package will not function properly if you don't obey the above guidelines.
Alpha itself is considered a package, with a version number, so that your code can request a particular version of Alpha. Alpha's version number also has a patchlevel which will be updated with each Tcl-only patch release. Hence you can write:
alpha::package require Alpha 9.0
You can similarly require particular versions of other packages. You should require as old a version as possible, so that you don't force users to upgrade unnecessarily.

Package requirements

A package can specify a separate script for testing whether the current environment is suitable for the package. This is called a requirements section, as in the following example:
alpha::extension iAppleX-tools 1.1 {
	# declaration script
} requirements {
	# This package only runs on OS X on Intel, and needs AlphaTcl 8.1
	if {$tcl_platform(platform) != "unix" ||
	  $alpha::macos != 2 || ![regexp "86" [exec arch]] } {
		error "The iAppleX-tools package requires OS X/Intel"
	}
	alpha::package require AlphaTcl 8.1
}
Packages may be dependent on particular operating systems or even hardware (see the Environment introspection section for more details), or depend on particular versions of Alpha or on other packages (e.g. filesets 2.0). Note that Alpha and AlphaTcl themselves are considered packages.
The main proc for testing whether dependencies are met is the proc [alpha::package] which is similar to the Tcl command [package] but differs in a few respects. As in the example above, you can use [alpha::package] to check/request the presence of other packages. The syntax is:
alpha::package require NAME ?VERSION?
Other sub-commands are exists names versions vcompare vsatisfies forget uninstall and mode, menu and package. These last three mimic the usual [alpha::mode] [alpha::menu] and [alpha::package] commands. Equivalent to alpha::mode, alpha::menu and alpha::extension For extensions only: Packages whose requirements fail cannot be activated in any of the preferences dialogs, and are listed separately in the "Installed Packages" help file, together with the reason that their requirements failed. The user can then perhaps see that, say, the package would work if they upgraded some component of Alpha, and may decide to do so.

Writing new features or extensions

An extension is a package which can be turned on once and then left alone. Something which requires turning on/off for different modes is a feature. In fact an extension is just implemented as a simple form of feature. A new extension must provide at the very least the following formal line, preferably as the first non-comment line of one of its files:
alpha::extension 'NAME' 'VERSION'
Normally it is useful for the user to be able to choose whether to activate an extension or not. In this case you must also provide a script for Alpha to evaluate if the user chooses to activate the extension. Such a script is given by a line of the form:
alpha::extension 'NAME' 'VERSION' 'SCRIPT'
If no such script argument is given, the extension is called auto-loading and really just provides some new procedures which can be used by other code.
A feature is more sophisticated and takes arguments of the following form:
alpha::feature 'NAME' 'VERSION' 'LIST OF MODES/GLOBAL' \
  'INIT SCRIPT' 'ACTIVATE SCRIPT' 'DEACTIVATE SCRIPT'
Here is an example of extension declaration from the package Bibtex Log Helper:
alpha::library marks 1.1 {
	marks::initializePackage
} 
Here we didn't bother to turn the feature on and off, since its initialization was so trivial, and it won't interfere with other modes at all. Here's a more complex example of a feature declaration:
alpha::feature latexMathbb 1.4 {TeX Bib} {
    # Initialization script.
    namespace eval TeX {}
    # Make sure TeX mode preferences are available.
    catch {latex.tcl}
    set TeX::UseMathbb 0
    newPref var blackboardBoldSymbols "NZQRCH" TeX {TeX::Mathbb::adjustBindings}
} {
    # Activation script.
    TeX::Mathbb::turnOnOff 1
} {
    # Deactivation script.
    TeX::Mathbb::turnOnOff 0
}
We didn't bother with activation / deactivation, since the definitions don't take effect in other modes. The simple extension and feature commands make it very, very easy to extend Alpha's functionality without messing with the user's preferences file, without creating any '...+.tcl' extension files and without a complex installation process. Alpha simply maintains a database of all extension scripts, and evaluates at startup all scripts for extensions which the user has activated.

Adding items to global menus

Packages can add menu items or submenus to global menus without further bureaucracy. The techniques were described above in Section Adding menu items. This code should typically be placed in the init script of the package declaration.

Writing new extensions (keyboard caveats)

Writers of any package for Alpha should pay some attention to the problems which can arise with international keyboards. Some bindings are simply not available on some keyboards. For instance, on some keyboards, you need to use shift to get the key '\' (unlike American keyboards where it is a single keypress). On such a keyboard there is no distinction between '' and '⇧⌘'. There is no simple workaround for this problem.
Possibilities are: (i) check the current keyboard definition and adjust bindings appropriately (based upon user feedback, presumably). (ii) let the bindings be user-definable either by using newPref binding to define things, or by using a menu-scheme such as is used by HTML mode.
See more information on keyboard settings in the International Menus package.

[alpha::library] packages

Packages that are declared using [alpha::library] provide extra functionality to AlphaTcl without requiring the user to turn on/off a menu or feature. These packages are essentially early and always-on features, so their activation scripts will be evaluated when Alpha is first started, before the user's global features are activated and before mode scripts are sourced.
This is most useful for packages which either (1) add different preferences (or additional options for current preferences) that can be used in other code, or (2) simply provide a library of Tcl code which requires a minimal script to properly enable the user-interface.
The basic formal syntax is
alpha::library 'NAME' 'VERSION' 'SCRIPT' args
Additional arguments can include the standard help, maintainer, uninstall, and requirements. If the requirements script throws an error then the activation script will not be sourced on startup. These packages should not include any preinit script.
For example, the various Version Control packages (such as Svn, Git, Bazaar, Mercurial, CVS, etc.) add different options that the user can set, so if the code is available and relevant to the user's platform, we simply evaluate the package's script when Alpha is first started. Thus we find this in vcMercurial.tcl :
# Feature declaration
alpha::library vcMercurial 0.1 {
    hook::register vcsSupportPackages {vcs::mercurialSupport}
    vcs::register Mercurial
    ;proc vcs::mercurialSupport {args} {
		hook::register preOpeningHook mercurial::preOpeningHook
		hook::register activateHook mercurial::activateHook
		hook::register closeHook mercurial::properClose mercurial
    }
	# Create a "minor mode" for the windows under mercurial control
	alpha::minormode "mercurial" +bindtags "mercurial" +hookmodes "mercurial" +featuremodes "mercurial"
} uninstall {
	this-file
} maintainer {
	...   
The result here is that a new Version Control option named Mercurial is added to the VCS popup menu presented in the editAFileset dialog.
Important: the [alpha::library] package declaration should _not_ be used to add new menu items or keyboard shortcuts. It can create new preferences or define new support procedures, but there should be _no_ impact on the user with regard to default behaviors, editing or otherwise.
Note that the runAlphaTcl.tcl file declares other packages in AlphaTcl to be early and/or always-on. These lists are hard-wired, reserved for those packages deemed universally useful, and only adjusted after discussion on one of the Alpha mailing lists.

Writing new menus

You may of course write your own menu for personal use.
In this section we use the word menu as meaning "package whose added functionality is a menu". In the AlphaTcl library, these are placed in the folder $HOME/Tcl/Menus.
The menu declaration contains a start-up section of much the same form as a mode or feature:
alpha::menu ftpMenu 1.2 global Ftp {
	# One-time initialization script 

	# here we do nothing
} {
	# Activation script

	# here we do the standard thing of calling the menu proc
	ftpMenu
} {
	# Deactivation script
}
# proc ftpMenu to auto-load
proc ftpMenu {} {}
The global parameter tells Alpha that this menu isn't associated with any particular mode (otherwise you can replace global by a list of modes possibly including the global keyword, e.g. {global WWW HTML}).
Older versions of Alpha used to call a procedure with the same name as the menu (here ftpMenu) automatically whenever the menu was to be inserted. The newer setup is a bit more verbose, but puts more control in your hands.
Note: if all you want to do is add a submenu to an already existing menu, go to the section Adding items to global menus: you don't need the alpha::menu statement, but actually need to write a feature using [alpha::feature].
A menu-package is a set of code which builds and handles a standalone menu which the user may choose as a global menu. Examples are the Ftp Menu, Fileset Menu, Mac Menu, User Menu, Color Menu and Mail Menu (in fact this last item, since it has a mode associated with it, could in fact be rewritten as a mode with attached menu).

Writing new modes

The mode is the basic editing environment which affects all users. Modes do not require any activation on the part of the user. As long as they are installed in AlphaTcl, they are always available.
Topic covered include:
Standard mode files
Multi-file modes
Mode procs
Smart mode lines
unixMode array
modeCreator array
Comment characters
Paragraph definitions
Indent On Return
Automatic indentation
Option-click-titlebar menu
Electrics
The Marks Menu
The Parse Functions popup menu

Standard mode files

To add a mode to Alpha, a file (usually ending with Mode.tcl) must be created and placed in in the $HOME/Tcl/Modes directory or in the Modes subfolder of Alpha's Application Support Folder.
The Alpha ↣ Global Setup ↣ Create New Mode assistant provides interactive help to set up the basics of your mode. It is highly recommended to use this assistant, but in most cases you'll need to elaborate on the output, and you'll need to know how a mode definition works, as described in this section.
The mode-definition file should begin with a call to the proc [alpha::mode]. This command has the following formal syntax:
alpha::mode mode version startupScript suffixes modeFeatures script
This proc is only designed to be called during package-indices rebuilding, and its effect is to store the script and the parameters in Cache/index/mode. If called in any other circumstances the proc simply returns. The reason for storing the script and the parameters is to make the characteristics of the mode available to Alpha without having to source the whole mode-definition file. This is important since a typical user will not use more than a few out of Alpha's 70+ modes.
The arguments to [alpha::mode] are:
mode
a four-letter signature of the mode.
version
the version number of the mode.
startupScript
a script executed the first time Alpha switches to the mode Typically this script will just be a dummy proc defined in the mode-definition file, and the effect is simply to source the file.
suffixes
a list of file extensions that will trigger the mode.
modeFeatures
a list of features that will be activated by the mode.
script
a script that Alpha will execute at start-up. This part is very important. It must contain everything that Alpha needs to know about the mode in advance, i.e. before the mode is used the first time and the mode-definition file is sourced. This script is stored in Cache/index/mode. Typically it contains declaration of a mode-specific menu, and definition of interface name.
Here is a simple example from Pascal mode:
alpha::mode Pasc 1.1 source {*.p} {} {
    # Script to execute at Alpha startup
    set unixMode(pascal) {Pasc}
    set ::mode::interfaceNames(Pasc) "Pascal"
}|))

The first time Alpha enters Pascal mode, AlphaTcl will create a ((i Pasc
i)) namespace and then the ((i startupScript i)) will be evaluated, in this
case the keyword ((i source i)) has the effect of evaluating the ((e
ah::link file pascalMode.tcl e)) file. Subsequent switches to Pascal mode
will not need to source the file and so the startup script is only ever
evaluated once. As a simpler alternative, you can use an empty dummy
procedure as a way of ensuring the file has been sourced once and once
only.

((nl)) The ((i suffixes i)) allow Alpha to automatically determine the
correct mode of a newly opened file. In this example, every file with file
extension ((i .p i)) will open in Pascal mode. There is another mechanism
for putting windows into the right mode, namely for so-called unix files,
for which the first line of the file may determine the mode. In this
example, the mode declaration says that every file with the string ((i
pascal i)) in its first line will open in Pascal mode. Note that this
declaration is in the ((i script i)) part: it has to be in this part
because clearly Alpha needs to know this rule before entering Pascal mode
for the first time!

((nl)) The ((i modeFeatures i)) argument does not involve any surprises in
this case: it is a list containing two menus to be activated whenever we
enter Pascal mode.

((nl)) In the ((i script i)) part, the second line is also worth an explanation: the line
((|
set ::mode::interfaceNames(Pasc) "Pascal"
tells Alpha to use the string Pascal instead of Pasc in the user interface, for example in the modes popup menu. Again, it is clear that this instruction must be placed in the script part so that Alpha can know this in advance and display the mode correctly.
Important: Perhaps the MOST important part of the above code is the existence of the startupScript. When this script is called, the result must be that all of the mode's preferences are declared. In other words, the startupScript should ensure that the Tcl code containing all the newPref declarations is evaluated. This is very, very important!
The normal way to do this is to have the startupScripts be a dummy procedure: e.g. proc dummyPascal {} {} as above. Tcl's autoloading mechanism will then source the file containing that procedure. Hence the dummy procedure should normally be in the same file as the mode's newPref declarations. This is important because almost directly after that call, Alpha expects all of the mode's preferences to be stored in the ${mode}modeVars array, which will only be true if all of the newPref commands have been evaluated.
Important: the result of calling dummyProc/startupScript must indeed be that all your newPref declarations are executed. As a result of this, the preferences will be stored in the <mode>modeVars array, but will not yet be copied into the global scope (i.e. the <mode>modeVars(myPref) array element will exist, but the global var myPref will not yet exist). Once your dummyProc/startupScript returns (which generally means your mode's initialization and sourcing of files is complete), only then are the array entries copied into the global scope (in the latter half of the changeMode proc).
Here is another simple example, from Perl mode:
alpha::mode Perl 3.7 source {*.pl *.ph *.pm} {
    perlMenu
} {
    # Script to execute at Alpha startup
    addMenu perlMenu Perl
    set unixMode(perl)    Perl
    # Make sure that we have a 'Perl::PrevScript' variable.
    ensureset Perl::PrevScript {*startup*}
    # Make sure that we have a 'PerlSearchPath' variable.
    ensureset PerlSearchPath ""
}
In this case the script contains the command addMenu:
addMenu mname ?name? ?<pertains to modes>?
which defines a new menu, with name the visible name of the menu. This menu can be used in any mode, although by default, it is only attached to Perl mode. mname is actually a variable which contains (will contain) the real menu name. The third argument usually contains a single mode with which this menu is distributed. Its use is mainly so that Alpha knows that this menu belongs primarily to this mode, so that if the user asks for information on the menu, Alpha knows to respond with information on the mode instead (curiously Alpha wouldn't otherwise know).
Here is an example from Diff mode:
alpha::mode Diff 1.0 diffMenu {*.diff} {diffMenu} {
    addMenu diffMenu diff Diff
} uninstall {
	file delete "$pkg_file"
	file delete [file join ${HOME} Tools "GNU Diff"]
} maintainer { "John Doe" john@doe.example }
The uninstall and maintainer sections are optional, and explained later. Here is a more complex example for Python mode:
# minimalist mode set-up #
alpha::mode Pyth 0.2 source {*.py *.pyc *.pyi} PythonMenu {
	addMenu PythonMenu
	#To set the mode from a unix-like "#!python" first line
	set unixMode(python) {Pyth}
}
# dummy proc to load this mode.  
proc dummyPython {} {}
# dummy proc to load the code to make the PythonMenu 
proc PythonMenu {} {}
# rest of mode's code follows...

# Lets the automatic comment insertion/continuation
# routines function with this mode. 
set Pyth::commentCharacters(General) "\#"
set Pyth::commentCharacters(Paragraph) [list "## " " ##" " # "]
set Pyth::commentCharacters(Box) [list "#" 1 "#" 1 "#" 3]
The package declaration should contain all code which is necessary to recognize a given file as belonging to that mode (hence the use of unixMode for python), which will then make Alpha call the dummyProc which will auto-load the entire file. Other information, such as the commentCharacters entries above should not go in the package declaration.
Notice that there are two types of dummy proc; each menu Alpha uses should have a proc of the same name associated with it. This proc is called by Alpha _each_ time Alpha tries to insert the menu into the menubar. The proc can be empty (as above), or could actually do something if desired. The second kind of dummy proc is the mode dummy proc, given in the [alpha::mode] command. Here it is called dummyPython. Alpha calls this proc the first time it switches to Pyth mode. Again the proc can do something if desired, but will usually be empty. If both procs are empty, as above, one can of course just use one proc (called PythonMenu in this case), and replace the [alpha::mode] line by:
alpha::mode Pyth 0.2 source {*.py *.pyc *.pyi} PythonMenu
The only advantage of this approach is that it saves a small amount of memory (you can delete the dummyPython proc from the file). Note that this only holds true for modes whose Tcl code is in one file.

Multi-file modes

Modes that consist of more than a single file should no longer use a source statement that assumes that the other files for the mode will be in the $HOME/Tcl/Modes directory or in the Modes subfolder of Alpha's Application Support Folder.
The best solution is to use Alpha's standard auto-loading capability which will source a file when it needs a procedure which is contained in that file. If you must use source manually, you can use 'file dirname [procs::find someProcInThisFile]' to get the current directory. Your other files should also be there.
A convenient way of implementing your multi-file loading is to create procs with the same name as the file at the beginning of each file. Then to load the file you just do catch "filename". For example if there is a proc defined proc perlEngine.tcl {} {} at the start of the file perlEngine.tcl, then I can auto-load that file by having the following code in perlMode.tcl (note: actual code differs slightly):
if {[catch perlEngine.tcl]} { 
	alertnote "Problem loading 'perlEngine.tcl'" 
}
Remember, you don't necessarily need to source all your mode/pkg's files in one go. Tcl is designed to source files for you when they are needed (when a procedure contained in one of them is called). Hence you only need to source files which are required immediately (to set up some data, variables, menus etc.) and not everything else. It is usually best to have a single file which contains all the initialization code, and let any other files be auto-loaded as necessary.

Mode procs

The following procs are either required or desired for a mode to be fully functional within Alpha.
Have a look at a standard mode like Tcl or C++ to see what some of these should do. (In fact if you are writing your own mode, it is always helpful to examine other modes and borrow from them.)

Marking procs

<mode>::MarkFile -w win
<mode>::parseFuncs
These provide indexes into code via the Parse Functions Docwin parse button and Marks Docwin marks button popups. See the sections below about The Marks Menu and The Parse Functions Popup Menu). Note that, for future compatibility if your mode makes use of the auto mark on open flag, the MarkFile procedure should be able to mark windows which are not the frontmost window.

Info providers (shift-command-double-click)

The following procedure may be used to provide access to source or file related info:
<mode>::DblClick
It is invoked when the user shift-command-double-clicks inside the text area. The proc takes two arguments representing the start and end positions of the relevant region in the text pane. See examples in the AlphaTcl library, for instance the proc [Tcl::DblClick].

Electric behaviour

These procs assist formatting and save on keystrokes.
<mode>::carriageReturn
This proc, supported by the following two, helps to keep indentation standard (indirectly called by a carriage return).
<mode>::indentLine
This proc indents a line by inserting spaces/tabs as appropriate. If a 'correct indentation' proc is given, then this procedure is not necessary.
<mode>::correctIndentation -w win pos {next ""}
This proc allows smart-paste package to function. This procedure must never throw an error.
<mode>::electricLeft
<mode>::electricRight
<mode>::electricSemi
These procs provide electric behaviour for '{', '}', and ';' respectively. Their use is primarily for languages that use '{' and '}' for code blocks, and ';' as the line terminator. They are indirectly called by the key they correspond to, and then, only if a corresponding mode preference flag has been defined and set to 1. See the Electric Braces And Semicolon section below.

Smart first line

If your mode will want to be able to use the first line of a file to determine what mode a file should be opened up in, you need to tell Alpha what word in the first line should trigger that mode:
set unixMode(python) {Pyth} 
A good place to do this is in the body of the your mode's package declaration alpha::mode … {… statement (see example for Python above). Note that the presence of the word itself is not sufficient; it must be of the form #! /usr/bin/python as is common on Unix (where it tells the shell with what application to run the script)
Note that there is already built in support for opening a file in a given mode if the first line contains:
-*-<mode_label>-*-
e.g.:
# -*-Tcl-*-
See also the Smart first line section in the Alpha Manual for more information about the editing settings that can be specified in this magic first line.

unixMode array

When you open unix files where the first non-empty line reads
#!/dir/subdir/command ...
then Alpha tries to find a mode corresponding to command. With the unixMode array, you can tell Alpha which mode to choose when opening such a file. You may add to this array with lines like:
set unixMode(command) mode
where command is the lowercase version of command in the line
#! /dir/subdir/command ...
and mode is the mode which you want Alpha set for the window. For example, to make Alpha open files with a line #! /usr/bin/perl ... in Perl mode use the line:
set unixMode(perl) Perl

modeCreator array

The modeCreator array allows you to tell Alpha which mode to choose when you open a window depending on which application has created the file. Add to this array with lines like:
set modeCreator(4_char_creator_code) mode_label
The 4_char_creator_code is the signature of the application which has created the file and mode is the mode which you want Alpha set for the window. For instance:
set modeCreator(ToyS) Scrp 
set modeCreator(MOZB) HTML
Tip: To find the signature of an application, launch it, open the Tcl Shell (⌘Y) and type ps at the prompt. This will list all running applications; the second column lists the signatures. Click here to do this now.
A good place to declare a modeCreator entry is in the body of the your mode's init script in the alpha::mode … {… statement.
Note: identifying applications by their 4-char creator code is deprecated and this array is not of great use in AlphaTcl which now makes use of bundle IDs.

Comment characters

If your mode will want to use the standard Alpha comment/uncomment block procedures, file headers, ... you need to tell Alpha what characters are used for comments. You should just define the following variables:
<mode>::commentCharacters(General)
<mode>::commentCharacters(Paragraph)
<mode>::commentCharacters(Box)
For instance, here are the values for C++ mode:
set C++::commentCharacters(General) [list "*" "//"]
set C++::commentCharacters(Paragraph) [list "/* " " */" " * "]
set C++::commentCharacters(Box) [list "/*" 2 "*/" 2 "*" 3]
If you do this then there is no need to mess with the commentCharacters procedure. (In general it is best if your mode does not need to redefine procedures in Alpha's core).
If you want to over-ride the standard proc [::CommentLine] , then you can include a mode proc, as in the proc [C::CommentLine].
There are currently three kinds of comments: General, Paragraph, and Box. Other kinds could also be added in the future, though as of this writing these are the only three that are widely defined by modes in AlphaTcl. They are not required. Some modes do not define Box comments.
General purpose comment characters are used to check if we're in a comment block, but are not used in the default Line/Paragraph/Box routines. This General category could be a list, such as
set C++::commentCharacters(General) [list "*" "//"]
if there are several different characters that could indicate a comment.
Paragraph comment characters should be a list with three items: the beginning, the end, and any character that should be used in between them. This is most useful for modes that only use bracketed comments, but allows for other modes to create Paragraph style comments like this block in Tcl mode:
## 
 # some comment here
 # continued...
 ##
obtained with the following setting:
set Tcl::commentCharacters(Paragraph) [list "## " " ##" " # "]
Box comment characters should be a list with six to eight items:
  1. Beginning Comment String
  2. Beginning Comment Length
  3. Ending Comment String
  4. Ending Commment Length
  5. Fill Character
  6. Space Offset
  7. String for Vertical Edges (optional)
  8. String for Top-Right and Bottom-Left Corners (optional)
Here's a typical example for a mode with a single comment character:
 set Tcl::commentCharacters(Box) [list "#" 1 "#" 1 "#" 3]
Here's an example for a mode using bracketed characters:
set yacc::commentCharacters(Box) [list "/*" 2 "*/" 2 "*" 3]
If item (7) is not specified, it is equal to (5). Here are examples with 7 items:
set HTML::commentCharacters(Box) [list "<!--" 4 "-->" 3 "-" 3 "|"]
set Aida::commentCharacters(Box) {"!!" 2 "!!" 2 "!" 3 "!!"}
If item (8) is not specified, it is equal to (7). Here is an example with 8 items:
set Text::commentCharacters(Box) {"+" 1 "+" 1 "-" 3 "|" "+"}
Experiment with the Text ↣ Comment Box menu item to determine correct values, and in particular how different Space Offset values change the construction of the box. The menu item Text ↣ Uncomment Box (obtained by pressing the Option key while the Text menu is opened) lets you remove a box.
Note: and yes, it seems that the Comment Length values could be pretty easily computed using [string length], but there are tricky exceptions. For instance, in Lex/Flex mode we have:
set lex::commentCharacters(Box) [list "%{\n/*" 2 "*/\n%}" 2 "*" 3]
with Comment Length equal to 2 and not 5.

Paragraph definitions

To customize your mode's paragraph filling, you can set the following variables:
<mode>::startPara
<mode>::endPara
For instance:
set Tcl::startPara {^(.*\{)?[ \t]*$}
set Tcl::endPara {^(.*\})?[ \t]*$}
The above example's regular expressions (third word) are for Tcl code.
Alpha uses these to determine what it should act on when it is requested to re-wrap, make a selection or navigate with respect to paragraphs.
Note that currently the wrapping routines take no notice of code formatting rules and are limited utility outside of the Text mode. The only proc's that use these are found in textFill.tcl.

Indent On Return

The Indent On Return mode preference allows pressing Return to indent correctly for the following line so you may begin typing immediately. To use this, simply include this preference as a default mode preference using something like
newPref flag indentOnReturn 1 modeName
but do not bind to the Return key.
If you want to modify the behavior of Indent On Return for your mode, then define a <mode>::carriageReturn proc, as in the proc [Tcl::carriageReturn].

Automatic indentation

Two variables are associated with a window's indentation scheme: indentationAmount and the window's tab-size (which can be read with the commmand [getWinInfo] or the proc [text::getTabSize]). If you are writing a custom indentation routine, the proc [indent::setup] will be useful to handle all these choices for you. Look at the relevant section of globals.tcl to see what that procedure sets up for you.
Most people use either
tab-size = 4, indentation-amount = 4 spaces
OR
tab-size = 8, indentation-amount = 4 spaces 
These cases are quite different, and it's nice if your mode allows the user to work with their preferred setup.

Electrics

Throughout the documentation and in actual proc names, you will see the use of the word electric, so a note on its usage might be helpful. Electric is used in the sense of automatic, power-assisted behaviour, it is intended to save time, keystrokes, and brainpower. Such behaviour is usually invoked by certain keystrokes (determined by various preference settings).
See the Electrics Preferences panel.

Electric code templates

If your mode wants to insert text into the window which contains template stops (usually bullets '•' in Alpha), so that the user can move from one to the next using the standard Alpha template packages (Alpha comes with a basic one, and more sophisticated ones build upon the same infrastructure), then you should insert template text with:
elec::Insertion "blah blah •• blah blah"
This is a simple example with a single template stop. Template stops are noted programmatically with a pair of bullets (even though only one appears in the text). You can place between the pair of bullets some more information about the template stop, for instance:
elec::Insertion "while \{•condition•\} \{\r\t•while body•\r\}\r••"
would be useful to insert a typical Tcl [while] loop. The template packages can prompt the user with the explanatory text making code entry a little bit easier.
The elec::Insertion routine works just like [text insert] except it treats any item •PROMPT• as a template stop called PROMPT. This procedure takes a variable number of arguments, just like [text insert]. It has one further side-effect. If there are any stops in the block, then the cursor is positioned at the first such stop. Hence you don't need to do this: set p [getPos] ; text insert "blah..." ; goto $p ; elec::nextStop. Instead you just do 'elec::Insert "blah..."'.
Use elec::nextStop, elec::prevStop etc. to move amongst tab stops. The basic Alpha distribution setup includes only basic template support. Activate the package Better Templates to extend this support to persistent stops, with user-prompting in the text or status bar, as well as other enhancements. You don't have to change your code to take advantage of the features of Better Templates. It comes for free if you use elec::Insertion etc.

Electric braces and semicolon

If your mode wants to use electric '{', '}', ';' (i.e. characters that end the current line and indent the next one automatically), you need to define a few procedures named
${mode}::electricLeft
${mode}::electricRight
${mode}::electricSemi
which will be called automatically. You do NOT need to bind anything to the keys. Alpha will automatically call your mode's procedures if (1) the preferences are in place, (2) they remain turned on by the user, and (3) the mode procs are named correctly. If you do not define these procedures, (but conditions (1) and (2) are met), then Alpha will use a default electric procedure which works pretty well for C, Perl and Java code:
[::electricLeft]
[::electricRight]
[::electricSemi]

Completions

If your mode is to use a variety of completion routines, define an array entry like this:
set completions(${mode}) \
	{completion::cmd completion::electric completion::word}
For the meaning of the list items, look at elecCompletion.tcl. If all you need is the basic Command, Electric and Word completion routines, the above list will do the trick. You will then need to define a variable ${mode}cmds like the following one (which is in C mode):
set Ccmds { #elseif #endif #include class default enum for register return 
 struct switch typedef volatile while }
It MUST be in alphabetical order. For electric template insertions, you need to create an array with entries like these (again taken from C mode):
set Celectrics(for) " (•init•;•test•;•increment•)\{\n\t•loop body•\n\}\n••"
set Celectrics(while) " (•test•)\{\n\t•loop body•\n\}\n••"
set Celectrics(switch) " (•value•)\{\n…case •item•:\n\t•case body•\n…default:\n\t•default body•\n\}\n••"
set Celectrics(case) " •item•:\n…•case body•\ncase"

Mode-specific completions

If your mode has its own completion routines, they must be named ${mode}::Completion::Type, where Type is an entry in the above list. You'll have to know a reasonable bit of Tcl to write your own routines like that. Look at the proc [C::Completion::Class] for a relatively simple example, or see the BibCompletions.tcl file.

<mode>Completions.tcl

Each mode can have a completions file full of defined electrics that will be used by the package Elec Completions. To use this, place the appropriate definitions in a file called <mode>Completions.tcl. Such files are located in the $HOME/Tcl/Completions directory or in the Completions subfolder of Alpha's Application Support Folder and they will also be sourced automatically the first time a file opens in your mode. There is therefore no need for you to source the file yourself.

Electric Menu templates

The variable ${mode}Templates is a list of names which are added to the electric menu's Templates sub-menu. The real procs should be called file::${name}. For instance, C modes defines:
lunion "CTemplates" createNewClass newFunction
which make use of the procs [file::newFunction] and [file::createNewClass].

The Marks popup menu

Each mode has a procedure <mode>::MarkFile which is called to create the contents of the Marks Docwin marks button popup menu. Just what text-patterns are used to trigger the formation of a namedMark, its name, text position and extent, and the order in which they are present in the menu, is all determined by the <mode>::MarkFile your procedure.
See the proc [Igor::MarkFile] for an example.
For computer language editing modes, the common convention was to create an index by routine names for each routine defined in the file, and to present it in alphabetical order. The more current convention is to either hardwire, or present the user with the option of listing the routine names in the order in which they were defined in the file, indented under the name of the code section in which it was defined.
The Tcl mode proc [Tcl::MarkFile] is a good example of the above -- by default the defined Tcl proc's are presented in alphabetical order. However if you check the Stuctural Marks flag in the Editing panel of the Tcl Mode Preferences preferences, you get an index with the above format (after regenerating the index via the Mark Window menu item). If you organize your Tcl code into sections of logically or functionally related proc's, and then give them a short header by using the Insert Divider option under the Tcl Editing submenu, you have an index that can be used to quickly get to a procedure when remember its position or functionality more than you do its exact name.
Of course, it is still often the case that you remember the name and just want to get to it quickly via an alphabetical index, so modes that use the above scheme usually provide an alphabetical listing via the Parse Functions popup, which is located right beside the marks popup (see next topic).

The Parse Functions popup menu

The Parse Functions Docwin parse button popup menu can be put to whatever use the mode author wants. If your are using the scheme mentioned in the above section, it is good to use this popup to present an alphabetical listing of the routines. Some modes add extras such as indicating the number of arguments a routine expects (see Tcl mode), whether an argument is a reference or a value pass (see the M2, i.e. modula mode) or anything else that might be useful. Languages that use multi-part (qualified) identifiers may name the first part of a group of identifiers and indent the rest of the identifiers that share that first part under it.
There is an automated mechanism to generate the contents of this popup menu. For this, Alpha requires two regular expressions, one which will match a pattern containing something which needs marking, and the other which will take the matched text and extract, or parse, as the first bracketed '()' subpattern, the name of the item (i.e. the section or function name). If you need help with this, please ask on the Alpha's Mailing Lists.
These regular expressions are specified as mode preferences named respectively funcExpr and parseExpr. For example, man mode uses ^\.de [^\r\n\t]+ and \.de ([^\r\n\t]+), where the first pattern matches a block of text starting with '.de ' and continuing up to the next new-line or tab character (this is what a function definition looks like in that mode), and the second pattern extracts from that block of text, as the first bracketed expression, the actual sub-string to use as the function name, in this case everything after the '.de '.
Power user tip: the key combo ⌥⌘K will put up a listpick dialog of the indexes under the '{}' popup, as this is usually alphabetical you can type the starting letters of the index you want to go to. (note: see Emacs Help for some other tips to navigate any scrolling list dialog box.)

Package preferences

AlphaTcl includes hundreds of different preferences that allow the user to modify the program's behavior without first being an AlphaTcl programmer. While preference bloat is always a problem, a well-defined preference provides a balance between flexibility and the learning curve, and sets a default value that is at least intuitive but not intrusive.
Topics covered include:
Preference types
Adding to the core prefs dialogs
Defining a package's flags and variables
Declaring help text

Preference types

Alpha stores preferences in three different places:
  1. Global preferences are set in the Alpha ↣ Preferences menus, and are for variables/flags which maintain a value at the global scope.
  2. Mode prefs are set in the Alpha ↣ Mode Setup ↣ Mode Preferences items, and are for variables/flags which are stored in a mode array, but are transferred into global scope when that mode is active (and hence temporarily override any global preferences with the same names)
  3. Packages may add to the global/mode preferences as they desire. They may also store preferences in their package array ${pkg}modeVars(…). Such variables/flags are never transferred into the global scope. Menu items to edit a package's preferences should be placed in the global menu, unless they are global/mode prefs which should be added to Alpha's default routines for use by the standard Alpha dialogs.
    There is a standard proc package::addPrefsDialog which you can use to add a panel to the standard dialog to edit the contents of your ${pkg}modeVars(…) array.
Any editing of preferences using the standard dialogs code in AlphaTcl will automatically save any changes when Alpha quits and they will be reloaded the next time Alpha starts up. If you need to make manual changes to preferences (or, indeed, any Tcl variable or array), pass the changed variable name to prefs::modified, for example:
prefs::modified myPrefName
prefs::modified myPrefArray
prefs::modified myPrefArray(justThisElement)
You can pass a variable name, an array name, or just one element of an array. This registers the corresponding variables for saving: actual saving occurs when the application quits. To save them immediately, you may use the prefs::saveModified proc.

Adding to the core prefs dialogs

If you wish to add items to any of the core preferences pages (Backups, Electric, Miscellaneous,...), you can do that like this:
lunion varPrefs(Electric) var1 var2
lunion flagPrefs(Electric) flag1 flag2
All non-registered global preferences are added to the Other Packages page, so there is no need to do that automatically. Make sure you don't add too much to any of these pages, because they will become too large to display correctly!
You can also add new core preferences pages. All you have to do is create a new flagPrefs entry (Alpha uses the command array names flagPrefs to list the different pages):
lunion flagPrefs(NewPage) flag1
Only add such pages if your package really does merit it; otherwise you're better off just add a new global preferences dialog in the global menu.

Defining a package's flags and variables

Preferences for a mode or package are defined formally as follows:
# description of the preference
newPref type name {val 0} {pkg "global"} {pname ""} \
	{options ""} {subopt ""}
The meaning of the arguments is as follows: The main possible types of preferences are
appan application's ID (declared with [app::registerID])
bindingkey-combo
colora color name
fileinput only
flagon/off only
foldera folder path
fonta font specification
geometrya list of form {x y w h}
io-fileeither input or output
menubindingkey-combo which works in a menu
rgba color triplet {R G B}
searchpathlist of paths
urlan URL string
variableanything
This list is not exhaustive, new types may be introduced in the future.
There are also three special types: Variables whose name ends in
App
Color
FilePaths
Folder
Font
Mode
Path
SearchPath
URL
(case matters here) are treated differently by the GUI, but are still considered of type variable. The proc newPref automatically does the mapping for you. The declared type is the same as the suffix but in lower case. For instance:
newPref color functionColor magenta C
Depending on the previous values, there are two optional arguments (called options and subopt) with the following uses (depending on the type of the preference):
variable:
options is a list of items from which this preference takes a single item. subopt is any of item, index, varitem or varindex or array, where item indicates the pref is simply an item from the given list of items, index indicates it is an index into that list, and var* indicates items is in fact the name of a global variable which contains the list. array means take one of the values from an array. If no value is given, item is the default
binding:
options is the name of a proc to which this item should be bound. If options = '1', then we bind to the proc with the same name as this variable. Otherwise we do not perform automatic bindings.
subopt indicates whether the binding is mode-specific or global. It should either be global or the name of a mode. If not given, it defaults to global for all non-modes, and to mode-specific for all packages. (Alpha tests if something is a mode by the existence of modeMenus($mode))
menubinding:
menubindings are like bindings, but they don't have any automatic binding capabilities, and are restricted to key-sequences which the MacOS allows in menus.

Declaring help text

Alpha has the ability to extract descriptive text for your preference items automatically, provided they are declared using newPref, and that you follow these guidelines.
If there is a comment (a line starting with '#') on the line/lines preceding the newPref command, Alpha will (when it rebuilds the package indices) store the text in that line/lines and use it to display helpful information for that preference. For example if you hit the help button in a dialog, Alpha will display this information. Note that if the preference is simply overriding one of the built-in global values (lineWrap, commentContinuation, etc), then there is no need to provide a comment. AlphaTcl's core already contains good descriptions which will be used automatically (but if your mode does provide a comment it will over-ride the core's description).
This information is also used for tip windows in the prefs dialog related to your package/mode, provided you use the standard mechanisms for declaring your mode/menu/feature/extension and you use the standard preference mechanism supplied. The format of the comment lines is simple for all except basic flags (newPref flag ...). These will display a different help text in tips depending on their state. There are four possible states, although Alpha only really uses the first and third such states at present. The first state is the unchecked state, and the third the checked state. You declare separate help text for the four possible states like this:
# it is unchecked|it is dimmed|it is checked|it is checked and dimmed 
newPref flag myFlag ... 
In fact all help items have four possible states, although you will usually not notice the other possibilities. As you can see, Alpha uses '|' to separate the different pieces of text. Currently a typical help text for a checkbox item should probably just look like this:
# To use a solid rectangular cursor, click this box||To use a thin 
# vertical cursor, click this box.
newPref flag blockCursor 0
Notice the syntax of the two messages. Apple's interface guidelines give some advice for tips which you should follow for two reasons: first, it's good advice for writing tips, and second, Alpha assumes your messages are of the above form to use the text effectively both for tips, and for descriptive text. Alpha will automatically convert the above to:
Block Cursor: To use a solid rectangular cursor, turn this item on.  To
use a thin vertical cursor, turn this item off.
which is used in the descriptive dialogs Alpha sometimes provides. This advice is of greatest importance for flag preference items, since they require two separate on/off tip help texts. Other items currently just expect one piece of text. Each text item should be no longer than 255 characters. The simplest tip methods impose this constraint.
A similar mechanism is also available for menus and packages, using a help argument in the package declaration. If this help argument looks like this:
alpha::menu filtersMenu 3.1 global Filters {
	addMode Fltr filtersMenuTcl {*.flt} {}
	package::addPrefsDialog filtersMenu
} {
	# Activation script.
	...
} {
	# Deactivation script.
	...
}  help {
	file "Filters Help"
}
then the proc [package::helpWindow] will send the name of the specified file to the proc [help::openFile] where it will be dealt with appropriately.
See the Doc Files Help file for more information on Alpha's Help file colorizing/marking/etc syntax that is used to create files like this one.
If a full help text or help file is not provided, otherwise, a tip will be created using the || etc. syntax described above, as in
alpha::feature colorPrefs 0.2 "global-only" {
	# Initialization script.
	...
} {
	menu::insertSubmenu ...
} {
	menu::removeItems ...
} help {
	This package provides support for coloring of text in Alpha windows||
	This package provides support for coloring of text in Alpha windows||

	Alpha supports automatic coloring of the text.  The way Alpha colors the
	text depends on the current mode.
In this case the fifth || clause is used by the proc [package::helpWindow] while the first four are used for tip help.
See the Menus Preferences dialog and the Features Preferences dialog for examples of tip windows (just hover over items with the mouse).

Installation and package requirements

For your private use, most likely you have already found a good place to keep your Tcl files so that both Alpha and yourself can find them.
In order to distribute your package to other users, the easiest is to take advantage of the installation facility provided, as described in this section. There are also a couple of words about licensing issues and coding standards, which should be considered if your code is going to be set free on the internet.

tclIndex files

Standard Tcl uses tclIndex files to find procedures which are called but not yet defined. Your installation directories may contain index files if you desire, but they are only installed if no current index file exists in the installation location. You cannot override this behaviour.

Uninstalling packages

Each package should provide an uninstall argument in its package declaration, as in
alpha::extension developerUtilities 1.1 {
	# declaration script
} uninstall {
	# uninstall script
	...
}
For a single file package, the following is normal:
} uninstall {
	this-file
}
If the uninstall argument is this-directory, then that entire file's directory is removed. Make sure you don't use uninstall this-directory for a single-file package, or you'll wipe out the entire package hierarchy. All alpha::<packageDeclaration> procs (like [alpha::mode], [alpha::menu] and friends) may contain an optional uninstall script like the above.

Disabling packages

A feature can add a script to be evaluated when the user disables the package. This is the 6th argument for the proc [alpha::feature]. Note that extensions do NOT have deactivation scripts, since these types of packages are intended to be turned on globally and add some extra functionality. If the extension adds a submenu or performs some other operation that needs to be undone when it is turned off, then make it a global-only feature instead. See the smarterSource.tcl file for an example.

Licensing issues

Obviously if you want to allow your scripts to be distributed with Alpha, you need to license it under a compatible license agreement -- one that allows free redistribution of your code. The most obvious choices are a Tcl/Tk/BSD style license or a GNU style license, although other licenses are possible.
If your Tcl code is of use with Tcl/Tk in general (i.e. not restricted to being used inside Alpha), then you are strongly urged to use a Tcl-compatible license, not a GNU license, since that is the norm in the Tcl community, and is also adopted by most of AlphaTcl.

Coding standards (tab sizes etc)

It is of course appreciated if contributed code follow the coding style of AlphaTcl, which is rather generic. Rather than being a question of strict rules, this is mostly a matter of mimicking the style perceived in the existing files, with the obvious variations.
The most important guidelines are 'DOCUMENT YOUR CODE' providing exact specifications in comments before each proc definition, as well as helpful explanations of tricky points inside the body of the proc. It is preferable if variable names have sufficient human-language (in fact, English) content, so that any reader can guess their meaning from their name. Although Tcl is very flexible with variable and command names, it is strongly encouraged to use only plain ascii letters, numbers, and underscore.
On the other hand, syntactic sugar like the word then in [if] clauses is generally not appreciated as helpful.
The core AlphaTcl library generally uses a tabsize of 8 but a visual indentation of 4 (this is the default for Alpha, and also the standard for Emacs and a lot of open-source projects in the unix world). If you are writing standalone packages for distribution with AlphaTcl there is no need to abide by that convention, but individual procedures contributed to AlphaTcl files will be (re)formatted according to that convention before being applied. Note that AlphaTcl contains facilities for individual files or filesets to specify their default tabsize, so Alpha can quite happily be made to work simultaneously on many different projects using different tabsizes.

Further technologies (miscellaneous extras)

This section, perhaps most useful to new modes, explains how to make a mode/menu/extension aware of and take advantage of certain existing packages and technologies. We cover the packages and mention also

Providing customisable menu shortcuts

This section gives information about user menu shortcuts support in the AlphaTcl packages. The information below is intended for developers who write a new menu for Alpha and want to offer the possibility of modifying the keyboard shortcuts associated with the items contained in this menu or its submenus.
Starting with version 8.2, Alpha provides a per-package interface to let users assign new shortcuts to menu items. Each package can decide which of its menus or submenus are thus configureable, it can install its own interface or rely on another package's interface, it can restrict the list of configureable items. All these possibilities are detailed in the following sections.

The user shortcuts API

Installing support for configureable menu item shortcuts is very simple. It involves two tasks: This is all there is to it.
The [prefs::dialogs::menuShortcuts] proc expects two or three arguments: The [menu::setUserShortcuts] proc has a first argument with value on or off in order to respectively enable or disable the user defined shortcuts. The remaining arguments are exactly the same as with the proc [prefs::dialogs::menuShortcuts] the same array, the same package name and the same optional mode.
There is a handy proc [menu::handleUserShortcuts] which is a wrapper around the previous procs. Its first argument is a subcommand amongst get, set, install and uninstall. The other arguments are the package name, the name of the array and optionnally the mode. Most packages make use of this proc to handle the user menu shortcuts.
There are many examples of this mechanism in the AlphaTcl library which can serve as sample code. See for example the Filters Menu package. This package defines a proc called flt::doMenuShortcuts like this:
proc flt::doMenuShortcuts {action} {
	variable menuToken
	set tmpArray(Main\ menu) $menuToken(main)
	set tmpArray(Utils\ submenu) $menuToken(utils)
	menu::handleUserShortcuts $action "FiltersMenu" tmpArray
}
Then all it has to do is:
  1. in its activation script, it calls
    flt::doMenuShortcuts install
    
  2. in its deactivation script, it calls
    flt::doMenuShortcuts uninstall
    
  3. in its menu building proc, it defines an item called Menu Shortcuts which triggers the following command:
    flt::doMenuShortcuts set
    
That's all there is to it.

The menu shortcuts hook

Some packages which bring extra functionalities to Alpha insert a small submenu in one of the basic submenus. In order not to clutter all the submenus with spurious commands to set menu shortcuts, it is also possible for a package to have its user-defined menu shortcuts managed by a parent package. For instance packages such as Window Utilities, Speech, Spelling, Redefine Colors would have their shortcuts managed by the AlphaTcl library itself. This means that the submenus inserted by these packages would be accessed via the same interface as the other basic menus: from the user's point of view, this will feel very natural since there is no reason to make a distinction between submenus.
Similarly one can imagine a package adding extra functionalities to a major mode menu: such a package would like its submenu to be managed, regarding shortcuts, by the same interface as the rest of the menu.
In order to achieve this, a package just has to register with the parent package using the [menu::shortcutsHook] proc. This proc is invoked during the activation or deactivation of the package in order to register or unregister respectively. Its arguments specify the package's name, the parent's name and a callback procedure which will be invoked by the parent package in order to get the names and the tokens of the submenus it has to manage. For instance here is how the Spellcheck package would register:
menu::shortcutsHook register spellcheck AlphaTcl spell::shortcutMenuTokens
To unregister, the instruction is simply
menu::shortcutsHook deregister spellcheck
The registered callback (spell::shortcutMenuTokens in the example above) is a proc which takes no argument and which returns a list with an even number of items of the form:
menuName menuToken...
This is a list containing alternately a menu name (which is displayed in the interface dialog) and the corresponding menu token. This is the format expected by the [array get] Tcl command in order to load a list in an array.
Note that there is no obligation to use this hook mechanism: many packages which insert a submenu in one of the basic menus still use a standalone interface as described in the previous section. This is the case of Columns Manipulation, Notes, Favorites, Function Comments, Window Lines, etc. for instance.

Partial menu lists

There is another hook which lets a package expose only certain items of its menus or submenus to the menu shortcuts interface. This can be useful for menus which display changing data: this is typically the case of the Open Recent submenu or the Windows menu. There is no point to attach a menu shortcut to items which are constantly updated and modified. Only the persistent items in these menus should be exposed.
In order to achieve this, the package must register a proc with the shortcutMenuItems hook. The hook is registered during activation and unregistered during deactivation. Here is how the Recent Files package registers:
hook::register shortcutMenuItems recentmulti::listItemsForShortcuts "Open Recent"
This instruction simply registers a callback (named recentmulti::listItemsForShortcuts in the previous example) for the Open Recent submenu. When the callback is invoked, it receives three arguments: the menu name, the associated menu token and the package's name. It should return the list of items it wants to be exposed in the user shortcuts interface.

Source-Header files

If your mode makes distinctions between Source and Header files, you should define these two variables sourceSuffices and headerSuffices like in the following example:
newPref var sourceSuffices { .cc .cp .cpp .c .icc } C++
newPref var headerSuffices { .h .hh } C++
They are used by the [file::sourceHeaderToggle] proc which is bound to ⌘-F2 when the Search Paths package is active.

Contextual Menu help

AlphaTcl implements the contextual menu in the package Contextual Menu. The contextual menu is accessed using the right mouse button or Ctrl-click. This menu is mode specific, and the context can also include the location of the current window, any surrounding files, any text surrounding the cursor position, etc.
What follows below is possibly more information than you want to know about how the contextual menu is created in Alpha -- see the contextualMenu.tcl file for information about how to add CM modules for your mode or package.
Alpha's core detects control-clicks in the text area of document windows (or any text pane if the window is split). It then invokes the contextualMenuHook passing two arguments: the position in the text corresponding to the location of the mouse click and the full name of the window. Alpha expects this hook to return the contextual menu, entirely rebuilt.
To rebuild the contextual menu, the contextualMenuHook does hook::callAll to invoke any registered CM hooks. It'll pass, via a global variable called alpha::CMArgs a list of four values: the position, the start and end positions of the current selection and the window. If there is no selection, the three first values are equal.
The contextual menu is a built-in menu created by the core with token contextual. Using this token, you can use the commands [menuRef] and [menuItem] as you would do with any other menu in Alpha.
Basically the contextual menu is divided in four sections, each separated by a divider: Information on how a package (mode or feature) can create contextual menu plug-ins is given in the Information for developers section of the Contextual Menu Help file.

Xserv and pipes

If your mode or feature involves communication with some external process or helper application, you should, when possible, take advantage of Alpha's external-applications API called xserv. By bundling the interaction into an xservice, you ensure that it integrates with the Helper Applications prefs panes, and is made available also for related features, and that it does not double existing functionality.
Xserv is documented in great detail in Xserv Help and Xserv Guide.
For more fine-grained two-way communication with a unix program, the xserv interface might not be sufficiently flexible. In this case it may be necessary to write the interaction from scratch using pipes, and then declaring the whole interface as an xservice. There are many predefined procs to help with this, found in appPath.tcl.
For advanced examples in AlphaTcl, see the next sections which explain the resources available to create consoles communicating with a unix tool. See also TeX mode which defines its own console in tetexComm.tcl.

Console attributes and 'strict console'

If your package uses console windows to display feedback from the program, you may take advantage of the functionality in consoleAttributes.tcl: this allows console windows to maintain their characteristics, such as window geometry, font size, command history, even when the window is closed, so that the user can adjust to his liking without having to do this every time the console is opened. It is very easy: you declare the console once and for all using
console::create "* My Console *" -mode Shel -g 100 100 100 100 \
        -font Monaco -fontsize 9
and then invoke it by
console::open "* My Console *"
For details, see the documentation in the file consoleAttributes.tcl.
There is a further package called strictConsole.tcl which attempts to simulate the behaviour found in many unix shells where there is a prompt, and where only the text situated after the last prompt can be edited. This package takes care of everything related to the prompt, including command history.
For an example which illustrates these technologies, see the implementation of most VCS modules related to the Version Control package. This is used notably by the Svn, Git, Mercurial, Bazaar, Fossil and Monotone consoles. The corresponding API is defined in vcsConsole.tcl.

Interactive console

The interactive console is a strict console which installs a pipe and the necessary callbacks so that the user can execute commands at the prompt of a command line and get the result exactly like in a shell window or any interactive unix tool, and then execute another command, and so on. It is used in particuler by the Bc, Coq, Gnuplot, Julia, Maxima, Matlab, Octave and R consoles. See the file Consoles Help for more information.
Client packages just have to declare the console with console::interactive::register and to open it with console::interactive::open. The important arguments to specify (besides the usual arguments supported by consoles as explained in consoleAttributes.tcl) are:
-prog
the command line tool you want to communicate with
-progOpts
options for the program
-shelltype
this argument is required: this is the namespace in which some callbacks may be defined, like <type>::Prompt
If -prog is specified, it designates the path of the command line tool that the console wants to establish its connection with. If it is not specified, the console gets the path by invoking a proc named ${type}::ensureProg where ${type} is the value of the -shelltype option. In that case, the client is responsible for providing this proc.
If -progOpts is specified, the console inserts these program options in the opened pipe. For instance, if the value is $opts, the pipe will be |prog $opts 2>@1, instead of just |prog 2>@1 by default.
Other more advanced (and usually unnecessary) options are explained in the next paragraphs.
To send a command to the program, the console invokes by default console::interactive::readlineProc defined in this file. A client may declare, for special purposes, its own readlineProc proc via the -readlineProc option in console::interactive::register.
Similarly, to receive the data sent back by the program, the console invokes by default console::interactive::writeResult defined in this file. A client may declare, for special purposes, its own writeResult proc via the -writeResult option in console::interactive::register.
The readlineProc makes sure that we have a valid pipe connection to the program. This is accomplished by the proc console::interactive::ensurePipe defined in this file. A client may declare, for special purposes, its own ensurePipe proc via the -ensurePipe option in console::interactive::register.
Client packages should define a proc <type>::Prompt (where <type> is the value declared via the -shelltype argument) to return the prompt string at the beginning of command lines in the console. If this proc is undefined, no prompt is written. If the prompt is never going to change, it is also possible to declare it once for all via the -prompt argument. In that case the <type>::Prompt proc is not necessary.
Example:
here is schematically how the bc mode declares its console to communicate with the bc Unix tool (basic console, the arbitrary precision numeric processing language):
set prog /usr/bin/bc
console::interactive::register "* Bc Console *" -shelltype bc \
  -mode bc -hookmodes [list bc Shel] \
  -startuptext "Welcome to Alpha's Bc console.\n" \
  -prog $prog -progOpts "-l"
Then the console can be opened with
console::interactive::open "* Bc Console *"
and that's all there is to it!

Temporary files

AlphaTcl has some facilities for working with temporary files. This involves creating unique names and keeping the files in package-specific subfolders inside the Prefs folder, and also some facilities for linking positions in a temporary file to the positions in the original file by specifying some offsets.
As an example of how this works, see the Diff mode. Here diff-selections work by creating a temporary file for each of the two selections under comparison, and redirect the various diff and merge operations from the temporary files to the original files, transparently so that it is never noticed that temporary files are involved.
See the files temp.tcl and tempWindows.tcl for instructions.

PART 3: ADVANCED TOPICS

Most of this part will not be relevant to the average developer, but this stuff needs documenting somewhere!
Topics covered include:
Embedding AlphaTcl
Window management
AlphaTcl window API
Standard window attributes (widgets)
Defining new window attributes
Defining minor modes and modifying window behaviours
Event hooks
Defining hooks
Window hooks
Alpha hooks
Mode hooks
Keyboard hooks
Miscellaneous hooks
Hooks, continued...
Hook definitions

Embedding AlphaTcl

Alpha (like AlphaX and Alphatk in the past) is an application which embeds the AlphaTcl library and uses it to provide almost all functionality outside of the basic editing window and core dialogs. This section is here to document what that actually means, since it isn't documented anywhere else.
Historically, (e.g. up to Alpha 7.x) embedding AlphaTcl has largely meant setting a HOME variable to the location of the AlphaTcl library files and sourcing '[file join $HOME Tcl SystemCode AlphaBits.tcl]'. As the AlphaTcl library has become more complex, this startup sequence has been retained, but more flexibility has been added. This is particularly important because parts of the gui presented to the user by the embedding application may be customizable by the user, yet all preference handling (which it would be nice to use for that customization) happens through the AlphaTcl library. Some very early preferences are thus defined as user defaults which can then be read by the embedding application to decide on the correct gui to display (e.g. position of the status bar) before the AlphaTcl library is loaded.
To start the AlphaTcl library, the embedding application must: Now preferences are available, so the GUI can be created. Then: This two-phase initialization is used in Alpha. AlphaTcl contains a directory called Init for the files required for the first phase.

Window management

AlphaTcl window API

When windows are created, renamed, or destroyed, various of the hooks defined later in this document are called (winCreatedHook, etc). These make use of the AlphaTcl Window API to keep track of window names, attributes, as follows:
win::created name
a window with this name has been created
win::destroyed name
a window with this name has been destroyed
win::nameChanged oldname newname
a window has been renamed
These three procedures may then be used by any AlphaTcl package to query information about the current windows:
win::Exists name
does a window with this name exist?
win::CreationOrder
return list of window names, ordered by creation
win::StackOrder
return list of window names, ordered frontmost to backmost
Any AlphaTcl variables (such as $win::Active, $win::attr(), $win::StackOrder) should be considered private to AlphaTcl's core and only accessed through the above functions.

Standard window attributes (widgets)

This provides control over all the widgets found outside the editable area of an Alpha window, e.g. toolbar, scrollbar, buttons and so on. Any of these can be turned on and off by passing appropriate values via the -attributes option in the core commands [openWindow] and [openFile].
The value to -attributes is an integer formed as a sum of squares of 2 depending on which widgets should be turned off. Possible values are found in the window attributes table.
For example, to create a window without the VCS Docwin vcs button, Parse Functions Docwin parse button, and Marks Docwin marks button popup controls, you need 4 + 8 + 16 = 28:
new -n FooWin -attr 28

Defining new window attributes

AlphaTcl provides very nice support for any mode/package/feature to attach, detach and query an arbitrary set of information associated with any window. Such information is automatically cleaned up when the window is closed, and automatically adjusted if the user renames/saves the window. AlphaTcl developers can use this to make it much easier to provide window-specific behaviours. This support has a public API defined by the following functions: For example, this can be used to make it much easier for, say, Diff mode to run multiple simultaneous diffs, or for Brws mode to have different browser geometries, etc.
So, how is this used? Each window has a set of attributes associated with it, which will persist for the lifetime of the window, and track the window as it is saved, renamed, moved, etc. Some of these attributes are termed core attributes which are used internally by Alpha's editing engine. An obvious example of this is the font and fontsize of the window. Other attributes are defined/read/set only in AlphaTcl - an important example is the mode attribute which defines the editing mode to use for the window. A more internal and less known one is the Modified attribute which stores the last known modification time of a window corresponding to a file on disk. It is used particularly to allow AlphaTcl to respond to the situation where the file on disk appears to be more recent than the contents of the editing window.
Here are the current attributes:
Core attributes for window mode-like behaviour:
bindtags
colortags
hookmodes
varmodes
featuremodes
Other core attributes:
charWidth
coloring
continuousSpellChecking
currLine
dashSubstitution
dataDetection
dirty
dispRange
encoding
font
grammarChecking
hasSpurious
hasURL
incrementalSearching
lineHeight
lineNumbers
linkDetection
needsBreak
numColumns
numDispLines
numLines
paneNum
platform
quoteSubstitution
readOnly
recordState
shell
showInvisibles
smartInsertDelete
spellingCorrection
spin
split
tabsize
textReplacement
toolbar
undo
wordbreak
wrap
AlphaTcl (some of these may only be defined if certain packages are active): When opening a new window, the appropriate value of these attributes must be calculated and assigned to the window. This is done in a prioritised fashion, taking account of five different priority levels:
global
the global default, which is the lowest priority level.
mode
the default mode-specific value (from proc [mode::getVar], which typically looks in the <mode>modeVars() array).
fileset
any fileset specific value, see e.g. package Fileset Indentation Preference.
window
a value which is specific just to this window, e.g. as read from the window's first line (tabsize:5).
command
effectively a forced value, as given, say in a direct command, like edit -tabsize 3 Readme.txt. This is the highest priority level.
The way this works is that any code may, during early window creation (e-g in the [winCreatedHook] proc), call the proc [win::setInitialConfig] with a window name, an attribute name, a value and a priority level. For example, one of the fileset packages does this:
proc fileset::checkIndentationPreference {fset name} {
	set tab [fileset::getInformation $fset "Tab Size"]
	set indent [fileset::getInformation $fset "Indentation Amount"]
	set spaces [fileset::getInformation $fset "Indent Using Spaces Only"]
	if {[string length $tab]} {
		win::setInitialConfig $name tabsize $tab "fileset"
	}
	if {[string length $indent]} {
		win::setInitialConfig $name indentationAmount $indent "fileset"
	}
	if {[string length $spaces]} {
		win::setInitialConfig $name indentUsingSpacesOnly $spaces "fileset"
	}
}
which therefore provides up to three different attributes (one for the core and two for AlphaTcl, although the code doesn't have to distinguish between them), each of which is given the fileset priority level. This means it will over-ride any global or mode default, but itself be over-ridden by any window-specific or direct command options.
The resolution between the different priority levels happens just once, when proc [win::getAndReleaseInitialInfo] is called in winCreatedHook. Once that resolution is complete, the original priority levels of the winning attribute values are forgotten.

Defining minor modes and modifying window behaviours

Each window has five different aspects of behaviour, relating to bindings, colouring, code hooks, variables and active features. For each such aspect, the window will have zero or more associated tags which dictate the details of that specific behaviour. Typically, an ordinary editing window will have just one tag for each behaviour, with each tag being just $mode, reflecting the editing mode of that window. However, Alpha and AlphaTcl provide support for modifying or replacing each behaviour aspect for any window, either directly (with the [win::setInfo] proc and/or the [setWinInfo] core command) or through the definition and application of minor modes.
We will first explain what the five editing aspects are, and how the list of associated tags are used, before explaining how to define and make use of minor modes in AlphaTcl packages.
To start with an example, the colouring aspect of any window is dictated by a prioritised list of color tags attached to the window. Here is a somewhat contrived example:
setWinInfo colortags [list "verb" "noun"]
As Alpha then colours the contents of the window, it examines each chunk of text (typically each word) and asks each colour tag in turn whether that tag wishes to colour the word. When one colour tag claims ownership of the word, it is coloured appropriately, and Alpha moves onto the next chunk of text.
So, for example, if the command colorTagKeywords has been used as follows:
colorTagKeywords -k green "verb" {be go dog run walk drive fly}
colorTagKeywords -k blue "noun" {person dog cat car}
Then any text in the window would be coloured with the given verbs in green and the given nouns in blue. Notice that dog would be coloured in green, since it is the verb tag which is the first to match.
Note
As of 2017-03-04, colorTags are not fully implemented in AlphaCocoa
Each of the five aspects of the window controls one behaviour type, in much the same way as just described: the aspect has an ordered list of tags, and when deciding what aspect-specific action to take, Alpha checks each tag in turn until it finds one that applies to the action in question. If none is found then a global default action would occur (which might be to do nothing).
So, let's examine a second example, this time with bindtags aspect used for keyboard bindings/shortcuts. Here a similar approach is taken: the window has a prioritised list of bind tags attached:
setWinInfo bindtags [list "shell" "Tcl"]
When the user presses a key in the window, Alpha asks each bind tag in turn whether that tag wishes to claim the key-sequence. If it does, the appropriate command is triggered. For example:
binding create -tag Tcl {"" '\n'} Tcl::carriageReturn
...
binding create -tag shell {"" '\n'} Shel::carriageReturn
...
Now if the user presses the return key in this window, the [Shel::carriageReturn] function will be the first to match, and it will therefore be triggered.
The five behaviour types are summarised as follows:
colortags
the list of colouring schemes to use for the window. For each of these tags, when colouring the window's contents Alpha will examine the colouring information defined in a call to 'regModeKeywords $tag' or 'colorTagKeywords $tag'. The first tag in the list is allowed to declare comment definitions and colours, string definitions and colours, etc., while all subsequent colouring tags may only declare keywords to colour.
bindtags
the list of binding schemes to use for the window. For each of these tags, when the user presses a certain key-combination, Alpha will examine the set of bindings defined with binding create -tag <tag>, searching for any match to the given key-combo.
hookmodes
the list of hook schemes to use for the window. For each of these tags, when executing hooks with hook::callProcForWin (e.g. hooks like electricLeft, correctIndentation, carriageReturn, etc), AlphaTcl will check for procs defined in the namespace $tag::. The first such hook found will be called (or a global hook if none is found).
varmodes
the list of variable schemes to use for the window. For each of these tags, when checking for a window/mode-specific variable value with proc [win::getModeVar] (typical variables are startPara, tabSize, indentationAmount, etc), AlphaTcl will check for variables defined in the namespace $tag:: or the array ${tag}modeVars() as appropriate. The first such variable found will be returned (or a global variable if none is found). Note that the following list of variables are searched for in the namespace: escapeChar quotedstringChar lineContinuationChar commentCharacters(General) commentCharacters(Paragraph) commentCharacters(Box) startPara endPara, and all others in the array. Note also that the only variables copied from a <mode>modeVar() array to the global namespace are those associated with the real mode of the window as given by proc [win::getMode].
featuremodes
the list of feature schemes to use for the window. For each of the tags in the featuremodes list, when activating the window, AlphaTcl will adjust the set of currently active features according to the information in mode::features($tag). Similarly when deactivating the window. In this activation/deactivation process, AlphaTcl always compares the set of features needed for the new window with those for the previously active window, and makes the appropriate minimal set of on/off calls to have the appropriate set of features active. Currently, for real modes, mode::features($mode) can be edited through the mode's preferences dialogs. There is no current way the user can edit this set for feature tags which are not modes (they must be hard-coded). This feature activation and deactivation all takes place through core-private proc [alpha::changeMode].
All of the above behaviour aspects can be set with proc [win::setInfo]. There is also a mechanism, with minor modes by which a whole set of modifications (for any or all of the five behaviour aspects) can be created as a set, and applied to any window. This is done with the proc [alpha::minormode], as follows:
alpha::minormode $name ?(+aspect|-aspect|aspect) value?+
Use '+' to extend, '-' to remove and nothing to set. For example:
alpha::minormode tclshell +bindtags TclShell -hookmodes Tcl varmodes TeX
Then you may use win::setInitialConfig winname minormode name window to apply a minor mode to a window (this only currently works before that window is created, but this limitation is due to be removed).

Event hooks

The flexibility of Tcl enables one to over-ride or otherwise intercept almost any operation in Alpha. However, to make it much easier for your code to take action on common events, a number of hooks are provided. It is better if you can use these hooks rather than do all the rename saveHook mySaveHook... stuff. To have a script called when under a particular circumstance, you just use
hook::register hookName script ?context? ?context...? 
Hooks are scripts executed automatically when a specified event occurs. For example, many modes have a date-stamp pre-save hook, which whenever the user says Save, updates the date stamp in the header of the file before actually saving.
When certain events occur, e.g. when opening and closing windows, Alpha (or AlphaTcl) calls an event hook. Core hooks call specific procedures defined in alphaHooks.tcl -- these procs might then in turn call the proc [hook::callAll], and in this case you can register your own event hooks to add to the default behavior when the corresponding event occurs. The core will never call [hook::callAll] directly. Other hooks are called from specific AlphaTcl procs (not by the core). This section lists all available hooks, and specifies when they are called and by whom.
The file hook.tcl contains the implementation of these calling mechanisms (if you need to look further), but it is more important to know exactly what hooks are available, under exactly what circumstances they are called, what contexts are available, and, of course, what arguments will be added to your script before it is evaluated. In almost all cases it does not really matter whether your script returns successfully or throws an error, but, some hooks do have a particular behaviour dependent on the return code, and it is good practise not to throw errors unnecessarily!
Topics covered in this section include:
Defining hooks
Window hooks
Alpha hooks
Mode hooks
Keyboard hooks
Miscellaneous hooks

Defining hooks

To add your own procedure to be called when the hook in invoked, there are two things you have to do. First write a proc to be called when some events occur. This proc must have the parameters shown in the table. Let's say you want to define a saveHook. Then define some proc
proc mysaveHook {name}{
	.
	.
}
The next thing you have to do is to register the proc. This is done with a line like:
hook::register 'hook-name' 'your proc' 'mode' ?... 'mode'?
The optional mode parameters specify in which mode(s) the hook will be called. If no mode parameters are given, the hook will be called regardless of the mode. Avoid this unless absolutely necessary.
Let's assume that you want your hook to be called in TeX and Perl modes. To register it, you would use the line:
hook::register saveHook mysaveHook TeX Perl
Note, however, that a few hooks don't use the mode to determine when to be called and should be registered slightly differently, see below.
Hooks may be invoked in three different ways, through one of the following commands:
[hook::callAll]
this proc invokes all the procedures registered with the hook. The order in which they are called is indefinite. Note that [hook::callAll] wraps all called hook procedures in a [catch], so you should not attempt to cancel the action calling the hook by throwing an error (throwing an error in a hooked procedure is usually considered a bug in that procedure).
[hook::callUntil]
this proc invokes the registered procedures one by one until one of them claims to be able to handle the request: it does that by taking action and returning '1'. Procedures which cannot handle the action return '0'. If a procedure has been executed successfully, the remaining callbacks are not invoked.
[hook::callUntilOk]
this proc invokes the registered procedures one by one until one of them claims to be able to handle the request, that is to say executes without raising an error. If a procedure has been executed successfully, the remaining callbacks are not invoked.
There is also a convenience proc [hook::callForWin] which is a wrapper around the preceding procs. It has a type argument (all, until, or untilok) and takes care of getting the mode(s) of the specified window.
Many of the hooks below are invoked by a procedure with the name of the hook to which you register your action (indicated below with something like proc someHookName), others are called during the sourcing of particular files or by other procedures as indicated.
Note that hooks are always invoked in a stacked fashion. This means that if one hook (say an openHook) causes the execution of other hooks (e.g. it calls [killWindow] which therefore causes the closeHook's to be called), then all the first hooks will be executed before any of the second hooks (so, in the example given, all openHooks will be executed, some of them possibly with no window in existence, and only then will all closeHooks be executed. This has the important benefit that code can always be sure openHook is called before closeHook, even if some other code has closed the window).
There are some subtleties associated with these hooks, and the additional parameters your hook receives are not directly documented anywhere. We suggest you look at existing code and ask on Alpha's Mailing Lists for further information. Contributed explanations will be added to this file.
In the next sections, when necessary, we list the parameters with which your hooked script is called. If your script is in the variable script, these will be evaluated like this:
eval $script [list $param1 $param2 ...]
Where a parameter is given the name winName, it may include the ' <2>' duplicate window markers. Where it is given as path, it is the name of a file (which may or may not exist on disk).
Here are some examples of hook registration:
hook::register saveHook modified "C" "C++"
hook::register saveHook modified "Pasc"
hook::register saveHook htmlLastModified HTML
hook::register savePostHook codeWarrior_modified "C++" "C"
hook::register savePostHook ftpPostHook
hook::register saveasHook htmlLastModified HTML
For these hooks, as with many others, the general form is:
hook::register 'hook-name' 'your script' 'mode' ?... 'mode'?
So, the context is the mode for which you would like your script evaluated (and more than one mode can be provided). If you don't include a mode argument, then your proc will be called no matter what the current mode is. Avoid this unless absolutely necessary.
You can get a list of all hooks for which something has already been registered with the proc [hook::information]. For example:
Welcome to Alpha's Tcl shell.
«» hook::information
	activateHook aevtodocHook changeMode closeHook contextualMenuHook
	contextualPostBuildHook deactivateHook dimThreshold dirtyHook
	fileset-delete fileset-file-opening fileset-new fileset-uncache
	fileset-update keyboard lockHook openHook openRecentMenu preCloseHook
	preOpeningHook procRenames quitHook removekeyboard resumeHook savePostHook
	shortcutMenuItems startupHook unlockHook vcsSupportPackages
	winChangedNameHook wwwMenuInit
However, other hooks which do not occur in this list may also be available (this happens if they are simply not used anywhere). For example, suspendHook is one which is called whenever the user shifts the focus from Alpha to another application.
While one set of hooked scripts (e.g. all openHooks) is being evaluated, any action which results in further hooks being called will be queued, and not take place until the first set of hooks is complete.

Window hooks

HookParameter(s)
[filePreOpeningHook]file name and full window name
The filePreOpeningHook is called when a file is going to be opened in Alpha. It is called by the core inside the [openFile] command just before the document is created. The first argument is the name of the file on disk, and the second argument is the name of the window we will use (e.g. it may have trailing <2>...), but that window does not yet exist at all.
The idea is that we can use this proc and the registered hooks it calls to set the window's mode or the window's default attributes, to adjust tab-size, encoding, etc, before the window is properly created, and before the contents of the file are read in (this is particularly important if we want to set a particular encoding to use for that reading!). One must call the proc win::setInitialConfig with the future name of the window in order to set any of these details.
The filePreOpeningHook returns a default value for the interface attributes of the window that will be opened (see the possible values here). A mode callback registered for the filePreOpeningHook has the opportunity to set a suggested value via the 'winAttrs' key in the initial config array. For instance like this:
    win::setInitialConfig $winname winAttrs 1234 "window"
This value (1234 in the previous example) is returned by filePreOpeningHook and retrieved by the core. It is then used as a default value for the -attr option. Note that an -attr option (if explicitely specified) has precedence over this default value.
HookParameter(s)
[activateHook]full window name
The activateHook is called when a window is brought to front, including, if it is a normal (non-minimized, non-hidden) window, when it is first created. The window should exist (and the command [getWinInfo], the command [winNames] and the proc [win::Current] should all work and behave as if the window is present). The window's contents will be available during this hook (even if called during window opening -- in such a case it is called after any openHooks). The current mode Alpha is in will have been adjusted just prior to calling this hook (but the activateHook could if desired change the mode of the window, although the desire to change the window would best be handled elsewhere). It is allowed to use the command [killWindow] to remove the window, but in that case the window will not exist for any other activateHooks which are to be called. Note that activateHook and deactivateHook events always occur in pairs. Any window that has the activateHook called on it will always, at some point in the future, have deactivateHook called (either when the window is closed or another window is brought to the front).
HookParameter(s)
[closeHook]full window name
The closeHook is called after a window has been closed. When the hook is called, the window no longer exists (so [getWinInfo] will fail, and the window should not appear in the [winNames] list, and [win::Current] will certainly not refer to it), but any extra AlphaTcl-attributes stored with the proc [win::setInfo] will still be available through proc [win::getInfo] (they will be cleaned up directly when this hook returns). Many uses of closeHook might perhaps be better implemented through preCloseHook. After all the closeHooks are called, AlphaTcl will arrange for any relevant requireOpenWindowHook menu dimming to be carried out to take account of the window's disappearance.
HookParameter(s)
[deactivateHook]full window name
The deactivateHook is called when a window ceases to be the frontmost window, for any reason (e.g. is sent to back, or the user switches attention to another window, or it is hidden or minimized, or the window was frontmost but is closed). Note that activateHook and deactivateHook events always occur in pairs. Any window that has the activateHook called on it will always, at some point in the future, have deactivateHook called (either when the window is closed or another window is brought to the front).
HookParameter(s)
[alpha::openHook]full window name
The alpha::openHook hook is called when a window is opened, once the contents are available, and before any activateHook is called. The window fully exists and has just been made visible to the user when this hook is called.
All window operations are available. Older versions of Alpha prohibited the calling of the command [killWindow] from this hook, but it should now be allowed in newer versions. Note that, if one hook has called [killWindow], then the window will no longer exist in any other hook. Therefore, for full reliability, openHooks should not actually assume the window exists and should use win::Exists to check if it does. Before any openHooks are called, AlphaTcl will arrange for any relevant requireOpenWindowHook menu dimming to be carried out to take account of the new window's existence.
HookParameter(s)
[preCloseHook]full window name
The preCloseHook is called just before a window is closed, but after the user has been asked if a dirty window should be saved (so we know for certain the window is going to disappear). This hook should not attempt to change any window contents or file information. However, all such contents is available when the hook is called, and the window will still appear in the [winNames] list. If the window was frontmost, then [win::Current] will still refer to it. Any uses of [win::getInfo] or [getWinInfo] will work. Basically the window exists in all respects. This hook cannot be used to abort the closing of the window, and any errors thrown by a hook are considered bugs in the hook.
HookParameter(s)
[saveHook]full window name
The saveHook is called when a window is saved, whether that save is through [save] or [saveAs], just before its contents are written to disk. This is the last chance to modify the contents of the window (e.g. a modification date) before the contents is committed to disk. A useful hook to, for example, update a last-modified date in a file's header.
HookParameter(s)
[savePostHook]full window name
The savePostHook is called after a window is saved (whether by [save] or [saveAs]).
HookParameter(s)
[titlebarPathHook]
The titlebarPathHook is called when the titlebar title is clicked. Hook must build a menu and return its name.
HookParameter(s)
[winChangedNameHook]full window name, oldName
The winChangedNameHook is called when a window's name has changed (e.g. through Save As), and after any change in mode which may have resulted from the new name. This may also result in the mode of the window changing (so changeMode hook may also be called). Alpha ensures, just before this hook is called that the new file exists on disk (even if only as a dummy file with size 0). The mode for which this hook is called is the final mode for the window (where that differs from the original mode).
This hook is also called if a file is moved outside of Alpha (e.g. it is dragged from one location in the OS to another, or it is renamed in the OS). In consistency with the usage in the other window hooks, the first argument is the name of the calling window (i.e. the new name), whereas the old name is just a secondary information.
HookParameter(s)
[winChangeModeHook]name, oldmode, newmode
The winChangeModeHook is called when a window's mode is changed (e.g. by saveAs, or the user's direct intervention). This hook is not mode-specific, at least at present (we have only one user of this hook - the Latex Accents package, so we could consider changing this with more widespread use).

Alpha hooks

HookParameter(s)Description
quitHook(none)Called when quitting Alpha
resumeHook(none)Called when switching to Alpha from another application.
startupHook(none)Called at the end of startup.
suspendHook(none)Called when switching to another application.
themeChangedHook(none)Called when switching appearance at System level.
screenParametersChangedHook(none)Called when user changes the screen geometry.
winChangedScreenHook(none)Called when user changes screen in a multi-display setting.
The startupHook is called by AlphaTcl (not by the core) at the end of startup (see [alpha::finishLoadingAlphaTcl]). There is no default proc for this hook. It will execute any proc registered by some packages in their initialization script. It is called when Alpha starts up, but after all other initialization has taken place (before any files are opened though)
The quitHook is called by the core after all the document windows have been saved and closed. All the preCloseHooks and closeHooks will have already been executed.
The themeChangedHook is called by the core when the user switches the general appearance between light and dark modes (on OS X 10.14 or greater) in the General System Preferences panel.
The screenParametersChangedHook is called by the core when the user changes the screen geometry, the position of the dock or the size of the status bar. At this point, the core has already updated the appropriate variables (screenWidth, screenHeight) and recalculated proposed values for defOrigX, defOrigY, defWidth, defHeight.

Mode hooks

HookCalling CodeParameter(s)
changeMode[alpha::finishChangingMode]newMode newPkgs
The changeMode hook is called when the mode is changed, after the new mode has been activated and all features/menus have been adjusted and the new mode's variables/prefs are in place.
HookCalling CodeParameter(s)
changeModeFrom[alpha::removePreviousMode]oldMode newMode
The changeModeFrom hook is called when the mode is about to change, before the new mode has been activated; no features/menus have yet been adjusted, and the old mode's variables/prefs are still in place.
HookCalling CodeParameter(s)
mode::editPrefsFile[mode::editPrefsFile](none)
The mode::editPrefsFile hook is called when a mode prefs file is opened for editing.
HookCalling CodeParameter(s)
mode::init[alpha::finishChangingMode](none)
The mode::init hook is called the first time a mode is loaded. Note that at that time the mode exists, but its variables have not yet been made global, and its menus have not yet been inserted into the menu bar.

Keyboard hooks

HookCalling CodeParameter(s)
keyboard[keys::keyboardChanged](none)
The keyboard hook is called at startup and when the keyboard preference is changed.
HookCalling CodeParameter(s)
removekeyboard[keys::keyboardChanged](none)
The removekeyboard hook is called when the keyboard preference is changed by the user. The keyboard hooks use the keyboard name (the ones in the keyboard popup menu in the International Preferences panel panel) rather than the mode to determine when to be called. Thus to register a keyboard or removekeyboard hook, use lines like:
hook::register 'hook-name' 'your proc' 'keyboard name' ?... 'keyboard name'?

Miscellaneous hooks

HookCalling CodeParameter(s)
launch[app::ensureRunning](none)
The launch hook is called when a helper application is launched by calling [app::ensureRunning].
The launch hook uses the application's bundle ID rather than the mode to determine when to be called. Thus to register a launch hook use a line like:
hook::register launch 'your proc' bundleID ?... bundleID?
HookCalling CodeParameter(s)
requireOpenWindowsHook[alpha::menuAdjustForOpenWins](none)
The requireOpenWindowsHook hook is called when opening and closing windows.
This hook is used to en-/disable meaningless menu items which would require the presence of a certain number of windows to be active. You can register your own menu items using a line like:
hook::register requireOpenWindowsHook [list ?-m? menu item] N
where N is the number of windows required (1 or 2 usually)
As an example, this is a line from Diff mode registering the item Compare Windows to require 2 open windows to be enabled, followed by a line from HTML mode (which shows the use of the -m menu flag in this hook):
hook::register requireOpenWindowsHook [list compare windows] 2
hook::register requireOpenWindowsHook [list -m Browsers "Send File to Browser"] 1

Credits and Copyright

This document has been placed in the public domain. All AlphaTcl code has license information specific to the packages/authors, assume that it can be distributed under a Tcl-style license unless otherwise specified.
Authors: Most of the material of Parts 2 and 3 was written by Vince Darley around 2004, with contributions from Craig B. Upright, Tom Fetherston and Pete Keleher. A thorough revision, documentation of many of the new technologies introduced since version 8.1, and most of the material in Part 1, is due to Joachim Kock (2011) with many contributions from Bernard Desgraupes.
Copyright (c) 2021, the Alpha Community.
All rights reserved.
This software is free software and distributed under the terms of the new BSD license:
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ALPHA COMMUNITY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.