LaTeX - WinEdt Hacker's Guide PDF
LaTeX - WinEdt Hacker's Guide PDF
LaTeX - WinEdt Hacker's Guide PDF
Jason Alexander
Colin Marquardt
1 Macros 5
1.1 Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.2 Variables/Registers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.2.1 Strings and things . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.2.2 Setting the values of registers . . . . . . . . . . . . . . . . . . . . . . 14
1.3 Procedures and Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.4 Recursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
1.4.1 A lengthy example . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.5 Interactive Macros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
1.5.1 Getting data from the user . . . . . . . . . . . . . . . . . . . . . . . . 25
1.6 Appendix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2 Syntax Highlighting 29
2.1 Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.1.1 Filter Sets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.1.2 Switches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.1.3 Reserved Words . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.2 Filter Sets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.2.1 The “Filter Sets” Dialog . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.2.2 Set Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.3 Switches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
2.3.1 Global Switches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.3.2 The “Switches” Dialog . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.3.3 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
2.4 Reserved Words . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
2.4.1 The “Reserved Words” Dialog . . . . . . . . . . . . . . . . . . . . . . 38
2.4.2 A small example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
3
4 CONTENTS
Chapter 1
Macros
If your reading this on the first time through, didn’t you pay attention to the warning in previous
paragraph? :-) I’ll let it go this time, but you should really try to avoid sections like these in the
future until you have experience with WinEdt’s macro language.
Sections which one might want to defer reading until the second or third time are marked
with two dangerous bend signs. Whenever possible, macro examples will be given following
the “two-column” format employed in The LATEX Companion by Goossens, Mittelbach, and
Samarin. The actual WinEdt macro code usually appears on the left-hand side with the
corresponding WinEdt output appear on the right. For example,
InsText("WinEdt's language");
WinEdt's language
NewLine;
...is powerful.
InsText("...is powerful.");
5
6 CHAPTER 1. MACROS
1.1 Basics
The simplest macros in WinEdt’s library insert text or additional lines into the current
document.
Ins("String to insert");
Inserts a specified string (or the contents of a string register, e.g. “%!9”) using the current wrapping
settings.
InsText("String to insert");
Same as Ins except WinEdt will not wrap the inserted string if it goes beyond the right margin.
NewLine;
Inserts a new line at the current position.
InsLine;
Inserts a new line at the current position if and only if the current line is not empty. Used judiciously,
this macro can prevent multiple blank lines from appearing in a document.
If you want to insert several copies of the same thing, use Repeat(n, "...") — where
n is a number (or a register containing a numeric value) and the string parameter contains
the argument to be repeated. The next example demonstrates how to insert multiple line
breaks into a document using Repeat and NewLine:
From alpha...
Ins("From alpha...");
Repeat(2, "NewLine");
Ins("...to omega.");
...to omega
Repeat also provides a way to move the cursor to a new position in the document when you
know the offset from the current position. E.g.,
Repeat(20, CMD("Char Left"));
Repeat(5, CMD("Line Down"));
moves the cursor twenty characters left and five lines down from the current position. (Luck-
ily, more efficient ways of moving the cursor exist since traveling long distances via Repeat
takes time.)
One important caveat about Repeat (which actually applies to many macros in WinEdt’s
library) concerns using Repeat with macros that take string arguments. Since the second
1.1. BASICS 7
argument of Repeat is itself a string, if you attempt to repeat a command that takes a string
argument, you must take care to correctly nest the strings. One correct use of Repeat to
insert ten copies of the letter a into the document is the following:
Repeat(10, "Ins('a')"); aaaaaaaaaa
Repeat(10, 'Ins("a")')
Repeat(10, 'Ins(''a'')')
Repeat(10, "Ins(""a"")").
It really doesn’t matter which convention you adopt, so long as you understand it and can
work with it. See §1.2.1 for a greater discussion of this topic.
Nothing keeps you from putting a lengthy sequence of macros in the second argument of Repeat:
any valid macro sequence can appear in this second argument, including additional uses of Repeat.
This allows one to write macros that perform a certain action a fixed number of times. Notice the word
fixed occurring in that last sentence. Because the first argument of Repeat is a numeric constant specifying
how many times the second argument ought to be repeated, you must always know at the time of writing
how many times the action must be repeated. More complicated macros, requiring an action to be repeated
until some condition occurs (where it is not know ahead of time how many times the action will need to be
repeated) should use the more powerful Loop macro.
Since we’ve already talked about moving the cursor around the screen, we might as
well mention a few more ways to do it. If you just want to automate the kinds of cursor
movements that you can do with the keyboard—i.e., move around the screen, or scroll a
bit—you’ll be happy to know that these operations get handled via the flexible CMD macro.
CMD("Char Left");
Move the cursor one character to the left.
CMD("Char Right");
Move the cursor one character to the right.
CMD("Line Up");
Move the cursor up one line.
CMD("Line Down");
Move the cursor down one line.
CMD("Page Up");
Move the cursor up one page.
CMD("Page Down");
Move the cursor down one page.
The CMD macro provides access to many, many more commands than listed here. Think of
CMD as the macro equivalent of a Swiss-army knife: over 170 different things can be done
with CMD (admittedly, not all of them are ones that you will use frequently, if at all). Using
8 CHAPTER 1. MACROS
CMD is a simple two-step process: (1) look up the name of the desired command in WinEdt’s
on-line documentation, (2) call CMD, giving it the name of the command in quotation marks
as above.
Basically, CMD invokes commands that are essential to WinEdt’s behavior — like cursor movements,
screen refreshes, inserting bullets, setting bookmarks, and so on. One can also invoke all the dialog
boxes used to customize WinEdt’s behavior, e.g., CMD("Preferences..."). Notice that there is some overlap
with the Menu macro here, since both Menu and CMD can be used to bring up the Preferences dialog box. The
need for two different macros, though, stems from the degree to which WinEdt allows customization of its
menus. For example, one could delete the Preferences. . . choice from the Options menu, making it impossible
to invoke the Preferences dialog box with the Menu macro. However, the Preferences dialog box will always
be available via the CMD macro.
The real power of WinEdt’s macro language doesn’t begin to emerge until we consider
macros capable of conditional behavior — taking different actions depending upon the cur-
rent state of some parameter. But this means that WinEdt must allow for certain parameters
to vary over time. It’s time to consider variables or registers.
1.2 Variables/Registers
The WinEdt documentation uses the terms ‘variable’ and ‘register’ interchangeably, so let’s first
note the difference between the two terms, as traditionally understood, and then see where WinEdt’s
macro language falls. Most (if not all) programming languages allow you to declare variables with names
descriptive of their contents, like mass, number_of_loops, and so on. When you declare a variable, a chunk
of memory gets allocated for storing a certain type of data.1 The important point being that variables have
names. A register, on the other hand, can’t be given a special name: it’s a chunk of storage that you have
to refer to by whatever name the designer gave it.
So what does WinEdt have? WinEdt has registers—so you can’t give them custom names—but WinEdt’s
registers are more flexible than variables in languages like C. WinEdt will automatically allocate memory on
an as-need basis for each of its registers—you don’t have to worry about that at all (if you were the sort of
person who would worry about it in the first place). If you want, you can copy several pages of a document
into a register that was previously used to hold a number, and WinEdt won’t complain. So even if you don’t
like not being able to declare named variables to make your macros easier to understand, WinEdt’s registers
can be quite powerful.
We can distinguish between four different types of registers: local, global, editor and
document. There are eleven local registers, eleven global registers, and numerous document
and editor registers. Luckily, though, one can usually identify the type of a register by
looking at its name alone (though there are some exceptions). Identifying registers is easy:
all WinEdt registers have a %-sign in front of them.
Both editor and document registers consist of a single letter, upper or lower. The dif-
ference between these types of registers is primarily semantic rather than syntactic: editor
registers contain values specifying the current state of WinEdt (current line position, column
position, and so forth) and document registers contain values identifying properties of the
1
With some exceptions. C’s union type allows you to store different types of data in the same (approxi-
mately) chunk of memory.
1.2. VARIABLES/REGISTERS 9
active file type, file name, path, etc.). One cannot directly change the value of a document
register, but macro functions exist for changing the value of editor registers.
For example, %n, %p, and %t are all document registers; %n contains the name of the
active file (the file currently having focus in the editor), %p contains the path of the active
file, and %t contains the extension of the current file. So, if the active file is:
2+3
((2+3)/16)
10 CHAPTER 1. MACROS
%!1+%!2
((%!1*%!2)/12)*(-17/%!3)
Correct:
"this is a 'string' inside a String"
'this is a "string" inside a String'
"this is a ""string"" inside a String"
'this is a ''string'' inside a String'
Incorrect:
'this is NOT a 'string' inside a String'
"this is NOT a "string" inside a String"
Although 1.3 used LetRegNum three times, that wasn’t necessary. You might have a complicated
integer expression that you want to evaluate several times, allowing the values stored in the registers
appearing within that expression to change between evaluations. Using LetRegNum like we did above will
2
Until you start working with nested strings. Then things become considerably more complicated even
though the rules stay the same. Working with registers and percent signs inside nested strings will be dealt
with in a later section, but see 1.4 and 1.5 for a taste of what will come.
1.2. VARIABLES/REGISTERS 11
give you headaches, since LetRegNum immediately evaluates its second argument to obtain an integer value
for the assignment.
The way around this problem is to store the complicated integer expression in a local register as a
string. This allows one to suppress expansion of the named registers until you actually want to evaluate the
expression. Here’s an example:
1 BeginGroup;
2 LetReg(1,'((100*%%!2)+(10*%%!3)+(%%!2*%%!3)');
3 LetRegNum(2,0);
4 LetRegNum(3,0);
5 Loop('>
6 Loop(">
7 LetRegNum(4, ''%%!1'');>
8 InsText(''%%%%%%%%!2 = %%%%!2, %%%%%%%%!3 = %%%%!3, %%%%%%%%!4 = %%%%!4'');>
9 NewLine;>
10 LetRegNum(3, %%%%!3+1);>
11 IfNum(%%%%!3,3,''='',''Stop'','''');>
12 ");>
13 LetRegNum(2, %%!2+1);>
14 LetRegNum(3,0);>
15 IfNum(%%!2,3,"=","Stop","");>
16 ');
17 EndGroup;
18 End;
How? First, the integer expression ((100*%!2)+(10*%!3)+(%!2*%!3) gets stored in %!1 (note the use of
double parentheses to suppress expansion). Then %!2 and %!3 are initialized to 0. We then enter a doubly-
nested loop. We take advantage of some expansion trickery in the first line of the double loop. Here,
LetRegNum is at level 2 since it appears in a string inside a string; if we wanted to suppress expansion of %!1,
we would have to use at least four percent signs %%%%!1 to raise that occurrence of that register to level 3
(or higher). However, we don’t want to suppress expansion since we want to use the contents of %!1 — the
complicated integer expression — when assigning a value to %!4. Thus %%!1 gets expanded before WinEdt
begins processing the LetRegNum call. When WinEdt begins processing the LetRegNum call, it first expands
the second argument of this macro — the complicated integer expression we want to use! Thus, %!4 gets
assigned the value 0 the first time through the double loop, since both %!2 and %!3 equal 0.
String arguments can be explicitly specified — e.g., "This is a string" — or they can
use registers (local or global) whose contents “make sense” when expanded. Make sense?
Here’s what I mean. Consider the macro InsText. It takes a single string argument and
inserts it at the current cursor position. Clearly any string you specify makes sense here,
for WinEdt will expand all registers present in the string and then insert the expanded
12 CHAPTER 1. MACROS
string into the document. However, consider the macro Loop. Here, the only strings which
make sense are those which expand into a sequence of macros WinEdt can execute. Giving
"This is a string" as an argument to InsText won’t result in an error, but giving it as
an argument to Loop will cause WinEdt to complain.
Defining the notion of a string “making sense” more precisely would require that we introduce the
notion of a valid string, where the validity of a string depends upon the macro we are speaking of.
(Exercise: prove that no string is valid for every macro.) I leave this to the hands of those more capable at
theoretical computer science than myself.
New users often find the way WinEdt handles string arguments one of the more puzzling
aspects of WinEdt’s macro language. Here’s an example:
LetReg(1, "This is some text.");
This is some text
Ins("%!1");
LetReg takes two arguments, a numeric argument telling which one of the local registers
(%!0,. . . ,%!9) to set and a string argument containing the soon-to-be value of the register.
registers can also be used in places where WinEdt expects a numeric argument and, by using registers
with the Do macro, one can use registers to access string registers. The following example shows
how to exploit this primitive type of pointer.
1 BeginGroup;
2 LetRegNum(0,4);
3 LetRegNum(1,5);
4 LetRegNum(2,6);
5 LetRegNum(3,7);
6 LetReg(%!0, "Jellical cats come out tonight,");
7 LetReg(%!1, "Jellical cats come one, come all,");
8 LetReg(%!2, "The Jellical moon is shining bright,"); %!4: Jellical cats come out tonight,
9 LetReg(%!3, "Jellicals come to the Jellical ball."); %!5: Jellical cats come one, come all,
10 LetRegNum(8,4); %!6: The Jellical moon is shining bright,
11 Loop("InsText('Reg. #%%!8: ');> %!7: Jellicals come to the Jellical ball.
12 Do('InsText(""%%%%!%%!8"");>
13 NewLine;>
14 ');>
15 LetRegNum(8,%%!8+1);>
16 IfNum(%%!8, 7, '>', 'Stop','');>
17 ");
18 EndGroup;
When the parameter gets expanded, all registers at the bottom level (i.e., registers that
aren’t suppressed) get replaced by their values, and every register of a higher level gets its
level lowered by one. When WinEdt processes the macro Ins("%!1"), WinEdt replaces the
register %!1 by its value because it occurs at the bottom level. WinEdt then inserts the
translated expression into the document.
Strictly speaking, WinEdt doesn’t keep track of levels at all; as far as WinEdt is concerned, all it
works with are strings (or nested strings) and registers. My reason for introducing the concept of a
level of a register is to make it easier to keep track of how many %-signs are needed at any given point.
If you prefer not to think in terms of levels, here’s how WinEdt actually handles strings and registers
inside nested strings. %!1 is the name of a string register and gets replaced by its contents whenever WinEdt
expands %!1. WinEdt also expands %% to a single percent sign: %. If you write a macro that has a register
appearing inside a nested string, you can control when that register gets replaced by its value by the number
of percent signs you stick in front of it.
Consider the following macro:
This macro is a convoluted way of inserting three copies of "The best of all possible strings" into
the document (with line breaks appearing between each copy). However, it illustrates how WinEdt expands
strings.
When WinEdt begins executing this macro, it begins on the first line with LetReg. WinEdt takes the
string argument, expands it, and assigns the expanded string to register %!1. Since there were no regis-
ter expressions occurring in the string argument, %!1 now contains The best of all possible strings.
WinEdt then processes the second line and assigns %!2 the numeric value 1.
When WinEdt begins to process the third line, it first concatenates all the lines ending with > (this
allows us to use line breaks to increase the readability of macros, since, technically, all WinEdt macros must
lie on a single line). Once that has been done, WinEdt checks to see whether %!2 equals 1 or not. Since it
does, WinEdt will execute the fourth argument of IfNum.
Before WinEdt executes this fourth argument, it expands the string. After expansion, WinEdt faces the
sequence of macros:
Notice how the four %-signs was reduced to two. Why? As WinEdt expanded the fourth argument of IfNum,
it encountered the expression %% which it replaced by %. WinEdt then found another occurrence of the
expression %% which also was replaced by %%. WinEdt left !1 alone since this was not part of any register.
(WinEdt also adjusts the quotation marks so that the strings are nested correctly.)
WinEdt then executes the Repeat macro. In doing so, WinEdt first expands the second argument of
Repeat. The sequence of commands after expansion is:
InsText("%!1"); NewLine;
which gets repeated three times. As WinEdt executes the InsText macro, it first expands the string argu-
ment. In the process of expansion, WinEdt finally finds an occurrence of the register %!1 and replaces it by
the text The best of all possible strings which WinEdt finally inserts into the document.
14 CHAPTER 1. MACROS
One might want to suppress WinEdt’s automatic replacement of registers (this happens most fre-
quently when writing complicated macros containing nested loops). WinEdt provides two ways to
suppress register replacement: (1) doubling the number of %-signs at the register’s name raises its level by
one (thus delaying its replacement), or (2) adding a ! before the string parameter prevents the entire string
from being translated, effectively raising the level of every register inside the string by one.
Suppressing translation of the entire string can be used to eliminate the need to include horribly long
streams of parenthesis in deeply nested macros, but it doesn’t provide the same level of control that method
(1) has.
Do not attempt to place an expression spanning multiple lines inside any global
string register. Since the values of these registers are stored permanently in your
WinEdt.ini file, this file can become corrupted if one assigns multi-line values to
the global string registers.
This restriction does not usually present a problem since one rarely is tempted to use a global
register. And, in the cases where one does need a global register, there is either no need
to use multi-line values, or this limitation can be easily circumvented. See §?? for further
discussion.
WinEdt provides several ways to modify the values of the local string registers. Modifi-
cations which do not require any input from the user can be done using LetReg (assigning
string values to local registers) or LetRegNum (assigning numerical values to a local register).
WinEdt also provides a way to write interactive macros that collect input from the user, but
discussion of these macro methods won’t appear until §1.5.
LetRegNum(StrRegister: 0..9, Num_Expression: -999999999..999999999);
This function can be used to assign the result of a numeric expression to the string Register (eg. %!0).
1.2. VARIABLES/REGISTERS 15
If you really want to fly in the face of danger, you can assign values to the global regis-
ters (but do heed the above warning) via LetStr—the global register equivalent of LetReg.
LetStr assumes you know what you’re doing when you make assignments and it will not
check to see if you attempt to assign a multi-line value to a global register. As said before,
unless you are careful this is a really easy way to irreversibly damage your WinEdt.ini file.
LetStr(StrRegister: 0..9, "Value");
Assigns the specified value to the Global String Register (eg. %0).
WinEdt provides another way to set the value of local string registers which often comes in handy.
GetSel copies the currently selected block of text into the specified string register, if the active file
has selected text. If no text is selected, the behavior of GetSel depends on the value of its first parameter: if
0, the specified string register receives the empty string; if 1, the specified string register receives the entire
document. Obviously, one should exercise caution when using the latter case: you probably don’t want to
select the entire document if the next command is CMD('Delete') or CMD('Sort Lines...')!
Occasionally, the need arises to check the character to the immediate left or right of the cursor, performing
some conditional action based on what you find there. GetSel provides a way to do this. Note, though, that
this technique should only be used for isolated tests; using this technique inside a loop can cause the macro
to run slowly because CMD('Select Char Left') and CMD('Select Char Right') do not execute quickly.
The following macro demonstrates how to use GetSel in this way. Can you guess what this macro might be
useful for?
1 CMD('Backspace');
2 CMD('Select Char Left');
3 GetSel(0,9);
4 CMD('Char Right');
5 IfStr('%!9',' ','=','InsText("‘‘");End','');
6 IfStr('%!9','.','=','InsText("''''");End','');
7 IfStr('%!9',',','=','InsText("''''");End','');
8 IfStr('%!9','!','=','InsText("''''");End','');
9 IfStr('%!9','?','=','InsText("''''");End','InsText(''"'')');
Let’s walk through this macro to see what, exactly, it does. First of all, line 1 shows I lied when I said
the macro checks the character to the left of the cursor; the macro begins by deleting the character to the
left of the cursor. Once that’s done, lines 2–4 copy the character to the left of the cursor into register %!9
and then move right. (We need to move right in line 4 because the command in line 2 causes the cursor to
move one character to the left. If we did not move right one character, the text inserted in lines 5–9 would
appear in the wrong place.)
Lines 5–9 demonstrate one way of performing a multiple-way branch—that is, a conditional operation
like C’s switch statement or TEX’s \ifcase. Since WinEdt doesn’t have command providing a multiple-way
branch outright, we need to manufacture one by using multiple If... statements. Simply use one If...
test for each possible branch, where each If... test (they need not all be the same) has an empty else-
clause. If you want to specify a default branch, that is, a sequence of commands to be executed when none
of your explicit If... tests succeed (always a good idea), put this sequence of commands in the else-clause
of the last If... test. The above macro uses this construction: notice the use of End; to terminate macro
execution after a successful IfStr test and how the IfStrs of lines 5–8 all have empty else-clauses.
16 CHAPTER 1. MACROS
Lines 5–9 check the character in register %!9 to see whether it’s a space, period, comma, exclamation
point, question mark, or other (that’s the default case). If it’s a space, WinEdt inserts ‘‘ into the text at
the current cursor position. If it’s one of the four punctuation symbols, WinEdt inserts '' into the text. In
all other cases, a single " gets inserted. Note how four '-marks were needed in lines 6–9 to get two '-marks
in the text.
When would such a macro be needed? Consider what would happen if " were made an active string
with this macro bound to it. Then whenever a " was typed, WinEdt would replacing the " with one of three
possibilities depending upon the character preceding the ". In other words, this macro would create “smart
quote” behavior inside WinEdt, similar to that available in Emacs or word processors like Microsoft Word.
Macro 1.6 runs slowly, so slowly it might frustrate some users. If you need to write macros that test
surrounding text in order to decide what type of action to take, a faster way needs to be found. The
author has found that, when speed is of the essence, avoiding CMD("Select Char Left") entirely gives the
best results.
Using CMD("Select Char Left") (or its sister command CMD("Select Char Right")) slows macro
execution down because they use Windows messaging commands to perform the indicated actions—internally,
essentially the same sorts of procedures as if you move the cursor into position, held the Shift key down,
and then moved either left or right. I.e., a Windows message is generated, sent through the message loop,
dispatched, and processed.
All that involves unnecessary computational overhead. This overhead can be avoided by using GotoCol,
GotoLin, or GotoCL to move the cursor into the correct position, SetSel(0) to first deselect everything,
and then SetSel(1) (some other nonzero number may also be used) to begin the selection process. At this
point, using GotoCol, etc. moves the cursor to the specified position, selecting all the text in between the
cursor position when SetSel(1) was called at the new position. At this point, GetSel may be used to copy
the selected text into the desired register.
Macro 1.6, rewritten using these techniques, will then look like:
1 CMD('Backspace');
2 Mark(0);
3 IfNum('%c',1,'=','InsText("‘‘");End','');
4 SetSel(1);
5 GotoCol('(%c-1)');
6 GetSel(0,9);
7 SetSel(0);
8 Goto(0);
9 IfStr('%!9',' ','=','InsText("‘‘");End','');
10 IfStr('%!9','.','=','InsText("''''");End','');
11 IfStr('%!9',',','=','InsText("''''");End','');
12 IfStr('%!9','!','=','InsText("''''");End','');
13 IfStr('%!9','?','=','InsText("''''");End',>
14 'InsText(''"'')');
15 End;
After deleting the undesired " character in line 1, the cursor is correctly positioned for inserting the desired
character(s) (either ‘‘ or '' or "). However, selecting the text requires that we move the cursor to the
right by one, once the text has been selected. The use of Mark(0) in line 2, following by Goto(0) in line
8, performs these needed movements. If you try both forms of the macro on a fast (but not blazingly so)
computer, you may detect the speed difference between the two versions.
1.3. PROCEDURES AND FUNCTIONS 17
Aside from the local and global string registers, most of WinEdt’s other registers have
their values changed indirectly through the use of other macro commands. For example, the
editor registers %c and %l contain, respectively, the current column and line number (the
current column and line number identifies the position of the cursor in the active document).
You cannot use LetRegNum to change the value of these registers. To change the value of %c
or %l, you must either manually move the cursor (the changes are automatically reflected
in the values of %c and %l) or use GotoCol, GotoLin or GotoCL to jump the cursor to a
particular spot in the document.
GotoLin(LineNum: 1..16000000);
Go to the specified line and track the Caret’s position.
GotoCol(ColumnNum: 1..99999999);
Go to the specified column and track the Caret’s position.
However, WinEdt does allows the user to change a few document registers directly
through the commands SetFileName and SetFileMode. These commands will probably
be used rather infrequently, but they are there in the event you need to use them.
SetFileName("File Name");
Changes the file name of the current document.
SetFileMode("File Mode");
Changes the ”Mode” of the current document and resets certain properties. Check WinEdt’s documen-
tation on modes for more information.
\documentclass[12pt]{article}
\usepackage{amsmath}
\usepackage{verbatim}
\begin{document}
\bibliography{mybibliography}
\bibliographystyle{plain}
\end{document}
One way to code the macro without using subroutines (or procedures) would be:
1 CMD("New");
2 Mark(0);
3 Ins("\documentclass[12pt]{article}"); NewLine;
4 Ins("\usepackage{amsmath}"); NewLine;
5 Ins("\usepackage(verbatim}"); NewLine; NewLine;
6 Ins("\begin{document}"); NewLine; NewLine;
7 Ins(" "); NewLine; NewLine;
8 CMD("Go To Beginning Of Line");
9 Ins("\bibliography{mybibliography}"); NewLine;
10 Ins("\bibliographystyle{plain}"); NewLine;
11 Ins("\end{document}");
12 Goto(0);
13 CMD("Next Bullet");
Strictly speaking, WinEdt doesn’t provide for subroutines. WinEdt provides the Exe macro, which
looks for a specified macro file; if the file exists, WinEdt executes the sequence of commands contained
within that file. But this allows us to write code that behaves as if WinEdt allowed one to define subroutines:
simply write your code for the function, but save it to a file with a descriptive name and use Exe("...") to
call the subroutine.
Rewriting macro 1.8 so it uses subroutines as described means we must create two macro
files on disk, one for the preamble and one for the postamble. You can save your macro
files wherever you want to, just make sure you remember where they are. The author finds
it convenient to prefix the name of macro files containing subroutines with two underscore
characters, __, so he can tell just by looking at the file name that they aren’t stand-alone
macro files (and that he might get into trouble if he deletes them!).
Since the postamble subroutine is the easiest to write, let’s start with it:
Relax;
Ins("\documentclass[12pt]{article}"); NewLine;
Ins("\usepackage{amsmath}"); NewLine;
Ins("\usepackage(verbatim}"); NewLine; NewLine;
1 CMD("New");
2 Mark(0);
3 Exe("%B\macros\__Preamble.edt");
4 Exe("%B\macros\__MiddleStuff.edt");
5 Exe("%B\macros\__Postamble.edt");
6 Goto(0);
7 CMD("Next Bullet");
1.4 Recursion
Good macro languages allow for recursive programming, and WinEdt’s language does not
prove exception to the rule. Recursive programming in WinEdt requires that we use the
method of subroutines sketched in §1.3. Since writing recursive functions often requires
several macro files to be saved to disk, we need to indicate in our examples what macro code
belongs to which macro file. The convention that shall be adopted is to surround macro code
by comments indicating the file name and where the file ends. This allows us to include the
code for several files in the same display. E.g.,
// Filename: _MyMacro.edt
...
// Endfile
// Filename: _MyOtherMacro.edt
...
// Endfile
// Filename: %B\macros\guide\_recursion.edt
InsText("a");
IfNum(%c,10,'<',‘Exe("%B\macros\guide\_recursion.edt")','');
InsText("b");
// Endfile
(Only four as appear when started five spaces in because column numbering starts at 1.
When at the beginning of a line, the cursor is in column 1. Five spaces in, the cursor is at
column 6, so WinEdt can only insert four as until the test fails.)
be a headache. However, if we use recursion, we have to be careful of how we set the initial
conditions. We cannot set the initial conditions inside the same subroutine used for the
recursion because each time the recursion occurs the initial conditions will be re-established!
Consequently, we will put the initialization code in a macro called _APstartup.edt, calling
the recursive subroutine at the very end.
1 // Filename: %B\macros\ap\_APstartup.edt
2 BeginGroup;
3 StartWorking("Adding separators...");
4 LetReg(5,','); // <--- Change this if you want commas instead of periods
5 LetRegNum(6,0); // Stop indicator
6 LetRegNum(7,%c); // Original column position
7 LetRegNum(8,0); // Found digit indicator
8 GotoCol('%c-1'); // Backup behind the space delimiter
9 Exe('%B\macros\AddPeriods\_APchew.edt');
10 // Endfile
1 SetSel(0); SetSel(1);
2 IfNum(%c,1,'=',>
3 'Exe("%B\macros\AddPeriods\_APend.edt")',>
4 '');
5 GotoCol('(%c-1)'); GetSel(0,9);
6 IfStr('%!9','0','=',>
7 'LetRegNum(8,"%%!8+1");>
8 IfNum("%%!8","4","=",>
9 "SetSel(0);>
10 GotoCol(''%%%%c+1'');>
11 InsText(''%%%%!5'');>
12 GotoCol(''%%%%c-1'');>
13 LetRegNum(8,0);>
14 LetRegNum(7,''%%%%!7+1'')",>
15 "">
16 );>
17 Exe("%B\macros\AddPeriods\_APchew.edt")',>
18 ''>
19 );
20 IfNum(%!6,1,'=','Exe("%B\macros\AddPeriods\_APend.edt")','');
Lines 1–5 copy the character to the left of the cursor (if there is one) into register %!9. The
test in line 2 checks to see if we at the beginning of a line (calling GotoCol with a negative
argument generates an error message). If the character to the left of the cursor is a digit,
one of two possible actions can occur. If we have counted four digits, insert a separator,
since three digits have passed since the end of the digit string or the last separator inserted,
and then set the digit counter (register %!8) to zero again. If we have not yet encounter four
digits, add one to the digit counter and move left one space.
Now, the trick is telling whether the character copied into register %!9 is a digit or
not. Recall the discussion on page 15 about how to get the logical equivalent of a switch
statement in WinEdt’s language. We use that technique here: we have ten different IfStr
tests to see whether the copied character is 0,. . . ,9. In 1.15, we have only listed the code for
the first IfStr test (the complete code can be found in the Appendix).
Line 7 of 1.15 increments register %!8 by 1. Line 8 checks to see if this is the fourth
digit found. If it is, all text is deselected by a call to SetSel. (At this point we have not
yet deselected the character copied into register %!9. Without deselecting it, the InsText
of line 11 would delete that digit!) Finally, we move the cursor to the left one column, reset
the digit counter, and increment the counter tracking the number of separators inserted.
Nothing is done if the character stored in %!9 was not the fourth digit found.
When the character in %!9 is not a digit, the ten IfStr tests in _APchew fail. Then
%!6 gets assigned the value 1 (this occurs at line 155 in the full listing of the macro in the
appendix). The IfNum test of macro 1.15, line 20, calls the shutdown routine. The complete
listing of this macro is listed below:
// Filename: %B\macros\ap\_APend.edt
GotoCol(%!7);
SetSel(0);
EndGroup;
StopWorking;
Exit;
// Endfile
The shutdown routine moves the cursor to the correct final position, deselects all text, ends
the group started in _APstart.edt, and returns the cursor to its normal mode.
You might wonder why we hassle with the %!6 flag indicating when the processing of the digit string
has completed. The reason has to do out of concern for speed. Exit causes the macro to prematurely
terminate, preventing it from backing out of the recursive Exe calls properly. Ordinarily, one wouldn’t need
to do this, but the multiple-way branching used in this macro results in a significant speed decrease.
24 CHAPTER 1. MACROS
GetLongString("Prompt","Caption")
Same as EnterLongReg except that the value is stored in a special %!? string register (an extension of
%!0. . . %!9)
GetString("Prompt","Caption")
Same as EnterReg except that the value is stored in a special %!? string register (an extension of
%!0. . . %!9)
GetDim
Displays the dialog allowing you to enter the values of %!x and %!y numeric registers. Their values are
used in Macros that insert n × m environments (such as Array.edt).
GetCounter
Displays the dialog that allows you to enter the values of %!z numeric register. Its value can be used for
repeat loop and such. . .
StartWorking("Message")
Changes the Cursor to the Hour Glass form and displays the specified message in the last field of the
Status Line. Intended to indicate time-consuming macros,
StopWorking
Restores the cursor and removes the message from the status line.
With the exception of the last two macros (whose function should, hopefully, be more-
or-less clear), all of these macros cause a dialog box to be displayed, allowing the user to
enter a certain kind of data. If you’ve never done any Windows programming before, you
might feel a certain rush of power at the ability to create a dialog box with such ease.
1.5. INTERACTIVE MACROS 25
Close inspection will reveal some apparent redundancy between some of the above macros.
For example, the macros GetLongString and GetString seem to be two ways of doing the
same thing (sticking a string in the register %!?), and the difference between EnterLongReg
and EnterReg also might not be immediately clear. The basic difference between them
concerns the form of the dialog box that gets created. If you use either GetLongString or
EnterLongReg the dialog box that appears has a large multi-line edit box allowing the user
to type in whole paragraphs of text. On the other hand, GetString and EnterReg only use a
single-line edit box, which (I suppose) implicitly tells the user to be concise. WinEdt doesn’t
perform any length checking on the argument for either of the short entry commands, so
nothing prevents the user from typing an entire paragraph into the single-line edit box if
they want.
The following macro illustrates one possible use of the GetString command:
1 BeginGroup;
2 GetString("What environment do you want to create?","Insert Environment");
3 LetRegNum(9,%c); // Store current column number
4 Mark(0);
5 InsText("\begin{%!?}");
6 NewLine;
7 GotoCol(%!9);
8 InsText(" "); NewLine;
9 GotoCol(%!9);
10 InsText("\end{%!?}");
11 Goto(0);
12 CMD("Next Bullet");
13 EndGroup;
where the cursor is at the point indicated by ‘ ’. Now, without keeping track of the column
that the Insert Environment macro was invoked from (and consequently without including
lines 3, 7, and 9 in the macro definition), the macro output would look like:
26 CHAPTER 1. MACROS
\end{cases}
which is probably not what the user wanted. The Newline macro creates a new line and
moves the cursor beneath the f, the InsText(" ") macro inserts the box directly beneath
the x, and the second Newline macro creates a new line and moves the cursor directly beneath
the (assuming that WinEdt’s default line wrapping conventions are on). Including lines 3,
7, and 9 causes the macro to insert the environment so that the \begin and \end have the
correct vertical alignment like so:
and so we define the incredibly important function as follows:
\[
f(x) = \begin{cases}
\end{cases}
1.6 Appendix
1 SetSel(0); SetSel(1);
2 // Check to see if we are at the beginning of a line. If so,
3 // invoke __APend.
4 IfNum(%c,1,'=',>
5 'Exe("%B\macros\AddPeriods\__APend.edt")',>
6 '');
7 GotoCol('(%c-1)'); GetSel(0,9);
8 IfStr('%!9','0','=',>
9 'LetRegNum(8,"%%!8+1");>
10 IfNum("%%!8","4","=",>
11 "SetSel(0);>
12 GotoCol(''%%%%c+1'');>
13 InsText(''%%%%!5'');>
14 GotoCol(''%%%%c-1'');>
15 LetRegNum(8,0);>
16 LetRegNum(7,''%%%%!7+1'')",>
17 "">
18 );>
19 Exe("%B\macros\AddPeriods\__APchew.edt")',>
20 ''>
21 );
22 IfNum(%!6,1,'=','Exe("%B\macros\AddPeriods\__APend.edt")','');
23 IfStr('%!9','1','=',>
24 'LetRegNum(8,"%%!8+1");>
25 IfNum("%%!8","4","=",>
26 "SetSel(0);>
27 GotoCol(''%%%%c+1'');>
28 InsText(''%%%%!5'');>
29 GotoCol(''%%%%c-1'');>
30 LetRegNum(8,0);>
31 LetRegNum(7,''%%%%!7+1'')",>
1.6. APPENDIX 27
32 "">
33 );>
34 Exe("%B\macros\AddPeriods\__APchew.edt")',>
35 ''>
36 );
37 IfNum(%!6,1,'=','Exe("%B\macros\AddPeriods\__APend.edt")','');
38 IfStr('%!9','2','=',>
39 'LetRegNum(8,"%%!8+1");>
40 IfNum("%%!8","4","=",>
41 "SetSel(0);>
42 GotoCol(''%%%%c+1'');>
43 InsText(''%%%%!5'');>
44 GotoCol(''%%%%c-1'');>
45 LetRegNum(8,0);>
46 LetRegNum(7,''%%%%!7+1'')",>
47 "">
48 );>
49 Exe("%B\macros\AddPeriods\__APchew.edt")',>
50 ''>
51 );
52 IfNum(%!6,1,'=','Exe("%B\macros\AddPeriods\__APend.edt")','');
53 IfStr('%!9','3','=',>
54 'LetRegNum(8,"%%!8+1");>
55 IfNum("%%!8","4","=",>
56 "SetSel(0);>
57 GotoCol(''%%%%c+1'');>
58 InsText(''%%%%!5'');>
59 GotoCol(''%%%%c-1'');>
60 LetRegNum(8,0);>
61 LetRegNum(7,''%%%%!7+1'')",>
62 "">
63 );>
64 Exe("%B\macros\AddPeriods\__APchew.edt")',>
65 ''>
66 );
67 IfNum(%!6,1,'=','Exe("%B\macros\AddPeriods\__APend.edt")','');
68 IfStr('%!9','4','=',>
69 'LetRegNum(8,"%%!8+1");>
70 IfNum("%%!8","4","=",>
71 "SetSel(0);>
72 GotoCol(''%%%%c+1'');>
73 InsText(''%%%%!5'');>
74 GotoCol(''%%%%c-1'');>
75 LetRegNum(8,0);>
76 LetRegNum(7,''%%%%!7+1'')",>
77 "">
78 );>
79 Exe("%B\macros\AddPeriods\__APchew.edt")',>
80 ''>
81 );
82 IfNum(%!6,1,'=','Exe("%B\macros\AddPeriods\__APend.edt")','');
83 IfStr('%!9','5','=',>
84 'LetRegNum(8,"%%!8+1");>
85 IfNum("%%!8","4","=",>
86 "SetSel(0);>
87 GotoCol(''%%%%c+1'');>
88 InsText(''%%%%!5'');>
89 GotoCol(''%%%%c-1'');>
90 LetRegNum(8,0);>
91 LetRegNum(7,''%%%%!7+1'')",>
92 "">
93 );>
94 Exe("%B\macros\AddPeriods\__APchew.edt")',>
95 ''>
28 CHAPTER 1. MACROS
96 );
97 IfNum(%!6,1,'=','Exe("%B\macros\AddPeriods\__APend.edt")','');
98 IfStr('%!9','6','=',>
99 'LetRegNum(8,"%%!8+1");>
100 IfNum("%%!8","4","=",>
101 "SetSel(0);>
102 GotoCol(''%%%%c+1'');>
103 InsText(''%%%%!5'');>
104 GotoCol(''%%%%c-1'');>
105 LetRegNum(8,0);>
106 LetRegNum(7,''%%%%!7+1'')",>
107 "">
108 );>
109 Exe("%B\macros\AddPeriods\__APchew.edt")',>
110 ''>
111 );
112 IfNum(%!6,1,'=','Exe("%B\macros\AddPeriods\__APend.edt")','');
113 IfStr('%!9','7','=',>
114 'LetRegNum(8,"%%!8+1");>
115 IfNum("%%!8","4","=",>
116 "SetSel(0);>
117 GotoCol(''%%%%c+1'');>
118 InsText(''%%%%!5'');>
119 GotoCol(''%%%%c-1'');>
120 LetRegNum(8,0);>
121 LetRegNum(7,''%%%%!7+1'')",>
122 "">
123 );>
124 Exe("%B\macros\AddPeriods\__APchew.edt")',>
125 ''>
126 );
127 IfNum(%!6,1,'=','Exe("%B\macros\AddPeriods\__APend.edt")','');
128 IfStr('%!9','8','=',>
129 'LetRegNum(8,"%%!8+1");>
130 IfNum("%%!8","4","=",>
131 "SetSel(0);>
132 GotoCol(''%%%%c+1'');>
133 InsText(''%%%%!5'');>
134 GotoCol(''%%%%c-1'');>
135 LetRegNum(8,0);>
136 LetRegNum(7,''%%%%!7+1'')",>
137 "">
138 );>
139 Exe("%B\macros\AddPeriods\__APchew.edt")',>
140 ''>
141 );
142 IfNum(%!6,1,'=','Exe("%B\macros\AddPeriods\__APend.edt")','');
143 IfStr('%!9','9','=',>
144 'LetRegNum(8,"%%!8+1");>
145 IfNum("%%!8","4","=",>
146 "SetSel(0);>
147 GotoCol(''%%%%c+1'');>
148 InsText(''%%%%!5'');>
149 GotoCol(''%%%%c-1'');>
150 LetRegNum(8,0);>
151 LetRegNum(7,''%%%%!7+1'')",>
152 "">
153 );>
154 Exe("%B\macros\AddPeriods\__APchew.edt")',>
155 'LetRegNum(6,1)'>
156 );
157 IfNum(%!6,1,'=','Exe("%B\macros\AddPeriods\__APend.edt")','');
Chapter 2
Syntax Highlighting
Syntax Highlighting is another one of the powerful features of WinEdt. Certain parts of
your text can be highlighted, that means formatted visually in a different color or font.
This allows to have your document structured in an easy to spot way. In addition, Syntax
Highlighting can help you to avoid typo’s. The behaviour of the Syntax Highlighting feature
is dependent on the mode of your document. Of course, you can customize the highlighting
completely. To show you how is the aim of this chapter.
2.1 Basics
Before experimenting with Syntax Highlighting settings, it is a good idea to save your current
state of WinEdt’s customization. All customizations are stored in the file winedt.ini1 . Use
the menu entry Options Save Settings As... make a backup copy of your current winedt.ini
under another name. If you want, you can then revert to your previous state by renaming
this file to winedt.ini. You also have a “factory settings” winedt.ini in the subdirectory
\support.
WinEdt provides a way to exchange settings from some dialogs (including the Syntax
Highlighting) via an human-readable format. You can access this feature by clicking the
secondary mouse button in the dialog. Now, the context menu offers you the entries Extract...,
Append... and Load From....
Syntax Highlighting in WinEdt is based on the idea of three different highlighting levels.
These levels specify the syntax elements which are subject to highlighting. Believe it, you
want it that way!
1
If you haven’t specified an alternative ini-file when calling WinEdt.
29
30 CHAPTER 2. SYNTAX HIGHLIGHTING
2.1.2 Switches
You look now at your partly colored text. It looks good, but you’d wish that also the values
itself would be colored, not only minus and plus. From what you know now, you could tell
WinEdt to color all ‘1’s green, all ‘2’s green, and so on. It would work, and you could even
group the numbers together, using only one of WinEdt’s Filter Sets. But no, you aren’t
satisfied with that, you want the negative numbers blue and the important positive numbers
with a plus before it in red. You have now entered a new dimension of highlighting, the
dimension of the Switches.
Switches set a number of successive, random characters to a certain color (or font),
depending on a condition. In our case, the condition is the minus or plus sign. If a minus
sign is followed by a number, then you want to have both in blue. You don’t want numbers
without minus or plus to be colored, nor do you want a blue hyphen or such. The condition
itself is specified as a Filter Set, as we have already seen.
2
How this is done is explained later in this chapter.
3
Often the criterion is “be any character”.
2.2. FILTER SETS 31
• if the option “Before:” is checked then the beginning of line is not an admissible
position for a character to belong to the filter,
• if the option “After:” is checked then the end of line is not an admissible position for
a character to belong to the filter.
Below the “Filters” field is “Options”, where you can enable a Filter Set for highlighting
of certain modes. You don’t have to enable highlighting for a Filter Set in order to use it
elsewhere! You only enable a Filter Set if you want to highlight something directly with it.
A Filter Set can be given a priority from “0” (lowest) to “9” (highest), which determines
highlighting inside Switches and Reserved Words.
Filter Sets (as well as Switches and Reserved Words) are highlighted with respect to the “Priority”
value. Priority can be specified to determine highlighting of the currently selected filter set inside
Switches and Reserved Words. This does not mean that when two or more Filter Sets compete, the one
4
As long as you do not specify entries with the same name. In this case, the last of these entries is used.
32 CHAPTER 2. SYNTAX HIGHLIGHTING
with the higher priority is highlighted. In such a case, always the last specified Filter Set applies, regardless
of priority. However, a Filter Set with a high priority rules over a Switch with a lower priority.
The “Sample” field shows you how your Filter Set will look if you have given it certain
“Font” or “Color” attributes in the right column of this dialog. Of course, this does only
apply in your document if it matches the enabled mode definition.
Note that certain fields in this dialog (or, to be correct, in almost every WinEdt dialog) give
useful context-sensitive menus, that means they respond to the secondary mouse button.
You use Set Expressions to specify the “Definition” field in the Filter Set dialog. There are
four predefined sets: Numeric, Alpha, Upper and Lower. These sets are language sensitive,
that means their definition is dependent on the Language Settings in Windows’ Control
Panel.
To define sets, you use the following syntax:
character : Either "?", where ? stands for any character, or #{code}, with 0 < code <= 255.
interval: character..character
set: Either a predefined set or a [sequence of characters and intervals].
[] is also allowed and means the empty set.
operators: ~ (not),
+ (union),
- (difference),
* (intersection)
2.3. SWITCHES 33
Examples:
Character:
"a" the letter a,
"b" the letter b,
#32 the ASCII code 32.
Interval:
a..z the lowercase letters a, b, c . . . z.
Set:
Numeric the numbers 0 to 9 (a predefined set),
["ab"] the letters a and b,
["a","b"] also the letters a and b,
["+-*/^<>=(){}&#[]"] Math stuff (from the default WinEdt entry),
[] the empty set.
Operators:
~[] not empty, that means All,
Alpha+Numeric union of the predefined sets Alpha and Numeric,
thus specifying all letters and all numbers,
Alpha-Lower all letters minus the lowercase ones, giving the uppercase ones
(which happens to have its own predefined set, Upper),
SetA*SetB gives you the elements that are in SetA as well as in SetB.
(I cannot think of a straightforward example, sorry . . . )
These examples show the basics of defining Set Expressions. We will come to some more
complicated definitions in later, concrete examples. Making up not-too-easy examples for
Filter Sets only is hard. Since a good and sensible Switch usually requires a good and sensible
Filter Set too, we will give its both definitions in the section about Switches.
If you are not sure about the correct syntax of a Filter Set’s definition: don’t hesitate
to experiment. You cannot do much wrong as long as you do not modify WinEdt’s default
entries. Enable the Filter Set you are working on and give it an easy to spot color. If you
think it is right, you can again switch it off and use it in e. g. the Reserved Words tab page
(remember, you don’t have to highlight a Filter Set to use it elsewhere).
2.3 Switches
A Switch tells WinEdt to highlight certain parts of your text. These parts are started by a
clearly defined condition, and are ended on another condition. Unless in Filter Sets, you don’t
define the part of the text to highlight, you define which condition “switches” highlighting
on instead.
34 CHAPTER 2. SYNTAX HIGHLIGHTING
predefined set, you don’t even have to create a new Filter Set. As already said, highlighting
starts according to the “Begin:” field. In this case, we have Numeric there, so the numbers
in our document will be highlighted. But, and this is the crucial point, the minus will not be
highlighted! You have to decide whether this is acceptable. You could, of course, set up and
enable a Filter Set with “minus” in addition. While this is practicable, it is usually better
to think about other ways.
Now, there seems to be a third way of setting up this Switch. This would be to make “-” the
“Begin:” specifier, and to set Numeric as the “Definition”. Good idea, but . . . With Filter Sets, you
were allowed to have (predefined) sets in the “Definition” field. This, however, is not possible with Switches.
WinEdt treats text in the “Definition” field in the Switches dialog verbatim! Specifying Numeric here would
expect the word “Numeric” after the “minus” sign.
Let’s sum up what this “Begin:” checkbox does:
“Begin:” unchecked: Definition + Filter Set – The Switch starts if the characters
specified in the “Definition” field (taken verbatim) precede the syntax elements as
specified by the Filter Set in the “Begin:” field. The characters in the “Definition”
field are not highlighted since Syntax Highlighting starts if the Filter Set matches.
“Begin:” checked: Filter Set + Definition – The Switch starts if the Filter Set in the
“Begin:” field matches and is followed by the “Definition”, which is taken verbatim.
Here, “Definition” is highlighted, since it comes after the Filter Set which begins the
Switch.
In the “Options” section of this dialog there is a checkbox named “BOLN” (Beginning Of
Line). If this box is checked, then the whole Switch only applies if it starts at the beginning
of a line.
Ending a Switch
After setting up a condition which begins a Switch, you now need another condition which
end this Switch. This is achieved by the “End:” field in the “Filters” section. Also, a
Switch has a “Scope” in which it is highlighted. Text outside the scope of a Switch is not
highlighted; this is the second condition which ends a Switch.
As you see, the listbox for “End:” gives the list of all defined Filter Sets. The Switch
is ended when the “End:” Filter Set applies. The checkbox before the “End:” field tells
whether the occurrence of this Filter Set is part of the Switch, that means whether it is
highlighted or not.
Now, what is the scope of a Switch? The “Scope” field in the “Options” section can have
a number from “0” to “4”. The meaning of these numbers is:
0 The Switch ends with the first non-alpha character. This is meant for TEX control se-
quences.
1 The Switch ends at the end of line. This is useful for one-line comments in programming
languages.
36 CHAPTER 2. SYNTAX HIGHLIGHTING
3 The Switch ends at the first empty line. This can be used for TEX Math sequences ($...$).
4 The Switch ends with the specified “End:” Filter Set. Take care, as this is potentially
slow in large documents.
Priority
Switches can be nested. The default settings of nested switches are combined if the switches
have equal priorities and the inner switch has the option “Default Font” or “Default Color”
enabled. A Switch with a lower priority is ignored inside a Switch with greater priority.
2.3.3 Examples
The following examples are given in the syntax which WinEdt uses to Extract... the entries
in the Syntax Highlighting dialogs. This syntax should be self-explanatory.
You can see, the “Definition” of the Filter Set is a minus, in a syntax that follows the rules
from section 2.2.2, “Set Expressions”. The “Before:” field is not checked (the ‘0’) and empty.
The “After:” field contains the (predefined) set Numeric and is checked, so that a minus
ending a line does not get highlighted (without this, in addition to Numeric, the end of the
line would be valid). The Filter Set itself is not enabled, since we only use it indirectly in
the Switch. Priority is zero, the color is the standard color, but this does not come to effect
since the Filter Set is not enabled.
Okay. We have all what we need to begin the Switch. But how do we switch it off? The
highlighting should stay in effect for all digits in the negative number, but not for text or
other non-numeric characters. Therefore, a good “End:” condition is “not numeric”. But
before we come to set this Filter Set up, let’s think a little: a number, if it is not an integer,
2.3. SWITCHES 37
can also have a decimal point. If we would simply say: “switch off on all but numbers”, the
decimal point would switch highlighting off too. Since we do not want this, we must also
allow the decimal point. We can count the decimal point as numeric in this case, but of
course it is not included in the predefined set Numeric. Thus the Filter Set with the name
Not Numeric is:
Name:Not Numeric
Definition:~Numeric-["."]
Before:0
After:0
Enabled:0
Priority:0
Color:1040
We remember: the tilde (~) is the negation symbol in the Set Expression syntax. The
“Definition” reads as follows: we want “not numeric”, which leaves all other characters in
the ASCII table except the numbers from ‘0’ to ‘9’. From this remaining set of characters
we subtract also the minus sign.5 Thus, the Filter Set specifies all characters except the
numbers from ‘0’ to ‘9’ and the ‘minus’. We can now use this set to end our Switch.
Since this is possibility One, let us call this Switch Negative Number 1.
Name:Negative Number 1
Definition:
Begin:1-Numeric
End:0Not Numeric
Enabled:1*
Priority:2
Color:3082
Case Sensitive:0
BOLN:0
Scope:1
As said before, this switch does not need a “Definition”, since all is done with Filter Sets.
The “Begin:” field is checked (the ‘1’). This means, we remember, that WinEdt expects
the sequence Filter Set + Definition. As our “Definition” is empty, it would not matter
whether this field is checked or not; the Filter Set alone does the work. But in contrast to
possibility Two, let us have this field checked.
The “End:” field is not checked, since we do not want the Filter Set after our Negative
Number to be highlighted. This Filter Set is our just created Not Numeric set.
The Switch itself is enabled (since we want the highlighting), the ‘*’ means “all modes”.
Of course, you can restrict highlighting of this Switch to specific modes, just enter the names
here (multiple entries divided by semicolons).
Priority is ‘2’, that means the Switch can be overridden by Filter Sets, Switches and
Reserved Words with higher priority values. The color is set to 3082, which happens to be
5
Of course, you can specify this Filter Set in other ways, as long as it is logically correct and follows the
syntax for Set Expressions.
38 CHAPTER 2. SYNTAX HIGHLIGHTING
bright green. The Switch is not case sensitive (why should it?) and it does not need to start
at the beginning of the line (but it can). The scope of the Switch is ‘1’, that means it is
switched off at the end of the line if it is not already switched off before.
Now, we have set up our first highlighting scheme!
The “Case Sensitive” checkbox tells whether the words given should be treated case sensitive
or case insensitive.
About speed, the WinEdt online help has to say this (in TEX, every command starts with
a backslash): “It makes a difference to specify a TEX command by its first letter and use ‘\’
as a Filter Set or to define all TEX Control Sequences under ‘\CS’. The second method is
less efficient!” (read: “slower”)
Both “Before:” and “After:” fields are not checked, so the Reserved Words in this group
can start at the beginning of the line and can end at the end of the line. The definition
~Alpha (“not Alpha”) ensures that the words are not highlighted if they are part of another
word. This group is enabled, the empty field here tells that highlighting is in effect in all
modes. Priority is “4”, so all highlighting with a lower priority is overridden. These words
are highlighted with a certain color.
Case Sensitive:1 tells WinEdt to take care to highlight only words which match the
entries in the group in case. Thus, “Latex” is not highlighted, only “LaTeX” is.
This group of Reserved Words contains eight words, namely ‘TeX’, ‘LaTeX’, ‘WinEdt’,
‘BibTeX’, ‘DVIWIN’, ‘MiKTeX’, ‘YAP’ and ‘emTeX’.
Most other entries in the Reserved Words dialog are no more complicated than this one.
If you understand what the Filter Set in the “Before:” and “After:” field does, you will have
no problem.
the words in decreasing order makes sure that longer words become before shorter ones when
having the first letters in common, which is essential in most cases.
Note: this example is a TEX example. You do not need to know about this language, just notice
that all TEX commands start with a backslash.
Say you have the Reserved Words \par and \part. If you have not taken care to sort the words
in decreasing order, WinEdt would highlight only the letters ‘p’, ‘a’ and ‘r’ of part. When applying its
algorithm, WinEdt goes through the list of Reserved Words and sees that the pattern \par matches the
word “\part” perfectly (see it as a stencil), and highlights it. This looks like “\part”. WinEdt does not go
further down the list (which can be rather long, and usually is) for speed reasons, so it does not see that the
stencil \part would match even better.
If, however, you have sorted the words in decreasing order, then \part is found first, and correctly
applied. WinEdt would not need to go further down the list of Reserved Words, since there will be only
\par, which does not fit the stencil because of the missing “t”.
There is another way to get correct highlighting in this case, and this has a pleasing side-effect. To be
honest, this second way was ‘invented’ in the first place to get the side-effect. So let’s see what the side-effect
is. In TEX or LATEX you can define functions yourself. You could now define a function called \parent. Since
this is neither standard TEX or LATEX you will not have it in the Reserved Words list. Without taking care,
you will have the “\par” part of your function highlighted, resulting in “\parent”. This is really annoying.
The solution is to specify an “After:” Filter Set. In our TEX example, a ~Alpha (not Alpha, you
remember) Filter Set matches best, since normally TEX commands may only have alphabetic characters. The
~Alpha Filter Set here says: “After a Reserved Word may come everything except an alphabetic character.”
This prevents highlighting of words that do not fit exactly in writing (while it leniently overlooks all non-
alphabetic characters after the word). Our \parent function does not fit exactly in writing, and thus is not
highlighted. Great.
Let’s get back to the “\part” example from the beginning: here too, \par does not fit “\part” exactly
anymore. It does not matter whether the list of Reserved Words is sorted in increasing or decreasing order:
WinEdt can not apply its highlighting. It has to find an exact match, and only \part matches “\part”.