< Previous Chapter | Next Chapter >

341 Chapter 12. Automating Nisus Writer

In this chapter, you’ll learn…

In this chapter, we’re going to discuss the most powerful and exciting aspects of Nisus Writer—its automation features. We’ll start with a look at glossaries, which can save you tons of effort by storing often-used text and graphic elements. But the real power of automation comes from macros, which we’ll cover in much greater detail. Because macros require a lot more thought than most Nisus Writer features 342 (and have a much steeper learning curve), we’re going to switch gears a bit when we get to the “Macros” section and take more of a tutorial approach. Try working through all the examples yourself, and the text will make a lot more sense.

Using Glossaries

When you’re typing, chances are, many of the same words and phrases crop up a lot—things like your name, phone number, E-mail address, or “Sincerely, John Smith.” Or perhaps there’s a certain equation you use a lot, or bibliographic entries that get used for every paper you write. With Nisus Writer’s glossaries, you can enter things like that using just a couple of keystrokes, rather than re-creating them each time.

A glossary is a special file Nisus Writer uses to store text, graphics, and other document elements along with abbreviations for each. The concept is simple: put the text (or graphic or whatever) in your glossary once, and give it a short, easy-to-remember abbreviation. When you want to insert that element into a document again, you can either choose the abbreviation from a menu or just type in the abbreviation, followed by a keyboard shortcut that “expands” it to its full form. In writing this book, for example, I used abbreviations like nw for “Nisus Writer” and pfp for “PowerFind Pro” to save quite a bit of typing and keep spelling errors to a minimum.

Creating and Expanding Abbreviations

Here’s how you do it. First, make sure you’re on the text layer and select the text, graphic, or whatever you want to store. Choose New Abbreviation… from the Glossary submenu of the Tools menu. The Glossary Entry dialog box (Figure 12.1) will appear, asking you to type in an abbreviation. Type in a short abbreviation (note that case is significant), and click OK. You’ll then see your entry in the glossary editing window (Figure 12.2), where you can edit if you wish. When you’re satisfied with the way your entry looks, close the glossary editing win-343dow. Your new abbreviation will appear on the Glossary submenu, and you can insert the glossary entry into your document by choosing that menu command. Or type in the abbreviation, then choose Expand Abbreviation from the Glossary submenu or press the keyboard shortcut Command-\.

Figure 12.1. The Glossary Entry dialog box.

Figure 12.2. The glossary editing window.

Abbreviations will only be expanded if they are typed into your document as whole words. That is, if you have the abbreviation ee associated with the glossary entry “Electrical Engineering” and select the word “tree” before choosing Expand Abbreviation, nothing will happen.

The Expand Abbreviation command (and its associated keyboard shortcut) can work in either of two ways. First, if you have no text selected and there is an abbreviation immediately to the left of the insertion point (no spaces in between), the abbreviation will be expanded. Or, if you select any range of text that includes one or more abbreviations as separate “words” before choosing Expand Abbreviation, all the abbreviations within the selection will be expanded to their full glossary entries. This means that, if you wish, you can simply type abbreviations without interrupting yourself as you create a document, then at the end choose Select All and Expand Abbreviation to expand all the abbreviations in your document at once.

The Expand Abbreviation command works not only in your document window, but also in the macro editing window, the glossary editing window itself, and even the Find/Replace dialog box.

344 Editing Glossary Entries

The glossary editing window appears whenever you choose New Abbreviation…, so that you can examine your glossary entry and make any desired changes to it before continuing. If you want to edit your glossary entries or abbreviations later, choose Edit Glossary File… from the Glossary submenu to display the glossary editing window. This window looks and acts like other Nisus Writer windows—you still have access to all of your formatting controls, though not to the Sound Bar or Graphics Bar. The most obvious difference is the “split-pane” layout of the window: the abbreviations are listed on the left, and the actual glossary entries on the right. You can’t edit an abbreviation directly, but double-clicking on an abbreviation will open a dialog box allowing you to rename it. You can, however, edit freely in the right side of the window. Glossary entries are separated by gaps that look like page breaks in your document window.

The abbreviations in this window are “attached to” the return character at the end of the preceding glossary entry (just like rulers in your document are). So if you want to copy a glossary entry (to duplicate it and make changes, or copy it to another glossary file, for example) and include its abbreviation, be sure to select that previous return character before copying, cutting, or dragging and dropping. When you close the glossary editing window, all your glossary entries will appear in alphabetical order on Glossary submenu of the Tools menu.

Working with Glossary Files

Your glossary entries are stored in a special Nisus Writer document called a glossary file. You can have as many different glossary files as you like (each with an unlimited number of entries), but only one can be open at a time. To open another glossary file, locate it using the Open dialog box or Catalog, and click Open. If there are glossary files you use frequently and would like to be able to switch to easily, you can add them to your “Essential Files” list.

345 Normally, changes to your current glossary file are not saved until you quit Nisus Writer. To save the file manually, just choose Save while the glossary editing window is the active window. If you have just added entries to your glossary for the first time, your glossary file will be named Nisus Glossary File and stored in the same folder as your Nisus Writer application. This file will then be opened automatically whenever you launch Nisus Writer. To change the default glossary file, simply move your current one from the Nisus Writer folder, move a new one into its place, and name the new file Nisus Glossary. To create a brand-new, empty glossary file, choose New Glossary File… from the Glossary submenu.

What Can You Put in a Glossary?

You can put anything in a glossary that you can put on the text layer of a document—not just text, but character graphics (including tables and equations), movies, sounds, page graphics, variables, and autonumbers. You can even include PowerFind or PowerFind Pro expressions, and anything in your glossary can have styles or markers applied to it. There is also no limitation on length—glossary entries can run several pages or more if you wish. There is a minor limitation, though. While the text in your glossary entries can contain footnotes, headers/footers, graphics, or sound, you can’t create any of these elements from within the glossary editing window. So if you need to include those elements in a glossary entry, type them into your document first, then select them and choose New Abbreviation….

The enclosed CD-ROM contains several new ready-made glossary files, which contain abbreviations for common phrases, various types of tables and equations, Find/Replace expressions, and more.

Styles and Rulers in Glossary Entries

When you’re in the glossary editing window, you can apply fonts, sizes, and styles to your text just like you would anywhere else. When you insert a styled glossary entry into your document, it will retain whatever attributes it had in the glossary. However, you can also make your text pick up the attributes of the surrounding text where it is inserted, if you 346 wish. To do that, select your glossary entry in the glossary editing window, and choose Any Font, Any Size, +Any Styles, and/or Any Color from their respective menus. Glossary entries styled with one of the “Any” attributes will pick up the characteristics of that attribute (font, size, style, or color) from the surrounding text when it is inserted.

You can also name rulers and define new styles in the glossary editing window. If you define a style in the glossary editing window and then insert a glossary entry that uses this style into your document, the new style name will be transferred into your document too and added to your Style menu. Similarly, if you name a ruler in the glossary editing window and then insert a glossary entry which includes that ruler into your document, the ruler name will be transferred along with the paragraph(s) to which it applies. However, a ruler will not be copied into your document if it is the first thing in your glossary entry. This is because the ruler is “attached to” the return character at the end of the previous entry, and is not considered “part of” the current entry. On the other hand, if you have a paragraph as your glossary entry that uses a defined style with an attached (named) ruler, inserting that paragraph into your document will bring the ruler with it.

Macros

While glossaries can save you lots of typing, they can only hold static items. You can use a glossary entry to insert an object into your document, but not to make changes to your document or perform any other activities. The next level of automation in Nisus Writer is macros, which will allow you to create a shortcut for nearly any imaginable activity. Macros are Nisus Writer’s most powerful, yet least understood feature. In the remainder of this chapter, I’ll try to make sense of macros and help you to unlock this power for your own use.

What’s a Macro?

So what is a macro anyway? Quite simply, it’s a single command that can activate any number of other commands in a 347 sequence. It’s a way of doing in a single step what would ordinarily take several. To take a trivial example, let’s suppose you regularly open a new file, paste in the contents of the clipboard, and then save the file. You could create a very simple macro that does those three steps for you with a single menu command, and thereby save a bit of effort. But macros can go far beyond this humble example. They can perform calculations, manipulate text, ask for input, and so on—in other words, they can do much more than just repeat sequences of activities you’d normally do by hand. Macros are stored in special Nisus Writer documents called macro files. A single macro file can contain any number of separate macros. The macros in the currently open macro file, along with commands for recording and editing macros, are found on the Macros submenu of the Tools menu (Figure 12.3).

Figure 12.3. The Macros submenu of the Tools menu. Macros in the currently installed macro file are listed at the bottom.

348 Macros: The Nickel Tour

Well, our macro adventure has to start somewhere, so let’s jump in and get started. I’ll show you around briefly to get you oriented, then we’ll sit down and talk details. We’ll start by recording, editing, and playing a simple macro. Then we’ll discuss the capabilities of macros in general before delving into the more sophisticated macro commands.

Recording a Macro

The easiest way of creating a macro in Nisus Writer is using the Record command. I often refer to this as the “watch-me” mode, because that’s exactly what it does: Nisus Writer watches what you do, and records each action you perform. When you stop recording, you can give a name to the sequence of activities you just did, and this name will then appear on the Macros submenu. Any time you want to repeat those same activities, just choose that name from the menu.

Recording Step-by-Step

Let’s walk through the exact procedure of recording a basic macro step-by-step. You can then apply this technique to your own activities.

  1. Choose Record from the Macros submenu of the Tools menu. While you are in “Record” mode, the Tools menu name will blink on and off.
  2. Choose New from the File menu.
  3. Type in Macros are FUN! and press return.
  4. Choose Select All from the Edit menu.
  5. Choose Bold from the Style menu.
  6. Double-click the word FUN and then choose Underline from the Style menu.
  7. Choose Stop Recording from the Macros submenu of the Tools menu.
  8. A dialog box will appear asking you to name the macro. Type in Test and click Name.
  9. 349 The macro editing window will appear. Click the close box to close this window.

What you just did was record a macro that will create a new file, type some text in it, apply the style Bold to it, and underline one word. In other words, all the steps you just performed manually have now been recorded. You can vary steps 2 through 6 (and add as many additional steps as you like) to make your macro perform different functions.

Playing a Macro

Now that you’ve recorded your first macro, let’s play it back. Before doing so, you may close the new document you just created (if you wish)—no need to save changes. Now go to the Macros submenu of the Tools menu, and you’ll see a new menu choice—Test (the command you just added). When you choose Test, your macro will run, repeating all the steps you recorded—but a lot faster than you could have performed those steps manually.

Nisus Writer’s Undo command works on macros, too. In fact, if you have just run a macro and then choose Undo, Nisus Writer will undo the entire macro (except for opening, closing and saving files, which cannot be undone anywhere in Nisus Writer). If you want to stop a macro before it finishes running, press and hold the Command and period (.) keys. The macro will pause and a dialog box will ask you if you want to stop the macro or continue to the end. To cancel the macro, click Stop, or to let the macro complete its activities, click Continue.

Editing a Recorded Macro

