Variables - Macro variables
Variables are part of MicroEmacs macro language and may be used wherever an argument is required. The variable space comprises:-
# - Register Variable
$ - System Variable
% - Global Variable
. - Command Variable
: - Buffer Variable
All variables hold string information, the interpretation of the string (numeric, string or boolean) is determined when the variable is used within the context of the command. There are five types of variable, Register Variables (prefixed with a hash #), System Variables (prefixed with a dollar $), Global Variables (prefixed with a percentage %), Buffer Variables (prefixed with a colon :) and Command Variables (prefixed with a period .).
Register Variables provide a set of 10 prefixed global (#g0 .. #g9), parent (#p0 .. #p9) and local (#l0 .. #l9) register variables. The interpreted decode time of the register variables is significantly smaller than other variable types as no name space search is performed.
Register variables are implemented like a stack, where the global registers are the top of the stack and every executing macro gets its own set of resister variables (#l?). The macro also has access to the global registers (#g?) and its calling, or parent macro (#p?). If the macro has no parent macro then the global registers are also the parent registers. Outside macros, i.e. using set-variable manually, the global parent and local registers are the same.
Register variables are typically used for retaining short term state, computation steps etc. As with the User Variables, the global register variables are global and care must be taken with nested macro invocations to ensure that the register usage does not conflict.
MicroEmacs defines many System variables which are used to configure many aspects of the editors environment. The functionality of each system variable has been documented, they can be set and described but cannot be unset. If the user attempts to set or describe a non-existent MicroEmacs system variable (e.g. $PATH) the system environment is used instead, allowing the user to query and alter the system environment.
The Global variables are denoted by an initial % character followed by the name of the variable variableName. The variableName may be any ASCII character string up to 127 characters in length, all characters of the name are significant. Shorter names are preferred as this speeds up execution. Global Variables exist in a global context which all macros have access to.
Command variables exist within the scope of a command, they are denoted by the period (.) character. They can be accessed by one of two forms, either .variableName or .commandName.variableName. The first form, without the command name, assumes the scope to be the current command, as such may only be used to access internal variables. The second form qualifies the scope by specifying the command, this form is much more versatile and may be used to access any command variable from any other command, e.g.
define-macro foo set-variable .foo "Hello world" 1000 ml-write &cat "foo1: " .foo 1000 ml-write &cat "foo2: " .foo.foo !emacro define-macro bar foo 1000 ml-write &cat "bar1: " .foo 1000 ml-write &cat "bar2: " .foo.foo !emacro bar
When bar is executed the following messages may be observed:-
foo1: Hello World foo2: Hello World bar1: ERROR bar2: Hello World
When a macro file or buffer is executed, they are executed within their own scope so local scope command variables (form 1) may be created and used in that scope. Any such variables created are automatically deleted at the end of execution. For example, the default color scheme generator macro file, schemed.emf, creates command variables for the created colors to aid readability:-
add-color &set .green 3 0 200 0 a0dd-color &set .lgreen 11 0 255 0 ... add-color-scheme .scheme.cardback .lgreen .green .lgreen ...
The variables only exist as a file or buffer is being executed, they are not accessible by another command once the command or buffer execution has finished.
Buffer variables are similar to Command variable in function and behaviour except that their scope is of a buffer and are denoted by the colon (:) character. Access can be in one of two forms, either :variableName where the scope is assumed to be the current buffer or :bufferName:variableName, where the scope is explicitly given allowing access to any buffer variable, e.g.
find-buffer "foo" set-variable :foo "Hello world" find-buffer "bar" set-variable :bar "Hello world" 1000 ml-write &cat ":foo " :foo 1000 ml-write &cat ":foo:foo " :foo:foo 1000 ml-write &cat ":bar " :bar 1000 ml-write &cat ":bar:bar " :bar:bar
When the above is executed the following messages may be observed:-
:foo ERROR :foo:foo Hello World :bar Hello World :bar:bar Hello World
Global, Buffer and Command variables are automatically defined when they are used. A variable is assigned with set-variable(2) and may be subsequently deleted with unset-variable(2). The current assignment of a variable may be queried from the command line using describe-variable(2). e.g.
define-macro foo !emacro set-variable %foo "Some string" set-variable :bar "Some string" set-variable .foo.bar "Some string" ... ml-write &spr "%s %s %s" %foo :bar .foo.bar ... unset-variable :bar unset-variable %foo unset-variable .foo.bar
An undefined variable returns the string ERROR, this known state is used to advantage with the hilighting initialization, e.g.
!if &sequal .hilight.c "ERROR" set-variable .hilight.c &pinc .hilight.next 1 !endif ; ; Hi-light C Mode ; 0 hilight .hilight.c 2 50 $global-scheme
In this case the variable .hilight.c is explicitly tested for definition, if it is undefined then it is assigned a new value.
Conventionally, names are separated with a minus sign character (-) e.g. foo-bar. It is strongly advised that the name space is kept reasonably clean, since there are no restrictions on the number of macros that may be defined, problems will arise if different macros use the same variables in different contexts. Where possible, Command or Buffer Variables are preferable to Global Variables since they have no side effects on other macros or buffers. It is advised that all variable names associated with a particular macro set are prefixed with short identifier to make the variable name space unique. e.g. the Metris macro prefixes all variables with :met-; the draw macro uses :dw-, the patience macro :pat- etc.
Macro writers should endeavor to use the minimal number of variables, obviously the more variables that exist in the system, the greater the lookup time to find a variable. Use Register Variables in preference to Command, Global or Buffer variables for intimidate computation steps, temporary state etc.
Note that Buffer Variables are automatically deleted when the buffer is deleted.
The following example is the macro to convert tabs to spaces, it is shown in two forms, with User Variables and with Register Variables, the register variable implementation is obviously preferable since no new variables have been defined.
; ; tabs-to-spaces. ; Convert all of the tabs to spaces. define-macro tabs-to-spaces set-variable %curline $window-line ; Remember line beginning-of-buffer !force search-forward "\t" !while $status 3 drop-history set-variable %curcol $window-acol backward-delete-char &sub %curcol $window-acol insert-space !force search-forward "\t" !done 3 drop-history goto-line %curline update-screen ml-write "Converted tabs!" !emacro
; ; tabs-to-spaces. ; Convert all of the tabs to spaces. define-macro tabs-to-spaces ; Remember line set-variable #l0 $window-line beginning-of-buffer !force search-forward "\t" !while $status set-variable #l1 $window-acol backward-delete-char &sub #l1 $window-acol insert-space !force search-forward "\t" !done goto-line #l0 screen-update ml-write "[Converted tabs]" !emacro
Copyright (c) 1998-2006 JASSPA
Last Modified: 2002/01/11
Generated On: 2006/10/07