PROGRAMMED COMMANDS

This section describes facilities for constructing more powerful commands from simple commands. So far, the only form of compound command structure introduced has been the facility to type more than one command in a single command line, with the consequential capability of repeating the complete sequence by subsequently typing a repetition number instead of another command.

Caution

The structuring facilities described in the following paragraphs can be used to carry out some quite complicated operations, but commands making heavy use of them tend to become rather difficult to understand. It is not sensible to try to devise a programmed command of any significant complexity while working at the terminal. Contemplation in tranquillity is required. Some users note in a log-book those which they have found useful in the past.

Command sequences

Any sequence of commands may be enclosed in parentheses and treated as a single command. In particular this permits a repetition count to be attached to a sequence of commands. For example, the command "(F.integer.I.%.)3" has the effect of inserting a percent sign in front of the next three occurrences of "integer". Compare "F.integer. i.%.3" which inserts three percent signs in front of the first occurrence of "integer" only, and "F.integer.3 i.%.3" which does the same in front of the third occurrence only. For this simple case, it would be almost as convenient to type the pair of commands as one command line, and then type a 2 to repeat it twice more, but that option would not cover cases where the bracketed sequence is just part of a complete command line. A command sequence fails when any component of it fails, so that an asterisk attached to a bracketed command sequence specifies indefinite repetition until one of the contained commands fails. As a check against infinite looping, a limit of 10,000 iterations is applied to the repetition of bracketed commands.

Alternative command sequences

Another form of compound command is one providing a number of alternatives. This consists of two or more individual commands or command sequences separated by commas. Execution starts with the first command and if that alternative is completed without failure, the other alternatives are ignored. If any of the commands making up the first alternative fails, then the second alternative (following the first comma) is executed, and so forth. Only if a failure occurs on the last alternative is the whole compound command considered to have failed. For example, it might be required to include, as a component of a more complex command, an instruction to position the pointer at the next space on the line, or at the end of the line if there is no space to the right of the pointer. The command "(F1/ /, R*)" could be used for the purpose.
Consider also the problem of interchanging two text strings, say "basically" and "actually", throughout a complete file. Obviously, the commands (F/basically/S/actually/)* M-* (F/actually/S/basically/)* would end up with all occurrences of both words converted to "basically". One solution would be to convert all occurrences of the word "basically" to some unique sequence of characters, make the other change through the file, and finally convert the unique character sequences to "actually". A preferable approach, using alternative sequences, permits this kind of edit to be made progressively on a single pass through the file.
First consider the sequence "(R,M)". Right-shift fails only when the pointer is at the end of a line, so that this sequence performs a Right-shift except at the end of a line, when it performs a Move. The Move, and hence the compound command, fails only at the end of the file. Accordingly this is a command which makes it possible to 'inch' through a file on a character by character basis. The case under consideration can be handled by expanding this sequence to include alternatives to test for the two text strings and make the necessary change, leading to: (V/basically/S/actually/, V/actually/S/basically/, R, M)* This framework, using a set of Verify commands together with the 'inching' sequence "R,M", is one that can be used for a variety of different requirements.

Inverted failure condition

If a command, simple or bracketed, is followed by the symbol '\', the failure condition for the command is inverted so that successful execution causes a failure and unsuccessful execution does not. This in no way alters what the Editor attempts to do by way of carrying out the command, which has its customary effect, if any, except that it is deemed to have failed when it has not, and conversely. This curious effect is sometimes useful, most obviously with the Verify command. For example, "V.+." makes it possible (in effect) to make the following command conditional on there being a plus-sign immediately to the right of the pointer; "V.+.\" to make the following command conditional on there not being a plus-sign immediately to the right of the pointer.

Cancelled failure condition

If a command, simple or bracketed, is followed by the symbol '?', any failure condition arising in the execution of the command is cancelled, that is, any further action is taken on the basis that the command succeeded. As with inversion, this in no way alters the effect of the command itself. For example, suppose it was required to insert an ampersand in front of each line in a file which started with a exclamation-mark. The sequence "(V/!/ I/&/ M)*" is not adequate since the part within brackets will fail on any line not starting with an exclamation mark and cause termination of the whole sequence. It is only the failure of the Move which should cause failure of the sequence. Bracketing the Verify and the Insert and appending a question-mark achieves the desired effect: ( (V/!/ I/&/)? M)*

Further examples

The examples which follow either might be useful in themselves or illustrate general techniques. Many such commands are not rigorous, but depend on the originator of the document maintaining a consistency of style in terms of such matters as the inclusion or omission of spaces. (a) (MR)* Find first blank line (MR\)* Find first non-blank line The command Right-shift fails at the end of the line. Immediately after a Move, it will fail only if the line is blank. Hence (MR)* causes Moves to be executed until either the end of the file or a blank line is reached. Inverting the failure condition on R locates the first non-blank line, but note that a final L is required if the pointer is to end up at the start of the line.
(b) (RI. .)* E- Double-space a line This sequence inserts a space to the right of each existing character (including spaces) on the line. The final E- removes the last space inserted, because trailing spaces can be a source of confusion. (c) (R* (L D/ /)* M)* Delete trailing spaces This command will eliminate any trailing spaces that may have crept into the file. On each line, the pointer is moved to the end and then successive attempts are made to Left-shift and Delete a space. (d) ( (RLI/ /4)? M)0 Create left margin (of 4 spaces) The obvious command would be simply "(I/ /4M)0", but that would add spaces to blank lines, which is undesirable. Hence the "RL" to check that the line is not blank.
(e) F.sin.(V.sin(.,S.evil.) Replace selected occurrences The form of this command illustrates the case where it is required to pick out certain occurrences of a word for alteration but not others. A programmer has inadvertently employed "sin" as a variable in a program which also makes use of the mathematical function "sin(...)". The command sequence locates an occurrence of "sin", then verifies that it is followed by a left parenthesis by "V.sin(." or else changes it to "evil".