MacroExtension Interface Shannon Stewman stew at uchicago.edu I've written some code that I think provides a safe and flexible way for plugins to directly add macro functions to the macro interpreter. It keeps your encapsulation of the macro internals within the ij.macro package while allowing these extensions to accept strings, values and arrays as arguments, and to return string and number values back to passed variables. Basic description (macro side): 1. Macros that wish to use extensions will first run a plugin that provides these extensions. If the plugin isn't there, the macro will terminate. The extensions are also local to macros that run the plugin. run("ROI Tracker Extensions"); // plugin that provides Ext.roiTracker() 2. Extensions are accessed via the 'Ext' namespace. For example: Ext.roiTracker("show", "track", 5); 3. Parameters can be strings, numbers, or arrays. Parameters can also be marked 'output', which allows the function to pass values back via macro variables (a la getCursorLoc). On the Java side: 1. Plugins register macro extensions via the Functions.registerExtensions() static function. The function takes one argument: an object that implements the ij.macro.MacroExtension interface. It registers the functions provided by this extension with a table in the Functions instance attached to the current interpreter (keeping the changes local to the running macro). 2. The MacroExtension interface provides two functions: (a) getExtensionFunctions() which returns an array of ExtensionDescriptor objects. These describe the functions and their argument types. (b) handleExtension(), which is the function that's called when an extension function is invoked. It takes two arguments: the name of the extension function, and an array of Object (Object[]) which are the Java-side parameters. 3. ExtensionDescriptor describe a single extension function and are responsible for converting between the macro-side values (Variable objects) and Java-side values. The goal was to keep function extensions from seeing/using the internals of the macro system. a. string values are passed as String objects b. numeric values are passed as Double objects c. array values are passed as Object[] objects Arguments can be marked as 'output', in which case they require a variable to be passed, like getCursorLoc(x,y). Only string and numeric output variables are supported, and are passed as arrays: d. string 'output' variables are passed as a 1-element String[] array e. numeric 'output' variables are passed as a 1-element Double[] array I wrote this to help me write macros for a couple of projects where the run(...) facility wouldn't work very well and the call(...) function felt clunky.