You’ll recall that when we finished recording our sample macro, we gave it a name and then saw the macro editing window. The reason this window opens automatically when you’re finished recording a macro is so that you can edit, or fine-tune, your macros. We chose not to do that with the macro we recorded, but you can go back at any time and change your macros. Let’s do that now. Choose Edit Macro File… from the Macros submenu, and you’ll see the macro 350 editing window, which looks something like Figure 12.4 (yours may be slightly different). You’ll notice that the macro you recorded consists mainly of menu commands, and you can probably tell just by looking at it what each line does. Nevertheless, let’s walk through it line by line.

Figure 12.4. The macro editing window, showing the Test macro.

New
This is the first menu command you chose after you began recording your macro. When you choose a menu command, it appears on a line all by itself. This one word is all you need in a macro to tell Nisus Writer to open a new file.
Key Macros are FUN!
“Macros are FUN!” is what you typed in. The word Key means that whatever comes after it is “typed in,” just as though you had pressed those keys on the keyboard. Note that there is a space between the word Key and the text you typed in.
Key
This line contains the word “Key,” and (though you won’t be able to see it if you have Space, Tab, & ¶ turned off) a space. The word “Key” on a line all by itself doesn’t mean anything, but Key followed by a space means “type a return”—which, you’ll recall, we did immediately after typing in Macros are FUN!
Select All
Once again, this is simply a menu command. It selects all the text in the document so we can apply a style to it.
351 Bold
This is the menu command that we applied to the text we just selected.
Click 86, 76
This line tells us that the mouse was clicked at a point 86 pixels from the left edge of the window and 76 pixels from the top (your numbers may be different, depending on where you clicked). This line represents the first click of our double-click to select the word “FUN.”
Click 86, 76
This line represents the second click of our double-click. How does Nisus Writer know that this was supposed to be a double-click and not two separate single clicks? Simple—both the coordinates are the same.
Underline
The last line of the macro is the menu command to underline text.

As you can see, there’s nothing complicated about this macro. It simply lists all the things you did, one activity per line. If you want to change it or add to it later on, just type in new commands. For example, if we decided that we wanted our text to be italic instead of bold, all we’d need to do is highlight the word Bold, and type in Italic instead. To delete a command from your macro, just delete the line that lists that command. To change a macro’s name, double-click on the macro’s name on the left side of the macro editing window. A dialog box will appear, giving you a text box to enter the new name in. Type in the name of your choice, and click OK.

Congratulations—you’ve done it. You have successfully recorded and edited a macro. While there are many, many more things you can do with macros, you will always be following roughly the same procedure. And if you can type in the commands you see on menus, plus words like “Key” and “Click,” then you can easily create macros from scratch—often without any recording at all. We’re ready to move on to bigger and better things…but first, let’s review exactly what Nisus Writer’s macros can do.

352 Macro Capabilities and Limitations

Before we go any further, you should know a few things about what macros can and cannot do. We’ll discuss the pros and cons of individual commands as we go along, but there are a few general features I’d like to mention up front. Keep in mind that the limitations I mention here need not be troublesome—anything can be worked around with a little creativity.

What Macros Do and Do Not Record

When you are using Nisus Writer’s “watch-me” recording mode, your mouse clicks and menu selections are automatically recorded in the macro file. However, for the most part, the recording is “blind.” For example, if you close a window by clicking the close box, what will be recorded is the mouse coordinates where the click occurred. If you close a window by pressing Command-W, that keystroke will be saved. The only way the Close command itself will be recorded is if you choose the command from a menu. However, at least when you click the mouse, the coordinates are recorded relative to the nearest corner of the active window where you first clicked. This means that, for example, clicking the close box or the zoom box can be performed by a macro even if the window is moved or resized. Unfortunately, floating tool bars are not seen as windows, meaning that if you record a click on a tool bar button and the tool bar moves, your macro will not work correctly, as Nisus Writer will try to click at the location on the screen where the button was when the macro was recorded.

Only individual mouse clicks are recorded. Clicking and dragging is not recorded, which means you can’t record resizing graphics or selecting text with the mouse. However, you can still select text in a macro using keyboard shortcuts (see Appendix A), and you can record resizing graphics using the Scale… command. Choices from pop-up menus (like the Ruler Name menu) are not recorded. However, you can type a ruler name directly into a macro to select that ruler. Some pop-up menus, though, like the Mail Services 353 pop-up in the Recipients area of the PowerTalk mailer, are “invisible” to the macro engine and cannot be accessed from a macro.

Nearly all keystrokes are recorded, including combinations that involve holding down the Command, Shift, and/or Option keys while typing something else, as well as the arrow keys. However, the Control key is not recorded, and if you have an extended keyboard, the Function Keys, Help, Page Up, Page Down, Home, and End keys will not be recorded.

Macro Language Features

Macros are not limited to just what you can record. You can also type in a macro by hand, and in so doing, include a lot of commands and functions that aren’t on any menu. For example, you can do many kinds of mathematical and trigonometric calculations, and you can have any number of variables in your macro, representing numbers, text, or both. You also have access to special storage units called arrays, which let you refer to many different values with a single name. Special commands like If() and Goto let you “branch” to different parts of your macro (or other macros) depending on various conditions that you specify. You can ask the user for input, and you also have complete control over your clipboards, rulers, styles, selections (even noncontiguous ones), display attributes, and more. We’ll explore all of these capabilities below.

When Macros Can Run

For the most part, macros only run when you choose the macro name from the Macros submenu of the Tools menu (or press a keyboard shortcut you’ve assigned to one of them). Macros are not designed to run continuously in the background while you do other editing tasks in Nisus Writer. However, it is possible to activate macros automatically when certain activities are performed. Several macro names (see Table 12.1) are treated specially such that when any macro has that name, it will execute automatically when the event indicated occurs.

354 Macro Name

Runs automatically when you…

option

option-double-click a word

command

command-double-click a word (note: command-double-clicking performs the Copy to Find command by default if there is no explicitly defined command macro)

CommandOption

command-option-double-click a word

InitInit

open the macro file (runs when you launch Nisus Writer if this macro is in your Nisus Macros file)

InitOpen

open a (non-stationery) file

InitNew

open a new file, a stationery file, or import a (nongraphic) file

SwitchIn

switch to Nisus Writer from another application

InitRevert

choose Revert to Saved from the File menu

Table 12.1. Macros with these names run automatically under the conditions stated.

I should point out that just as macros cannot run in the background within Nisus Writer, they also can’t run while Nisus Writer itself is in the background and another application is active.

If you want to prevent the InitInit macro from running when a macro file is opened, hold down the Command key while you open the file (or launch Nisus Writer).

Macro Writing School

OK, now that you’ve got your feet wet and know what Nisus Writer macros are all about, you’re ready for the major leagues. You are now enrolled in Joe’s Macro Writing School. Instead of presenting the entire macro system in a big chunk, I’ve broken down macro writing into ten fairly short lessons. If you walk through these step by step, you’ll learn how to perform all the major macro functions and get all the background you need to write complex macros yourself.

A Note to the Macrophobic

A lot of people are put off by the idea of writing macros because it seems too much like programming (not some-355thing ordinary mortals should be able to comprehend). Well, I have a secret to tell you. I am not a programmer. Really. I probably could, if it came right down to it, program my way out of the proverbial paper bag—after all, I did have an entire semester of BASIC in high school. But that’s it. However—and this is a big however—I am a geek, and this means that I like to experiment with my computer. I am also lazy, which means I want to avoid extra work whenever possible. These two sterling qualities are, it turns out, just what it takes to perform incredible feats of electronic legerdemain with Nisus Writer’s macros. And in fact, if you can write an outline for a paper, get your kids ready for school, or play checkers, you too have all the skills you need. We’ll walk through everything here step by step, and in no time you’ll be automating your work like you never dreamed you could. Fair enough?

About These Lessons

We’re going to look methodically at the steps involved in creating and debugging macros. We will not cover every single command in detail (though they are all listed in Appendix C for your reference), but instead look at a small number of the macro commands very thoroughly. As I looked through all the macro files I have, I discovered two amazing things. First, there were dozens of commands that were never used at all. Second, there were a few very simple commands (especially Find/Replace) that were used over and over in a staggering number of macros. In fact, the vast majority of my most useful macros involved only simple commands, and nothing like “programming” at all. So we’ll concentrate on the most useful and important commands, and leave the other details in Appendix C for your own exploration later.

Lesson 1: Organizational Details

Welcome to class. Sit anywhere you want, but please, no chewing gum. Our first lesson will get you acquainted with the macro writing environment, the conventions used, and some shortcuts to make your macro writing easier.

356 The Macro Editing Window

When you finish recording a macro, the macro editing window (see Figure 12.5) opens automatically, allowing you to review your macro and make any desired changes. You can also open this window manually to edit existing macros or to add new macros from scratch without recording. To open the macro editing window, choose Edit Macro File… from the Macros submenu of the Tools menu. If you want to add a new macro to your file without recording, choose New Macro Command… from the Macros menu. A dialog box will appear asking you to name the new macro, and the macro editing window will open (if it’s not already open), showing a new, blank macro at the bottom of the window with the name you’ve just entered.

Figure 12.5. The macro editing window.

The macro editing window is very similar to other Nisus Writer windows. You still have access to the Text Bar, and most of the familiar commands on the menus (Tools, Insert, Font, Size, Style, etc.) are still available. You can use the Spelling Checker, the Thesaurus, and Find/Replace within the macro editing window. There are some things you can’t do in this window, like access the Graphics Bar or the 357 Sound Bar, insert headers, footers or footnotes, or print. But for the most part, you can use all the same editing tools you’re used to using. Like the glossary editing window, the macro editing window lists the macro names on the left and the macro text on the right. There is a gap between macros that looks like a page break in the document editing window. If you double-click one of the names on the left, the Macro Name dialog box will pop up, allowing you to rename or delete the macro. Like entries in the glossary window, the macro name is “attached to” the last return character in the preceding macro. So if you want to copy a macro, including its name (either to duplicate it in the current macro file or to paste it into another one), be sure to select the previous return character as well (see Figure 12.6). Since the first macro has no return character preceding it, you cannot copy its name along with the macro text.

Figure 12.6. If you want to copy an entire macro, including its name, select the preceding macro’ last return character, as shown here.

To print out the text of your macro(s), you must first copy it into a regular Nisus Writer document. However, macro text in the special Any Font font will take on the characteristics of the surrounding text where it was pasted. To display and print your macros in the Any Font font, place an opening chevron («, entered by typing Option-\) at the beginning of the macro and a closing chevron (», or Shift-Option-\) at the end. Then select the chevrons and everything between them. You will now be able to choose Any Font from the Font menu, and your macro text will look the same way it did in the macro editing window.

Macros are, generally speaking, insensitive to font, size, and style. A macro written in Zapf Chancery will work just the same as one written in Geneva. By default, the macro editing window uses the Any Font font (which looks like Chicago), because it contains special symbols for keys like Shift, Option, Command, and Delete—but you may use any character attributes you wish. The only times font, size, and style are relevant in your macros are in Find/Replace expressions and when using the Paste command (both of which will be discussed in more detail below).

