Macros

Iron Resource Files

Iron macro resource files are text files that are compiled and used by Iron to define macros that are used by keymap and menu item bindings.

Macros provide pairs of context and command expressions that are employed by the keymap’s or menu item’s context and command expressions.

The iron.macro file can be loaded using the Tools|Macros|Load Macro File menu option or via the Command Palette (press F8) and type iron.macro and Enter.

This document will describe the Iron macro resource file format, it’s grammar, content and uses.

Refer to the Iron Resource Files: Customizing documentation on how to compile (press F7) and debug (press F4) Iron resource files in more detail.

The more we reduce ourselves to machines in the lower things, the more force we shall set free to use in the higher.

Anna Brackett

Philosopher, translator, feminist, and educator. (1836–1911)

Why Use Macros?

Why use user-defined and customizable macros?

  • Like in other programming languages, macros are used to descriptively name functionality and can be referenced multiple places throughout the Iron resource file set.
  • Macros have up to four pairs of context and command expressions. This allows Iron to match a key binding and then attempt to validate up to four different contexts. This is equivalent to using a boolean OR operator i.e. allows for more complex context validation.
  • When the same macro is referenced by a key binding and a menu item, the menu item will render the key combo (shortcut) on the right side of the menu item.

Macros have pairs of context and command expressions. When a macro is referenced by a key binding’s context expression, the key binding is using the macro’s context expression. When the key binding’s command expression references a macro, the key binding is using the macro’s command expression. The same applies to menu item’s context and command expressions.

For detailed description and discussion of context expressions and command expressions, see the Iron Resource Files: Keymaps documentation.

In brief, context and command expressions are simplified boolean expressions that are evaluated or executed by Iron. When you type on the keyboard or use the mouse, Iron matches key combos (patterns of pressed keys and buttons) from the list of key bindings in the iron.keymap file and then attempts to validate the context before executing the corresponding command expression.

For menu items, Iron uses macros for a similar purpose, first to validate a context which enables the menu item (allows it to be picked) and then executes the command expression when the menu item is picked (mapped to a mouse button release by default).

Macros used by both a menu item and a key binding are consider loosely coupled. This allows the key binding’s key combo to be rendered as a shortcut on the right side of the menu item.

Note: To display a key combo on a menu item, Iron will seek out the first key binding in the iron.keymap file that references the same macro. This mechanism works well enough but may be replaced with a stronger coupling i.e. use of some kind of tagging. To be determined.

Note: Keymaps and key bindings are described in detail in the Iron Resource Files: Keymaps documentation. Menus and menu items are described in detail in the Iron Resource Files: Menus documentation.

Zinc Macro File Format

User-defined macros are all located in the iron.macro file by default. They can, however, be defined in any of Iron’s resource files and referenced from anywhere in the Iron resource file set. All of Iron’s resource files use the Zinc grammar and file format and are compiled by Iron’s built-in Zinc compiler.

Note:  For the timing being, macros and other Zinc declarations all have global scope and visibility between all the Iron resource files. The namespace statements, though required, are ignored.

Here’s is a simple macro with one pair of context and command expressions:

macro macro_results_jump_to( void )
{
                context = file.is_extension( extension = “results” );
                command = fif.enter();
}

A macro declaration consists of the keyword macro followed by the macro’s descriptive name (e.g. macro_results_jump_to) and a parameter list enclosed in parentheses and a macro body. The macro body is delimited by curly braces {} and contains up to four pairs of context and command expression assignment statements.

Note:  Macros do not support parameters at this time, hence the parameter list is always void.

The order of macro declarations in the iron.macro file does not matter (or across files). The Zinc language does not require forward declaration i.e. macros can be referenced before they’re declared. All references and parameters in Zinc are resolved and types validated as part of late-stage semantic processing which happens as-you-type.

Odd Macros

Though expressions used by keymaps, menus and other macros are simple AND’ed boolean expressions, they can be quite complex particularly when determining the proper context.

TLDR: This section, by the way, describes esoteric uses of macros, short-circuit evaluation and a complex set of macros intended for advanced users. You may certainly skip this section unless you’re deep into customizing Iron’s macros.

In the future, the Zinc grammar and run-time evaluation will support new semantics for increased fidelity. For now, as an example, the boolean OR operator is not supported other than through having four pairs of context and command expressions in a single macro. Each context is evaluated one at a time, in order, by Iron’s keymap processing until a context result is true. Otherwise (as in a boolean OR) the next context is tested.

One macro programming trick involves cascading expressions where one macro expression references another macro that references yet another macro. This can continue to any depth and is demonstrated by the Escape Everything set of macros at the bottom of the iron.macro file. This allows, in essence, for more than just four OR’ed context expressions.

In this example, Iron is attempting to cancel everything, all activity, using cascading expressions and two other tricks (explained just below) that requires more than four context checks. This odd set of macros is necessary because Zinc expressions don’t yet support the boolean OR operator directly and there are more than four things that may need to be canceled simultaneously.

The other two tricks involve, first, the fact that command expressions are optional in macros. When absent, no actions take place. So what’s the point? The point is that a context expression can have side-effects which executes built-in actions that actually change an Iron state, not just evaluates the state, and then return a value of true or false.

As mentioned elsewhere, changing an Iron state in a context expression isn’t really good form or good practice but it comes in handy here. Normally, changing state should only happen in a command expression.

The second trick is to cause a context expression to always fail by appending and false to the expression.

So what is happening in macro_cancel_everything() for example is that the first context statement is canceling the playing of any audio clips. The audio.cancel() action will return true if a clip was canceled and false if no clip was playing. Either way, once the AND’ed false value is consider, that ensures that the entire context expression is false which means Iron will continue to the next context statement to see if it’s valid.

In this way, all the contexts in this cascading set of macros are evaluated, executing all their actions every time macro_cancel_everything() is called. No command expressions are ever executed (and don’t exist). Thus all the activity in Iron is canceled, one context expression at a time.

It’s definitely an odd set of macros.

Very Important:  Never make a macro self-reference or a recursive set of macro references. Iron will crash due to a stack overflow as-you-type with continuous compilation engaged (the default). Work will be lost.