9.9. Using different sets of macros in different situations

Name-spaces, contexts and binding contexts

TrEd adopts mechanisms similar e.g. to Emacs major-modes which allow the user to safely create several sets of macros with possibly coliding key and menu bindings as well as macro names. These mechanisms are called contexts, or more specifically: name-spaces and binding contexts.

To prevent macros from colliding or modifying the internal TrEd variables or functions the Perl concept of packages or namespaces is used. Unless the Perl package command is used, each macro belongs to a default package (or name-space) called TredMacro. Beside the user-defined macros, the pre-defined macros are defined within this package.

New package named say MyPackage is created using the following command:

package MyPackage;

To be able to call macros defined in the TredMacro package (e.g. the pre-defined macros) without having to prefix their names with one of TredMacro-> or TredMacro:: prefixes the following command may be used to import the TredMacro name-space to the current package's name-space:

import TredMacro;

Now all the subsequent macro definitions (or global variable declarations) are created within the MyPackage name-space unless other package command occurs. Thus the following example defines a macro named my_macro in a new name-space of the MyPackage package:

package MyPackage;
import TredMacro;

sub my_macro {
  # macro code comes here 
}

To call the my_macro of the previous example from a different package than MyPackage, the full package name must be given together with the name of the macro:

MyPackage::my_macro();   # call to a macro defined in MyPackage

In the interactive work, name-space are combined with a concept of binding-contexts. Binding contexts usually correspond to the package names. Analogously to the package command, a special directive exists for creating or switching a binding context, however in this case, more then one binding-contexts may be used at once:

#binding-context context_name_1 context_name_2 ...

The default binding-context is again named TredMacro. To switch to a new context, say MyContext, the following directive should be used:

#binding-context MyContext

Now, all the subsequent directives #bind, #insert, #unbind-key, and #remove-menu would apply to this context and all the bound macros, when invoked, will be first searched in the package named MyContext.

There is a separate submenu created for each binding-context in the User-defined menu. In TrEd there may be only one context active at one time. The active context may be choosen from the menu on the right end of the menu bar. If a keyboard shortcut is pressed, TrEd first searches for a macro bound to the shortcut within the active binding-context and if such macro exists, TrEd invokes it. In this case, the macro is supposed to be defined or imported in a package of the same name as is the name of the active context. If no macro is bound to the shortcut within the active binding-context, TrEd tries to find a binding in the default TredMacro context. The macro is then supposed to be defined within the TredMacro package. If the search fails, no action is taken. The same holds for hooks as well.

The following example shows how to create a set of macros which enable TrEd to automatically decide which context to use when a file is opened. It is quite similar to the Emacs concept of “auto-modes”, except that content of the file is considered here, not the file-name extension. In the example, existence of a certain attribute is used to decide which context to use. The example is extracted form the set of macros written for the annotation of the Prague Dependency Treebank. There are two contexts for annotation: for the “Analytic” and “Tectogrammatic” layers. The “tectogrammatic” trees may be easily distinguished from the “analytical” ones because (among others) a special attribute named TR is defined for them.

Example 2. Using contexts

package TredMacro; # Ensure we are in the default package
                   # (This may not be necessary.)

# we use a hook to set the context
sub file_opened_hook {
  if ($grp->{FSFile}->FS->exists('TR')) {
    SwitchContext('Tectogrammatic'); 
  } else {
    SwitchContext('Analytic');
  }
}

#binding-context Analytic
package Analytic;
import TredMacro;


#bind SubtreeAfunAssign to Ctrl+Shift+F1
sub SubtreeAfunAssign {
   # automatic assignment of some analytical attributes
}

sub ReorderTree {
   # ...
}


# the following binding of ReorderTree will apply to both binding contexts

#binding-context Analytic Tectogrammatic
#bind ReorderTree to Ctrl+R

#binding-context Tectogrammatic
package Tectogrammatic;
import Analytic;   # all macros of the Analytic package (eg. ReorderTree) 
	           # will now be available here directly

#bind SubtreeAfunAssign to Ctrl+Shift+F1
sub SubtreeFuncAssign {
   # automatic assignment of some tectogrammatical attributes
}