Every new macro you create will be listed by name on the Macros submenu of the Tools menu. However, new macros will not show up on this menu until you close the macro editing window. Macros are listed alphabetically on the menu and in the macro editing window. Sometimes, however, when you add a new macro (which appears initially at the bottom of the window) and save the macro file before closing the window, it gets “stuck” there. The remedy is to open the macro editing window and close it without saving, then open it again. If that doesn’t work (and occasionally it doesn’t), double-click the name of the misplaced macro to display the Macro Name dialog box, then just click Name without making any changes. Close the macro editing window, and it should jump to the right position.

358 To rearrange the order in which your macros appear, change their names so that their alphabetical order changes. To move a macro to the top of the menu, add a space at the beginning of its name. To move it to the bottom, try a tilde (~). By using other special characters like bullets (•, option-8), you can group macros together without needing very much naming creativity. Note that except for the space character, any special characters at the beginning of a macro name must be included in the name when you call the macro from another macro.

As mentioned earlier, macros are stored in macro files. All the macros in the currently open macro file (only one can be open at a time) are shown in the Macros submenu. If you make changes to the macro file, they are not saved along with your document, but when you quit Nisus Writer or try to open another macro file, a dialog box will appear asking if you want to save the changes. To save changes to the macro file manually without opening a new file, choose Save from the File menu while the macro editing window is in the foreground.

When you first install Nisus Writer, there is no “default” macro file. If you record or create new macros and then choose Save from the File menu (or click Save when asked if you want to save the file when you quit), the macros will be stored in a file called Nisus Macros. This file will be placed in the same folder as your Nisus Writer application.

You can open a different macro file at any time using the Open command or the Catalog. If you want to explicitly create a new macro file, instead of adding macros to the current file, choose New Macro File… from the Macros submenu. The new macro file will contain a single, empty macro (called <Untitled macro>), and you can then record, type in, or paste in additional macros of your choice. Macro files, like any other Nisus Writer document, can be placed on your “Essential Files” list for quick access.

While working in the macro editing window, you still have access to unlimited undos, and as always, they remember the window in which a command was performed. However, as soon as you close the macro editing window, you lose the ability to undo anything you did there (even though the file itself is still open). If you do seriously munge your macro file and then close it, you can recover the previously saved version using Revert to Saved.

359 Macro Editing Shortcuts

If you do more than casual editing of macros from time to time, you’ll soon discover that it’s a real drag (pun intended) to display the Macros submenu of the Tools menu every time you want to use a macro command. Fortunately, there’s a great shortcut to display that menu. Just hold down the Option key while clicking anywhere on the title bar of your document (or any other window except the glossary window or clipboard window), and the Macros menu will pop down (see Figure 12.7). Better still, if you want to edit (rather than run) a particular macro, press either Shift or Command (along with Option) as you choose a macro from the menu. The macro editing window will be opened right where the text for that particular macro starts.

Figure 12.7. The Macros menu, displayed by pressing Option while clicking on the title bar.

Use Comments!

