Programmed Macros in vile

vile presents a couple of forms of what are commonly called "macros". This document presents information on those written in the builtin "macro language". (The other form of macro is a "keyboard macro", a simple stored sequence of vile keystrokes, which can be replayed on command.) Macros written in the macro language can be bound to keys, run from files or buffers, given names (in which case they're known as "procedures"), and in the last case, those names may be directly introduced into vile's command set.

The language can execute any valid vile command, using one of it's "named" forms. I.e. the command that would be executed would be "down-line", "forward-line", or "next-line", but it would not work to write the macro to use 'j'.

vile commands can be linked together in repetitive or conditional ways using various builtin directives (e.g. "if", "else", "while", "break", etc), and intermediate results can be stored in string-valued temporary variables. Other forms of variable can be used to reference parts of vile's current state, e.g. the current line number. Finally, there is a set of functions that can act on variables, to concatenate them, compare them, increment them, change their representation, etc.

Each of these language aspects will be described in turn, but first the execution framework must be explained.

Creating, executing, storing macros

In the simplest case, valid macro language constructs are placed in a file or buffer and subsequently executed with one of these editor commands:

command applies to example
execute-buffer buffer execute-buffer cfgcmds
execute-file disk file execute-file ~/.projcfg
source disk file source c:/utils/proj.cfg

The most common example of this usage is vile's startup file, which is "sourced" during the editor's invocation. Typically, the startup file configures the user's preferences and looks something like this:

set ai
set ts=4
set flash

A startup/configuration file might also use macro language directives to conditionally configure the editor. For example, if xvile executes this startup file fragment:

~if &sequal $progname "xvile"
    set-variable $title $cbufname

then the editor's X window titlebar changes. However, "standard" vile (i.e., non-gui vile) ignores this fragment and thus, a single startup file can be used to configure both the gui and non-gui versions of the editor.

vile also provides constructs that encapsulate macro language elements as numbered and named programs. These programs represent the entity that most programmers identify as a "true" macro. And in fact, the remainder of this document will simply assume that the word "macro" refers to one of aforementioned program types.

Numbered macros (anachronism)

The numbered macro syntax looks like so:

    <language element>
    <language element>

A numbered macro is executed using this command:


To bind a keystroke to this macro, use this command:

bind-key execute-macro-<number> <keystroke>

Here's an actual example:

30 store-macro
    write-message "this is a test macro"
bind-key execute-macro-30 #h

Now, whenever "#h" is pressed, a message is written on the editor's message line.

Although this syntax serves a purpose, it's obvious that numbered programs don't lend themselves to easy recall (quick, what does macro 22 do?). But this format was an integral part of vile for many years, simply because named macros could not be bound to keystrokes. This restriction has been removed, rendering this feature essentially obsolete. The only advantage of numbered macros over named macros is that the former do not share the same namespace as vile's commands. This attribute can be advantageous when creating macros recalled solely via key bindings.

For completeness sake, it should be mentioned that numbered macros are allocated from a fixed pool (default is 40 macros). This fixed pool can be increased via the following configuration option:

        --with-exec-macros=N    specify count of numbered macros

Named macros

A named macro, aka "stored procedure", uses this syntax:

store-procedure <unique-name> ["help-string"]
    <language element>
    <language element>


is an alpha-numeric identifier that does not conflict with the name of any existing editor command (the show-commands command generates a list of all existing commands).
is an optional description of the macro. This string is displayed in the listing created by show-commands.

A stored procedure is executed by simply referencing its name. To bind a keystroke to this macro, use this command:

        bind-key <unique-name> <keystroke>

Here's the stored procedure equivalent of macro number 30 above:

store-procedure write-msg-tst "displays test message"
    write-message "this is a test macro"
bind-key write-msg-tst #h

Two mechanisms now exist for executing this macro:

Named macros may have parameters. Like Bourne shell, the parameters are denoted '$' followed by a number, e.g., $1 for the first parameter.

The individual parameters are evaluated when the macro is invoked, and may consist of expressions. They are stored as strings.

The macro interpreter uses a template in the definition to define the types of parameters which are accepted. For each parameter, a keyword, optionally followed by the prompt string is required. Keywords (which may be abbreviated) include

        enum            (see below)

Unless overridden, the prompt for each parameter is named after the keyword. Override the prompt by an assignment, e.g.,

store-procedure Filter f="Input" f="Output"

to begin a macro 'Filter' with two parameters, Input and Output, internally referenced by $1 and $2.

Here is a simple macro which accepts two parameters and uses them to position the cursor on a given line and zero-based character offset.

; macro for wingrep and similar applications that can pass
; both line- and column-number to external tools.
; usage: "winvile +WinGrep $L $C $F"
store-procedure WinGrep i="Line" i="Offset"
        ~local %col
        setv %col &sub $2 1
        $1 goto-line
        ~if &ge %col 1
                %col forward-character-to-eol

The 'enum' parameter type is special; it requires a second keyword which denotes the symbol table which is used for name-completion. The table name (which cannot be abbreviated) follows the 'enum' after a colon (:), e.g.,

store-procedure Scheme e:fcolor="Foreground"

The 'enum' tables correspond to the enumerated modes:

        record-attrs (VMS only)
        record-format (VMS only)

Returning values

Any macro can return a value to a calling script. This is done using special variables:
is a symbol that a macro can set to any string.
is copied from $return when completing a macro. If no string was assigned to $return within the macro, $_ will contain a readable form of the exit status. These are the standard values used within vile:

$_ may also contain the special symbol ERROR if the macro could not run, e.g., due to too much recursion, or if the exit status was none of the standard values.

Storing macros

In general, macros are stored in the editor's startup file. Prolific macro authors may instead opt to sprinkle their macros across one or more external text files and source those file(s) from the startup file.

This concludes the discussion of the macro language execution framework.

The remainder of this document describes individual language constructs. The presentation is bottom-up (i.e., reference format), so individual sections may be read in any order.


A semi-colon (;) or double-quote (") denotes a comment that extends from the delimiter to end of line. The semi-colon is inherited from MicroEMACS, the double-quote is for vi compatibility.

Note 1: The double-quote also delimits string arguments, but the command parser correctly distinguishes the various use cases.

Note 2: Inline comments (comment text that follows a command) are permitted except when used in conjunction with commands that take optional arguments. Here follow two examples of unacceptable usage:

winopen    ; invoke win32 common open dialog
write-file ; flush curr buffer to disk

In the first case, the winopen command attempts to browse ';' as a directory. In the second case, write-file flushes the current buffer to disk using ';' as the filename.

Misc macro syntax features

Lines ending with '\' are joined before interpretation.


The length of a variable name may not exceed 255 (NLINE-1) bytes of storage. Most other strings are allocated dynamically.


Like many simple languages, the macro language operates exclusively on strings. That is to say, variables are always of type "string", and need not be declared in advance.

Strings may be surrounded by double quotes. As in C-like languages, a few special characters may be represented using an "escape" notation, using a backslash and another character to represent the "special character:"

Escape code Actual character Example
\n newline character (control-J)
\r carriage return (control-M)
\\ backslash (itself: '\')
\b backspace (control-H)
\f formfeed (control-L)
\t tab (control-I)
\a bell (control-G)
\s space (ASCII SPACE)
\" quote (the '"' character)
\xNN the character in hex (i.e. 0xNN)
\NNN the character in octal (i.e. 0NNN)
\C (any char) itself

It is permissible to omit the double quotes surrounding a string if the parser will not confuse it with another element of the macro language, and if it contains no whitespace, but it's probably better practice to use the quotes all the time, to reinforce the idea that all values are strings.

You may also use strings surrounded by single quotes. The single quotes override double quotes and backslashes, making it simpler to enter regular expressions. Double a single quote to insert one into a string.


As noted above, variables hold strings. These strings may represent words, text, numerical values, logical values, etc, depending on the context in which they are used. There are several distinct classes of variables, distinguished syntactically by the character preceding their name.

Class Example
Temporary variable %foo
State variable $curcol
Buffer variable <main.c
Interactive variable @"Enter a filename: "
Mode variable $autoindent

All temporary variables, and some state variables, may be assigned to, using the "set-variable" command, or "setv" for short:

set-variable $search "new pattern to look for"
setv %index "1"
setv %index2="2"

An assignment may use either an equals (=) sign, or whitespace to delimit the left/right sides of the assignment, as shown.

Temporary variables

Temporary variables are used in macros to hold intermediate values. They are only temporary in that they aren't a "fixed" part of vile — but they _are_ persistent across invocations of one or more macros. (That is, they have global scope.) Temporary variables are prefixed with the % character, and their names may be constructed from any printing character.

State Variables

State variables allow a macro to refer to and change some aspects of vile's behavior. State variables are prefixed with a $ character, and are always referred to in lowercase. Not all state variables are settable — some are read-only, and are so marked in the table below. You can also refer to the value of a mode by prefixing its name with a $ character. However:

Here are the state variables:

[READ ONLY] Name of the "other" buffer, the one most recently visited. This is what you would get if you typed '#' at a prompt. (E.g. ":e #")
name of the hook to run when attempting to do automatic syntax coloring.
[READ ONLY] Number of characters in current buffer.
[READ ONLY] Number of characters in current buffer.
[READ ONLY] Status flags for current buffer, as shown in [Buffer List].
Flag Description
a autobuffer caused this to be created
d directory listing
i invisible, e.g., tags
m modified
s scratch, will be removed when popped down
u unread
[READ ONLY] Number of lines in current buffer.
RGB levels for gray, normal, bright in the 0-255 range (winvile version only).
[READ ONLY] Shows the character encoding for the current buffer. The values are the same as for the file-encoding mode, but are always resolved, i.e., no "auto" or "locale".
[READ ONLY] Combines bufname-expr and pathname-expr modes for the current buffer.
Name of procedure to run when switching to a buffer.
current buffer-name under the cursor. This is computed from the bufname-expr and pathname-expr patterns.
[READ ONLY] Number of windows open on current buffer.
The current buffer's "buffername". (As opposed to the name of the file it may contain.)
Name of procedure to run when changing directories.
editor's copy of the $CDPATH env var (read/write)
[READ ONLY] Comma-delimited list of "interesting" compiled options. Currently tracked options include:
Option Description
athena xvile built with Athena widgets
curses editor uses curses terminal driver
locale editor uses system's LC_CTYPE locale
motif xvile built with Motif libraries
nextaw xvile built with Athena widgets (NeXtaw)
noshell shell commands are disabled
oleauto editor supports OLE automation.
openlook xvile built with OpenLook libraries
perl editor includes perl interpreter
termcap editor reads TERMCAP db for screen info.
terminfo editor reads TERMINFO db for screen info.
xaw xvile built with Athena widgets (Xaw)
xaw3d xvile built with Athena widgets (Xaw3D)

If none of the above options are in effect, $cfgopts will be empty ("").

Full pathname of the current buffer, unless it is a special vile buffer, in which case it will return the empty string.
Decimal representation of the ASCII character at the cursor location.
[READ ONLY] Counts repetition of the current macro, from 1 up to the given repeat count. If not in a macro, this is zero.
Character set to use for the minibuffer, i.e., the buffer used for commands and messages. The default (auto) tells vile to set it to match the character set of the current buffer.
[READ ONLY] Returns the motion (keyword) associated with the current macro if it was defined using store-operator. Use with $cmd-count to compose the complete motion, e.g.,

set-variable $search "new pattern to look for"
setv %index "1"
setv %index2="2"

[WRITE ONLY] encryption key.
The index of the cursor in the buffer, in characters (counting from 1).
The cursor's column number (counting from 1).
The cursor's line number (counting from 1).
Current working directory.
The relative line number of the cursor in the current window.
Boolean value which enables runtime tracing of macro execution. This can be set in the ~trace command (described in detail below) as well as via set-variable.
Location of temp files. This is unused, but its initial value is set from the user's TMP environment variable.
Boolean value which will prevent vile from printing some status messages. It is automatically set to FALSE while sourcing a file, or while executing a macro (after prompting for missing parameters). Set it to TRUE to allow nested macros to show a prompt-string for missing parameters.
Boolean value which will prevent vile from displaying command line input characters.
The force-empty-lines command uses this value to decide whether to add or delete blank lines to make all line-gaps the same size.
[READ ONLY] The character encoding, e.g., ISO-8859-1.
Boolean which is true if user entered the cmd with a carriage return (Some commands may expect to receive additional arguments if their name is terminated with a space character rather than a carriage return.)
Buffer name associated with vile's error-buffer feature. This variable commonly appears in a ~local statement in macros that temporarily reassign error-buffer (e.g., the ShowManpage macro in macros/manpage.rc).
Regular expression expanded from [Error Expressions] which matched the most recent find-next-error command.
Text from the current buffer which which was matched in the most recent find-next-error command.
Tabstop value to use when computing the column that a "%C" pattern will produce. If zero or negative, use the current buffer's tabstop, otherwise use the given value. The default is 8.
[READ ONLY] Where to find vile.
[READ ONLY] suffix, if any, for execable programs. Use this in portable macros, with &lookup, to get the actual program path.
Name of procedure to run when quitting.
[READ ONLY] Path to favorites folder (win32 only)
Boolean, true if file for current buffer is modified.
iteration limit for complex fences, in seconds.
actual pattern for %F in [Error Expressions]. Note that vile wraps this in "\(" and "\+\)", so the 1-or-more applies to the last subexpression in %F. We use this side-effect in the win32 port, for example '\([a-zA-Z]:\)\?[^ \t:]' to make the last range repeat 1-or-more times.
[READ ONLY] list of builtin-filters.
editor's copy of the $VILE_FINDPATH environment var (read/write). Available on win32 and unix hosts. For more details, refer to that section of the help file entitled "Working in a project hierarchy".
[READ ONLY] last shell command spawned via the capture command's builtin "find" interface. Available on win32 and unix hosts.
Name of the current font (in xvile/winvile only).
Boolean value indicating search direction.
Boolean value telling whether to ensure that state variables which return a match for a regular expression match (such as $bufname, $identifier, $pathname) or character type ($line, $qidentifier, $word) must include the current editing position "dot".

The default (false) allows vile to search forward until it gets a match which may not necessarily include "dot".

Boolean value telling whether to set state variables which return a match for a regular expression (such as $bufname, $identifier, $pathname) or character type ($line, $qidentifier, $word) to the complete match.

The default (false) behavior in vile matches from the current editing position onward.

This number is set as a side-effect of computing a state variable which is a match for a regular expression (such as $bufname, $identifier, $pathname) or character type ($line, $qidentifier, $word).

The number is the character offset (starting at zero) of the match. It is set to -1 if there is no match.

This number is set as a side-effect of computing a state variable which is a match for a regular expression (such as $bufname, $identifier, $pathname) or character type ($line, $qidentifier, $word).

The number is the character length of the match. It is set to -1 if there is no match.

Filename referred to when help is requested (usually vile.hlp).
With xvile, contains current icon name.
The current "identifier-like" word under the cursor. This is computed from the identifier-expr pattern. Also see the "tagword" mode.
This is the encoding used by the keyboard, which is normally the same as $term-encoding.
[READ ONLY] This is the contents of the keyboard macro buffer.
[READ ONLY] This is vile's "unnamed" yank register, which contains the result of the last line-oriented yank or delete.
[READ ONLY] Character most recently entered at the keyboard.
pattern to match locales using ISO-8859-1 in case they are not installed. Normally vile looks for a narrow locale to correspond with the wide (UTF-8 encoding) locale. If locale data is incomplete, vile can still support ISO-8859-1 encoding, but checks to ensure that the locale is compatible. Some systems lack a full set of locale data. This pattern helps it decide if the (missing) narrow locale would use ISO-8859-1 encoding.
[READ ONLY] The length (in columns) of the current line.
This value will be used to augment the user's PATH environment variable when running filters, so that vile-specific filters needn't clutter general purpose bin directories.
Contains the text of the current line of the current buffer starting with the cursor position.
[READ ONLY] The length (in characters, not columns) of the current line.
[READ ONLY] The character locale, e.g., en_US.
[READ ONLY] Current majormode, if any.
name of the hook to run when attempting to determine the majormode for the current buffer. If this is not defined, vile uses the prefixes and suffixes values to decide.
[READ ONLY] After a successful search, contains the text that matched the search pattern.
The name of the menu file (e.g. .vilemenu)
[READ ONLY] "insert", "command", or "overwrite" mode.
Format of mode lines. See "Mode line customization" in the vile help file.
[READ ONLY] is current buffer modified or not?
Number of displayed colors, must be power of two.
Percent of window filled by ~ chars, at end of buffer.
[READ ONLY] Previous current directory.
[READ ONLY] "Operating system" for which was vile was built. Currently "unix" (if no more-specific name is derived from the configure script), "dos", "os/2", "vms" and "win32".
Length of the vile screen.
Width of the vile screen.
Some versions of vile implement screen coloring. The variable consists of digits which control the current color set, usually one digit per color.
[READ ONLY] current patch-level (empty for release).
separates directory names in lists such as $PATH.
current "path-like" word, under the cursor. This is computed from the pathname-expr pattern. If the current buffer is a directory, use the entire line, overriding the regular expression.
separates levels of directory names in a path. Usually this is '/', for Unix.
[READ ONLY] Boolean which is true when the user has "typed ahead", i.e. there are waiting keystrokes.
[READ ONLY] vile's process-id.
Format of ^G command. See "Mode line customization" in the vile help file.
[READ ONLY] The string "vile", "xvile", or "winvile" as appropriate.
The string ": ", used in command-line prompts.
the name of the current "qualified-identifier-like" word under the cursor, useful for C++ programmers.
Name of procedure to run after a file is read.
The current replacement strings, used in substitutions.
The current search pattern.
The seed for the internal random number generator.
Name of the shell program for spawned commands. For Unix, this corresponds to $SHELL, while DOS, OS/2 and related systems use $COMSPEC.
Current screen size on a DOS PC (meaningless on a Win32 host). Values:
$sres screen size
"2" "25"
"4" "43"
"5" "50"
"6" "60"
Values for VMS:
Other drivers ignore the value.
The name of the startup file (e.g. .vilerc). Normally this is only a filename, but can be an absolute path to override $startup-path.
Where to find the startup file, i.e., a colon-separated list of directories on Unix-like systems. On Windows, use semicolon for separating the items in the list.
[READ ONLY] Boolean representing success of most recent command. Since a failed command will usually cause an entire macro to fail, the ~force directive is often used to suppress a command's failure. $status preserves its exit status.
The default value for dos mode, this is initially determined by the platform: DOS, Windows use dos mode, while other platforms use nodos mode. Because it is common to edit files on Windows from other systems, this variable can be overridden by setting it in a script. To affect the initial files opened when vile first starts, you must use the -u or -U option, since those buffers may be initialized before the initialization script is processed.
[READ ONLY] Shows the generic operating system name.
[READ ONLY] Shows the character encoding which the terminal/display driver can handle. The values are the same as for the file-encoding mode. If it can display UTF-8 (terminfo/termcap) or UTF-16 (winvile), and the terminal is initialized to match, vile shows the corresponding "utf-8" or "utf-16" value.
The current window title (X11, win32 versions only).
Tell whether to send title-change escape sequences to xterm in ISO-8859-1 (8bit) or UTF-8 (utf-8). A "locale" setting is provided, which tells vile to use UTF-8 if the locale encoding uses UTF-8, and ISO-8859-1 otherwise. ISO-8859-1 is standard; some terminal emulators require UTF-8. Even with this, other programs such as GNU screen interfere with setting titles with non-ASCII content.
The format for the window title (X11, win32 versions). If this variable is not set, the title is the program name and the current buffer, separated by a dash, e.g., %{$progname} - %{$cbufname} Use the swap-title mode to control the order of those strings. If $title-format is set, swap-title has no effect. See "Mode line customization" in the vile help file.
[READ ONLY] Contains vile's version string.
[READ ONLY] String which is set by "~with" directive in macros. If no prefix was set, this returns ERROR.
Height of current window.
The "word" at the cursor location. The word is a contiguous sequence of nonblank characters, rather than the vi-style "word".
Name of procedure to run before a file is written
The value to set $DISPLAY when running $xshell.
Name of the terminal program for spawned xvile commands. The default is "xterm", but may also be set by the environment variable $XSHELL.
Command-line flags after $xshell, normally "-e" The $XSHELLFLAGS environment variable determines the default value.

Mode variables

You may set and use the values of the editor modes (i.e., universal modes, buffer-only modes or window-only modes) as if they were state variables (e.g., "setv $errorbells=true"). The global values of the editor modes are not visible to the expression evaluator.

Realistically, this feature is little used, since vile's set/setl commands, as well as the &global/&local functions, serve the same purpose.

Buffer variables

Buffer variables (a '<' followed by a buffer name) return the current line of the specified buffer, automatically setting the position to the next line.

Interactive variables

Interactive variables are not actually "variables" at all — they're really more like functions that return a string, entered by the user in response to a prompt. The prompt is the name of the "variable".

They are so similar to a query function that there is function which serves this exact purpose, and which should be used in preference. Thus, one might have previously written:

set-variable %file @"What file?"

Instead, one should now write:

set-variable %file &query "What file?"


Functions always return strings. Functions can take 0, 1, 2, or 3 arguments. Function names are always preceded by the & character, and can usually be shortened to just three characters, though there is little reason to do so.

Tasks that are usually implemented as "operators" in other languages are implemented as functions in vile's macro language. Thus, for example, arithmetic division which is usually written as "6 / 2" is written as "&div 6 2". (I believe this is sometimes called "prefix" notation, as opposed to the normal operator "infix" notation, or the "postfix" notation used on a stack-oriented calculator, i.e. "6 2 /".)

Depending on the function, arguments may be expected to represent generic strings, numeric values, or logical (boolean) values.

Arithmetic functions —

These all return numeric values:

&add "N1" "N2"
Add "N1" and "N2".
&sub "N1" "N2"
Subtract "N2" from "N1".
&times "N1" "N2"
Multiply "N1" by "N2".
&divide "N1" "N2"
Divide the "N1" by "N2"
&mod "N1" "N2"
Divide the "N1" by "N2", return remainder.
&negate "N"
Return -(N).
&ascii "S"
Return the ASCII code of the first character in "S"
&random "N"
&rnd "N"
Random number between 1 and N
&abs "N"
Absolute value of "N"
&ftime "N"
The modification time of the file "N"
The system time.

String manipulation functions —

These two return numeric values:

&length "S"
Returns length of string "S".
&sindex "S1" "S2"
Returns index of "S2" within "S1", or 0.

The rest return strings:

&bind "S"
Return the function name bound to the key sequence "S".
&cat "S1" "S2"
Concatenate S1 and string "S".
&chr "N"
Converts numeric "N" to an ASCII character.
&cclass "S"
Character class (see "show-printable")
&env "S"
Return the value of the user's environment variable named "S".
(alias for &gtkey).
Prompt for and return name-completion. There are two parameters:
  1. category (any of "command", "buffer", "directory", "filename", "tags")
  2. value to complete, e.g., $identifier, $word or just a string in quotes.
(alias for &gtmotion).
(alias for &gtsequence).
Get a single raw keystroke from the user.
&gtmotion "N"
Get a key sequence from user which must be bound to a motion. The parameter is one of the binding names: If successful, the name of the corresponding motion function is returned.
Get a complete vile key sequence from user.
&left "S" "N"
Extract first "N" characters from "S"
&lower "S"
Return lowercase version of "S".
&right "S" "N"
Extract chars from position "N" onward.
&middle "S" "N1" "N2"
Extract "N2" chars at position "N1".
&upper "S"
Return uppercase version of "S".
&trim "S"
Remove whitespace at either end of "S", reduce multiple spaces within "S" to just one space each.

Boolean/logical functions —

These all return TRUE or FALSE:

&not "B"
Return inverse of boolean "B".
&and "B1" "B2"
Return logical AND of "B1" and "B2".
&or "B1" "B2"
Return logical OR of "B1" and "B2".
&equal "N1" "N2"
Is "N1" numerically equal to "N2"?
&geq "N1" "N2"
Is "N1" numerically not less than "N2"?
&greater "N1" "N2"
Is "N1" numerically greater than "N2"?
&gt "N1" "N2"
(same as &greater)
&isa "C" "N"
Is "N" a member of class "C". Classes include: buffer, color, mode, submode, Majormode.
&leq "N1" "N2"
Is "N1" numerically not greater than "N2"?
&lessthan "N1" "N2"
Is "N1" numerically less than "N2"?
&lt "N1" "N2"
(same as &lessthan)
&neq "N1" "N2"
Is "N1" numerically not equal to "N2"?
&sequal "S1" "S2"
Is "S1" the same string as "S2"?
&sgeq "S1" "S2"
Is "S1" lexically not less than "S2"?
&sgreater "S1" "S2"
Is "S1" lexically greater than "S2"?
&sgt "S1" "S2"
(same as &slessthan)
&sleq "S1" "S2"
Is "S1" lexically not greater than "S2"?
&slessthan "S1" "S2"
Is "S1" lexically less than "S2"?
&slt "S1" "S2"
(same as &slessthan)
&sneq "S1" "S2"
Is "S1" lexically not equal to "S2"?
&readable "S"
&rd "S"
Is the named file "S" readable?
&writable "S"
Is the named file "S" writable?
&execable "S"
Is the named file "S" exec'able?
&bchanged "S"
Is given buffer "S" modified?
&fchanged "S"
Is file for given buffer "S" modified?
&cmatch "R" "V"
Does the given regular expression "R" match the value "V" (ignoring case)?
&error "S"
Was the string set with the ERROR token? For example, a &query that is aborted will return an ERROR result.
&match "R" "V"
Does the given regular expression "R" match the value "V"?
&filter "M"
Does the given majormode have a built-in highlighting filter?
&stoken "T" "D" "S"
Is token "T" in string "S", given delimiters "D"?

Miscellaneous functions —

These all return string values:

&classof "N"
Retrieves the class(es) to which the given name may return. Usually this is a single name, e.g., one of those checked by &isa. If multiple matches are found, the result contains each classname separated by a space.
&default "MODENAME"
Retrieves initial/default value for the given mode or state variable.
&global "MODENAME"
Retrieves universal/global mode setting.
&indirect "S"
Evaluate value of "S" as a macro language variable itself. Thus if %foo has value "HOME", then

&env &indirect %foo

will return the home directory pathname.

&local "MODENAME"
Retrieves local mode setting (for current buffer).
&lookup "N" "P"
The "N" keyword tells which field to use looking for the file "P":

bin – look in vile's directory
current – look in the current directory
home – look in user's $HOME directory
libdir – look along $libdir-path
path – look along user's $PATH
startup – look along $startup-path

as well as associated access tests:

execable - test if file is exec'able
readable - test if file is readable
writable - test if file is writable

The search order is fixed: current, home, bin, startup, path, libdir. Note that the directory lists may overlap.

&mclass "M"
Retrieve the class to which the given mode belongs. This is different from &mclass since it distinguishes the modes Return values include: universal buffer window submode Majormode.
&qpasswd "S"
Present "S" to the user and return their response. Each typed character is echoed as '*'. The response is not recallable via the editor's history mechanism.
&query "S"
Present "S" to the user, and return their typed response.
&date "F" "T"
If strftime() is found, format the time "T" using the "F" format. Otherwise, use ctime() to format the time. Times are numbers (see &ftime and &stime).
&dquery "S" "D"
Present "S" to the user, and return their typed response. If "D" is given, use that as the default response. Otherwise use the previous response as the default.
&path "N" "P"
The "N" keyword tells which field to extract from the pathname "P":

end – suffix of the filename
full – absolute path
head – directory
root – filename without suffix
short – relative path
tail – filename

&pcat "D" "F"
Concatenate directory and filename, handing syntax and ensuring that if the filename is absolute, that the directory is ignored.
&pquote "P"
Quote the pathname if it contains characters such as space that cannot be passed to the shell without special handling.
&register "S"
Return contents of register "S". Only the first character of "S" is used for the name. Note that the contents may be more than one line.
&token "N" "D" "S"
Select N'th token of string "S", given delimiters "D".
&translate "F" "T" "S"
Translate from "F" to "T" each character of string "S". The "F" and "T" are strings of equal length; characters from "S" found in "F" are translated to the character in "T" at the same index.
&word "N" "S"
Select N'th word of string "S", blank separated.


The macro language has the capability for controlling flow and repetition through conditional, branching, and looping instructions. Complex text processing or user input tasks can be constructed in this way. The keywords that introduce this control are called "directives". They are always prefixed with the ~ character, and they are always in all lowercase.


The "store-procedure" and "store-macro" commands both indicate the start of the body of a macro routine. ~endm indicates the end of that routine.


To prevent a failed command from terminating the macro which invokes it, the ~force directive can be used to "hide" a bad return code. For instance, the "up-line" command might fail if executed at the top of a buffer. "~force up-line" will suppress the failure. The $status variable can be used to determine whether the command succeeded or not.


You can suppress not only the check for success or failure of a macro as in ~force, but also the screen refresh, making macros run more rapidly. For example

30 store-macro
    write-message "[Attaching C/C++ attributes...]"
    ~local $curcol $curline
    ~hidden goto-beginning-of-file
    ~hidden attribute-from-filter end-of-file "vile-c-filt"
    write-message "[Attaching C/C++ attributes...done ]"
bind-key execute-macro-30 ^X-q

causes the screen updates from moving the current position to the beginning of the file and then filtering (which moves the position to the end-of-file) to be suppressed. The screen will be updated after completion of the macro, after the current position has been restored from the values saved with the ~local directive.


Rather than suppress all screen updates, you may suppress any messages that are written as the command progresses.

~if, ~elseif, ~else, and ~endif

These control execution of macro commands in the expected manner. The ~if directive is followed by a string which is evaluated for truth or falsehood according to the rules outlines for boolean variables, above. The following fragment demonstrates the use of this family of directives:

; test for '#'
~if &equ $char 35
    set-variable %comment-type "shell comment"
; test for ';'
~elseif &equ $char 59
    set-variable %comment-type "vile macro language comment"
    write-message "Not an expected comment type"
write-message &cat "The current line is a " %comment-type


What would a decent programming language be without a "goto"? The ~goto directive is followed by the name of a label. Labels may appear anywhere in the current macro definition, and are themselves preceded with a * character.

    ~force up-line
    if &not $status
      ~goto foundtop

    write-message "At top of buffer"

~while and ~endwhile

The block of statements bracketed by ~while and ~endwhile are executed repeatedly, until the condition being tested by ~while becomes false.

; how many occurrences of a given pattern in a buffer?
set nowrapscan
set-variable %lookfor somepattern
; we'll count one too many
set-variable %howmany "-1"

set-variable %continue yes
~while %continue
    ~force search-forward %lookfor
    set-variable %continue $status
    set-variable %howmany &add %howmany "1"

write-message &cat &cat %howmany " appearances of " %lookfor


The ~break directive allows early termination of an enclosing while-loop. Extending the above example:

; count the occurrences of a pattern in all buffers
set nowrapscan
set noautobuffer

set-variable %lookfor pgf
set-variable %howmany "0"
set-variable %buffers "1"
set-variable %cont yes

~while true
    ~while true
        ~force search-forward %lookfor
        ~if &not $status
        set-variable %howmany &add %howmany "1"
    ~force next-buffer
    ~if &not $status
    set-variable %buffers &add %buffers "1"

set-variable %msg  %lookfor
set-variable %msg  &cat " appeared "
set-variable %msg  &cat %howmany
set-variable %msg  &cat %msg " times in "
set-variable %msg  &cat %msg %buffers
set-variable %msg  &cat %msg " buffers."
write-message %msg


This causes immediate exit of the current macro, back to the calling macro, or to user control, as appropriate.


The ~local directive causes the variables which are listed to be saved at that point (once if the directive is within a loop), and automatically restored at the end of the current macro. If the directive specifies a temporary variable which was not defined before, it will be deleted rather than restored.

For example:

~local $curcol $curline

will restore the cursor position. The order is important in this example, because vile restores the variables in the reverse order of the ~local declaration. If $curline is set, $curcol will be reset to the first column as a side effect. So we specify that $curcol is restored last.

~local can save/restore the state of mode variables [1], user variables and the state variables shown with show-variables. Note that setting certain variables, such as the cursor position, will have side effects, i.e., modifying the display. If these are distracting, use ~hidden or ~quiet to suppress display updates until the macro completes.

[1] Subject to the limitations described above for "Mode variables". Namely, "global values of the editor modes are not visible to the expression evaluator."

~with, ~elsewith and ~endwith

Tokens following the ~with directive will be prepended to succeeding lines of macro until the next ~endwith directive, or the end of the current macro. This is useful for simplifying majormode directives, which are repetitive. Use ~elsewith as a convenience for fences; otherwise it functions just as ~with does.

For example, use

define-mode txt
~with define-submode txt
        suf "\\.txt$"
        comment-prefix "^\\s*/\\?--"
        comments "^\\s*/\\?--\\s+/\\?\\s*$"

rather than

define-mode txt
define-submode txt suf "\\.txt$"
define-submode txt comment-prefix "^\\s*/\\?--"
define-submode txt comments "^\\s*/\\?--\\s+/\\?\\s*$"


No program is complete without a few bugs. Use vile's builtin macro tracing to see what the macros really do. The ~trace command sets the $debug variable, which controls whether vile appends to the [Trace] buffer a copy of each line executed, the local variables saved/restored and intermediate states of expression evaluation.

For example,

~trace on

activates tracing,

~trace off

deactivates it, and


prints a message telling if tracing is active.

Editor commands

The "show-commands" command lists _all_ available editor commands. This is, admittedly, a large list and generally grows with successive releases of the editor. Fortunately, most editor commands include short help strings that describe their purpose. To winnow the list to a particular area of interest, use the "apropos" command (e.g., "apropos append"). To determine the command bound to a specific key, use "describe-key". The format of the apropos, describe-key, and show-commands listing is as follows:

command-name             optional-key-binding(s)

Commands fall into three broad categories: simple, motion, operator.

Simple commands

A simple command neither acts on a region nor does it explicitly move the cursor through a region (the "region" concept is explained in the "Motion commands" section below). An example of a simple command is "find-tag", and here's the listing returned by show-commands:
"find-tag"               ^]
  or            "ta"
  or            "tag"
  ( look up the given (or under-cursor) name as a "tag" )

From the perspective of writing a macro, it can be seen that find-tag has two aliases, either of which may be substituted for the "find-tag" name within a macro definition. Notice that the help string mentions a "name" argument and sure enough, if you type ":find-tag" within the editor, you'll be prompted for a "Tag name". This gives us enough information to write a contrived macro that finds a fixed tag name:

store-procedure tryit
        tag "filterregion"

Note also that some help strings include a "CNT" keyword, which indicates that the command name may be preceded by an integer count that repeats the command action that many times (default CNT value is 1). For example, here's the "join-lines" listing:

        "join-lines"     J
          ( join CNT lines together with the current one )
And here's a macro that joins 4 lines:

store-procedure join4
        4 join-lines

Motion commands

Motions move the cursor and, consequently, may be used to define a region. This latter property is an important aspect of an "operator command". The "show-motions" command lists the editor's motion commands.

Within a macro, the following general syntax invokes a motion:

[count] region-spec

The optional "count" specifies the number of affected region-specs (default value is 1). An example motion is "back-line", and here is its show-commands listing:

"back-line"              k         #-A
  or    "previous-line"
  or    "up-arrow"
  or    "up-line"
  (motion: move up CNT lines )

Note that the help string is prefixed with the word "motion", which unambiguously identifies the nature of this command. Given the above information, we can write a contrived macro to move the cursor up three lines:

store-procedure upthree
        3 back-line

Operator commands

Operators manipulate regions. The "show-operators" command lists the editor's operator commands. By convention, most operator names end with "-til" (short for "until").

Within a macro, the following general syntax invokes an operator:

[count] operator-name region-spec [args...]


may be replaced with any motion command or the special word "lines" (the latter is a synonym for a single buffer line).
optionally specifies the number of region-specs affected by operator-name (default value is 1).
denotes optional string arguments(s) required by some operators (e.g., "filter-til").
An example operator is "flip-til", and here's its show-commands info:
"flip-til"               ^A-~
  or    "~"
  (operator:  exchange upper and lowercase on characters in the
  region) (may follow global command)

A salient point to note within the help string is the "operator" keyword, which unambiguously identifies the purpose of this command. Given the above information, we can write a macro to flip the case of the current paragraph.

store-procedure flippara
        up-paragraph            ; move to beginning of para
        flip-til down-paragraph ; flip case of entire para

One might be tempted to bind this macro to a key using this syntax:

bind-key flippara g

and then attempt to use a numerical argument to control the number of affected paragraphs. I.E., type "3g" to flip three paragraphs. But this actually invokes "flippara" three times in a row, which (due to the sequential up- and down-paragraph motions), flips the case of the _same_ paragraph three times. However, we can workaround that obstacle with the use of an interactive variable:

store-procedure flippara
    setv %dflt 1
    setv %quest @&cat &cat "Flip how many para [" %dflt "]? "
    ~if &sequal %quest ""
            setv %quest %dflt
    %quest flip-til down-paragraph

Debugging macros

vile's popup-msgs mode pops up the [Messages] buffer to show text written to the message line. Closing the [Messages] buffer window clears its content until the next message is written. This mode is most useful when debugging macros, since many messages may appear, each overwriting a previous one.

Let's use this macro fragment for illustration:

~if &greater $blines 0
        ; buffer has at least one line of data, proceed
        ; this is unexpected!

Suppose the macro is taking the unexpected code path in one of several buffers, but you don't know which. To trace the path, modify the macro like so:

~if &greater $blines 0
        ; buffer has at least one line of data, proceed
        ; this is unexpected!
        setv %msg &cat "Error: Buffer " &cat $cbufname " empty"
        write-message %msg

Next, enable popup-msgs (i.e., set popup-msgs) and then start the macro. When the "write-message" command is executed, the [Messages] buffer pops up and displays the string written by the unexpected code path.

Disable popup-msgs using this command:

:set nopopup-msgs

Example startup file

The startup file included below illustrates several of the language constructs described in this document. This example is crafted for the win32 environment, but its syntax and usage are applicable to any host OS supported by vile.

set ai aw ts=4 sw=4 flash
bind-key next-window ^N
bind-key previous-window ^P
~if &sequal $progname "winvile"
    set-variable $font "r_ansi,8"
~if &equal 0 &sindex &lower $shell ""
    set w32pipes
    set now32pipes
~if &not &equal 0 &sindex $cfgopts "perl"
    perl "use hgrep"
    perl "use dirlist"
~if &not &equal 0 &sindex $cfgopts "oleauto"
    set redirect-keys=&cat &global redirect-keys ",MULTIPLY:A:S"
; modify ^A-i and ^A-o so that they don't wrap inserted text.
store-procedure save-wrap-state
    setv %wm=$wrapmargin
    setv %ww=$wrapwords
    setl nowrapwords wm=0
store-procedure restore-wrap-state
    setl wrapmargin=%wm
    ~if %ww
        setl wrapwords
        setl nowrapwords
store-procedure insert-chars-noai-nowrap
bind-key insert-chars-noai-nowrap ^A-i
store-procedure open-line-below-noai-nowrap
bind-key open-line-below-noai-nowrap ^A-o
;Rather than composing documents in a word processor, it's much
;more efficient to use vile.  But pasting vile-formatted text into,
;say, MS Word is a pain in the neck because each paragraph needs
;to be reformatted.  Example:
;      vile txt
;      ========
;      para 1 line1,
;      line 2,
;      line 3,
;      line 4
;      para 2 line 1,
;      line 2,
;      line 3,
;      line 4
;If "vile txt" is copied and pasted into Word, it looks awful because
;the lines of the paragraphs do not flow together (i.e., the new lines
;terminating each vile paragraph serve as a "hard" paragraph break).
;'Twould be nice if vile could join each paragraph so that "vile txt"
;above looked like this:
;      vile txt
;      ========
;      para 1 line1, line 2, line 3, line 4
;      para 2 line 1, line 2, line 3, line 4
;Then, when this version is pasted into Word, all paragraphs are
;automatically reformatted.  Here's a macro that adds this feature:
store-procedure join-all-para
    write-message "[joining all paragraphs...]"
    ~while true
        ~force join-lines-til down-paragraph
        ~if &not $status
        ~force 2 down-line ;skip to next para
        ~if &not $status


This document, and the macro language it describes, owes a debt of thanks to Dan Lawrence and his MicroEMACS text editor. Many of the features described herein first appeared in this form in MicroEMACS.