Macros can be called from Macro menu commands, the window background menu, within the smart-indent framework, from the autoload macro file (see Preferences), and from the command line. Macro menu and window background menu commands are defined under Preferences → Default Settings → Customize Menus. Help on creating items in these menus can be found in Preferences.
NEdit-ng's macro language is a simple interpreter with integer arithmetic, dynamic strings, and C-style looping constructs (very similar to the procedural portion of the Unix awk program). From the macro language, you can call the same action routines which are bound to keyboard keys and menu items, as well additional subroutines for accessing and manipulating editor data, which are specific to the macro language (these are listed in Macro Subroutines, and Action Routines).
Syntax
An NEdit-ng macro language program consists of a list of statements,
each terminated by a newline. Groups of statements which are executed
together conditionally, such as the body of a loop, are surrounded by
curly braces {}
.
Blank lines and comments are also allowed. Comments begin with a #
and end with a newline, and can appear either on a line by themselves,
or at the end of a statement.
Statements which are too long to fit on a single line may be split
across several lines, by placing a backslash \
character at the end
of each line to be continued.
Data Types
The NEdit-ng macro language recognizes only three data types, dynamic character strings, integer values and associative arrays. In general strings and integers can be used interchangeably. If a string represents an integer value, it can be used as an integer. Integers can be compared and concatenated with strings. Arrays may contain integers, strings, or arrays. Arrays are stored key/value pairs. Keys are always stored as strings.
Integer Literals
Integers are non-fractional numbers in the range of -2147483647
to
2147483647
. In other words, they are 32-bit signed integers.
Integer literals must be in decimal. For example:
a = -1
b = 1000
Character String Literals
Character string literals are enclosed in double quotes. For example:
a = "a string"
dialog("Hi there!", "OK")
Strings may also include C-language style escape sequences:
\\
Backslash\t
Tab\f
Form feed\"
Double quote\b
Backspace\a
Alert\n
Newline\r
Carriage return\v
Vertical tab
Also allowed is the escape control character sequence:
\e
Escape
For example, to send output to the terminal from which NEdit-ng was
started, a newline character is necessary because, like printf
,
t_print
requires explicit newlines, and also buffers its output on a
per-line basis:
t_print("a = " a "\n")
Other characters can be expressed as backslash-escape sequences in macro
strings. The format is the same as for regular expressions, described in
the paragraphs headed "Octal and Hex Escape Sequences" in Metacharacters,
except that an octal escape sequence can start with any octal digit, not just 0
,
so the single character string "\0033"
is the same as "\33"
, "\x1B"
and "\e"
.
Note that if you want to define a regular expression in a macro string, you need to "double-up" the backslashes for the metacharacters with special meaning in regular expressions. For example, the expression
(?N(\s|/\*(?n(?:(?!\*/).)*)\*/|//.*\n|\n)+)
which matches whitespace or C/C++/Java-style comments, should be written as a macro string as
"(?N(\\s|/\\*(?n(?:(?!\\*/).)*)\\*/|//.*\n|\n)+)"
(The \n
s towards the end add literal newline characters to the string.
The regular expression interpretation treats the newlines as themselves.
It can also interpret the sequence \\n
as a newline, although the
macro string here would then contain a literal backslash followed by a
lowercase N
.)
Variables
Variable names must begin either with a letter (local variables), or a
$
(global variables). Beyond the first character, variables may also
contain digits and underscores _
. Variables are called into existence
just by setting them (no explicit declarations are necessary).
Local variables are limited in scope to the subroutine (or menu item definition) in which they appear. Global variables are accessible from all routines, and their values persist beyond the call which created them, until reset.
Built-in Variables
NEdit-ng has a number of permanently defined variables, which are used to access global editor information and information about the window in which the macro is executing. These are listed along with the built in functions in Macro Subroutines.
Functions and Subroutines
The syntax of a function or subroutine call is:
function_name(arg1, arg2, ...)
where arg1
, arg2
, etc. represent the argument values which are passed to
the routine being called. A function or subroutine call can be on a line
by itself, as above, or if it returns a value, can be invoked within a
character or numeric expression:
a = fn1(b, c) + fn2(d)
dialog("fn3 says: " fn3())
Arguments are passed by value. This means that you cannot return values via the argument list, only through the function value or indirectly through agreed-upon global variables.
Built-in Functions
NEdit-ng has a wide range of built in functions which can be called from the macro language. These routines are divided into two classes, macro-language functions, and editor action routines. Editor action routines are more flexible, in that they may be called either from the macro language, or bound directly to keys. They are also limited, however, in that they cannot return values. Macro language routines can return values, but cannot be bound to keys.
Nearly all of the built-in subroutines operate on an implied window,
which is initially the window from which the macro was started. To
manipulate the contents of other windows, use the focus_window
subroutine to change the focus to the ones you wish to modify.
focus_window
can also be used to iterate over all of the currently
open windows, using the special keyword names, last
and next
.
NEdit used to support hyphenated action routine names of the form subroutine-name
and eventually deprecated support of this. Use of these names was discouraged.
NEdit-ng has taken this a step further and has fully dropped support for it in favor
of names which use a underscores eg. subroutine_name
.
User Defined Functions
Users can define their own macro subroutines, using the define
keyword:
define subroutine_name {
< body of subroutine >
}
Subroutine definitions cannot appear within other definitions, nor
within macro menu item definitions. They can only appear in (macro)
files, such as the autoload macro file (see Preferences). Macro
files can be loaded with File → Load Macro File... or with the
load_macro_file()
action.
The arguments with which a user-defined subroutine or function was
invoked, are presented as $1
, $2
, ... , $9
or $args[<expr>]
,
where <expr>
can be evaluated to an integer from 1 to the number of
arguments. The number of arguments can be read from $n_args
or
$args[]
. The array $args[<expr>]
is the only way to access arguments
beyond the first 9
.
To return a value from a subroutine, and/or to exit from the subroutine
before the end of the subroutine body, use the return
statement:
return <value to return>
Operators and Expressions
Operators have the same meaning and precedence that they do in C, except
for ^
, which raises a number to a power (y^x
means y
to the x
power), rather than bitwise exclusive OR. The table below lists
operators in decreasing order of precedence.
Operators | Associativity |
---|---|
() |
right to left |
^ |
(unary) |
- ! ++ -- |
left to right |
* / % |
left to right |
+ - |
left to right |
> >= < <= == != |
left to right |
& |
left to right |
\| |
left to right |
&& |
left to right |
\|\| |
left to right |
(concatenation) |
left to right |
= += -= *= /= %=, &= \|= |
right to left |
The order in which operands are evaluated in an expression is undefined,
except for &&
and ||
, which like C, evaluate operands left to right,
but stop when further evaluation would no longer change the result.
Numerical Operators
The numeric operators supported by the NEdit-ng macro language are listed below:
+
addition-
subtraction or negation*
multiplication/
division%
modulo^
power&
bitwise and|
bitwise or
Increment (++
) and decrement (--
) operators can also be appended or
prepended to variables within an expression. Prepended
increment/decrement operators act before the variable is evaluated.
Appended increment/decrement operators act after the variable is
evaluated.
Logical and Comparison Operators
Logical operations produce a result of 0
(for false) or 1
(for true). In
a logical operation, any non-zero value is recognized to mean true. The
logical and comparison operators allowed in the NEdit-ng macro language
are listed below:
&&
logical and||
logical or!
not>
greater<
less>=
greater or equal<=
less or equal==
equal (integers and/or strings)!=
not equal (integers and/or strings)
Character String Operators
The "operator" for concatenating two strings is the absence of an operator. Adjoining character strings or variable names with no operator in between means concatenation:
d = a b "string" c
t_print("the value of a is: " a)
Comparison between character strings is done with the ==
and !=
operators, (as with integers). There are a number of useful built-in
routines for working with character strings, which are listed in
Macro Subroutines.
Arrays and Array Operators
Arrays may contain either strings, integers, or other arrays. Arrays are associative, which means that they relate two pieces of information, the key and the value. The key is always a string; if you use an integer it is converted to a string.
To determine if a given key is in an array, use the in
keyword.
if ("6" in x)
<body>
If the left side of the in
keyword is an array, the result is true if
every key in the left array is in the right array. Array values are not
compared.
To iterate through all the keys of an array use the for
looping
construct. Keys are not guaranteed in any particular order:
for (aKey in x)
<body>
Elements can be removed from an array using the delete
command:
delete x[3] # deletes element with key 3
delete x[] # deletes all elements
The number of elements in an array can be determined by referencing the array with no indices:
dialog("array x has " x[] " elements", "OK")
Arrays can be combined with some operators. All the following operators only compare the keys of the arrays.
result = x + y (Merge arrays)
result
is a new array containing keys from both x
and y
. If
duplicates are present values from y
are used.
result = x - y (Remove keys)
result
is a new array containing all keys from x
that are not in
y
.
result = x & y (Common keys)
result
is a new array containing all keys which are in both x
and
y
. The values from y
are used.
result = x | y (Unique keys)
result
is a new array containing keys which exist in either x
or
y
, but not both.
When duplicate keys are encountered using the +
and &
operators, the
values from the array on the right side of the operators are used for
the result. All of the above operators are array only, meaning both the
left and right sides of the operator must be arrays. The results are
also arrays.
Array keys can also contain multiple dimensions:
x[1, 1, 1] = "string"
These are used in the expected way, e.g.:
for (i = 1; i < 3; i++)
{
for (j = 1; j < 3; j++)
{
x[i, j] = k++
}
}
gives the following array:
x[1, 1] = 0
x[1, 2] = 1
x[2, 1] = 2
x[2, 2] = 3
Internally all indices are part of one string, separated by the string
$sub_sep
(ASCII 0x1c
, 'FS'). The first key in the above example is in
fact:
["1" $sub_sep "1"]
If you need to extract one of the keys, you can use split()
, using
$sub_sep
as the separator.
You can also check for the existence of multi-dimensional array by
looking for $sub_sep
in the key.
Last, you need $sub_sep
if you want to use the 'in' keyword.
if ((1,2) in myArray)
{..}
doesn't work, but
if (("1" $sub_sep "2") in myArray)
{..}
does work.
Looping and Conditionals
NEdit-ng supports looping constructs: for
and while
, and conditional
statements: if
and else
, with essentially the same syntax as C:
for (<init>, ...; <condition>; <increment>, ...) <body>
while (<condition>) <body>
if (<condition>) <body>
if (<condition>) <body> else <body>
<body>
, as in C, can be a single statement, or a list of statements
enclosed in curly braces {}
. <condition>
is an expression which must
evaluate to true for the statements in <body>
to be executed. for
loops may also contain initialization statements, <init>
, executed
once at the beginning of the loop, and increment/decrement statements
(or any arbitrary statement), which are executed at the end of the loop,
before the condition is evaluated again.
Examples:
for (i=0; i<100; i++)
j = i * 2
for (i=0, j=20; i<20; i++, j--) {
k = i * j
t_print(i, j, k)
}
while (k > 0)
{
k = k - 1
t_print(k)
}
for (;;) {
if (i-- < 1)
break
}
Loops may contain break
and continue
statements. A break
statement
causes an exit from the innermost loop, a continue
statement transfers
control to the end of the loop.