One of the first things any good programmer will tell you—not that I’d know from personal experience, mind you—is that you should add liberal comments to your code (geekspeak for “program”; in our terms, the “code” is the series of instructions that makes up your macro). Comments are remarks that don’t affect the function of the macro in any way, but just give you reminders of what’s going on. In a macro, any time you have two slashes (//) in your text, the rest of that paragraph is considered a comment and not part of the macro itself. This means that you need not put your comments on a line by themselves (though that’s how it’s usually done). You can put as many comments in your macro as you like without affecting its performance.

While most of the sample macros in this book don’t contain comments (since they’re explained in the text), the macros on the CD-ROM do. Take a look at some of those to get an idea of what constitutes “thorough” commenting.

Why use comments? Two reasons. First, they serve as a reminder to you of why you did things the way you did—so you don’t have to figure them out again later. Second, if you are writing macros that somebody else will be using, your comments will help them to understand the reasoning you used. While macros (including comments) can be in any font or style, it’s a good idea to use a different font and size for comments (Geneva 9 is my personal preference) so that you don’t confuse them with the rest of the macro.

360 Using “Execute Selection”

You should also know about the odd command on the Macro menu called Execute Selection. This command will be your close friend (so close that you will definitely want to assign an easy keyboard shortcut to it, like Command-E-S). It lets you test a macro, or part of it, without leaving the macro editing window—just highlight your macro text and choose Execute Selection. The macro editing window will move to the back, and your macro will be immediately performed in the window that was immediately behind it. What’s especially nice about Execute Selection is that you can use it on just a small portion of your macro, if you want to test a certain command without running the whole thing. (If your macro contains any variable definitions (see below) that are used in the selection, be sure to select those definitions.) Execute Selection even works on noncontiguous selections!

The Execute Selection command will work anywhere in Nisus Writer—not just in the macro editing window. You can actually type a command right into your document window (or, for that matter, even in the Find/Replace dialog box or in a clipboard window!) and run it like a macro by selecting it and choosing this command. The thing to keep 361 in mind is that this command always runs the macro in the next window back, not in the current window (unless you only have one window open). So if your macro involves manipulating any text, be sure the text in question is in the window immediately behind the current one, or that first line of the selection is the name of the window in which you want the macro to run.

Lesson 2: Using Menu Commands

As we saw earlier, you can put any Nisus Writer menu command on a line by itself and it will be executed as though the command had been chosen with the mouse. This is one of the easiest things you can do with a macro, yet some very complex macros can be constructed by doing no more than typing in a series of menu commands. Now, you may be wondering which commands you can use for this. In fact, people have written to Nisus asking for a list of all the menu commands that can be used this way. The simplest answer is, “All of them.” That’s right—any command on any menu in Nisus Writer can be used in a macro. If you want a list, all you need to do is pull down your menus and look. In addition to your “regular” menus, you can use named rulers in your Ruler Name menu, clipboards on the Clipboard menu, and items on the Display Attributes menu. But that’s not all. Even commands on menus that you can modify yourself can be used. These menus are File Access (Essential/Last Used Files), Jump To, Glossary, Macros, Windows, defined styles on the Style menu and the Apple menu (main level only). The only exceptions are the Application menu, the Keyboard menu, and the Guide menu.

While it’s true that any command on any menu can be activated from a macro, you should remember that just as in “manual” operation, not all menu choice are available all the time. For instance, the Cut command is dimmed when nothing is selected, and the commands on the Graphics menu only make sense when the graphics layer is active. These same restrictions apply to macros. If you try to activate a menu command at an inappropriate time, Nisus Writer will just beep at you.

When you type in a menu command, be careful to use exactly the same spelling that appears on the menu (including spaces, if any). However, you don’t need to worry about case—typing bOLd will have exactly the same effect as typing Bold. You also don’t need to worry about typing the ellipsis () that comes after some commands, like Print…. There may be cases, though, in which exactly the same command appears on two different menus. For example, there may be a window named Letter and a glossary entry or macro that’s also named Letter. If this happens, you need to 362 specify which command you mean. The way to do this is to type the name of the menu first, then a colon, then the menu command (no spaces), as in Insert:Table or Macros:Update. In this last example, Macros:Update, notice that the Macros menu doesn’t appear on your main menu bar; it’s a submenu of the Tools menu. However, as far as macros are concerned, a submenu is just another menu.

As you know, many of Nisus Writer’s menus can be changed by pressing one or more modifier keys. Modified menu commands can also be used in macros, but with a little more effort. To use a modified menu command, you need to type in the command as it usually appears (without modifier keys), and precede it with the special symbol(s) from the Any Font font representing the modifier key(s) you want to use (see Figure 12.8 for some examples).

Figure 12.8. A macro showing the use of modified menu items. Note that you cannot simply type the command as it appears on the menu when it is modified.

There are several ways to get the modifier keys into your macros:

  1. Use the “watch-me” recording mode. Modifier keys are recorded along with other keystrokes, and you can then copy, paste, move, or modify them as you need. (Note that Command, Option, and Shift are only recorded when choosing a modified menu command or when pressing another key at the same time.)
  2. Keep the modifier symbols in a macro. I keep all these special symbols (which I initially recorded) in a “dummy” macro at the bottom of my macro file. That way, whenever I need them for a new macro, I can copy and paste without having to record again.
  3. Keep the modifier symbols in your glossary. The glossary can easily handle “Any Font” characters, and since 363 you can always access your glossary from the macro editing window, it’s easy to enter them when you need them.
  4. Use the Character Table. Unless you can remember the ASCII codes, you may have to scroll to find them, but using the Character Table in Any Font font is an easy way to access all of the characters you have available.

It goes without saying—but I’ll say it anyway—that I’ve included these special symbols in both the macro and glossary files on the CD-ROM.

Menu Commands with Arguments

While any menu command can be entered on a line by itself, some menu commands can optionally include additional information to specify how they are to be applied or what extra work they are to do. Let’s take a simple example. You want your macro to create a new file named “Report.” How would you do this? Well, you’d undoubtedly begin with the command New, which will (depending on how your preferences are set) open a new, untitled document. But then you’d have to give the document a name. To do this, you’d need to enter Save As, type in the name “Report” using the Key command described later on in this lesson, and then click the Change Name, Don’t Save button, either using its keyboard shortcut (Command-R), or by recording the mouse clicking the button. That’s a lot of steps for a very small result. Luckily, there’s an easier way. Instead of just typing New, type New "Report" and your new file will automatically be named “Report.” The word "Report" after the word New is known as an argument—it is a modifier which supplies additional information to the menu command.

Using arguments with menu commands can save you a lot of extra steps, as you’ve seen, and it can also allow you to perform some fancy tricks with certain menu commands. The commands that take optional arguments are: New, Open, Show Catalog, Save As, Quit, Cut, Copy, Paste, Find/Replace (along with some variations that we’ll discuss in Lesson 3), Jump, and Mark. Many of these commands can take two separate arguments, and some of them can also be used with modifier keys to produce even more combinations. Because there are so many variations on these commands, I won’t give an example of each one here—but if you take a 364 look at Appendix C you’ll find a complete list of all the possibilities. Instead, let me give you a few interesting examples here to try out, and ask you to look in the appendix for additional options.

You must use straight quotes, not smart quotes, to enclose arguments. If you have Smart Quotes turned on, you can type a straight quote by pressing the Command key while you type the quote character.

Pathnames will come up again. A (full) pathname starts with the name of your hard drive (or whatever volume the file is on), followed by a colon (:), then the name of the folder the file’s in, another colon, and the name of the file itself. For files nested several folders deep, just include each folder name in order before the name of the file.

Using Rulers in Arguments

There are a few menu commands (notably Cut, Copy, Paste, and Find/Replace) that, as we have seen, can take as an argument any amount of text. There may come a time when, in addition to (or instead of) text, you’d like to use a ruler as an argument for one of these commands. As you know, rulers are attached to return characters, so any time you use a ruler in one of these commands, a return character must be included too. I’ll show you how to do this with Paste; the rest function the same way. Take a look at Figure 12.9. You’ll see on the first line is the Paste command, followed by two double quotes (to indicate that we’re not going to do a 366 “swap paste”), then an opening quote and a backslash. The backslash within an argument tells it that the return character that follows should not be taken as the end of the command but should be interpreted literally. This return character, then, is the one to which we must attach the ruler. This is done by going to the next line, choosing Paragraph Ruler from the Insert menu, and applying the desired attributes to the new ruler. Finally, the closing quote (on the line with the ruler) completes the argument. When this command is executed, a single return character with the ruler attributes we just set will be pasted into the document.

Figure 12.9. Using a ruler in an argument of the Paste command.

The “margin” settings for your macro editing window may be different from that of your document, and unfortunately, the macro window’s margins cannot be changed. So all ruler settings are taken to be relative to the left margin, rather than absolute.

While the procedure just mentioned will certainly get a ruler into your document, depending on what you’re trying to accomplish, there may be an easier way. The menu command Paragraph Ruler in a macro will insert a blank paragraph ruler (plus a return unless you’re at the beginning of a line). Or, if the ruler you want to use is named, you can simply use the ruler name as a menu command to apply that ruler.

Turning Menu Commands On or Off

You may wish to do something in a macro like making sure the Info Bar is showing. At first, this might seem easy; just type the Info Bar command on a line by itself. But this assumes the Info Bar is not currently visible. What if it is? This command will then turn it off, which is not what we wanted to do. Sometimes you need to be sure that something is specifically “on” or “off” at certain time, regardless of its previous condition. For such occasions, you’ll be delighted to know that some menu commands can take as an argument either "on" or "off" (as in Info Bar "on"). This is true of any menu command which can be “toggled” on and off in your document by choosing it and re-choosing it; commands in the “on” mode have a checkmark next to them on their menu. Examples of commands that can be “on” or “off” are Info Bar, Space, Tab & ¶, Headers/Footers, and any style. (The command Show Clipboard can also take an "on" or "off" argument, even though it does not toggle on or off using the menu command.) Here are some sample lines from a macro that show the usage of the "on" and "off" arguments:

367

Info Bar "off"
Sound Bar "on"
Show Clipboard "on"
Italic "off"

Recording versus Typing

You can get menu commands into Nisus Writer macros either by recording what you do or by typing. In most of these lessons, I assume you’ll be typing in your commands, because it allows you to see (and correct) what you’re doing as you enter the macro, and because it gives you a lot more flexibility than recording your macros. However, there are still times when even an advanced user will want to record, rather than type, a macro—or at least record a few steps, which can then be pasted into another macro. In general, use recording when:

The Key Command

Macros can simulate the effect of typing using the command Key, as we saw earlier when we recorded our first sample macro. To use Key, type it at the beginning of a line, then type a space, then type in the actual text you’d like to be entered. No quote marks are needed, unless you want the quote marks themselves to be typed. The space is, however, obligatory. To simulate pressing the return key (which works both in your document window and in dialog boxes where this has the effect of clicking a button), type Key followed by a space and press Return to make that the entire contents of the line. To simulate typing the tab key, enter Key followed by a space and a tab.

The Key command can also “type” the modifier keys Command, Option, and Shift (but not Control); the arrow keys; and the Delete (or Backspace) key. It can even type 368 combinations of these keys, like Command-P, Shift-Option-J, or Option-Up Arrow. This means that, among other things, you can use a macro to activate a keyboard shortcut you’ve defined in lieu of entering the command itself. The modifier keys are represented in your macro editing window by special symbols that are part of the Any Font font. They always appear after the word Key but before the characters they modify (if any). To get the special symbols into your macro, you can use any of the techniques described above under “Menu Commands with Arguments.”

Examples of the use of Key are shown in Figure 12.10. Try typing this in, exactly as written, to test the various permutations of the command—then experiment with your own variations.

Figure 12.10. Examples of the use of Key in a macro.

You can record keystrokes that activate multi-key keyboard shortcuts, like Command-C-A-T for Show Catalog. But be careful when using several keyboard shortcuts in a row, because when playing these back, Nisus Writer does not pause between them. So if you have a multi-key shortcut defined that is the same as two or three individual shortcuts in a row, the macro will always play back as though you were pressing the longer sequence.

Lesson 3: Find/Replace in Macros

Without question, the most frequently used macro command is Find/Replace. Why? Two main reasons. First, it’s very easy to use—after all, you already know how to use PowerFind and PowerFind Pro; this is just more of the same thing. Second, it’s very powerful. Virtually any kind of document reformatting can be done using nothing more than a series of Find/Replace commands. You already know this, too—macros simply give you a way to automate the searches further. Because of this, our next lesson in Macro Writing School 369 is how to use Find/Replace in macros. If you learn nothing else—branching, variables, stacks, or whatever—learn this.

One of the most highly praised new features in Nisus Writer was instigated by yours truly: a button in the Find/Replace dialog box called Macroize. It takes whatever (Normal, PowerFind, or PowerFind Pro) expression is currently in the Find/Replace dialog box, along with any options on the Find/Replace menu, and creates the appropriate line of a macro for you automatically. So if all the syntax and options you‘re about to read about still strike you as a little obscure, save yourself the effort and just click the button!

A Basic Find/Replace

As we saw in the last lesson, Find/Replace is one of the menu commands that can take arguments. In this case, there will usually be three arguments: what you’re looking for, what you want to replace it with, and what the Find/Replace options are. Let’s look at a basic example:

Find/Replace "these" "those" "aA"

This reads, “Find the word ‘these’ and replace it with the word ‘those’ using the options a (Replace All) and A (Whole File).” (We’ll return to discuss the available options shortly.) If it’s helpful for you in reading and constructing Find/Replace commands, you can actually put words between the arguments like so:

Find/Replace "these" with "those" using "aA"

Anything between the arguments is ignored by the macro, but it can make it clearer to you what each argument is for.

You are not limited to using literal text in your Find/Replace macro commands—you can also use PowerFind or PowerFind Pro expressions. This means that you can do anything the Find/Replace dialog box can do from within a macro, without actually having to display the window, type in Find and Replace expressions, and click buttons. To enter a PowerFind expression into a macro, you must first build it out of metacharacters in your Find/Replace dialog box as usual, then copy and paste it into the macro. The metacharacters must still go between quotes, and in addition, you need to use the option e, which means “this is a PowerFind expression” (PowerFind was originally called “EasyGREP,” which accounts for the “e”). Other options may be added as needed. Figure 12.11 shows the way a PowerFind expression will look in the macro editing window.

370

Figure 12.11. A macro command containing a PowerFind expression.

You can apply fonts, sizes, and styles to parts of your Find and Replace expressions in the macro editing window just as you can in the Find/Replace dialog box.

Most often, though, you’ll probably want to use PowerFind Pro expressions in the macro window, since they don’t require any copying and pasting, and are a lot more flexible than PowerFind. (Also all the examples in this book and on the CD-ROM use PowerFind Pro!) To tell the macro that what you’ve entered should be interpreted as PowerFind Pro metacharacters and not as literal text, you’ll use the option g (for “grep”). Figure 12.12 shows the same command we just looked at, this time as a PowerFind Pro expression.

Figure 12.12. A macro command containing a PowerFind Pro expression.

Find Options

Since you won’t be displaying the Find/Replace dialog box or the Find/Replace menu, you need some way of telling your macro which Find/Replace options to use in a given search—like Ignore Case, Whole File, and so on. Each of these options is represented by a single character (see list below), and when this character is included in the “options” argument, the corresponding option will be used for that particular search. The list of options you supply may be short or long, depending on the specificity you need, and options can be listed in any order. We’ve already seen the e option meaning “PowerFind” and the g option meaning “PowerFind Pro.” A full list of options is found in Appendix B, but Table 12.2 gives you a basic list to get you started.

371 Option

Argument Character

Ignore Case

i

Don’t Ignore Case

-i

Whole Word

w

Not Whole Word

-w

Whole File

A

Don’t Wrap Around

-A

Search All Open Documents

G

Search Front Window Only

-G

PowerFind

e

PowerFind Pro

g

Literal Text

-e or -g

Find Text Only

o

Replace Text Only

O

Replace All

a

Terse (don’t display a dialog box telling how
many replacements were made)

t

Terminate (exit the macro if nothing is found)

T

Use options as set in Find/Replace dialog box

* (must be first in the list)

Table 12.2. A partial list of options for Find/Replace commands in macros.

The default options Nisus Writer assumes are -e (literal text), -G (front document only), i (Ignore Case), o and O (Find and Replace text only), t (terse), -w (not Whole Word), and A (Whole File). In other words, if you want to use any of these options, you don’t need to list them explicitly. You only need to list the options that differ from the defaults (though in this book, just to make things clearer, I’ll frequently list more than is required). Any options you set will be used for that command only, and then the defaults will apply again.

Here are a few sample Find/Replace commands, with a variety of options, along with explanations so you can see what’s happening.

While all the above examples used three arguments, you can also use the Find/Replace command with two arguments or four arguments. If you have only two arguments (as in Find/Replace "this" "that"), the first one is assumed to be the Find expression and the second one, the Replace expression. Since there is no “options” argument, the default options are used. If you have four arguments (as in Find/Replace "this" "that" "gaAt" "Letter"), the fourth argument is taken to be a window name. Use this argument to restrict your search to a particular window.

Variations on the Find/Replace Command

If you have been experimenting with the Find/Replace command in macros, you may have discovered that there doesn’t seem to be any way of performing a Find All or a Find Next 373 without replacing anything. There is a way of doing it, but it does not involve changing the options argument—it involves changing the Find/Replace command itself. Recall from Chapter 11 that by pressing various modifier keys, the Find/Replace command on the Tools menu can be changed to Find Next, Find All, and several other options. It so happens that you can use any of these commands in a macro as well, in place of the Find/Replace command. For example, the command Find All "the" will find and noncontiguously select all instances of the word “the” in your document; Find Next "the" will find and select just the next instance.

The variations on the Find/Replace command that can be used in macros are an exception to the usual way of entering modified menu commands. With most modified menu commands, you would have to enter the special symbol for the Shift, Option, and/or Command key followed by the command name that appears on the menu when no modifier keys are pressed. With these commands, however, no special symbols are needed.

The commands that can be used in this fashion are: Find Next, Find All, Find in Selection, Replace With, Replace All, and Replace in Selection. The commands Find Next, Find All, Find in Selection, and Replace With can take one, two, or three arguments. If there is just one argument, it is taken to be the “Find” (or “Replace”) expression. If there are two arguments, the second one is the Find/Replace options to be used, as listed above (default options are used if none are specified). And if there are three arguments, the third one is taken to be a window name. The commands Replace All and Replace in Selection require both a “Find” argument and a “Replace” argument, with optional “options” and “windows” arguments. Here are some examples of modified Find/Replace commands:

374 Recess Story: A Tale of Two Dialects

At this point I need to mention something that it pains me to say. I was hoping to avoid this subject altogether, but I couldn’t find a way. O.K. (deep breath)—the Nisus Macro Language (yes, it is a “language”) is actually composed of two mutually exclusive “dialects.” Unlike other programming or scripting languages, there are two distinct varieties of commands you can use in writing Nisus Writer macros, and if you mix them in the wrong way, your macros won’t work. Now, I hasten to add that for many people, this distinction will make no difference at all (as we’ll see). But it is important to be aware of it and to keep it in mind when writing macros.

The Menu Command Dialect consists of—you guessed it—menu commands (with or without arguments). Any command on any menu in Nisus Writer can be typed on a line by itself in a macro; the set of all these menu commands constitutes the Menu Command Dialect. In other words, it’s what we’ve talked about so far. This dialect also includes a few special items that don’t actually appear on a menu. First is the word Key, which as we saw earlier, is used to type literal text (including return characters) and keyboard shortcut sequences. Next is the command :1, which as you will see below is used to display a dialog box, optionally with user input. Third are the Clipboard commands (also discussed below), \CC and \C0 through \C9. And the commands click (to simulate a mouse click) and beep (to play the system alert sound) are also part of the Menu Command Dialect. Every other command is part of the Programming Dialect.

So what difference does it make that there are two dialects? Well, the significance is that you can’t have commands from both dialects on the same line. Ever. Now, in most cases, you’ll only have one command per line anyway, so this won’t matter. But sometimes you need to combine commands, and this is where the problem arises. Fortunately, there is always another way to accomplish the same task. For example (Programming Dialect commands are underlined):

375 Bad (mixing dialects)

Good (not mixing)

If(count>5)Copy If(count>5) MacroCopy
:1 "The number is:" 'myVar * 2' clipboard = myVar * 2
:1 "The number is:" '\CC'
Copy; x = x + 1 Copy
x = x + 1

If you can keep in mind while you write macros that mixing dialects is a no-no, you’ll be in great shape. And if you ever get confused as to which dialect something’s in, consult Appendix C for a complete reference. Having said all of that, we’re going to turn our attention primarily to Programming Dialect commands in the next lesson and the ones that follow.

Lesson 4: Variables

If your mathematical background includes at least a junior-high algebra class, you know what a variable is—a letter that can stand for any number. The exact value of the variable at any given time depends on the context, but the great thing about variables is that you can use a single pattern to represent a lot of specific cases. In Nisus Writer macros, too, variables are quite handy, because they allow you to make general statements that will apply to a lot of specific cases. They also let you perform calculations, count, and much more.

Variables in macros go beyond the x’s and y’s you used in algebra. For one thing, variable names are not limited to just one letter—they can include many letters, uppercase or lowercase (or even numbers). So the word count could be a variable name, and so could Joe7. Also, variables can store not just numbers but also strings of alphabetic characters, the time or date, or a “true/false” value. Let’s take a look at what’s involved in using variables in macros.

376 Variable Names

For starters, every variable has to have a name. You can name a variable pretty much anything you want, but it’s a good idea to give it a name that you can remember easily, and that has some relevance to what it represents (so TicketCount and Input are good variable names, w34_A7ls and xyz are not so good). There are just a few rules you need to be aware of:

Variable Types

In Nisus Writer there are five different kinds of variables, corresponding to the five data types the macro language can work with—long integers, double-precision floating-point numbers, strings, date/time, and Boolean (true/false) data. Any given variable name can only have one type in a particular macro. Let’s look more carefully at each type.

The reason we need to be so picky about what “type” of variable we have is that only certain operations can be performed on certain kinds of variables. For example, you can take the square root of a number, but not of a letter. So any time you use a variable, you have to be aware of what its type is, and what operations are and are not permissible for that type.

Defining Variables

So how do you give a variable a name, determine its type, and give it a value? Very easily—in fact, it’s all done in a single step. This step can be referred to as “defining” a variable, “declaring” a variable, or “instantiating” a variable. In some programming languages—so I’ve heard—you can’t use a variable until you have named it and assigned it a particular 378 type. In Nisus Writer, variables automatically “figure out” what their type is based on the value they’re assigned when they are first used. This all-in-one process of naming, getting a data type, and getting a value, is known as autoinstantiation. Let’s look at some examples of how this works:

Variables can change their values repeatedly, but they will keep their type throughout the duration of the macro, unless explicitly cleared using a command like free (see Appendix C for details).

Your first use of a variable in a macro must give it some specific value, so that it can figure out what type it’s supposed to be. A statement like count = count + 1 would not be O.K. as an instantiating statement, because count can’t tell what its starting value should be.

Local and Global Scope

When a macro ends, any variables that were used in that macro are erased. So the next time you run a macro, you start with a clean slate. Any variables you want to use must be defined again, and whatever values a variable had before are forgotten. A variable whose value is remembered only in 379 the current macro is said to have local scope. And unless you specify otherwise, all variables will be locally scoped automatically. If one macro calls another, any local variables that were used in the first macro retain their value in the second macro. The macro values are only cleared when the original macro—where the variable was defined—ends.

But there may be times when you want a variable to remember its value even after the macro that defined it has stopped. You can give a macro global scope, so that it will retain its value until you quit Nisus Writer, and any macro that runs after the variable is initially defined can access the global variable without having to redefine it. To make a variable global, just add an extra line before its definition with the command global followed by the variable name:

global CupOfSoup
CupOfSoup = "Cream of Chicken"

There’s actually quite a bit more that could be said about local and global scope. And there are a number of commands that let you override the default behaviors of both types of variables, clear them at any time, and so on. While it’s important to know how long variables retain their memory, you won’t need to worry further about global and local commands unless you are writing pretty complex macros. But never fear—Appendix C contains a complete list of macro commands that you can refer to when the time comes.

Numeric Variables

When you have a numeric variable (either “long” or “double”), you can use it in calculations, variable assignments, and so forth as though it were a number. The most important symbol you need to know about when working with numeric variables (or any variable, for that matter) is the equal sign (=). This means “is being assigned the value”—for instance, abc = 37 says “the value 37 is hereby assigned to the variable abc.” You can also use = in conjunction with mathematical operators—for example cde = 8 + 5 sets cde equal to 13. You can even use parentheses—nested to any level—in calculations, and you don’t need to worry about 380 preceding them with backslashes as you do in PowerFind Pro. So if you run this macro:

value = (2 + (5 * 3) / 5 - (4 - 2)) * 3
clipboard = value
:1 '\CC'

it will give you a result of 9, which is just what you’d expect. Notice that I have added spaces around all the mathematical operators to make the expression more readable, but the spaces are not required—spaces are ignored in numeric calculations.

You may need to assign the value of one type of variable to a variable of another type. For example, let’s say you have a “double” variable called pi whose value is 3.1415926, and you assign this value to a variable of type “long” called pizza, using the command pizza = pi. When a “double” value is assigned to a “long” variable, everything past the decimal point is truncated—no rounding occurs. So in this example, pizza would be equal to 3. But if pi had started out being 3.9, pizza would still end up equal to 3.

Strings

Once a variable has a string value assigned, there are lots of neat things you can do with it. You can add more to the end of the string, take out parts of it, look at what the various characters are, and compare one string to another. Here are some activities you can try:

Date and Time Variables

Date and time variables are interesting because they share properties of both numbers and strings. Nisus Writer has a number of predefined date and time variables (e.g., date, DayOfWeek, year) that store different parts of the date or time. When you set another variable equal to one of these, your variable also takes on the date/time type. Date/time variables can be treated like numbers. For example, you can compare two dates as you would compare numbers, and the later date will evaluate as the larger number. This macro will give you a result of true:

vacation = date + 12
work = date + 9
schedule = vacation > work
clipboard = schedule
:1 '\CC'

382 But you can also treat date/time variables like text. For example, if you assign the date to a string variable, the string will have the text form of the date as its content (the format is determined by the preference you set with the Date Format… command on the Variable Stamp submenu of the Tools menu). In this example, the macro will display the date as text:

RightNow = ""
RightNow = date
clipboard = RightNow
:1 '\CC'

Quotes and Other Mysteries

As we have seen, strings go inside (double) quotes—that’s how a macro can tell they’re strings and not variable names, commands, or who knows what else. In Nisus Writer macros, double quotes always mean, “This is a string.” That being the case, how do you get the quote character (") into a string? Let’s say we want the string quote to have the value A "fine" time. If we use a statement like quote = "A "fine" time" then the macro will get confused because it doesn’t know what to do with all those quotes. Next we might try something like quote = "A " + """ + "fine" + """ + "time"—that is, putting a quote character itself within quotes, and separating that out as another string. Unfortunately, that doesn’t work either. But it can be done! The trick is to use the ASCII value of the quote character directly instead of typing the character. It so happens that the quote is ASCII 34. So we can use the special command NumToChar (number to character) to make the conversion. It works like this:

qm = NumToChar(34)
quote = "A " + qm + "fine" + qm + " time"

and that, in fact, does the trick. Use NumToChar any time you need to put a quote mark into a variable or onto the clipboard without actually copying it from your document.

These acrobatics are only required in the Programming Dialect. In the Menu Command Dialect, if you want to include quotes in an argument, just type them twice within another set of double quotes—for example, to find and select the next quote mark, use the command Find Next """".

383 If there’s a variable that you’d like to use with the same value in all of your macros (like qm above), make it a global variable and assign it a value in your InitInit macro. That way it will assume that value automatically whenever that macro file is opened. The macro might read global qm; qm = NumToChar(34).

There are also times when you’ll need to use single quotes around an expression. For arguments to Menu Command Dialect commands, single quotes mean that the macro evaluates the expression before doing whatever the command is. That is, it turns any metacharacters into real characters, and in the case of clipboard variables (see the next lesson), replaces the variable with the contents of the clipboard. For example, Paste "" 'horse \t buggy' will paste the word “horse” followed by a tab and the word “buggy.” But the command Paste "" 'horse \CC buggy' will paste the word “horse” followed by the contents of the current clipboard and the word “buggy.”

Lesson 5: Using the Clipboards

We already know how to use the Cut, Copy, and Paste commands in macros, how to switch clipboard numbers, and even how to move the contents of one clipboard to another. But in addition to being temporary storage places for things that you’re moving around your document, clipboards can be thought of as a kind of variable. Because of this fact, there are special ways of dealing with the clipboard in macros that give you some additional capabilities over regular menu commands. We’ll look at some of the other uses of clipboards in macros in this lesson.

Whenever you do a Cut or Copy (either manually or as part of a macro), you store something on the clipboard. The contents of the current clipboard can be used within a macro by using the word clipboard as though it were a variable. Here are some examples:

384 Since clipboard is a variable, you can also put things on the clipboard without having to cut or copy. And because it is part of the programming dialect, the things that go on the clipboard can be the values of variables, mathematical expressions, and so on. For example:

There are times, though, in which you can’t achieve the desired result using the variable clipboard, because in some contexts (like arguments), what is required is a string rather than a variable. For instance, you may want to name a new document with the string that’s on the clipboard. If you tried to use the command New clipboard to do this, Nisus Writer would have no idea what you mean. And if you tried New "clipboard" the new file would be named clipboard! So you need a way to access the clipboard as a string instead of a variable. As you’ll recall from working with PowerFind Pro, the metacharacter for “Current Clipboard” is \CC. And as we saw in the last lesson on variables, using single quotes around an expression causes it to be evaluated before it is used. So if you put it together, you get the expression '\CC' which means “the contents of the current clipboard.” '\CC' can be used anywhere a string in double quotes can—including as an argument to commands like Find/Replace, and Jump To. For example:

As in PowerFind Pro, not only '\CC' but also '\C0' through '\C9' can be used this way to access the contents of all ten clipboards. To switch the number of the current clipboard, you need to use one of the (Menu Command Dialect) commands 0 through 9 on a line by itself.

385 Interacting with the User

There are several ways of interacting with the user during a macro. The reason they are included in this lesson is that they frequently make use of the '\CC' command we’ve just learned.

The first thing you can do is present a simple alert dialog box containing text of your choice. To do this, use the command :1 followed by the text you want to appear in the dialog box, enclosed in straight quotes. For example, :1 "Hello there!" will display the dialog box in Figure 12.13. To use the contents of the clipboard as the displayed text, use the command :1 '\CC'. A typical use of this construction is to display the value of some variable, as in the following example:

Var = DocPath
clipboard = Var
:1 '\CC'

All alert dialog boxes displayed in this fashion have exactly one button—OK—and nothing else will happen until the user clicks this button.

Figure 12.13. A simple alert dialog box created in a macro.

You can also use this alert as a means of getting input from the user at any point in your macro. All you need to do is add a second argument (that is, a second pair of straight quotes), and a text entry field will be added to the dialog box. Your command might then look something like :1 "Enter a name." "" (see Figure 12.14). If you want to provide a “default” answer that will be filled in automatically (so that the user just has to click OK if that’s the desired response), place that text 386 between the second set of quotes: :1 "Enter a name." "Bob". The contents of the clipboard can be used as either argument, by substituting the '\CC' statement for the quoted argument (as in :1 "Enter a name." '\CC'). You can even include the contents of the clipboard within a string of text by surrounding the entire text with single quotes—for example, :1 'What’s so great about \CC? I’m telling you, \CC is not the answer.' 'But I like \CC!' (observe that since the entire argument is in single quotes, you don’t need single quotes around \CC too).

Figure 12.14. An alert dialog box with a text entry field allows you to get input from the user during a macro.

When your alert dialog box includes a text entry field, whatever the user types in is placed on the current clipboard when OK is clicked. If the text entry field is left blank, then the clipboard will be cleared. This macro gives you an idea of how the :1 command gets and processes input:

:1 "Enter a color." ""
Col = clipboard
:1 "Enter another color." ""
Sentence = "Roses are " + Col + ", violets are " + clipboard + "."
clipboard = Sentence
:1 '\CC'

Though we mentioned it before, it’s worth repeating: the :1 command is part of the Menu Command dialect, not the Programming Dialect. This means that you can’t use a variable name, mathematical expression, or the like as an argument to :1—statements like :1 Wanda or :1 cos(3) will produce an error message.

Before we end this lesson, I wanted to mention briefly two other ways of interacting with the user. First is the Speak command (again, part of the Menu Command dialect). Your macro can speak any text as an alert. You simply type the text you want spoken as an argument of the Speak command: Speak "How very nice to be working with you again." Or, to speak whatever is on the clipboard, use '\CC' (with or without additional text)—for example, Speak 'You are very \CC'. Make sure your computer’s volume is turned on before using Speak—there is, annoyingly, no macro command to adjust the volume! Also, be aware that while the speech engine’s 387 pronunciation is far from perfect, you can often make it sound a lot better by spelling out words the way you think they should sound. For example, the command Speak "Now reformatting your hard drive" doesn’t sound very convincing, but if you change it to Speak "Now reeformatting your hartdrive" you’ll find the inflection much more natural. Try it!

And finally, there is the simple command Beep. This command, which is also part of the Menu Command Dialect, will simply play your currently selected system alert sound once.

Lesson 6: Labels, Subroutines & Loops

So far, all of our macros have run in linear order from start to finish. But there are times when you need more flexibility than that. For one thing, you may want a macro to repeat some activity multiple times (without having to copy the same part of the macro over and over). For another thing, you may want all or part of your macro to run only under certain circumstances—e.g., do one thing if the user gives one type of input, and another thing if the user gives a different type. And of course, if you are trying to break down your macro into small chunks to work with, it would be helpful to have an easy way to label, refer to, and run any particular chunk. In this lesson we’ll talk about the mechanisms that let you do all of these things.

Labels and the “Goto” Command

A label is a word whose only purpose is to mark or identify a certain spot in your macro that can be “jumped to” easily. A label is created by typing a single word, followed by a colon, on a line by itself (no spaces allowed). Label names are completely arbitrary, and you can use any word you want. When you want to jump to a labeled part of a macro, type Goto followed by the label name (without the colon). Here’s an example you can type in and try.

Select All
Goto France
Bold
Italic
France:
18
Red

388 In the first line, the Select All command is performed. In the second line, the command Goto France tells the macro to go to the line labeled France: and continue from there. So it skips the commands Bold and Italic and goes on to make the text 18 points and red. Of course, there wouldn’t be any point to including extra lines in a macro if you’re always going to skip over them—that’s where conditionals come in, which we’ll talk about next. But there are just two simple points to absorb here. First, you make a label by putting a word, followed by a colon, on a line by itself. Second, you jump to the label using the Goto command.

Conditionals

In some cases, it’s O.K. for your macros to press on with their assigned tasks blindly. Often, though, you will want for some part of your macro to run only if certain things are true—only if your document contains a certain word or only if the user responds a certain way to an alert, for example. In other words, you’d like the macro to be able to check one or more conditions—states that may be true or false—and act accordingly. The statement in Nisus Writer’s macro language that lets you do this is the If() conditional test. It is often used in conjunction with Goto, but as we’ll see it has other uses as well.

The If() statement allows you to say, in effect, “If such-and-such is the case, then do this.” The condition, or that which is being checked for its value, is what goes in parentheses. When a macro comes to the If() statement, it looks at the condition and evaluates it—determines what its value is (true/false, a number, or a string). If the condition evaluates to “true” (in the case of a logical statement), a non-zero number (if it’s a mathematical expression), or a non-empty string (if it’s a string variable), then whatever comes after the parentheses will be executed as a (programming dialect) macro command. If the expression evaluates to “false,” zero, or an empty string, the command after If() will simply be ignored; there is no “Else” statement in Nisus Writer. In the examples that follow, I’ll concentrate on the “true/false” evaluation.

You can also say, “If such-and-such is not true, then do something.” To create a negative “If,” use an exclamation point (!) as the first character inside the parentheses. For example, the command If(!x == 3) goto Egypt says, “if it’s not true that x is 3, go to the line labeled Egypt.” This is the same as saying If(x != 3) goto Egypt.

Be careful not to include a command after If() that isn’t part of the programming dialect. For the record, the command that follows If() cannot be a menu command, the Key command, or the alert (:1) command.

Let’s look at a really easy example: If(4>3) Goto AddNumbers. This command says, “If it is true that 4 is greater than 389 3, then go to the line labeled AddNumbers: and proceed from there.” Since we know that 4 is always greater than 3, the condition is true and this line would always make the macro jump to the AddNumbers: label. Needless to say, there’s very little point in making a conditional statement if whatever you’re evaluating is always true (or always false). So what you want to put inside the parentheses is a statement having a value that can change. If we change the statement to If(x>3) Goto AddNumbers, then the command Goto AddNumbers will be executed or not, depending on what value the variable x has at the moment. Another form the conditional statement can take is testing what’s on the clipboard. The statement If(Clipboard == "Suzie") Goto MainLoop first determines whether the current clipboard’s content is the name “Suzie” (and nothing else), and then if so, jumps to the MainLoop: label.

Notice that in If() constructions, we need to use double equal signs (==) instead of a single equal sign (=). In Nisus Writer’s programming dialect, = means “is now being made equal to,” and is used to assign a value to a variable—for instance, a = 2 means “I hereby set a to the value of 2.” On the other hand, == means simply “is equal to” in the ordinary sense, and can be used as part of a test to come up with a “true” or “false” value.

With this in mind, let’s return to the macro we used above and make some modifications:

Select All
:1 "Where should I go?" ""
if(clipboard != "France") goto Italy
   18
   Red
   goto MacroEnd
Italy:
   Bold
   Italic
MacroEnd:

First, after the Select All command, we give the user an alert and an opportunity to give some input. If the user types in anything other than France (note the != sign), the macro will skip to the Italy: label and make the text bold and italic. But if the user does type in France, the condition will not be 390 met, so the Goto command will not be performed. The macro will continue on to the next line, making the text 18 points, then red. When it comes to the line that says goto MacroEnd it will skip to the last line of the macro, and finding nothing left to do, it will quit.

While the If() statement is most often used to evaluate the clipboard or a variable, then jump to another part of your macro, there are other things you can do with it. Here are a few examples just to give you an idea, followed by “plain English” translations:

Subroutines

In traditional programming, a subroutine is a kind of “program-within-a-program.” Typically the program is performing a series of steps, then it comes to a command to perform a subroutine. It jumps to the part of the code containing the subroutine and runs that. After the subroutine has finished, the program automatically goes back to where it left off and continues its work. Some programming languages have a special command like “GoSub” which specifically means, 391 “go and do this other thing, but when you’re done, come back!” Nisus Writer accomplishes the same thing in a different way: a “subroutine” can simply be another macro. To have one macro activate another, put the second macro’s name on a line by itself (after all, it is a menu command), and when the second macro is finished (unless a Stop command is encountered), the first macro will pick up where it left off. When one macro sends a command to run another macro, it is said to call the second macro. Figure 12.15 gives an example of a subroutine.

Figure 12.15.“Subroutines” in macros: one macro activates another.

A macro can also call itself. If a macro comes to a command which is its own name, it will skip back to the top of the macro and begin performing each command again. This is a kind of “loop”—but see below under “Loops” for more advanced ways.

There is another sense of the word “subroutine” which is a little less exact, but also quite important. You can think of a subroutine as simply a smaller portion of a macro that does a particular job, whether or not you actually return to the place you left off later. Subroutines in this sense are invariably accessed using the Goto command, usually in conjunction with If(). When a macro chooses between one “path” (subroutine) and another based on some condition, this is known as conditional branching. Macros can include any number of branches, and sometimes the path the macro follows can become quite complex. But note that you cannot say If(test) Goto MacroName (or If(test) MacroName), since commands calling other macros are considered part of the Menu Command Dialect.

When working with macros that involve calling other macros or performing these “pseudo-subroutines,” it’s important to know how to end a portion of your macro (and optionally go on to another portion). We’ve already seen the 392 Stop command, which stops not only the current macro, but also any macro that may have called the current macro. Another way to stop a macro is to use the Exit command. It will exit the current macro, but if another macro had called it, it will go back to where that macro left off and allow it to continue. The third way to end a subroutine is to use the Goto command again. In addition to jumping to another portion of your macro, you can have Goto jump to a label that appears at the very end of your macro to end the macro without using Exit or Stop (as we saw a short while ago). The following fairly pointless macro illustrates some ways of performing one sequence of activities or another, based on user input:

:1 "Go to bed or watch a movie?" "bed"

if(clipboard != "movie") Goto Bed
  :1 "What do you want to do now?" "study"
  if(clipboard != "study") goto FinishNext
    :1 "What is your favorite subject?" "philosophy"
    clipboard = "I love to study " + clipboard + "!"
    :1 '\CC'
  FinishNext:
  Goto Finish
Bed:
  :1 "Good night!"
  Goto Finish

Finish:
:1 "This macro is about to end."
Exit

There are a few things you should notice here. First, the macro is arranged to run in linear order, no matter what the user chooses. Second, some seemingly superfluous labels and Goto commands have been used; the idea is to have them there so that the macro could be expanded or added to later without a lot of reworking. Try to figure out the path this macro would follow given different combinations of input, then try running it to test your skills!

393 Loops

A loop is part of a macro (or the whole thing) that is repeated. There are any number of things you might want to do repeatedly, especially if they involve getting new input from the user each time. Now that you know how to use Goto, it should be pretty obvious how to make a loop (at least a simple one): end a labeled portion of your macro with a Goto command that refers to the same label again. So you might have something like this:

:1 "Where should I go?" "France"
If(Clipboard == "France") Goto France
:1 "Goodbye!"
Exit

France:
:1 "What is your favorite number?" "5"
:1 'No kidding! \CC is my favorite number too!'
Goto France

There’s just one teensy problem with this: the loop never ends! So the problem with loops is not so much how to get into them, but how to get out!

The key to getting out of loops is to include some kind of “hook”—a conditional statement or other command that will exit the loop (or the entire macro) under certain conditions. Let’s look at a few ways to do this. One way is to ask the user, each time through the loop, whether the macro should continue. So we could modify the subroutine like this:

France:
:1 "What is your favorite number?" "5"
:1 'No kidding! \CC is my favorite number too!'
:1 "Do it again?" "No"
If(Clipboard != "No") Goto France

In other words, we have to get permission in order to continue—otherwise, we quit.

Another way is to use a counter (discussed in more detail in Lesson 7) to restrict the loop to a given number of 394 passes. This works by adding 1 to a variable each time through the loop, and including a command that stops the macro if the variable gets to a certain number. For example:

x = 0
France:
x = x + 1
:1 "What is your favorite number?" "5"
:1 'No kidding! \CC is my favorite number too!'
If(x < 5) Goto France

Here, we start out by giving x a value of 0 before the loop, and each time through the loop we add 1. When x gets to 5, the macro ends.

The last way of adding a hook to a loop (sounds like Velcro, doesn’t it?) is to use the "T" option in a Find/Replace command. "T" means “Terminate the macro if nothing is found.” So if your loop is doing a series of replacements and you want the macro to end when it runs out of things to replace, use the "T" option after the Find/Replace command.

Branching conditionals, subroutines, and loops are very powerful, and also lots of fun to experiment with. After some practice, you’ll be able to thread your way through very complex activities without any trouble at all. But remember, it does take practice to get the knack of how to break things up, where to put Goto commands and so forth. Be sure to check out the many macros on the enclosed CD-ROM for samples of these constructions. And one final thought: if all else fails, try sketching a flowchart of the path you want your macro to take before actually writing the macro. You may find, as I do, that this helps you to organize the flow of your thinking more easily (as well as catch some bugs before they happen).

Lesson 7: Working with Numbers

This is going to be a fairly short lesson, since we already talked quite a bit about numerical variables in Lesson 4. However, there are a few other important things you should know about numbers—specifically, counting, doing math, and using random numbers.

395 Counting

One important use for numeric variables is to act as counters—variables that increment (or decrement) with every pass of a loop. There are several reasons you may want to keep track of how many times a loop has been run. For one thing, you may want the loop to execute only a limited number of times. Using a counter, you can add 1 to the value of a variable each time through the loop, and then check to see if it has reached your limit. If it has, you can tell the macro to exit or branch somewhere else. Another reason is to keep track of your progress—letting you know how many times a macro loop has run so far (using Speak, perhaps).

To make a counter, assign a number (usually 0 is best) to a variable. Make sure this assignment is done outside the counting loop, or it will be reset each time! Then, add a label to begin your loop, and enter a command like Counter = Counter + 1. This will add 1 to whatever the counter’s previous value was. Then, include a command to do something with that number, like report it to the user or check to see if it’s gotten too high. Here’s a brief sample macro that does both, by counting out loud from one to ten:

Counter = 0
loop:
  Counter = Counter + 1
  clipboard = Counter
  Speak '\CC'
If(Counter < 10) goto loop

Speak "I’m done now."

Math

Nisus Writer’s macro language offers a full range of mathematical and trigonometric functions that can be used to perform nearly any kind of calculation within a macro. These are all listed in Appendix C. Most mathematical operations can be performed using familiar operators (symbols that indicate an operation is taking place) like +, -, *, and /. The mathematical functions, however, generally ask for one or more 396 arguments in parentheses, for example sqrt(16) or fmod(5,3). Functions and operators can be combined freely in a given statement, for expressions like y = sqrt(3+13) / floor(18.239) * log(5*5) or x = 12 * sqrt(fmod(3,5)). Since math in Nisus Writer macros is so straightforward, I will not go into any more detail here, except to remind you that all mathematical operations are considered part of the Programming Dialect, and will produce an error if you try to put them on the same line as a Menu Command Dialect command.

Random Numbers

There are times when you’d like a macro to behave a little unpredictably. On such occasions, you can use either the function random, which chooses a random integer, or rrandom, which chooses a random floating point number within a given range. I’ll give you a simple example of how these commands could be useful. Every month at Nisus Software, we hold a random drawing of the entries to the electronic “Guest Book” on our World Wide Web site, and award the lucky winner a free T-shirt or other prize. We don’t bother printing out the entries and pulling one from a hat; we use a macro to choose. It asks what the total number of entries was for the month, then selects a random number in that range. Since all of the entries are numbered as they come in, we simply find the message with the winning number and send the winner a congratulatory note.

Here’s how you use random. To have Nisus Writer pick any random number in the range –32767 to 32767, you simply use random all by itself, assigning a variable that value. Here’s a macro that will display the random number:

number = random
clipboard = number
:1 '\CC'

However, the number that this macro generates may be either positive or negative. If you want to restrict the output to positive numbers, you can add the fabs() function, which takes the absolute value of a number (i.e., the number without a + or – sign). So the revised command would be number = fabs(random). Now let’s suppose you want to make sure the number is no 397 higher than 100. To do this, you add a percent (%) sign after the command random, followed by the maximum value (the minimum value is always assumed to be zero). The command would now be number = fabs(random%100).

But what if you don’t want zero to be the bottom of the range? What if you want a random number between 150 and 250? Simple: just add 150 to the random number chosen. In other words, the range from 150 to 250 is 100 units large. If we take the minimum value of fabs(random%100), which is 0, and add 150 to it, we have the minimum value within the range we want. And if we take the maximum value of fabs(random%100), which is 100, and add 150 to it, we have 250, the maximum value in our desired range. So our final macro looks like this:

number = fabs(random%100) + 150
clipboard = number
:1 '\CC'

If you want to decrease the range—for example, look for numbers just between 150 and 175—then change the value after the % sign (e.g., fabs(random%25)+150).

Lesson 8: Arrays, Stacks, and Queues

Variables, as we have seen, are wonderfully useful objects, but they can only store one value at a time. There are many cases in which it is useful to store many values in the same place. For example, let’s say you have a macro that will create random sentences by putting together a noun, a verb, and another noun. You might want to have a list of possible verbs that the macro can choose among when it gets to the right place. However, just using ordinary variables, you’d have to give each possible verb its own variable name, and then come up with a clever way of choosing one of the variables. It would be much easier if you could say, “This special variable contains ten different verbs; pick one of its possible values.” In this lesson, we’ll look at a variety of ways to do just that, using a kind of storage device known as an array.

An array is basically just a list, like a list of words, numbers, or things to pick up at the store on your way home. This list can contain any number of items, and you can refer 398 to each item individually by number if you like. Or you can talk about just the first item, or just the last item, for example. You can remove things from one end of the list, or add things to either end. However, you can’t add new things to the middle of the list or remove things from the middle. While all arrays in Nisus Writer are the same kind of object, they are not always treated like ordinary lists—there are two additional metaphors for referring to them: the stack and the queue. At any moment, you can treat an array as either an “ordinary” array, a stack or a queue, and the way you choose to look at it will influence what you can do with it and what commands you’ll use. We’ll talk about stacks and queues shortly; first, let’s look at “raw” arrays.

If you’re a programmer, you may be surprised to find that a stack and a queue are not two different things in Nisus Writer. You’ll also be surprised to know that an array can contain any combination of data types (numeric, string, etc.) at once. There may be other surprises as well. My advice: take this material at face value—it’ll make a lot more sense!

Arrays qua Arrays

Let’s create a simple array. To do this, we’ll use the command create. When using this command, you need to decide up front how many elements (“slots”) you want the array to have (keeping in mind that you can add to it later on). Let’s start with 5. We also need a name for our array—let’s call it Clyde. To create an array named Clyde with 5 elements, we use the command: Clyde -> create(5), which says: “Apply the method ‘create’ to the array ‘Clyde’ using a value of 5.” The symbol -> (a hyphen followed by a greater than sign) is called the method operator, and what it does is apply the method on its right to the array or variable on its left. A method is, for our current purposes, a way of accessing data. The method we just used is that of creation. And the create command requires a specific value, which is placed inside parentheses after it. So what we’ve done is created an array (a list) named Clyde with 5 empty slots.

Putting values into the slots, and getting them back out, is done just the way it is with regular variables, except that you refer to the slots by their number, which goes in brackets. So to put the string baseball in slot 3 of the array, we’d enter Clyde[3] = "baseball". You can repeat this procedure for each slot. To use the contents of a slot, once again you can treat it like any variable—for example Clipboard = Clyde[3] would put the word baseball on the clipboard.

399 In addition to referring to a particular slot by number, you can refer to a slot’s position relative to the last slot that was accessed. The “relative” slot numbers are placed inside double brackets. The number you use is added to the last value accessed to determine the current value. For example, if after saying Clyde[3] = "baseball", you enter Clyde[[2]] = "popcorn", the word “popcorn” will be placed in slot 5 of the array Clyde. The 2 (inside double brackets) is added to the last value used (3) to arrive at the current value of 5. Relative numbers can be positive, negative, or zero (zero refers to the same value that was used last time).

You may be wondering how arrays are actually used in macros. Here’s a quick example. Let’s create a shopping list with three items. Then we’ll ask for input: you can choose a number from one to five and the macro will tell you which item is stored at that location in the array. Not very impressive, but it shows how arrays are constructed and used:

list -> create(3)
list[1] = "cookies"
list[2] = "milk"
list[3] = "tofu"
:1 "Which item do you want to see (1–3)?" ""
ListNum = clipboard
clipboard = "Item " + ListNum + " is " + list[ListNum] + "."
:1 '\CC'

Stacks

Think back to your high school cafeteria. If yours was anything like mine, there was a big contraption at the beginning of the food line which held the trays. Funny thing, though: the stack of trays was always at the same height. This happened because there was a big spring-loaded mechanism that would compress or expand as needed. When you took a tray off the top, the rest of the stack would pop up, and if a stack of new trays got put on top, they’d all get pushed down so that the top stayed at a constant height. Of course, this also meant that you couldn’t just reach into the stack and grab any tray you wanted—you had to take the 400 one off the top, and if somebody put another tray on, the only place in the stack it could go is on top.

The point of this tale is that if you understand how the cafeteria tray holder works, you know everything you need to know about stacks—one of the ways of looking at arrays in Nisus Writer. A stack can hold any number of different values at one time, but with a catch: when you add new values to the list, you can only “push” them onto the top of the stack, and when you remove them, you have to “pop” them off the top in the reverse of the order that they were pushed. So let’s look at how we can “push” or “pop” values in an array.

The command push() will put a new value onto the “top” of a stack, “top” in this case being slot 1. Let’s see how this works. Suppose we have an array with two elements:

Fred -> create(2)
Fred[1] = "coffee"
Fred[2] = "tea"

Now we want to add a third element, but we want to “push” it onto the top of the stack. We add this command:

Fred -> push("milk")

This says, “Apply the method push to the array Fred using a value of milk.” Now, if we were to look at the values in the array, we’d find that Fred[1] is milk, Fred[2] is coffee, and Fred[3] is tea. So the new value assumed position 1 and pushed the other values down one. Note that you don’t need to use the create command before using push()—the first time you use push with an array, it will create the necessary number of elements if they’re not already there.

The other part of the stack metaphor is the pop command. It does the opposite of push—it gives you back the first (top) value in an array, shrinking the number of elements by one. So if we have the same three-element array that we just worked with and entered the command Fred -> pop, the first item would be removed and everything would move up one position. You can also use the pop command as part of another expression, if you want to actually do something with that value rather than just remove it. For 401 example, we could have said clipboard = Fred -> pop, which would have put the first value of Fred (namely, milk) onto the clipboard.

Queues

Besides treating arrays as stacks, we can treat them as queues. A queue (pronounced “cue”) is a line, like a line of people waiting to buy tickets. The first people to arrive are the first to be served; when new people arrive, they need to go to the end of the line. As people are served, they leave the beginning of the line. So a queue works the opposite of the way a stack does—in a stack, you add new elements to the “top” or “beginning”; in a queue, you add new elements to the “end.”

What this means in terms of arrays is that just as you can push() an item into the first position in an array, you can qpush() an item into the last position in an array. If your array is a line of people waiting to be served, you might think of qpush as a new person politely lining up at the end, and push as someone shoving into the front of the line. Or, to use the cafeteria tray metaphor, to qpush an item onto the stack would be to stick it directly on the very bottom (the last item to be used). However, there is no qpop() command—while you can find out the value of the “last” item in an array, you can’t remove it directly until the other elements are used.

Fun with Arrays

Arrays have a lot of potential uses, many of which you’ll see in the sample macros included on the CD-ROM. But there’s a set of special keywords that give arrays special power, by referring to any selection(s) in your document, even noncontiguous ones. They allow you to put all the selected elements (text or numbers) into individual elements of an array all at once, or to store all the starting points and/or ending points of all the selections at once.

Let’s assume that you have one or more blocks of text selected. If you then have a line in a macro that says Selections -> push(strings), every selected block of text will be stored in an array named Selections, each as a separate text 402 string. To store the selected items as integers, use the keyword ints instead of strings; to store them as floating point numbers, use floats. Instead of storing the contents of the selections, you may want to store just the starting and/or ending points. To store all the starting points, use a command like Selections -> push(starts). To store the ending points, use ends instead of starts. And to store both starting and ending points (in order of selection start then selection end, etc.), use StartEnds.

To get an idea of how this would work, let’s construct a simple but very useful pair of macros. The first will store all the selections in your document, and the second will restore them after they’ve been deselected. This could be very useful to do if you begin making a lot of selections, then realize you need to copy or work with something else separately, but don’t want to lose the other selections. The second macro uses another pair of commands you haven’t seen yet—SetSelect and SetSelectMore, which actually make selections in your text when given arguments that contain the offsets of beginning and ending points. Here is the first macro:

global Selections
Selections -> push(StartEnds)

Pretty simple, right? After you’ve made a series of selections, run the above macro, which we’ll call Save Selections. Now click somewhere to deselect what you’ve selected. Next, use the following macro, which we’ll call Restore Selections.

SetSelect(0,0)
if(!Selections -> size) Exit
loop:
  SetSelectMore(Selections -> pop, Selections -> pop)
if(Selections -> size) goto loop:

When you run this macro, all of your selections will be restored (one at a time). Of course, if you make changes to your text before running Restore Selections, all bets are off, because it only counts the number of characters from the beginning of the document, and if the number changes…tough. But if you just deselect the text (or select other text), it will work beautifully.

403 There are quite a few other commands that can be used with arrays, but we don’t have space to cover them here. Refer to Appendix C for a complete list with brief explanations, and look through the other macros in this book and on the CD-ROM for examples of how they’re used.

Lesson 9: Scripting with Frontier

While Nisus Writer’s built-in macro language is quite powerful and capable, you can go even further by using macros to control other applications. This is done by way of Frontier, a system-level scripting environment that can communicate with the Finder or any OSA (Open Scripting Architecture)-compliant application. Nisus Writer includes a copy of Frontier Runtime, and the full version of Frontier 4.0 (a.k.a. Aretha) is available free on-line. To download the latest version or for more information on Frontier, point your Web browser at:

http://www.hotwired.com/staff/userland/aretha/

The current version of Frontier is now 6, and it can be found at frontier.userland.com/. Unfortunately, it is no longer free—in fact, it's obscenely expensive. However, you can still download an older version (5.0.1) for free at www.scripting.com/frontier5/downloads/.

It is important to emphasize that as yet, Nisus Writer itself is not scriptable, either with Frontier or with AppleScript. Nisus Writer can send commands to other applications, but not receive commands. In order to remote-control Nisus Writer, you’ll need to use a macro utility like QuicKeys or KeyQuencer, or PreFab Software’s Player program to “play” the interface from an AppleScript or Frontier script. Future versions of Nisus Writer are expected to address this deficiency.

In what follows, I will not teach you much about Frontier. To learn about UserTalk, Frontier’s scripting language, surf to the URL mentioned above or consult Tom Trinko’s Applied Mac Scripting (M&T Books, 1995). Here I’ll give just a brief sketch of how Frontier commands can be activated from Nisus Writer and included within macros.

There are two Nisus Writer commands that pertain to Frontier: Frontier Do Script… (found on the Macros menu) and Frontier Do Selection (which replaces Frontier Do Script… when you press the Shift key). When you choose Frontier Do Script…, Frontier is launched in the background (if it’s not already running), and a dialog box appears asking you to type in a Frontier command. After you type in the 404 command and click OK, the command is sent to Frontier for processing. If you already have a Frontier script typed into your document, you can select it and choose Frontier Do Selection (which is analogous to Nisus Writer’s Execute Selection).

You can also use Frontier Do Script in a macro. It must be followed by a valid Frontier command in either single or double quotes—for example, to place the pathname to the System Folder on the clipboard, you’d say:

Frontier Do Script "file.getSystemFolderPath ()"

If the Frontier command itself needs to include something in quotes, then you put the whole command in single quotes. For example, to open the control panel named “Monitors,” you would enter:

Frontier Do Script 'launch.controlPanel ("Monitors")'

For some reason, double quotes inside single quotes don’t always work. One case where they don’t work is when you’re trying to list the parameters to send an Apple event. This command sends a “GetURL” event to Netscape using the contents of the current clipboard as the URL:

Frontier Do Script 'appleEvent (''MOSS'', ''GURL'', ''GURL'', ''----'', "\CC")'

To get around the problem of double quotes inside single quotes not working, you need to use a pair of single quotes on each side of the expression. So in the above example, MOSS, GURL (twice) and ---- each have two single quotes on each side; only the command \CC is surrounded by regular (double) quotes. When the \CC command is sent as an argument to Frontier, it is always in double quotes, with the whole expression being in single quotes.

When you send a command to Frontier, it will return a result (e.g., “true” or “false”) on the clipboard. To avoid having the result placed on the clipboard, place the argument "-" at the end of the Frontier Do Script command.

There’s not much more I can say here about Frontier without giving you a lesson in UserTalk, and that’s beyond the scope of this book. However, I do recommend that you check out the macros on the enclosed CD-ROM—particularly the file Joe’s Internet Macros—for further examples of what can be done and how to do it.

405 Lesson 10: Debugging

Despite your best efforts, your macros may not always work perfectly the first time. Often, when you run a macro and it doesn’t work correctly, the reason is fairly obvious. But other times everything looks right and it still doesn’t work. This can be very frustrating, especially if your macro is long and complex. Since there are a nearly infinite number of things that could cause your macro not to work properly, I can’t pretend to give you all the answers here. However, I can give you a few helpful hints that will help you to overcome some common problems.

First, watch out for the old “mixing dialects in a single line” problem. Although as I mentioned when we first talked about this, many people never experience this problem at all, it is a trap that’s easy to fall into if you’re not careful. Sometimes mixing dialects will produce an error message like the one shown in Figure 12.16. This means that neither the Menu Command Dialect nor the Programming Dialect can interpret the line as an available command. You’ll get this same message if you have a menu command in your macro that is misspelled, or another command which for one reason or another can’t be found. To avoid problems like this:

Figure 12.16. This alert appears when neither dialect can figure out what to do with your command.

Another common problem is trying to manipulate variables before they have been instantiated. For example, the command myVar = 10 is perfectly fine anywhere in your macro. But if you make a statement like myVar = myVar + 10 without first giving myVar some value (and, at the same time, a data type), the macro engine will get confused and display a 406 message like the one in Figure 12.17. To avoid this problem, make sure that the first time you use any variable, you assign it some value (even if the value is 0 or ""), so that the macro will know what kind of variable it is and how it needs to be used. Also, when testing a portion of your macro using Execute Selection, make sure that you have selected the instantiating statement for any variables that are used in your selection; otherwise, the selected part of the macro won’t work properly.

Figure 12.17. This alert appears when you try to use a variable before it has been instantiated.

Here are some additional assorted tips for dealing with common problems in macros:

Learning More

The possibilities for macros are nearly endless, as you can imagine, and we can’t cover every possibility here. But if you want to learn more about writing macros, there are several sources you can consult. First, after working through the examples in this chapter, you’ll want to consult Appendix C for a complete list of macro commands (not all of which could be discussed here for reasons of space). Each command in the appendix includes a brief explanatory example. Beyond that, for help with macros, you can try any of these things:

Summary

Whew! You made it! Now that you know how to automate your work with glossaries and macros, you are well on your way to becoming the geek you were always meant to be. I’m proud of you. Sad though it may be to move on, we have more thrills ahead. Chapter 13 rounds out our Power Techniques section with a discussion of multilingual word processing with WorldScript. Then we move on to the “real world” with Section IV, “Applied Document Processing,” in which we put all the pieces together in the context of some actual projects for which Nisus Writer is ideally suited.

Copyright © 1995, 1996, 1999 by Joe Kissell

< Previous Chapter | Next Chapter >