SECTION 9 1 THE INTERLISP EDITOR The INTERLISP editor allows rapid, convenient modification of list structures. Most often it is used to edit function definitions, (often while the function itself is running) via the function editf, e.g., EDITF(FOO). However, the editor can also be used to edit the value of a variable, via editv, to edit a property list, via editp, or to edit an arbitrary expression, via edite. It is an important feature which allows good on-line interaction in the INTERLISP system. This chapter begins with a lengthy introduction intended for the new user. The reference portion begins on page 9.11. 9.1 Introduction Let us introduce some of the basic editor commands, and give a flavor for the editor's language structure by guiding the reader through a hypothetical editing session. Suppose we are editing the following incorrect definition of append: [LAMBDA (X) Y (COND ((NUL X) Z) (T (CONS (CAR) (APPEND (CDR X Y] We call the editor via the function editf: _EDITF(APPEND) EDIT * The editor responds by typing EDIT followed by *, which is the editor's prompt character, i.e., it signifies that the editor is ready to accept ------------------------------------------------------------------------ 1 The editor was written by and is the responsibility of W. Teitelman. 9.1 2 commands. At any given moment, the editor's attention is centered on some substructure of the expression being edited. This substructure is called the current expression, and it is what the user sees when he gives the editor the command P, for print. Initially, the current expression is the top level one, i.e., the entire expression being edited. Thus: *P (LAMBDA (X) Y (COND & &)) * Note that the editor prints the current expression as though printlevel were set to 2, i.e., sublists of sublists are printed as &. The command ? will print the current expression as though printlevel were 1000. *? (LAMBDA (X) Y (COND ((NUL X) Z) (T (CONS (CAR) (APPEND (CDR X Y)))))) * and the command PP will prettyprint the current expression. A positive integer is interpreted by the editor as a command to descend into the correspondingly numbered element of the current expression. Thus: *2 *P (X) * A negative integer has a similar effect, but counting begins from the end of the current expression and proceeds backward, i.e., -1 refers to the last element in the current expression, -2 the next to the last, etc. For either positive integer or negative integer, if there is no 3 such element, an error occurs, the editor types the faulty command ------------------------------------------------------------------------ 2 In other words, all lines beginning with * were typed by the user, the rest by the editor. 3 'Editor errors' are not of the flavor described in Section 16, i.e., they never cause breaks or even go through the error machinery but are direct calls to error! indicating that a command is in some way faulty. What happens next depends on the context in which the command was being executed. For example, there are conditional commands which branch on errors. In most situations, though, an error will cause the editor to type the faulty command followed by a ? and wait for more input. Note that typing control-E while a command is being executed aborts the command exactly as though it had caused an error. 9.2 followed by a ?, and then another *. The current expression is never changed when a command causes an error. Thus: *P (X) *2 2 ? *1 *P X * A phrase of the form "the current expression is changed" or 'the current expression becomes' refers to a shift in the editor's attention, not to a modification of the structure being edited. When the user changes the current expression by descending into it, the old current expression is not lost. Instead, the editor actually operates by maintaining a chain of expressions leading to the current one. The current expression is simply the last link in the chain. Descending adds the indicated subexpression onto the end of the chain, thereby making it be the current expression. The command 0 is used to ascend the chain; it removes the last link of the chain, thereby making the previous link be the current expression. Thus: *P X *0 P (X) *0 -1 P (COND (& Z) (T &)) * Note the use of several commands on a single line in the previous output. The editor operates in a line buffered mode, the same as evalqt. Thus no command is actually seen by the editor, or executed, until the line is terminated, either by a carriage return, or a matching right parenthesis. The user can thus use control-A and control-Q for line-editing edit commands, the same as he does for inputs to evalqt. In our editing session, we will make the following corrections to append: delete Y from where it appears, add Y to the end of the argument 4 list, change NUL to NULL, change Z to Y, add Z after CAR, and insert a right parenthesis following CDR X. ------------------------------------------------------------------------ 4 These two operations could be though of as one operation, i.e., MOVE Y from its current position to a new position, and in fact there is a MOVE command in the editor. However, for the purposes of this introduction, we will confine ourselves to the simpler edit commands. 9.3 First we will delete Y. By now we have forgotten where we are in the function definition, but we want to be at the "top" so we use the command ^, which ascends through the entire chain of expressions to the top level expression, which then becomes the current expression, i.e., ^ removes all links except the first one. *^ P (LAMBDA (X) Y (COND & &)) * Note that if we are already at the top, ^ has no effect, i.e., it is a NOP. However, 0 would generate an error. In other words, ^ means "go to the top," while 0 means "ascend one link." The basic structure modification commands in the editor are: (n) n > 1 deletes the corresponding element from the current expression. (n e1 ... em) n,m > 1 replaces the nth element in the current expression with e1 ... em. (-n e1 ... em) n,m > 1 inserts e1 ... em before the nth element in the current expression. Thus: *P (LAMBDA (X) Y (COND & &)) *(3) *(2 (X Y)) *P (LAMBDA (X Y) (COND & &)) * All structure modification done by the editor is destructive, i.e., the editor uses rplaca and rplacd to physically change the structure it was given. Note that all three of the above commands perform their operation with respect to the nth element from the front of the current expression; the sign of n is used to specify whether the operation is replacement or insertion. Thus, there is no way to specify deletion or replacement of the nth element from the end of the current expression, or insertion before the nth element from the end without counting out that element's position from the front of the list. Similarly, because we cannot specify insertion after a particular element, we cannot attach something at the end of the current expression using the above commands. Instead, we use the command N (for nconc). Thus we could have performed the above changes instead by: 9.4 *P (LAMBDA (X) Y (COND & &)) *(3) *2 (N Y) *P (X Y) *^ P *(LAMBDA (X Y) (COND & &)) * Now we are ready to change NUL to NULL. Rather than specify the sequence of descent commands necessary to reach NUL, and then replace it with NULL, e.g., 3 2 1 (1 NULL), we will use F, the find command, to find NUL: *P (LAMBDA (X Y) (COND & &)) *F NUL *P (NUL X) *(1 NULL) *0 P ((NULL X) Z) * Note that F is special in that it corresponds to two inputs. In other words, F says to the editor, "treat your next command as an expression to be searched for." The search is carried out in printout order in the current expression. If the target expression is not found there, F automatically ascends and searches those portions of the higher expressions that would appear after (in a printout) the current expression. If the search is successful, the new current expression 5 will be the structure where the expression was found, and the chain will be the same as one resulting from the appropriate sequence of ascent and descent commands. If the search is not successful, an error 6 occurs, and neither the current expression nor the chain is changed: ------------------------------------------------------------------------ 5 If the search is for an atom, e.g., F NUL, the current expression will be the structure containing the atom. 6 F is never a NOP, i.e., if successful, the current expression after the search will never be the same as the current expression before the search. Thus F expr repeated without intervening commands that change the edit chain can be used to find successive instances of expr. 9.5 *P ((NULL X) Z) *F COND P COND ? *P *((NULL X) Z) * Here the search failed to find a cond following the current expression, although of course a cond does appear earlier in the structure. This last example illustrates another facet of the error recovery mechanism: to avoid further confusion when an error occurs, all commands on the line beyond the one which caused the error (and all commands that may 7 have been typed ahead while the editor was computing) are forgotten. We could also have used the R command (for replace) to change NUL to NULL. A command of the form (R e1 e2) will replace all occurrences of e1 in the current expression by e2. There must be at least one such occurrence or the R command will generate an error. Let us use the R command to change all Z's (even though there is only one) in append to Y: *^ (R Z Y) *F Z Z ? *PP [LAMBDA (X Y) (COND ((NULL X) Y) (T (CONS (CAR) (APPEND (CDR X Y] * The next task is to change (CAR) to (CAR X). We could do this by (R (CAR) (CAR X)), or by: *F CAR *(N X) *P (CAR X) * The expression we now want to change is the next expression after the current expression, i.e., we are currently looking at (CAR X) in (CONS (CAR X) (APPEND (CDR X Y))). We could get to the append expression by ------------------------------------------------------------------------ 7 i.e., the input buffer is cleared (and saved) (see clearbuf, Section 14). It can be restored, and the type-ahead recovered via the command $BUFS (alt-mode BUFS), described in Section 22. 9.6 typing 0 and then 3 or -1, or we can use the command NX, which does both operations: *P (CAR X) *NX P (APPEND (CDR X Y)) * Finally, to change (APPEND (CDR X Y)) to (APPEND (CDR X) Y), we could perform (2 (CDR X) Y), or (2 (CDR X)) and (N Y), or 2 and (3), deleting the Y, and then 0 (N Y). However, if Y were a complex expression, we would not want to have to retype it. Instead, we could use a command which effectively inserts and/or removes left and right parentheses. There are six of these commands: BI,BO,LI,LO,RI, and RO, for both in, both out, left in, left out, right in, and right out. Of course, we will always have the same number of left parentheses as right parentheses, because the parentheses are just a notational guide to 8 structure that is provided by our print program. Thus, left in, left out, right in, and right out actually do not insert or remove just one parenthesis, but this is very suggestive of what actually happens. In this case, we would like a right parenthesis to appear following X in (CDR X Y). Therefore, we use the command (RI 2 2), which means insert a right parentheses after the second element in the second element (of the current expression): *P (APPEND (CDR X Y)) *(RI 2 2) *P (APPEND (CDR X) Y) * We have now finished our editing, and can exit from the editor, to test append, or we could test it while still inside of the editor, by using the E command: *E APPEND((A B) (C D E)) (A B C D E) * The E command causes the next input to be given to evalqt. If there is another input following it, as in the above example, the first will be applied (apply) to the second. Otherwise, the input is evaluated (eval). We prettyprint append, and leave the editor. ------------------------------------------------------------------------ 8 Herein lies one of the principal advantages of a LISP oriented editor over a text editor: unbalanced parentheses errors are not possible. 9.7 *PP [LAMBDA (X Y) (COND ((NULL X) Y) (T (CONS (CAR X) (APPEND (CDR X) Y] *OK APPEND _ 9.2 Commands for the New User As mentioned earlier, the INTERLISP manual is intended primarily as a reference manual, and the remainder of this chapter is organized and presented accordingly. While the commands introduced in the previous scenario constitute a complete set, i.e., the user could perform any and all editing operations using just those commands, there are many situations in which knowing the right command(s) can save the user considerable effort. We include here as part of the introduction a list of those commands which are not only frequently applicable but also easy to use. They are not presented in any particular order, and are all discussed in detail in the reference portion of the chapter. UNDO undoes the last modification to the structure being edited, e.g., if the user deletes the wrong element, UNDO will restore it. The availability of UNDO should give the user confidence to experiment with any and all editing commands, no matter how complex, because he can always reverse the effect of the command. BK like NX, except makes the expression immediately before the current expression become current. BF backwards find. Like F, except searches backwards, i.e., in inverse print order. \ Restores the current expression to the expression before the last "big jump", e.g., a find command, an ^, or another \. For example, if the user types F COND, and then F CAR, \ would take him back to the COND. Another \ would take him back to the CAR. \P like \ except it restores the edit chain to its state as of the last print, either by P, ?, or PP. If the edit chain has not been changed since the last print, \P restores it to its state as of the printing before that one, i.e., two chains are always saved. 9.8 Thus if the user types P followed by 3 2 1 P, \P will take him back to the first P, i.e., would be equivalent to 0 0 0. Another \P would then take him back to the second P. Thus the user can use \P to flip back and forth between two current expressions. &,-- The search expression given to the F or BF command need not be a literal S-expression. Instead, it can be a pattern. The symbol & can be used anywhere within this pattern to match with any single element of a list, and -- can be used to match with any segment of a list. Thus, in the incorrect definition of append used earlier, F (NUL &) could have been used to find (NUL X), and F (CDR --) or F (CDR & &), but not F (CDR &), to find (CDR X Y). Note that & and -- can be nested arbitrarily deeply in the pattern. For example, if there are many places where the variable X is set, F SETQ may not find the desired expression, nor may F (SETQ X &). It may be necessary to use F (SETQ X (LIST --)). However, the usual technique in such a case is to pick out a unique atom which occurs prior to the desired expression, and perform two F commands. This "homing in" process seems to be more convenient than ultra-precise specification of the pattern. $ (alt-mode) $ is equivalent to -- at the character level, e.g., VER$ will match with VERYLONGATOM, as will $ATOM, $LONG$, (but not $LONG) and $V$N$M$. $ can be nested inside of a pattern, e.g., F (SETQ VER$ (CONS --)). If the search is successful, the editor will print = followed by the atom which matched with the $-atom, e.g., *F (SETQ VER$ &) =VERYLONGATOM * Frequently the user will want to replace the entire current expression, or insert something before it. In order to do this using a command of the form (n e1 ... em) or (-n e1 ... em), the user must be above the current expression. In other words, he would have to perform a 0 followed by a command with the appropriate number. However, if he has reached the current expression via an F command, he may not know what that number is. In this case, the user would like a command whose effect would be to modify the edit chain so that the current expression became the first element in a new, higher current expression. Then he could perform the desired operation via (1 e1 ... em) or (-1 e1 ... em). UP is provided for this purpose. 9.9 UP after UP operates, the old current expression is the first element of the new current expression. Note that if the current expression happens to be the first element in the next higher expression, then UP is exactly the same as 0. Otherwise, UP modifies the edit chain so that 9 the new current expression is a tail of the next higher expression: *F APPEND P (APPEND (CDR X) Y) *UP P ... (APPEND & Y)) *0 P (CONS (CAR X) (APPEND & Y)) * The ... is used by the editor to indicate that the current expression is a tail of the next higher expression as opposed to being an element (i.e., a member) of the next higher expression. Note: if the current expression is already a tail, UP has no effect. (B e1 ... em) inserts e1 ... em before the current expression, i.e., does an UP and then a -1. (A e1 ... em) inserts e1 ... em after the current expression, i.e., does an UP and then either a (- 2 e1 ... em) or an (N e1 ... em), if the current expression is the last one in the next higher expression. (: e1 ... em) replaces current expression by e1 ... em, i.e., does an UP and then a (1 e1 ... em). DELETE deletes current expression; equivalent to (:). Earlier, we introduced the RI command in the append example. The rest of the commands in this family: BI, BO, LI, LO, and RO, perform similar functions and are useful in certain situations. In addition, the commands MBD and XTR can be used to combine the effects of several commands of the BI-BO family. MBD is used to embed the current expression in a larger expression. For example, if the current expression is (PRINT bigexpression), and the user wants to replace it by (COND (FLG (PRINT bigexpression))), he could accomplish this by (LI 1), (-1 FLG), (LI 1), and (-1 COND), or by a single MBD command, page 9.35. ------------------------------------------------------------------------ 9 Throughout this chapter "tail" means "proper tail" (see Section 5). 9.10 XTR is used to extract an expression from the current expression. For example, extracting the PRINT expression from the above COND could be accomplished by (1), (LO 1), (1), and (LO 1) or by a single XTR command. The new user is encouraged to include XTR and MBD in his repertoire as soon as he is familiar with the more basic commands. This ends the introductory material. 9.3 Attention Changing Commands Commands to the editor fall into three classes: commands that change the current expression (i.e., change the edit chain) thereby "shifting the editor's attention," commands that modify the structure being edited, and miscellaneous commands, e.g., exiting from the editor, printing, evaluating expressions, etc. Within the context of commands that shift the editor's attention, we can distinguish among (1) those commands whose operation depends only on the structure of the edit chain, e.g., 0, UP, NX; (2) those which depend on the contents of the structure, i.e., commands that search; and (3) those commands which simply restore the edit chain to some previous state, e.g., \, \P. (1) and (2) can also be thought of as local, small steps versus open ended, big jumps. Commands of type (1) are discussed on page 9.11-16, type (2) on page 9.16-25, and type (3) on page 9.25-26. 9.3.1 Local Attention-Changing Commands UP (1) If a P command would cause the editor to type ... before typing the current expression, ie.., the current expression is a tail of the next higher expression, UP has no effect; otherwise (2) UP modifies the edit chain so that the old current expression (i.e., the one at the time UP was called) is the first element in the new 10 current expression. ------------------------------------------------------------------------ 10 If the current expression is the first element in the next higher expression UP simply does a 0. Otherwise UP adds the corresponding tail to the edit chain. 9.11 Examples: The current expression in each case is (COND ((NULL X) (RETURN Y))). 1. *1 P COND *UP P (COND (& &)) 2. *-1 P ((NULL X) (RETURN Y)) *UP P ... ((NULL X) (RETURN Y)) *UP P ... ((NULL X) (RETURN Y))) 3. *F NULL P (NULL X) *UP P ((NULL X) (RETURN Y)) *UP P ... ((NULL X) (RETURN Y))) The execution of UP is straightforward, except in those cases where the current expression appears more than once in the next higher expression. For example, if the current expression is (A NIL B NIL C NIL) and the user performs 4 followed by UP, the current expression should then be ... NIL C NIL). UP can determine which tail is the correct one because the commands that descend save the last tail on an internal editor variable, lastail. Thus after the 4 command is executed, lastail is (NIL C NIL). When UP is called, it first determines if the current expression is a tail of the next higher expression. If it is, UP is finished. Otherwise, UP computes memb[current-expression;next-higher-expression] to obtain a tail 11 beginning with the current expression. If there are no other instances of the current expression in the next higher expression, this tail is the correct one. Otherwise UP uses lastail to select the correct ------------------------------------------------------------------------ 11 The current expression should always be either a tail or an element of the next higher expression. If it is neither, for example the user has directly (and incorrectly) manipulated the edit chain, UP generates an error. 9.12 12 tail. n (n > 1) adds the nth element of the current expression to the front of the edit chain, thereby making it be the new current expression. Sets lastail for use by UP. Generates an error if the current expression is not a list that contains at least n elements. -n (n > 1) adds the nth element from the end of the current expression to the front of the edit chain, thereby making it be the new current expression. Sets lastail for use by UP. Generates an error if the current expression is not a list that contains at least n elements. 0 Sets edit chain to cdr of edit chain, thereby making the next higher expression be the new current expression. Generates an error if there is no higher expression, i.e., cdr of edit chain is NIL. Note that 0 usually corresponds to going back to the next higher left parenthesis, but not always. For example, if the current expression is (A B C D E F B), and the user performs: *3 UP P ... C D E F G) *3 UP P ... E F G) *0 P ... C D E F G) If the intention is to go back to the next higher left parenthesis, 13 regardless of any intervening tails, the command !0 can be used. ------------------------------------------------------------------------ 12 Occasionally the user can get the edit chain into a state where lastail cannot resolve the ambiguity, for example if there were two non-atomic structures in the same expression that were eq, and the user descended more than one level into one of them and then tried to come back out using UP. In this case, UP prints LOCATION UNCERTAIN and generates an error. Of course, we could have solved this problem completely in our implementation by saving at each descent both elements and tails. However, this would be a costly solution to a situation that arises infrequently, and when it does, has no detrimental effects. The lastail solution is cheap and resolves 99% of the ambiguities. 13 !0 is pronounced bang-zero. 9.13 !0 does repeated 0's until it reaches a point where the current expression is not a tail of the next higher expression, i.e., always goes back to the next higher left parenthesis. ^ sets edit chain to last of edit chain, thereby making the top level expression be the current expression. Never generates an error. 14 NX effectively does an UP followed by a 2, thereby making the current expression be the next expression. Generates an error if the current expression is the last one in a list. (However, !NX described below will handle this case.) BK makes the current expression be the previous expression in the next higher expression. Generates an error if the current expression is the first expression in a list. For example, if the current expression is (COND ((NULL X) (RETURN Y))): *F RETURN P (RETURN Y) *BK P (NULL X) (NX n) n > 1 equivalent to n NX commands, except if an error occurs, the edit chain is not changed. (BK n) n > 1 equivalent to n BK commands, except if an error occurs, the edit chain is not changed. Note: (NX -n) is equivalent to (BK n), and vice versa. !NX makes current expression be the next expression at a higher level, i.e., goes through any number of right parentheses to get to the next expression. ------------------------------------------------------------------------ 14 Both NX and BK operate by performing a !0 followed by an appropriate number, i.e., there won't be an extra tail above the new current expression, as there would be if NX operated by performing an UP followed by a 2. 9.14 For example: *PP (PROG ((L L) (UF L)) LP (COND ((NULL (SETQ L (CDR L))) (ERROR!)) ([NULL (CDR (FMEMB (CAR L) (CADR L] (GO LP))) (EDITCOM (QUOTE NX)) (SETQ UNFIND UF) (RETURN L)) *F CDR P (CDR L) *NX NX ? *!NX P (ERROR!) *!NX P ((NULL &) (GO LP)) *!NX P (EDITCOM (QUOTE NX)) * !NX operates by doing 0's until it reaches a stage where the current expression is not the last expression in the next higher expression, and then does a NX. Thus !NX always goes through at least one unmatched right parenthesis, and the new current expression is always on a different level, i.e., !NX and NX always produce different results. For example using the previous current expression: *F CAR P (CAR L) *!NX P (GO LP) *\P P (CAR L) *NX P (CADR L) * (NTH n) n ~= 0 equivalent to n followed by UP, i.e., causes the list starting with the nth element of the current expression (or nth from the end if 15 n < 0) to become the current expression. Causes an error if current expression does not have at least n elements. ------------------------------------------------------------------------ 15 (NTH 1) is a NOP, as is (NTH -n) where n is the length of the current expression. 9.15 A generalized form of NTH using location specifications is described on page 9.24. 9.3.2 Commands That Search All of the editor commands that search use the same pattern matching 16 routine. We will therefore begin our discussion of searching by describing the pattern match mechanism. A pattern pat matches with x if: 1. pat is eq to x. 2. pat is &. 3. pat is a number and eqp to x. 4. pat is a string and strequal[pat;x] is true. 5. If car[pat] is the atom *ANY*, cdr[pat] is a list of patterns and pat matches x if and only if one of the patterns on cdr[pat] matches x. 6a. If pat is a literal atom or string containing one or more 17 alt-modes, each $ can match an indefinite number (including 0) of contiguous characters in a literal atom or string, e.g., VER$ matches both VERYLONGATOM and "VERYLONGSTRING" as do $LONG$ (but not $LONG), and $V$L$T$. 6b. If pat is a literal atom or string ending in two alt- modes, pat matches with the first atom or string that is "close" to pat, in the sense used by the spelling corrector (Section 17). E.g. CONSS$$ matches with CONS, CNONC$$ with NCONC or NCONC1. The pattern matching routine always types a message of the form =x to inform the user of the object matched by a 18 pattern of type 6a or 6b, e.g. =VERYLONGATOM. 7. If car[pat] is the atom --, pat matches x if a. cdr[pat]=NIL, i.e., pat=(--), e.g. (A --) matches (A) (A B C) and (A . B) ------------------------------------------------------------------------ 16 This routine is available to the user directly, and is described on page 9.68. 17 except that the atom $ (alt-mode) matches only with itself. 18 unless editquietflg=T. 9.16 In other words, -- can match any tail of a list. b. cdr[pat] matches with some tail of x, e.g., (A -- (&)) will match with (A B C (D)), but not (A B C D), or (A B C (D) E). However, note that (A -- (&) --) will match with (A B C (D) E). In other words, -- can match any interior segment of a list. 8. If car[pat] is the atom ==, pat matches x if and only if 19 cdr[pat] is eq to x. 9. Otherwise if x is a list, pat matches x if car[pat] matches car[x], and cdr[pat] matches cdr[x]. When the editor is searching, the pattern matching routine is called to match with elements in the structure, unless the pattern begins with ..., in which case cdr of the pattern is matched against proper tails in the structure. Thus if the current expression is (A B C (B C)), *F (B --) *P (B C) *0 F (... B --) *P ... B C (B C)) Matching is also attempted with atomic tails (except for NIL). Thus *P (A (B . C)) *F C *P ... . C) Although the current expression is the atom C after the final command, it is printed as ... . C) to alert the user to the fact that C is a tail, not an element. Note that the pattern C will match with either instance of C in (A C (B . C)), whereas (... . C) will match only the second C. The pattern NIL will only match with NIL as an element, i.e., it will not match in (A B), even though cddr of (A B) is NIL. However, (... . NIL) (or equivalently (...)) may be used to specify a NIL tail, e.g., (... . NIL) will match with cdr of the third subexpression of ((A . B) (C . D) (E)). Search Algorithm Searching begins with the current expression and proceeds in print ------------------------------------------------------------------------ 19 Pattern 8 is for use by programs that call the editor as a subroutine, since any non-atomic expression in a command typed in by the user obviously cannot be eq to already existing structure. 9.17 order. Searching usually means find the next instance of this pattern, and consequently a match is not attempted that would leave the edit 20 chain unchanged. At each step, the pattern is matched against the next element in the expression currently being searched, unless the pattern begins with ... in which case it is matched against the next tail of the expression. If the match is not successful, the search operation is recursive first in the car direction and then in the cdr direction, i.e., if the element under examination is a list, the search descends into that list before 21 attempting to match with other elements (or tails) at the same level. However, at no point is the total recursive depth of the search (sum of number of cars and cdrs descended into) allowed to exceed the value of the variable maxlevel. At that point, the search of that element or tail is abandoned, exactly as though the element or tail had been completely searched without finding a match, and the search continues with the element or tail for which the recursive depth is below maxlevel. This feature is designed to enable the user to search circular list structures (by setting maxlevel small), as well as protecting him from accidentally encountering a circular list structure 22 in the course of normal editing. maxlevel is initially set to 300. If a successful match is not found in the current expression, the search 23 automatically ascends to the next higher expression, and continues searching there on the next expression after the expression it just finished searching. If there is none, it ascends again, etc. This process continues until the entire edit chain has been searched, at which point the search fails, and an error is generated. If the search fails (or, what is equivalent, is aborted by control-E), the edit chain is not changed (nor are any conses performed). If the search is successful, i.e., an expression is found that the pattern matches, the edit chain is set to the value it would have had had the user reached that expression via a sequence of integer commands. ------------------------------------------------------------------------ 20 However, there is a version of the find command which can succeed and leave the current expression unchanged (see page 9.19). 21 There is also a version of the find command (see page 9.20) which only attempts matches at the top level of the current expression, i.e., does not descend into elements, or ascend to higher expressions. 22 maxlevel can also be set to NIL, which is equivalent to infinity. 23 See footnote on page 9.18. 9.18 If the expression that matched was a list, it will be the final link in the edit chain, i.e., the new current expression. If the expression that matched is not a list, e.g., is an atom, the current expression 24 will be the tail beginning with that atom, i.e., that atom will be the first element in the new current expression. In other words, the search 25 effectively does an UP. Search Commands All of the commands below set lastail for use by UP, set unfind for use by \ (page 9.25), and do not change the edit chain or perform any conses if they are unsuccessful or aborted. F pattern i.e., two commands: the F informs the editor that the next command is to be interpreted as a pattern. This is the most common and useful form of the find command. If successful, the edit chain always changes, i.e., F pattern means find the next instance of pattern. If memb[pattern;current-expression] is true, F does not proceed with a full recursive search. If the value of the memb is NIL, F invokes the search algorithm described earlier. Thus if the current expression is (PROG NIL LP (COND (-- (GO LP1))) ... LP1 ...), F LP1 will find the prog label, not the LP1 inside of the GO expression, even though the latter appears first (in print order) in the current expression. Note that 1 (making the atom PROG be the current expression), followed by F LP1 would find the first LP1. (F pattern N) same as F pattern, i.e., finds the next instance of pattern, except the memb check of F pattern is not performed. (F pattern T) Similar to F pattern, except may succeed without changing edit chain, and does not perform the memb check. Thus if the current expression is (COND ..), F COND will look for the next COND, but (F COND T) will "stay here". ------------------------------------------------------------------------ 24 Unless the atom is a tail, e.g., B in (A . B). In this case, the current expression will be B, but will print as ... . B). 25 Unless upfindflg=NIL (initially set to T). For discussion, see page 9.33-33. 9.19 (F pattern n) n > 1 Finds the nth place that pattern matches. Equivalent to (F pattern T) followed by (F pattern N) repeated n-1 times. Each time pattern successfully matches, n is decremented by 1, and the search continues, until n reaches 0. Note that the pattern does not have to match with n identical expressions; it just has to match n times. Thus if the current expression is (FOO1 FOO2 FOO3), (F FOO$ 3) will find FOO3. If the pattern does not match successfully n times, an error is generated and the edit chain is unchanged (even if the pattern matched n-1 times). (F pattern) or only matches with elements at the (F pattern NIL) top level of the current expression, i.e., the search will not descend into the current expression, nor will it go outside of the current expression. May succeed without changing edit chain. For example, if the current expression is (PROG NIL (SETQ X (COND & &)) (COND &) ...), F COND will find the COND inside the SETQ, whereas (F (COND --)) will find the top level COND, i.e., the second one. (FS pattern1 ... patternn) equivalent to F pattern1 followed by F pattern2 ... followed by F patternn, so that if F patternm fails, edit chain is left at place patternm-1 matched. (F= expression x) equivalent to (F (== . expression) x), i.e., searches for a structure eq to expression, see page 9.17. (ORF pattern1 ... patternn) equivalent to (F (*ANY* pattern1 ... patternn) N), i.e., searches for an expression that is matched by either pattern1, pattern2, ... or patternn. See page 9.16. BF pattern backwards find. Searches in reverse print order, beginning with expression immediately before the current expression (unless the current expression is the top level expression, in which case BF searches the entire expression, in reverse order). BF uses the same pattern match routine as F, and maxlevel and upfindflg have the same effect, but the searching begins at the end of each list, 9.20 and descends into each element before attempting to match that element. If unsuccessful, the search continues with the next previous element, etc., until the front of the list is reached, at which point BF ascends and backs up, etc. For example, if the current expression is (PROG NIL (SETQ X (SETQ Y (LIST Z))) (COND ((SETQ W --) --)) --), F LIST followed by BF SETQ will leave the current expression as (SETQ Y (LIST Z)), as will F COND followed by BF SETQ. (BF pattern T) search always includes current expression, i.e., starts at the end of current expression and works backward, then ascends and backs up, etc. Thus in the previous example, where F COND followed by BF SETQ found (SETQ Y (LIST Z)), F COND followed by (BF SETQ T) would find the (SETQ W --) expression. (BF pattern) same as BF pattern. (BF pattern NIL) Location Specification Many of the more sophisticated commands described later in this chapter use a more general method of specifying position called a location specification. A location specification is a list of edit commands that are executed in the normal fashion with two exceptions. First, all commands not recognized by the editor are interpreted as though they had 26 been preceded by F. For example, the location specification (COND 2 3) 27 specifies the 3rd element in the first clause of the next COND. Secondly, if an error occurs while evaluating one of the commands in the location specification, and the edit chain had been changed, i.e., was not the same as it was at the beginning of that execution of the location specification, the location operation will continue. In other words, the location operation keeps going unless it reaches a state where it detects that it is "looping", at which point it gives up. Thus, if (COND 2 3) is being located, and the first clause of the next COND contained only two elements, the execution of the command 3 would cause an error. The search would then continue by looking for the next COND. However, if a point were reached where there were no further CONDs, then the first command, COND, would cause the error; the edit ------------------------------------------------------------------------ 26 Normally such commands would cause errors. 27 Note that the user could always write F COND followed by 2 and 3 for (COND 2 3) if he were not sure whether or not COND was the name of an atomic command. 9.21 chain would not have been changed, and so the entire location operation would fail, and cause an error. The IF command in conjunction with the ## function provide a way of using arbitrary predicates applied to elements in the current expression. IF and ## will be described in detail later in the chapter, along with examples illustrating their use in location specifications. Throughout this chapter, the meta-symbol @ is used to denote a location specification. Thus @ is a list of commands interpreted as described above. @ can also be atomic, in which case it is interpreted as list[@]. (LC . @) provides a way of explicitly invoking the location operation, e.g., (LC COND 2 3) will perform the the search described above. (LCL . @) Same as LC except the search is confined to the current expression, i.e., the edit chain is rebound during the search so that it looks as though the editor were called on just the current expression. For example, to find a COND containing a RETURN, one might use the location specification (COND (LCL RETURN) \) where the \ would reverse the effects of the LCL command, and make the final current expression be the COND. (2ND . @) Same as (LC . @) followed by another (LC . @) except that if the first succeeds and second fails, no change is made to the edit chain. (3RD . @) Similar to 2ND. (_ pattern) ascends the edit chain looking for a link which matches pattern. In other words, it keeps doing 0's until it gets to a specified point. If pattern is atomic, it is matched with the first element of each link, otherwise with the entire 28 link. ------------------------------------------------------------------------ 28 If pattern is of the form (IF expression), expression is evaluated at each link, and if its value is NIL, or the evaluation causes an error, the ascent continues. 9.22 For example: *PP [PROG NIL (COND [(NULL (SETQ L (CDR L))) (COND (FLG (RETURN L] ([NULL (CDR (FMEMB (CAR L) (CADR L]] *F CADR *(_ COND) *P (COND (& &) (& &)) * Note that this command differs from BF in that it does not search inside of each link, it simply ascends. Thus in the above example, F CADR followed by BF COND would find (COND (FLG (RETURN L))), not the higher COND. If no match is found, an error is generated, and the edit chain is unchanged. (BELOW com x) ascends the edit chain looking for a link 29 specified by com, and stops x links below 30 that, i.e. BELOW keeps doing 0's until it gets to a specified point, and then backs off x 0's. (BELOW com) same as (BELOW com 1). For example, (BELOW COND) will cause the cond clause containing the current expression to become the new current expression. Thus if the current expression is as shown above, F CADR followed by (BELOW COND) will make the new expression be ([NULL (CDR (FMEMB (CAR L) (CADR L] (GO LP)), and is therefore equivalent to 0 0 0 0. The BELOW command is useful for locating a substructure by specifying something it contains. For example, suppose the user is editing a list of lists, and wants to find a sublist that contains a FOO (at any depth). He simply executes F FOO (BELOW \). ------------------------------------------------------------------------ 29 x is evaluated, e.g., (BELOW com (IPLUS X Y)). 30 Only links that are elements are counted, not tails. 9.23 (NEX x) same as (BELOW x) followed by NX. For example, if the user is deep inside of a SELECTQ clause, he can advance to the next clause with (NEX SELECTQ). NEX same as (NEX _). The atomic form of NEX is useful if the user will be performing repeated executions of (NEX x). By simply MARKing (see page 9.25) the chain corresponding to x, he can use NEX to step through the sublists. (NTH x) generalized NTH command. Effectively performs (LCL . x), followed by (BELOW \), followed by UP. In other words, NTH locates x, using a search restricted to the current expression, and then backs up to the current level, where the new current expression is the tail whose first element contains, however deeply, the expression that was the terminus of the location operation. For example: *P (PROG (& &) LP (COND & &) (EDITCOM &) (SETQ UNFIND UF) (RETURN L)) *(NTH UF) *P ... (SETQ UNFIND UF) (RETURN L)) * If the search is unsuccessful, NTH generates an error and the edit chain is not changed. Note that (NTH n) is just a special case of (NTH x), and in fact, no special check is made for x a number; both commands are executed identically. 31 (pattern .. @) e.g., (COND .. RETURN). Finds a cond that contains a return, at any depth. Equivalent to (but more efficient than) (F pattern N), (LCL . @) followed by (_ pattern). For example, if the current expression is (PROG NIL [COND ((NULL L) (COND (FLG (RETURN L] --), then (COND .. RETURN) will make (COND (FLG (RETURN L))) be the current expression. Note that it is the innermost COND that is found, because this is the first COND encountered when ascending from the RETURN. In other words, (pattern .. @) is not always equivalent to (F pattern N), followed by (LCL . @) followed by \. ------------------------------------------------------------------------ 31 An infix command, ".." is not a meta-symbol, it is the name of the command. @ is cddr of the command. 9.24 Note that @ is a location specification, not just a pattern. Thus (RETURN .. COND 2 3) can be used to find the RETURN which contains a COND whose first clause contains (at least) three elements. Note also that since @ permits any edit command, the user can write commands of the form (COND .. (RETURN .. COND)), which will locate the first COND that contains a RETURN that contains a COND. 9.3.3 Commands That Save and Restore the Edit Chain Several facilities are available for saving the current edit chain and later retrieving it: MARK, which marks the current chain for future 32 reference, _, which returns to the last mark without destroying it, and __, which returns to the last mark and also erases it. MARK adds the current edit chain to the front of the list marklst. _ makes the new edit chain be (CAR MARKLST). Generates an error if marklst is NIL, i.e., no MARKs have been performed, or all have been erased. __ similar to _ but also erases the MARK, i.e., performs (SETQ MARKLST (CDR MARKLST)). Note that if the user has two chains marked, and wishes to return to the first chain, he must perform __, which removes the second mark, and then _. However, the second mark is then no longer accessible. If the user wants to be able to return to either of two (or more) chains, he can use the following generalized MARK: (MARK atom) sets atom to the current edit chain, (\ atom) makes the current edit chain become the value of atom. If the user did not prepare in advance for returning to a particular edit chain, he may still be able to return to that chain with a single command by using \ or \P. \ makes the edit chain be the value of unfind. Generates an error if unfind=NIL. ------------------------------------------------------------------------ 32 An atomic command; do not confuse _ with the list command (_ pattern). 9.25 unfind is set to the current edit chain by each command that makes a "big jump", i.e., a command that usually performs more than a single ascent or descent, namely ^, _, __, !NX, all commands that involve a 33 search, e.g., F, LC, .., BELOW, et al and \ and \P themselves. For example, if the user types F COND, and then F CAR, \ would take him back to the COND. Another \ would take him back to the CAR, etc. \P restores the edit chain to its state as of the last print operation, i.e., P, ?, or PP. If the edit chain has not changed since the last printing, \P restores it to its state as of the printing before that one, i.e., two chains are always saved. For example, if the user types P followed by 3 2 1 P, \P will return to 34 the first P, i.e., would be equivalent to 0 0 0. Another \P would then take him back to the second P, i.e., the user could use \P to flip back and forth between the two edit chains. (S var . @) Sets var (using setq) to the current expression after performing (LC . @). Edit chain is not changed. Thus (S FOO) will set foo to the current expression, (S FOO -1 1) will set foo to the first element in the last element of the current expression. This ends the section on "Attention Changing Commands." ------------------------------------------------------------------------ 33 Except that unfind is not reset when the current edit chain is the top level expression, since this could always be returned to via the ^ command. 34 Note that if the user had typed P followed by F COND, he could use either \ or \P to return to the P, i.e., the action of \ and \P are independent. 9.26 9.4 Commands That Modify Structure The basic structure modification commands in the editor are: (n) n > 1 deletes the corresponding element from the current expression. (n e1 ... em) n,m > 1 replaces the nth element in the current expression with e1 ... em. (-n e1 ... em) n,m > 1 inserts e1 ... em before the nth element in the current expression. (N e1 ... em) m > 1 attaches e1 ... em at the end of the current expression. As mentioned earlier: all structure modification done by the editor is destructive, i.e., the editor uses rplaca and rplacd to physically change the structure it was given. However, all structure modification is undoable, see UNDO page 9.59. All of the above commands generate errors if the current expression is not a list, or in the case of the first three commands, if the list contains fewer than n elements. In addition, the command (1), i.e., delete the first element, will cause an error if there is only one element, since deleting the first element must be done by replacing it with the second element, and then deleting the second element. Or, to look at it another way, deleting the first element when there is only one element would require changing a list to an atom (i.e., to NIL) 35 which cannot be done. If the value of changesarray is a hash array, the editor will mark all structures that are changed by doing puthash[structure;fn;changesarray], where fn is the name of the function. The algorithm used for marking is as follows: (1) If the expression is inside of another expression already marked as being changed, do nothing. ------------------------------------------------------------------------ 35 However, the command DELETE will work even if there is only one element in the current expression, since it will ascend to a point where it can do the deletion. 9.27 (2) If the change is an insertion of or replacement with a list, mark the list as changed. (3) If the change is an insertion of or replacement with an atom, or a deletion, mark the parent as changed. changesarray is primarily for use by prettyprint (Section 14). When the value of changechar is not NIL, prettyprint, when printing to a file or display terminal, prints changechar in the right margin while printing an expression marked as having been changed. changechar is initially |. 9.4.1 Implementation of Structure Modification Commands Note: Since all commands that insert, replace, delete or attach structure use the same low level editor functions, the remarks made here are valid for all structure changing commands. For all replacement, insertion, and attaching at the end of a list, 36 unless the command was typed in directly to the editor, copies of the corresponding structure are used, because of the possibility that the exact same command, (i.e., same list structure) might be used again. Thus if a program constructs the command (1 (A B C)) e.g., via (LIST 1 FOO), and gives this command to the editor, the (A B C) used for 37 the replacement will not be eq to foo. The rest of this section is included for applications wherein the editor is used to modify a data structure, and pointers into that data structure are stored elsewhere. In these cases, the actual mechanics of structure modification must be known in order to predict the effect that various commands may have on these outside pointers. For example, if the value of foo is cdr of the current expression, what will the commands (2), (3), (2 X Y Z), (-2 X Y Z), etc. do to foo? Deletion of the first element in the current expression is performed by replacing it with the second element and deleting the second element by patching around it. Deletion of any other element is done by patching around it, i.e., the previous tail is altered. Thus if foo is eq to the ------------------------------------------------------------------------ 36 Some editor commands take as arguments a list of edit commands, e.g., (LP F FOO (1 (CAR FOO))). In this case, the command (1 (CAR FOO)) is not considered to have been "typed in" even though the LP command itself may have been typed in. Similarly, commands originating from macros, or commands given to the editor as arguments to editf, editv, et al, e.g., EDITF(FOO F COND (N --)) are not considered typed in. 37 The user can circumvent this by using the I command, which computes the structure to be used. In the above example, the form of the command would be (I 1 FOO), which would replace the first element with the value of foo itself. See page 9.47. 9.28 current expression which is (A B C D), and fie is cdr of foo, after executing the command (1), foo will be (B C D) (which is equal but not eq to fie). However, under the same initial conditions, after executing (2) fie will be unchanged, i.e., fie will still be (B C D) even though 38 the current expression and foo are now (A C D). Both replacement and insertion are accomplished by smashing both car and cdr of the corresponding tail. Thus, if foo were eq to the current expression, (A B C D), after (1 X Y Z), foo would be (X Y Z B C D). Similarly, if foo were eq to the current expression, (A B C D), then after (-1 X Y Z), foo would be (X Y Z A B C D). The N command is accomplished by smashing the last cdr of the current expression a la nconc. Thus if foo were eq to any tail of the current expression, after executing an N command, the corresponding expressions would also appear at the end of foo. In summary, the only situation in which an edit operation will not change an external pointer occurs when the external pointer is to a proper tail of the data structure, i.e., to cdr of some node in the structure, and the operation is deletion. If all external pointers are to elements of the structure, i.e., to car of some node, or if only insertions, replacements, or attachments are performed, the edit operation will always have the same effect on an external pointer as it does on the current expression. 9.4.2 The A, B, and : Commands In the (n), (n e1 ... em), and (-n e1 ... em) commands, the sign of the integer is used to indicate the operation. As a result, there is no direct way to express insertion after a particular element, (hence the necessity for a separate N command). Similarly, the user cannot specify deletion or replacement of the nth element from the end of a list without first converting n to the corresponding positive integer. Accordingly, we have: (B e1 ... em) inserts e1 ... em before the current expression. Equivalent to UP followed by (-1 e1 ... em). For example, to insert FOO before the last element in the current expression, perform -1 and then (B FOO). ------------------------------------------------------------------------ 38 A general solution of the problem just isn't possible, as it would require being able to make two lists eq to each other that were originally different. Thus if fie is cdr of the current expression, and fum is cddr of the current expression, performing (2) would have to make fie be eq to fum if all subsequent operations were to update both fie and fum correctly. Think about it. 9.29 (A e1 ... em) inserts e1 ... em after the current expression. Equivalent to UP followed by (-2 e1 ... em) or (N e1 ... em) whichever is appropriate. (: e1 ... em) replaces the current expression by e1 ... em. Equivalent to UP followed by (1 e1 ... em). DELETE or (:) deletes the current expression. DELETE first tries to delete the current expression by performing an UP and then a (1). This works in most cases. However, if after performing UP, the new current expression contains only one element, the command (1) will not work. Therefore, DELETE starts over and performs a BK, followed by UP, followed by (2). For example, if the current expression is (COND ((MEMB X Y)) (T Y)), and the user performs -1, and then DELETE, the BK-UP-(2) method is used, and the new current expression will be ... ((MEMB X Y))) However, if the next higher expression contains only one element, BK will not work. So in this case, DELETE performs UP, followed by (: NIL), i.e., it replaces the higher expression by NIL. For example, if the current expression is (COND ((MEMB X Y)) (T Y)) and the user performs F MEMB and then DELETE, the new current expression will be ... NIL (T Y)) and the original expression would now be (COND NIL (T Y)). The rationale behind this is that deleting (MEMB X Y) from ((MEMB X Y)) changes a list of one element to a list of no elements, i.e., () or NIL. If the current expression is a tail, then B, A, :, and DELETE all work exactly the same as though the current expression were the first element in that tail. Thus if the current expression were ... (PRINT Y) (PRINT Z)), (B (PRINT X)) would insert (PRINT X) before (PRINT Y), leaving the current expression ... (PRINT X) (PRINT Y) (PRINT Z)). The following forms of the A, B, and : commands incorporate a location specification: 39 40 (INSERT e1 ... em BEFORE . @) Similar to (LC .@) followed by (B e1 ... em). ------------------------------------------------------------------------ 39 i.e., @ is cdr[member[BEFORE;command]] 40 except that if @ causes an error, the location process does not continue as described on page 9.21. For example if @=(COND 3) and the next COND does not have a 3rd element, the search stops and the INSERT fails. Note that the user can always write (LC COND 3) if he intends the search to continue. 9.30 *P (PROG (& & X) **COMMENT** (SELECTQ ATM & NIL) (OR & &) (PRIN1 & T) (PRIN1 & T) (SETQ X & *(INSERT LABEL BEFORE PRIN1) *P (PROG (& & X) **COMMENT** (SELECTQ ATM & NIL) (OR & &) LABEL (PRIN1 & T) ( 41 * Current edit chain is not changed, but unfind is set to the edit chain after the B was performed, i.e.,\ will make the edit chain be that chain where the insertion was performed. (INSERT e1 ... em AFTER . @) Similar to INSERT BEFORE except uses A instead of B. (INSERT e1 ... em FOR . @) similar to INSERT BEFORE except uses : for B. 42 (REPLACE @ WITH e1 ... em) 43 Here @ is the segment of the command between REPLACE and WITH. Same as (INSERT e1 ... em FOR . @). Example: (REPLACE COND -1 WITH (T (RETURN L))) (CHANGE @ TO e1 ... em) Same as REPLACE WITH. 44 (DELETE . @) does a (LC . @) followed by DELETE. Current ------------------------------------------------------------------------ 41 Sudden termination of output followed by a blank line return indicates printing was aborted by control-E. 42 BY can be used for WITH. 43 See footnote on page 9.30. 44 See footnote on page 9.30. 9.31 45 edit chain is not changed, but unfind is set to the edit chain after the DELETE was performed. Example: (DELETE -1), (DELETE COND 3) Note: if @ is NIL (i.e., empty), the corresponding operation is performed here (on the current edit chain). For example, (REPLACE WITH (CAR X)) is equivalent to (: (CAR X)). For added readability, HERE is also permitted, e.g., (INSERT (PRINT X) BEFORE HERE) will insert (PRINT X). before the current expression (but not change the edit chain). Note: @ does not have to specify a location within the current expression, i.e., it is perfectly legal to ascend to INSERT, REPLACE, or DELETE For example, (INSERT (RETURN) AFTER ^ PROG -1) will go to the top, find the first PROG, and insert a (RETURN) at its end, and not change the current edit chain. The A, B, and : commands, commands, (and consequently INSERT, REPLACE, and CHANGE), all make special checks in e1 thru em for expressions of the form (## . coms). In this case, the expression used for inserting or replacing is a copy of the current expression after executing coms, a 46 list of edit commands. For example, (INSERT (## F COND -1 -1) AFTER 47 3) will make a copy of the last form in the last clause of the next cond, and insert it after the third element of the current expression. ------------------------------------------------------------------------ 45 Unless the current expression is no longer a part of the expression being edited, e.g., if the current expression is ... C) and the user performs (DELETE 1), the tail, (C), will have been cut off. Similarly, if the current expression is (CDR Y) and the user performs (REPLACE WITH (CAR X)). 46 The execution of coms does not change the current edit chain. 47 Not (INSERT F COND -1 (## -1) AFTER 3), which inserts four elements after the third element, namely F, COND, -1, and a copy of the last element in the current expression. 9.32 9.4.3 Form Oriented Editing and the Role of UP 48 The UP that is performed before A, B, and : commands makes these operations form-oriented. For example, if the user types F SETQ, and then DELETE, or simply (DELETE SETQ), he will delete the entire SETQ expression, whereas (DELETE X) if X is a variable, deletes just the variable X. In both cases, the operation is performed on the corresponding form, and in both cases is probably what the user intended. Similarly, if the user types (INSERT (RETURN Y) BEFORE SETQ), 49 he means before the SETQ expression, not before the atom SETQ. A consequent of this procedure is that a pattern of the form (SETQ Y --) can be viewed as simply an elaboration and further refinement of the pattern SETQ. Thus (INSERT (RETURN Y) BEFORE SETQ) and 50 (INSERT (RETURN Y) BEFORE (SETQ Y --)) perform the same operation and, in fact, this is one of the motivations behind making the current expression after F SETQ, and F (SETQ Y --) be the same. Occasionally, however, a user may have a data structure in which no special significance or meaning is attached to the position of an atom in a list, as INTERLISP attaches to atoms that appear as car of a list, versus those appearing elsewhere in a list. In general, the user may not even know whether a particular atom is at the head of a list or not. Thus, when he writes (INSERT expression BEFORE FOO), he means before the atom FOO, whether or not it is car of a list. By setting the variable 51 upfindflg to NIL, the user can suppress the implicit UP that follows searches for atoms, and thus achieve the desired effect. With upfindflg=NIL, following F FOO, for example, the current expression will be the atom FOO. In this case, the A, B, and : operations will operate with respect to the atom FOO. If the user intends the operation to refer to the list which FOO heads, he simply uses instead the pattern (FOO --). ------------------------------------------------------------------------ 48 and therefore in INSERT, CHANGE, REPLACE, and DELETE commands after the location portion of the operation has been performed. 49 There is some ambiguity in (INSERT expr AFTER functionname), as the user might mean make expr be the function's first argument. Similarly, the user cannot write (REPLACE SETQ WITH SETQQ) meaning change the name of the function. The user must in these cases write (INSERT expr AFTER functioname 1), and (REPLACE SETQ 1 WITH SETQQ). 50 assuming the next SETQ is of the form (SETQ Y --). 51 Initially, and usually, set to T. 9.33 9.4.4 Extract and Embed Extraction involves replacing the current expression with one of its subexpressions (from any depth). (XTR . @) replaces the original current expression with the expression that is current after performing 52 (LCL . @). For example, if the current expression is (COND ((NULL X) (PRINT Y))), (XTR PRINT), or (XTR 2 2) will replace the cond by the print. If the current expression after (LCL . @) is a tail of a higher expression, its first element is used. For example, if the current expression is (COND ((NULL X) Y) (T Z)), then (XTR Y) will replace the cond with Y, even though the current expression after performing (LCL Y) is ... Y). If the extracted expression is a list, then after XTR has finished, the current expression will be that list. Thus, in the first example, the current expression after the XTR would be (PRINT Y). If the extracted expression is not a list, the new current expression will be a tail whose first element is that non-list. Thus, in the second example, the current expression after the XTR would be ... Y followed by whatever followed the COND. If the current expression initially is a tail, extraction works exactly the same as though the current expression were the first element in that tail. Thus if the current expression is ... (COND ((NULL X) (PRINT Y))) (RETURN Z)), then (XTR PRINT) will replace the cond by the print, leaving (PRINT Y) as the current expression. The extract command can also incorporate a location specification: ------------------------------------------------------------------------ 52 See footnote on page 9.30. 9.34 53 54 (EXTRACT @1 FROM . @2) Performs (LC . @2) and then (XTR . @1). Current edit chain is not changed, but unfind is set to the edit chain after the XTR was performed. Example: If the current expression is (PRINT (COND ((NULL X) Y) (T Z))) then following (EXTRACT Y FROM COND), the current expression will be (PRINT Y). (EXTRACT 2 -1 FROM COND), (EXTRACT Y FROM 2), (EXTRACT 2 -1 FROM 2) will all produce the same result. While extracting replaces the current expression by a subexpression, embedding replaces the current expression with one containing it as a subexpression. 55 (MBD e1 ... em) MBD substitutes the current expression for all instances of the atom * in e1 ... em, and replaces the current expression with the result of that substitution. Examples: If the current expression is (PRINT Y), (MBD (COND ((NULL X) *) ((NULL (CAR Y)) * (GO LP)))) would replace (PRINT Y) with (COND ((NULL X) (PRINT Y)) ((NULL (CAR Y)) (PRINT Y) (GO LP))). If the current expression is (RETURN X), (MBD (PRINT Y) (AND FLG *)) would replace it with the two expressions (PRINT Y) and (AND FLG (RETURN X)) i.e., if the (RETURN X) appeared in the cond clause (T (RETURN X)), after the MBD, the clause would be (T (PRINT Y) (AND FLG (RETURN X))). If * does not appear in e1 ... em, the MBD is interpreted as (MBD (e1 ... em *)). Examples: If the current expression is (PRINT Y), then (MBD SETQ X) will replace it with (SETQ X (PRINT Y)). If the current expression is (PRINT Y), (MBD RETURN) will replace it with (RETURN (PRINT Y)). MBD leaves the edit chain so that the larger expression is the new current expression. If the current expression initially is a tail, embedding works exactly the same as though the current expression were the first element in that tail. Thus if the current expression were ... (PRINT Y) (PRINT Z)), (MBD SETQ X) would replace (PRINT Y) with (SETQ X (PRINT Y)). ------------------------------------------------------------------------ 53 @1 is the segment between EXTRACT and FROM. 54 See footnote on page 9.30. 55 as with subst, a fresh copy is used for each substitution. 9.35 The embed command can also incorporate a location specification: 56 57 (EMBED @ IN . x) does (LC . @) and then (MBD . x). Edit chain is not changed, but unfind is set to the edit chain after the MBD was performed. Example: (EMBED PRINT IN SETQ X), (EMBED 3 2 IN RETURN), (EMBED COND 3 1 IN (OR * (NULL X))). WITH can be used for IN, and SURROUND can be used for EMBED, e.g., (SURROUND NUMBERP WITH (AND * (MINUSP X))). 9.4.5 The MOVE Command The MOVE command allows the user to specify (1) the expression to be moved, (2) the place it is to be moved to, and (3) the operation to be performed there, e.g., insert it before, insert it after, replace, etc. 58 (MOVE @1 TO com . @2) where com is BEFORE, AFTER, or the name of a list command, e.g., :, N, etc. performs 59 (LC . @1), and obtains the current expression there (or its first element, if it is a tail), which we will call expr; MOVE then goes back to the original edit chain, performs (LC . @2) 60 followed by (com expr), then goes back to @1 and deletes expr. Edit chain is not changed. Unfind is set to edit chain after (com expr) was performed. For example, if the current expression is (A B C D), (MOVE 2 TO AFTER 4) will make the new current expression be (A C D B). Note that 4 was executed as of the original edit chain, and that the second element had ------------------------------------------------------------------------ 56 @ is the segment between EMBED and IN. 57 See footnote on page 9.30. 58 @1 is the segment between MOVE and TO. 59 see footnote on page 9.30. 60 Setting an internal flag so expr is not copied. 9.36 61 not yet been removed. As the following examples taken from actual editing will show, the MOVE command is an extremely versatile and powerful feature of the editor. *? (PROG ((L L)) (EDLOC (CDDR C)) (RETURN (CAR L))) *(MOVE 3 TO : CAR) *? (PROG ((L L)) (RETURN (EDLOC (CDDR C)))) * *P ... (SELECTQ OBJPR & &) (RETURN &) LP2 (COND & &)) *(MOVE 2 TO N 1) *P ... (SELECTQ OBJPR & & &) LP2 (COND & &)) * *P (OR (EQ X LASTAIL) (NOT &) (AND & & &)) *(MOVE 4 TO AFTER (BELOW COND)) *P (OR (EQ X LASTAIL) (NOT &)) *\ P ... (& &) (AND & & &) (T & &)) * *P ((NULL X) **COMMENT** (COND & &)) *(-3 (GO NXT] *(MOVE 4 TO N (_ PROG)) *P ((NULL X) **COMMENT** (GO NXT)) *\ P (PROG (&) **COMMENT** (COND & & &) (COND & & &) (COND & &)) *(INSERT NXT BEFORE -1) *P (PROG (&) **COMMENT** (COND & & &) (COND & & &) NXT (COND & &)) Note that in the last example, the user could have added the prog label NXT and moved the cond in one operation by performing (MOVE 4 TO N (_ PROG) (N NXT)). Similarly, in the next example, in the course of specifying @2, the location where the expression was to be moved to, the user also performs a structure modification, via (N (T)), thus creating the structure that will receive the expression being moved. ------------------------------------------------------------------------ 61 If @2 specifies a location inside of the expression to be moved, a message is printed and an error is generated, e.g., (MOVE 2 TO AFTER X), where X is contained inside of the second element. 9.37 *P ((CDR &) **COMMENT** (SETQ CL &) (EDITSMASH CL & &)) *MOVE 4 TO N 0 (N (T)) -1] *P ((CDR &) **COMMENT** (SETQ CL &)) *\ P *(T (EDITSMASH CL & &)) * If @2 is NIL, or (HERE), the current position specifies where the operation is to take place. In this case, unfind is set to where the expression that was moved was originally located, i.e., @1. For example: *P (TENEX) *(MOVE ^ F APPLY TO N HERE) *P (TENEX (APPLY & &)) * *P (PROG (& & & ATM IND VAL) (OR & &) **COMMENT** (OR & &) (PRIN1 & T) ( PRIN1 & T) (SETQ IND 62 *(MOVE * TO BEFORE HERE) *P (PROG (& & & ATM IND VAL) (OR & &) (OR & &) (PRIN1 & *P (T (PRIN1 C-EXP T)) *(MOVE ^ BF PRIN1 TO N HERE) *P (T (PRIN1 C-EXP T) (PRIN1 & T)) * Finally, if @1 is NIL, the MOVE command allows the user to specify where the current expression is to be moved to. In this case, the edit chain is changed, and is the chain where the current expression was moved to; unfind is set to where it was. *P (SELECTQ OBJPR (&) (PROGN & &)) *(MOVE TO BEFORE LOOP) *P ... (SELECTQ OBJPR & &) LOOP (FRPLACA DFPRP &) (FRPLACD DFPRP &) (SELECTQ * ------------------------------------------------------------------------ 62 Sudden termination of output followed by a blank line indicates printing was aborted by control-E. 9.38 9.4.6 Commands That "Move Parentheses" The commands presented in this section permit modification of the list structure itself, as opposed to modifying components thereof. Their effect can be described as inserting or removing a single left or right parenthesis, or pair of left and right parentheses. Of course, there will always be the same number of left parentheses as right parentheses in any list structure, since the parentheses are just a notational guide to the structure provided by print. Thus, no command can insert or remove just one parenthesis, but this is suggestive of what actually happens. In all six commands, n and m are used to specify an element of a list, usually of the current expression. In practice, n and m are usually positive or negative integers with the obvious interpretation. However, all six commands use the generalized NTH command, page 9.24, to find their element(s), so that nth element means the first element of the tail found by performing (NTH n). In other words, if the current expression is (LIST (CAR X) (SETQ Y (CONS W Z))), then (BI 2 CONS), (BI X -1), and (BI X Z) all specify the exact same operation. All six commands generate an error if the element is not found, i.e., the NTH fails. All are undoable. (BI n m) both in, inserts a left parentheses before the nth element and after the mth element in the current expression. Generates an error if the mth element is not contained in the nth tail, i.e., the mth element must be "to the right" of the nth element. Example: If the current expression is (A B (C D E) F G), then (BI 2 4) will modify it to be (A (B (C D E) F) G). (BI n) same as (BI n n). Example: If the current expression is (A B (C D E) F G), then (BI -2) will modify it to be (A B (C D E) (F) G). (BO n) both out. Removes both parentheses from the nth element. Generates an error if nth element is not a list. Example: If the current expression is (A B (C D E) F G), then (BO D) will modify it to be (A B C D E F G). (LI n) left in, inserts a left parenthesis before the nth element (and a matching right parenthesis at the end of the current expression), i.e. equivalent to (BI n -1). Example: if the current expression is (A B (C D E) F G), then (LI 2) will modify it to be (A (B (C D E) F G)). 9.39 (LO n) left out, removes a left parenthesis from the nth element. All elements following the nth element are deleted. Generates an error if nth element is not a list. Example: If the current expression is (A B (C D E) F G), then (LO 3) will modify it to be (A B C D E). (RI n m) right in, inserts a right parenthesis after the mth element of the nth element. The rest of the nth element is brought up to the level of the current expression. Example: If the current expression is (A (B C D E) F G), (RI 2 2) will modify it to be (A (B C) D E F G). Another way of thinking about RI is to read it as "move the right parenthesis at the end of the nth element in to after its mth element." (RO n) right out, removes the right parenthesis from the nth element, moving it to the end of the current expression. All elements following the nth element are moved inside of the nth element. Generates an error if nth element is not a list. Example: If the current expression is (A B (C D E) F G), (RO 3) will modify it to be (A B (C D E F G)). Another way of thinking about RO is to read it as "move the right parenthesis at the end of the nth element out to the end of the current expression." 9.4.7 TO and THRU EXTRACT, EMBED, DELETE, REPLACE, and MOVE can be made to operate on several contiguous elements, i.e., a segment of a list, by using in their respective location specifications the TO or THRU command. (@1 THRU @2) does a (LC . @1), followed by an UP, and then a (BI 1 @2), thereby grouping the segment into a single element, and finally does a 1, making the final current expression be that element. For example, if the current expression is (A (B (C D) (E) (F G H) I) J K), following (C THRU G), the current expression will be ((C D) (E) (F G H)). (@1 TO @2) Same as THRU except last element not included, i.e., after the BI, an (RI 1 -2) is performed. If both @1 and @2 are numbers, and @2 is greater than @1, then @2 counts from the beginning of the current expression, the same as @1. In other words, if the current expression is (A B C D E F G), (3 THRU 5) means (C THRU E) not (C THRU G). In this case, the corresponding BI command is (BI 1 @2-@1+1). 9.40 THRU and TO are not very useful commands by themselves; they are intended to be used in conjunction with EXTRACT, EMBED, DELETE, REPLACE, and MOVE. After THRU and TO have operated, they set an internal editor flag informing the above commands that the element they are operating on is actually a segment, and that the extra pair of parentheses should be removed when the operation is complete. Thus: *P (PROG (& & ATM IND VAL WORD) (PRIN1 & T) (PRIN1 & T) (SETQ IND &) (SETQ VAL &) **COMMENT** (SETQQ *(MOVE (3 THRU 4) TO BEFORE 7) *P (PROG (& & ATM IND VAL WORD) (SETQ IND &) (SETQ VAL &) (PRIN1 & T) (PRIN1 & T) **COMMENT** * *P (* FAIL RETURN FROM EDITOR. USER SHOULD NOTE THE VALUES OF SOURCEXPR AND CURRENTFORM. CURRENTFORM IS THE LAST FORM IN SOURCEXPR WHICH WILL HAVE BEEN TRANSLATED, AND IT CAUSED THE ERROR.) *(DELETE (USER THRU CURR$)) =CURRENTFORM. *P (* FAIL RETURN FROM EDITOR. CURRENTFORM IS * *P ... LP (SELECTO & & & & NIL) (SETQ Y &) OUT (SETQ FLG &) (RETURN Y)) *(MOVE (1 TO OUT) TO N HERE] *P ... OUT (SETQ FLG &) (RETURN Y) LP (SELECTQ & & & & NIL) (SETQ Y &)) * *PP [PROG (RF TEMP1 TEMP2) (COND ((NOT (MEMB REMARG LISTING)) (SETQ TEMP1 (ASSOC REMARG NAMEDREMARKS)) **COMMENT** (SETQ TEMP2 (CADR TEMP1)) (GO SKIP)) (T **COMMENT** (SETQ TEMP1 REMARG))) (NCONC1 LISTING REMARG) (COND ((NOT (SETQ TEMP2 (SASSOC *(EXTRACT (SETQ THRU CADR) FROM COND) *P (PROG (RF TEMP1 TEMP2) (SETQ TEMP1 &) **COMMENT** (SETQ TEMP2 &) (NCONC1 LISTING REMARG) (COND & & * 9.41 63 TO and THRU can also be used directly with XTR. Thus in the previous example, if the current expression had been the COND, e.g., the user had first performed F COND, he could have used (XTR (SETQ THRU CADR)) to perform the extraction. (@1 TO), (@1 THRU) both same as (@1 THRU -1), i.e., from @1 through the end of the list. Examples: *P (VALUE (RPLACA DEPRP &) (RPLACD &) (RPLACA VARSWORD &) (RETURN)) *(MOVE (2 TO) TO N (_ PROG)) *(N (GO VAR)) *P (VALUE (GO VAR)) *P (T **COMMENT** (COND &) **COMMENT** (EDITSMASH CL & &) (COND &)) *(-3 (GO REPLACE)) *(MOVE (COND TO) TO N ^ PROG (N REPLACE)) *P (T **COMMENT** (GO REPLACE)) *\ P (PROG (&) **COMMENT** (COND & & &) (COND & & &) DELETE (COND & &) REPLACE (COND &) **COMMENT** (EDITSMASH CL & &) (COND &)) * ------------------------------------------------------------------------ 63 Because XTR involves a location specification while A, B, :, and MBD do not. 9.42 *PP [LAMBDA (CLAUSALA X) (PROG (A D) (SETQ A CLAUSALA) LP (COND ((NULL A) (RETURN))) (SERCH X A) (RUMARK (CDR A)) (NOTICECL (CAR A)) (SETQ A (CDR A)) (GO LP] *(EXTRACT (SERCH THRU NOT$) FROM PROG) =NOTICECL *P (LAMBDA (CLAUSALA X) (SERCH X A) (RUMARK &) (NOTICECL &)) *(EMBED (SERCH TO) IN (MAP CLAUSALA (FUNCTION (LAMBDA (A) *] *PP [LAMBDA (CLAUSALA X) (MAP CLAUSALA (FUNCTION (LAMBDA (A) (SERCH X A) (RUMARK (CDR A)) (NOTICECL (CAR A] * 9.4.8 The R Command (R x y) replaces all instances of x by y in the current expression, e.g., (R CAADR CADAR). Generates an error if there is not at least one instance. The R command operates in conjunction with the search mechanism of the editor. The search proceeds as described on page 9.17-19, and x can employ any of the patterns on page 9.16-17. Each time x matches an element of the structure, the element is replaced by (a copy of) y; each time x matches a tail of the structure, the tail is replaced by (a copy of) y. For example, if the current expression is (A (B C) (B . C)), (R C D) will change it to (A (B D) (B . D)), (R (... . C) D) to (A (B C) (B . D)), (R C (D E)) to (A (B (D E)) (B D E)), and (R (... . NIL) D) to (A (B C . D) (B . C) . D). If x is an atom or string containing alt-modes, alt-modes appearing in y stand for the characters matched by the corresponding alt-mode in x. For example, (R FOO$ FIE$) means for all atoms or strings that begin with 9.43 64 FOO, replace the characters "FOO" by "FIE". Applied to the list (FOO FOO2 XFOO1), (R FOO$ FIE$) would produce (FIE FIE2 XFOO1), and (R $FOO$ $FIE$) would produce (FIE FIE2 XFIE1). Similarly, (R $D$ $A$) 65 will change (LIST (CADR X) (CADDR Y)) to (LIST (CAAR X) (CAADR)). The user will be informed of all such alt-mode replacements by a message of the form x->y, e.g., CADR->CAAR. Note that the $ feature can be used to delete or add characters, as well as replace them. For example, (R $1 $) will delete the terminating 1's from all literal atoms and strings. Similarly, if an alt-mode in x does not have a mate in y, the characters matched by the $ are effectively 66 deleted. For example, (R $/$ $) will change AND/OR to AND. y can also be a list containing alt-modes, e.g., (R $1 (CAR $)) will change FOO1 to (CAR FOO), FIE1 to (CAR FIE). If x does not contain alt-modes, $ appearing in y refers to the entire expression matched by x, e.g., (R LONGATOM '$) changes LONGATOM to 'LONGATOM, (R (SETQ X &) (PRINT $)) changes every (SETQ X &) to 67 (PRINT (SETQ X &)). Since (R $x$ $y$) is a frequently used operation for replacing characters, the following command is provided: (RC x y) equivalent to (R $x$ $y$) ------------------------------------------------------------------------ 64 If x matches a string, it will be replaced by a string. Note that it does not matter whether x or y themselves are strings, i.e. (R $D$ $A$), (R "$D$" $A$), (R $D$ "$A$"), and (R "$D$" "$A$") are equivalent. Note also that x will never match with a number, i.e., (R $1 $2) will not change 11 to 12. 65 Note that CADDR was not changed to CAAAR, i.e., (R $D$ $A$) does not mean replace every D with A, but replace the first D in every atom or string by A. If the user wanted to replace every D by A, he could perform (LP (R $D$ $A$)). 66 However, there is no similar operation for changing AND/OR to OR, since the first $ in y always corresponds to the first $ in x, the second $ in y to the second in x, etc. 67 If x is a pattern containing an alt-mode pattern somewhere within it, the characters matched by the alt-modes are not available, and for the purposes of replacement, the effect is the same as though x did not contain any alt-modes. For example, if the user types (R (CAR F$) (PRINT $)), the second $ will refer to the entire expression matched by (CAR F$). 9.44 R and RC change all instances of x to y. The commands R1 and RC1 are available for changing just one, (i.e., the first) instance of x to y. (R1 x y) find the first instance of x and replace it by y. (RC1 x y) (R1 $x$ $y$). In addition, while R and RC only operate within the current expression, R1 and RC1 will continue searching, a la the F command, until they find an instance of x, even if the search carries them beyond the current expression. (SW n m) switches the nth and mth elements of the current expression. For example, if the current expression is (LIST (CONS (CAR X) (CAR Y)) (CONS (CDR X) (CDR Y))), (SW 2 3) will modify it to be (LIST (CONS (CDR X) (CDR Y)) (CONS (CAR X) (CAR Y))). The relative order of n and m is not important, i.e., (SW 3 2) and (SW 2 3) are equivalent. SW uses the generalized NTH command to find the nth and mth elements, a la the BI-BO commands. Thus in the previous example, (SW CAR CDR) would produce the same result. 9.5 Commands That Print PP prettyprints the current expression. P prints the current expression as though printlevel were set to 2. (P m) prints mth element of current expression as though printlevel were set to 2. (P 0) same as P (P m n) prints mth element of current expression as though printlevel were set to n. (P 0 n) prints current expression as though printlevel were set to n. ? same as (P 0 100) 9.45 Both (P m) and (P m n) use the generalized NTH command to obtain the corresponding element, so that m does not have to be a number, e.g., (P COND 3) will work. PP causes all comments to be printed as **COMMENT** (see Section 14). P and ? print as **COMMENT** only those 68 comments that are (top level) elements of the current expression. PP* prettyprints current expression, including comments. PP* is equivalent to PP except that it first resets **comment**flg to NIL (see Section 14). In fact, it is defined as (RESETVAR **COMMENT**FLG NIL PP), see page 9.58. PPV prettyprints current expression as a variable, i.e., no special treatment for LAMBDA, COND, SETQ, etc., or for CLISP. PPT prettyprints current expression, printing CLISP translations, if any. ?= prints the argument names and corresponding values for current expression. Analagous to ?= break command (Section 15). For example, if the current expression is (STRPOS "AO???" X N (QUOTE ?) T), ?= prints X = "AO???" Y = X START = N SKIP = (QUOTE ?) ANCHOR = T TAIL = All printing functions print to the terminal, regardless of the primary output file. All use the readtable T. No printing function ever changes the edit chain. All record the current edit chain for use by \P, page 9.26. All can be aborted with control-E. ------------------------------------------------------------------------ 68 Lower expressions are not really seen by the editor; the printing command simply sets printlevel and calls print. 9.46 9.6 Commands That Evaluate 69 E only when typed in, causes the editor to call 70 lispx giving it the next input as argument. Example: *E BREAK(FIE FUM) (FIE FUM) *E (FOO) (FIE BROKEN) : (E x) evaluates x, i.e., performs eval[x], and prints the result on the terminal. (E x T) same as (E x) but does not print. The (E x) and (E x T) commands are mainly intended for use by macros and subroutine calls to the editor; the user would probably type in a form for evaluation using the more convenient format of the (atomic) E command. (I c x1 ... xn) same as (C y1 ... yn) where y1=eval[xi]. Example: (I 3 (GETD (QUOTE FOO))) will replace the 3rd element of the 71 current expression with the definition of foo. (I N FOO (CAR FIE)) will attach the value of foo and car of the value of fie to the end of the current expression. (I F= FOO T) will search for an expression eq to the value of foo. If c is not an atom, c is evaluated also. ------------------------------------------------------------------------ 69 e.g, (INSERT D BEFORE E) will treat E as a pattern, and search for E. 70 lispx is used by evalqt and break for processing terminal inputs. If nothing else is typed on the same line, lispx evaluates its argument. Otherwise, lispx applies it to the next input. In both cases, lispx prints the result. See above example, and Sections 2 and 22. 71 The I command sets an internal flag to indicate to the structure modification commands not to copy expression(s) when inserting, replacing, or attaching. 9.47 Example: (I (COND ((NULL FLG) (QUOTE -1)) (T 1)) FOO), if flg is NIL, inserts the value of foo before the first element of the current expression, otherwise replaces the first element by the value of foo. ##[com1;com2; ... ;comn]is an NLAMBDA, NOSPREAD function (not a command). Its value is what the current expression would be after executing the edit commands com1 ... comn starting from the present edit chain. Generates an error if any of com1 thru comn cause errors. The current edit chain 72 is never changed. Example: (I R (QUOTE X) (## (CONS .. Z))) replaces all X's in the current expression by the first cons containing a Z. The I command is not very convenient for computing an entire edit command for execution, since it computes the command name and its arguments separately. Also, the I command cannot be used to compute an atomic command. The following two commands provide more general ways of computing commands. (COMS x1 ... xn) Each xi is evaluated and its value is executed as a command. For example, (COMS (COND (X (LIST 1 X)))) will replace the first element of the current expression with the value of x if non-NIL, otherwise do 73 nothing. (COMSQ com1 ... comn) executes com1 ... comn. COMSQ is mainly useful in conjunction with the COMS command. For example, suppose the user wishes to compute an entire list of commands for evaluation, as opposed to computing each command one at a time as does the COMS command. He would then write (COMS (CONS (QUOTE COMSQ) x)) where x computed the list of commands, e.g., (COMS (CONS (QUOTE COMSQ) (GETP FOO (QUOTE COMMANDS)))). ------------------------------------------------------------------------ 72 Recall that A, B, :, INSERT, REPLACE, and CHANGE make special checks for ## forms in the expressions used for inserting or replacing, and use a copy of ## form instead (see page 9.32). Thus, (INSERT (## 3 2) AFTER 1) is equivalent to (I INSERT (COPY (## 3 2)) (QUOTE AFTER) 1). 73 because NIL as a command is a NOP, see page 9.53. 9.48 9.7 Commands That Test (IF x) generates an error unless the value of eval[x] is true, i.e., if eval[x] causes an error or eval[x]=NIL, IF will cause an error. For some editor commands, the occurrence of an error has a well defined meaning, i.e., they use errors to branch on, as cond uses NIL and non- NIL. For example, an error condition in a location specification may simply mean "not this one, try the next." Thus the location specification (IPLUS (E (OR (NUMBERP (## 3)) (ERROR!)) T)) specifies the first IPLUS whose second argument is a number. The IF command, by equating NIL to error, provides a more natural way of accomplishing the same result. Thus, an equivalent location specification is (IPLUS (IF (NUMBERP (## 3)))). The IF command can also be used to select between two alternate lists of commands for execution. (IF x coms1 coms2) If eval[x] is true, execute coms1; if eval[x] causes an error or is equal to NIL, execute 74 coms2. For example, the command (IF (READP T) NIL (P)) will print the current expression provided the input buffer is empty. (IF x coms1) if eval[x] is true, execute coms1; otherwise generate an error. (LP . coms) repeatedly executes coms, a list of commands, until an error occurs. For example, (LP F PRINT (N T)) will attach a T at the end of every print expression. (LP F PRINT (IF (## 3) NIL ((N T)))) will attach a T at the end of each print expression which does not already have a second 75 argument. When an error occurs, LP prints n OCCURRENCES. ------------------------------------------------------------------------ 74 Thus IF is equivalent to (COMS (CONS (QUOTE COMSQ) (COND ((CAR (NLSETQ (EVAL X))) COMS1) (T COMS2)))). 75 i.e., the form (## 3) will cause an error if the edit command 3 causes an error, thereby selecting ((N T)) as the list of commands to be executed. The IF could also be written as (IF (CDDR (##)) NIL ((N T))). 9.49 where n is the number of times coms was successfully executed. The edit chain is left as of the last complete successful execution of coms. (LPQ . coms) same as LP but does not print the message n OCCURRENCES. In order to prevent non-terminating loops, both LP and LPQ terminate 76 when the number of iterations reaches maxloop, initially set to 30. Since the edit chain is left as of the last successful completion of the loop, the user can simply continue the LP command with REDO (Section 22). (SHOW . x) x is a list of patterns. SHOW does a LPQ printing all instances of the indicated expression(s), e.g. (SHOW FOO (SETQ FIE &)) will print all FOO's and all (SETQ FIE &)'s. Generates an error if there aren't any instances of the expression(s). (EXAM . x) like SHOW except calls the editor recursively (via the TTY: command described on page 9.53) on each instance of the indicated espression(s) so that the user can examine and/or change them. (ORR coms1 ... comsn) ORR begins by executing coms1, a list of commands. If no error occurs, ORR is finished. Otherwise, ORR restores the edit chain to its original value, and continues by executing coms2, etc. If none of the command lists execute without errors, i.e., the ORR "drops off the end", ORR generates an error. Otherwise, the edit chain is left as of the completion of the first command list which executes without an 77 error. For example, (ORR (NX) (!NX) NIL) will perform a NX, if possible, ------------------------------------------------------------------------ 76 maxloop can also be set to NIL, which is equivalent to infinity. 77 NIL as a command list is perfectly legal, and will always execute successfully. Thus, making the last "argument" to ORR be NIL will insure that the ORR never causes an error. Any other atom is treated as (atom), i.e., the above example could be written as (OR NX !NX NIL). 9.50 otherwise a !NX, if possible, otherwise do nothing. Similarly, DELETE could be written as (ORR (UP (1)) (BK UP (2)) (UP (: NIL))). 9.8 Macros Many of the more sophisticated branching commands in the editor, such as ORR, IF, etc., are most often used in conjunction with edit macros. The macro feature permits the user to define new commands and thereby expand 78 the editor's repertoire. Macros are defined by using the M command. (M c . coms) For c an atom, M defines c as an atomic 79 command. Executing c is then the same as executing the list of commands coms. For example, (M BP BK UP P) will define BP as an atomic command which does three things, a BK, and UP, and a P. Macros can use commands defined by macros as well as built in commands in their definitions. For example, suppose Z is defined by (M Z -1 (IF (READP T) NIL (P))), i.e., Z does a -1, and then if nothing has been typed, a P. Now we can define ZZ by (M ZZ -1 Z), and ZZZ by (M ZZZ -1 -1 Z) or (M ZZZ -1 ZZ). Macros can also define list commands, i.e., commands that take arguments. (M (c) (arg1 ... argn) . coms) c an atom. M defines c as a list command. Executing (c e1 ... en) is then performed by substituting e1 for arg1, ... en for argn throughout coms, and then executing coms. For example, we could define a more general BP by (M (BP) (N) (BK N) UP P). Thus, (BP 3) would perform (BK 3), followed by an UP, followed by a P. A list command can be defined via a macro so as to take a fixed or indefinite number of "arguments", as with spread vs. nospread functions. The form given above specified a macro with a fixed number of arguments, as indicated by its argument list. If the "argument list" is atomic, 80 the command takes an indefinite number of arguments. ------------------------------------------------------------------------ 78 However built in commands always take precedence over macros, i.e., the editor's repertoire can be expanded, but not redefined. 79 If a macro is redefined, its new definition replaces its old. 80 Note parallelism to EXPR's and EXPR*'s. 9.51 (M (c) arg . coms) c, arg both atoms, defines c as a list command. Executing (c e1 ... en) is performed by substituting (e1 ... en), i.e., cdr of the command, for arg throughout coms, and then executing coms. For example, the command 2ND, page 9.22, can be defined as a macro by (M (2ND) X (ORR ((LC . X) (LC . X)))). Note that for all editor commands, "built in" commands as well as commands defined by macros, atomic definitions and list definitions are completely independent. In other words, the existence of an atomic definition for c in no way affects the treatment of c when it appears as car of a list command, and the existence of a list definition for c in no way affects the treatment of c when it appears as an atom. In particular, c can be used as the name of either an atomic command, or a list command, or both. In the latter case, two entirely different definitions can be used. Note also that once c is defined as an atomic command via a macro definition, it will not be searched for when used in a location specification, unless it is preceded by an F. Thus (INSERT -- BEFORE BP) would not search for BP, but instead perform a BK, and UP, and a P, and then do the insertion. The corresponding also holds true for list commands. Occasionally, the user will want to employ the S command in a macro to save some temporary result. For example, the SW command could be defined as: (M (SW) (N M) (NTH N) (S FOO 1) MARK 0 (NTH M) (S FIE 1) 81 (I 1 FOO) __ (I 1 FIE)) Since this version of SW sets foo and fie, using SW may have undesirable side effects, especially when the editor was called from deep in a computation, we would have to be careful to make up unique names for dummy variables used in edit macros, which is bothersome. Furthermore, it would be impossible to define a command that called itself recursively while setting free variables. The BIND command solves both problems. (BIND . coms) binds three dummy variables #1, #2, #3, (initialized to NIL), and then executes the edit commands coms. Note that these bindings are only in effect while the commands are being ------------------------------------------------------------------------ 81 A more elegant definition would be: (M (SW) (N M) (NTH N) MARK 0 (NTH M) (S FIE 1) (I 1 (## _ 1)) __ (I 1 FIE)), but this would still use one free variable. 9.52 executed, and that BIND can be used recursively; it will rebind #1, #2, and #3 each time it is 82 invoked. Thus we could now write SW safely as: (M (SW (N M) (BIND (NTH N) (S #1 1) MARK 0 (NTH M) (S #2 1) (I 1 #1) __ (I 1 #2)))). User macros are stored on a list usermacros. The prettydef command USERMACROS (Section 14), is available for dumping all or selected user macros. 9.9 Miscellaneous Commands NIL unless preceded by F or BF, is always a NOP. Thus extra right parentheses or square brackets at the ends of commands are ignored. TTY: calls the editor recursively. The user can then type in commands, and have them executed. The TTY: command is completed when the user exits from the lower editor. (see OK and STOP below). The TTY: command is extremely useful. It enables the user to set up a complex operation, and perform interactive attention-changing commands part way through it. For example the command (MOVE 3 TO AFTER COND 3 P TTY:) allows the user to interact, in effect, within the MOVE command. Thus he can verify for himself that the correct location has been found, or complete the specification "by hand." In effect, TTY: says "I'll tell you what you should do when you get there." The TTY: command operates by printing TTY: and then calling the editor. The initial edit chain in the lower editor is the one that existed in the higher editor at the time the TTY: command was entered. Until the user exits from the lower editor, any attention changing commands he 83 executes only affect the lower editor's edit chain. When the TTY: command finishes, the lower editor's edit chain becomes the edit chain of the higher editor. OK exits from the editor ------------------------------------------------------------------------ 82 BIND is implemented by (PROG (#1 #2 #3) (EDITCOMS (CDR COM))) where com corresponds to the BIND command, and editcoms is an internal editor function which executes a list of commands. 83 Of course, if the user performs any structure modification commands while under a TTY: command, these will modify the structure in both editors, since it is the same structure. 9.53 STOP exits from the editor with an error. Mainly for use in conjunction with TTY: commands that the user wants to abort. Since all of the commands in the editor are errorset protected, the user 84 must exit from the editor via a command. STOP provides a way of distinguishing between a successful and unsuccessful (from the user's standpoint) editing session. For example, if the user is executing (MOVE 3 TO AFTER COND TTY:), and he exits from the lower editor with an OK, the MOVE command will then complete its operation. If the user wants to abort the MOVE command, he must make the TTY: command generate an error. He does this by exiting from the lower editor with a STOP command. In this case, the higher editor's edit chain will not be changed by the TTY: command. SAVE exits from the editor and saves the "state of the edit" on the property list of the function or variable being edited under the property EDIT-SAVE. If the editor is called again on the same structure, the editing is effectively "continued," i.e., the edit chain, mark list, value of unfind and undolst are restored. For example: *P (NULL X) *F COND P (COND (& &) (T &)) *SAVE FOO . . . _EDITF(FOO) EDIT *P (COND (& &) (T &)) *\ P (NULL X) * SAVE is necessary only if the user is editing many different expressions; an exit from the editor via OK always saves the state of ------------------------------------------------------------------------ 84 Or by typing a control-D. STOP is preferred even if the user is editing at the evalqt level, as it will perform the necessary "wrapup" to insure that the changes made while editing will be undoable (see Section 22). 9.54 85 the edit of that call to the editor. Whenever the editor is entered, it checks to see if it is editing the same expression as the last one edited. In this case, it restores the mark list, the undolst, and sets unfind to be the edit chain as of the previous exit from the editor. For example: _EDITF(FOO) EDIT *P (LAMBDA (X) (PROG & & LP & & & &)) . . . *P (COND & &) *OK FOO . . any number of lispx inputs . except for calls to the editor _EDITF(FOO) EDIT *P (LAMBDA (X) (PROG & & LP & & & &)) *\ P (COND & &) * Furthermore, as a result of the history feature (section 22), if the editor is called on the same expression within a certain number of lispx 86 inputs, the state of the edit of that expression is restored, regardless of how many other expressions may have been edited in the meantime. ------------------------------------------------------------------------ 85 on the property list of the atom EDIT, under the property name LASTVALUE. OK also remprops EDIT-SAVE from the property list of the function or variable being edited. 86 Namely, the size of the history list, initially 30, but it can be increased by the user. 9.55 For example: _EDITF(FOO) EDIT * . . . *P (COND (& &) (& &) (&) (T &)) *OK FOO _ . less than 30 lispx inputs, including editing . . _EDITF(FOO) EDIT *\ P (COND (& &) (& &) (&) (T &)) * Thus the user can always continue editing, including undoing changes from a previous editing session, if (1) No other expressions have been edited since that 87 session; or (2) That session was "sufficiently" recent; or (3) It was ended with a SAVE command. RAISE is an edit macro defined as UP followed by (I 1 (U-CASE (## 1))), i.e., it raises to upper- case the current expression, or if a tail, the first element of the current expression. LOWER Similar to RAISE, except uses l-case. CAP First does a RAISE, and then lowers all but the first character, i.e., the first character is left capitalized. Note: RAISE, LOWER, and CAP are all NOPs if the corresponding atom or string is already in that state. ------------------------------------------------------------------------ 87 Since saving takes place at exit time, intervening calls that were aborted via control-D or exited via STOP will not affect the editor's memory of this last session. 9.56 (RAISE x) equivalent to (I R (L-CASE x) x), i.e., changes every lower-case x to upper-case in the current expression. (LOWER x) similar to RAISE, except performs (I R x (L- CASE x)). Note in both (RAISE x) and (LOWER x), x is typed in in upper case. REPACK Permits the "editing" of an atom or string. For example: *P ... "THIS IS A LOGN STRING") REPACK *EDIT P (T H I S % I S % A % L O G N % S T R I N G) *(SW G N) *OK 88 "THIS IS A LONG STRING" * REPACK operates by calling the editor recursively on unpack of the current expression, or if it is a list, on unpack of its first element. If the lower editor is exited successfully, i.e., via OK as opposed to STOP, the list of atoms is made into a single atom or string, which replaces the atom or string being 'repacked.' The new atom or string is always printed. (REPACK @) does (LC . @) followed by REPACK, e.g. (REPACK THIS$). (; . x) x is the text of a comment. ; ascends the edit chain looking for a "safe" place to insert the comment, e.g., in a cond clause, after a prog statement, etc., and inserts (* . x) after that point, if possible, otherwise before. For example, if the current expression is (FACT (SUB1 N)) in [COND ((ZEROP N) 1) (T (ITIMES N (FACT (SUB1 N] (; CALL FACT RECURSIVELY) would insert ------------------------------------------------------------------------ 88 Note that this could also have been accomplished by (R $GN$ $NG$) or simply (RC GN NG). 9.57 (* CALL FACT RECURSIVELY) before the itimes 89 expression. ; does not change the edit chain, but unfind is set to where the comment was actually inserted. JOINC is used to join two neighboring COND's together, e.g. (COND clause1 clause2) followed by (COND clause3 clause4) becomes (COND clause1 clause2 clause3 clause4). JOINC does an (F COND T) first so that you don't have to be at the first COND. (SPLITC x) splits one COND into two. x specifies the last clause in the first COND, e.g. (SPLITC 3) splits (COND clause1 clause2 clause3 clause4) into (COND clause1 clause2) (COND clause3 clause4). Uses generalized NTH command, so that x does not have to be a number, e.g.,the user can say (SPLITC RETURN), meaning split after the clause containing RETURN. SPLITC also does an (F COND T) first. CL Clispifies current expression. See Section 23. DW Dwimifies current expression. See Section 17 and 23. (RESETVAR var form . coms) executes coms while var is reset to the value of form, and then restores var, i.e. effectively calls the function resetvar (Section 5). GET* If the current expression is a comment "map" (see Section 14), reads in the full text of the comment and replaces the current expression by it. ------------------------------------------------------------------------ 89 If inserted after the itimes, the comment would then be (incorrectly) returned as the value of the cond. However, if the cond was itself a prog statement, and hence its value was not being used, the comment could be (and would be) inserted after the itimes expression. 9.58 9.10 UNDO Each command that causes structure modification automatically adds an entry to the front of undolst that contains the information required to restore all pointers that were changed by that command. UNDO undoes the last, i.e., most recent, structure modification command that has not yet been 90 undone, and prints the name of that command, e.g., MBD UNDONE. The edit chain is then exactly what it was before the "undone" command 91 had been performed. If there are no commands to undo, UNDO types NOTHING SAVED. !UNDO undoes all modifications performed during this editing session, i.e. this call to the editor. As each command is undone, its name is printed a la UNDO. If there is nothing to be undone, !UNDO prints NOTHING SAVED. Whenever the user continues an editing session as described on page 9.54-56, the undo information of the previous session is protected by inserting a special blip, called an undo-block, on the front of undolst. This undo-block will terminate the operation of a !UNDO, thereby confining its effect to the current session, and will similarly prevent an UNDO command from operating on commands executed in the previous session. Thus, if the user enters the editor continuing a session, and immediately executes an UNDO or !UNDO, the editor will type BLOCKED ------------------------------------------------------------------------ 90 Since UNDO and !UNDO cause structure modification, they also add an entry to undolst. However, UNDO and !UNDO entries are skipped by UNDO, e.g., if the user performs an INSERT, and then an MBD, the first UNDO will undo the MBD, and the second will undo the INSERT. However, the user can also specify precisely which commands he wants undone by identifying the corresponding entry on the history list as described in Section 22. In this case, he can undo an UNDO command, e.g., by typing UNDO UNDO, or undo a !UNDO command, or undo a command other than that most recently performed. 91 Undoing an event containing an I, E, or S command will also undo the side effects of the evaluation(s), e.g., undoing (I 3 (/NCONC FOO FIE)) will not only restore the 3rd element but also restore FOO. Similarly, undoing an S command will undo the set. See discussion of UNDO in Section 22. (Note that if the I command was typed directly to the editor, /NCONC would automatically be substituted for NCONC as described in Section 22.) 9.59 instead of NOTHING SAVED. Similarly, if the user executes several commands and then undoes them all, another UNDO or !UNDO will also cause BLOCKED to be typed. UNBLOCK removes an undo-block. If executed at a non- blocked state, i.e., if UNDO or !UNDO could operate, types NOT BLOCKED. TEST adds an undo-block at the front of undolst. Note that TEST together with !UNDO provide a "tentative" mode for editing, i.e., the user can perform a number of changes, and then undo all of them with a single !UNDO command. 9.11 Editdefault Whenever a command is not recognized, i.e., is not "built in" or defined as a macro, the editor calls an internal function, editdefault, to 92 determine what action to take. If a location specification is being executed, an internal flag informs editdefault to treat the command as though it had been preceded by an F. If the command is a list, an attempt is made to perform spelling 93 correction on car of the command using editcomsl, a list of all list ------------------------------------------------------------------------ 92 Since editdefault is part of the edit block, the user cannot advise or redefine it as a means of augmenting or extending the editor. However, the user can accomplish this via edituserfn. If the value of the variable edituserfn is T, editdefault calls the function edituserfn giving it the command as an argument. If edituserfn returns a non-NIL value, its value is interpreted as a single command and executed. Otherwise, the error correction procedure described below is performed. 93 unless dwimflg=NIL. See Section 17 for discussion of spelling correction. 9.60 94 95 edit commands. If spelling correction is successful, the correct command name is rplacaed into the command, and the editor continues by executing the command. In other words, if the user types (LP F PRINT (MBBD AND (NULL FLG))), only one spelling correction will be necessary to change MBBD to MBD. If spelling correction is not successful, an error is generated. If the command is atomic, the procedure followed is a little more elaborate. 1) If the command is one of the list commands, i.e., a member of editcomsl, and there is additional input on the same terminal line, 96 treat the entire line as a single list command. Thus, the user may omit parentheses for any list command typed in at the top level (provided the command is not also an atomic command, e.g. NX, BK). For example, *P (COND (& &) (T &)) *XTR 3 2] *MOVE TO AFTER LP * If the command is on the list editcomsl but no additional input is on the terminal line, an error is generated, e.g. *P (COND (& &) (T &)) *MOVE MOVE ? * If the command is on editcomsl, and not typed in directly, e.g., it appears as one of the commands in a LP command, the procedure is similar, with the rest of the command stream at that level being treated as "the terminal line", e.g. ------------------------------------------------------------------------ 94 When a macro is defined via the M command, the command name is added to editcomsa or editcomsl, depending on whether it is an atomic or list command. The prettydef command USERMACROS (Section 14), is aware of this, and provides for restoring editcomsa and editcomsl. 95 Throughout this discussion, if the command was not typed in directly, the user will be asked to approve the spelling correction. See Section 17. 96 The line is read using readline (Section 14). Thus the line can be terminated by a square bracket, or by a carriage return not preceded by a space. 9.61 97 (LP F (COND (T &)) XTR 2 2). 2) If the command was typed in and the first character in the command is an 8, treat the 8 as a mistyped left parenthesis, and and the rest of the line as the arguments to the command, e.g., *P (COND (& &) (T &)) *8-2 (Y (RETURN Z))) =(-2 *P (COND (Y &) (& &) (T &)) 3) If the command was typed in, is the name of a function, and is followed by NIL or a list car of which is not an edit command, assume the user forgot to type E and means to apply the function to its arguments, type =E and the function name, and perform the indicated computation, e.g. *BREAK(FOO) =E BREAK (FOO) * 4) If the last character in the command is P, and the first n-1 characters comprise a number, assume that the user intended two commands, e.g., *P (COND (& &) (T &)) *0P =0 P (SETQ X (COND & &)) 98 5) Attempt spelling correction using editcomsa, and if successful, execute the corrected command. 6) Otherwise, if there is additional input on the same line, or command stream, spelling correct using editcomsl as a spelling list, e.g., ------------------------------------------------------------------------ 97 Note that if the command is being executed in location context, editdefault does not get this far, e.g., (MOVE TO AFTER COND XTR 3) will search for XTR, not execute it. However, (MOVE TO AFTER COND (XTR 3)) will work. 98 See footnote on page 9.62. 9.62 *MBBD SETQ X =MBD * 7) Otherwise, generate an error. 9.12 Editor Functions edite[expr;coms;atm] edits an expression. Its value is the last element of editl[list[expr];coms;atm]. Generates an error if expr is not a list. 99 editl[l;coms;atm;mess] editl is the editor. Its first argument is the edit chain, and its value is an edit chain, namely the value of l at the time editl is 100 exited. coms is an optional list of commands. For interactive editing, coms is NIL. In this case, editl types EDIT and then waits for input from 101 terminal. All input is done with editrdtbl as a readtable. Exit occurs only via an OK, STOP, or SAVE command. If coms is not NIL, no message is typed, and each member of coms is treated as a command and executed. If an error occurs in the execution of one of the commands, no error message is printed, the rest of the commands are ignored, and editl exits with an error, i.e., the effect is the same as though a STOP command had been executed. If all commands execute successfully, editl returns the current value of l. atm is optional. On calls from editf, it is the name of the function being edited; on calls from ------------------------------------------------------------------------ 99 edit-ell, not edit-one. 100 l is a specvar, and so can be examined or set by edit commands. For example, ^ is equivalent to (E (SETQ L (LAST L)) T). However, the user should only manipulate or examine l directly as a last resort, and then with caution. 101 If mess is not NIL, editl types it instead of EDIT. For example, the TTY: command is essentially (SETQ L (EDITL L NIL NIL (QUOTE TTY:))). 9.63 editv, the name of the variable, and calls from editp, the atom whose property list is being edited. The property list of atm is used by the SAVE command for saving the state of the edit. Thus SAVE will not save anything if atm=NIL, i.e., when editing arbitrary expressions via edite or editl directly. 102 editl0[l;coms;mess;editlflg] like editl except does not rebind or initialize the editor's various state variables, such as lastail, unfind, undolst, marklst, etc. editf[x] nlambda, nospread function for editing a function. car[x] is the name of the function,cdr[x] an optional list of commands. For the rest of the discussion, fn is car[x], and coms is cdr[x]. The value of editf is fn. (1) In the most common case, fn is an expr, and editf simply performs putd[fn;edite[getd[fn];coms;fn]]. However, if fn is an expr by virtue of its being broken or advised, and (1a) the original definition is also an expr, then the broken/advised definition is given to edite to be edited (since any changes there will also affect the original definition because all changes are destructive). However, a warning message is printed to alert the user that he must first position himself correctly before he can begin typing commands such as (-3 --), (N --), etc. (1b) the original definition is not an expr, and there is no EXPR property, and the file package "knows" which file fn is contained in, then the expr definition of fn is loaded onto its property list as described in (3) below, and proceeds to (1c), otherwise a warning message is printed, and the edit proceeds, e.g., the user may have called the editor to examine the advice on a subr. (1c) the original definition is not an expr, and there is an EXPR property, then the function is unbroken/unadvised (latter only with user's approval, since the user may really want to edit the advice) and proceed as in (2). (2) If fn is not an expr, but has an EXPR property, editf prints PROP, and performs edite[getp[fn;EXPR];coms;fn]. If edite returns (i.e., ------------------------------------------------------------------------ 102 editlflg=T is for internal use by the editor. 9.64 if the editing is not terminated by a STOP), and some changes were made, editf performs unsavedef[fn], prints UNSAVED, and then does putd[fn;value-of-edite]. (3) if fn is neither an expr nor has an EXPR property, and the file package (see section 14) "knows" which file fn is contained in, the expr definition of fn is automatically loaded (using loadfns) onto 103 its property list, and proceed to (2) above. In addition, if fn is a member of a block (see section 18), the user will be asked whether he wishes the rest of the functions in the block to be 104 loaded at the same time. (4) If fn is neither an expr nor has an EXPR property, but it does have a definition, editf generates an fn NOT EDITABLE error. (5) If fn is neither defined, nor has an EXPR property, but its top level value is a list, editf assumes the user meant to call editv, prints =EDITV, calls editv and returns. Similarly, if fn has a non- NIL property list, editf prints =EDITP, calls editp and returns. (6) If fn is neither a function, nor has an EXPR property, nor a top level value that is a list, nor a non-NIL property list, editf 105 attempts spelling correction using the spelling list userwords, and if successful, goes back to (1). Otherwise, editf generates an fn NOT EDITABLE error. ------------------------------------------------------------------------ 103 Because of the existence of the file map (see section 14), this operation is extremely fast, essentially requiring only the time to perform the READ to obtain the actual definition. 104 The editor's behaviour in case (3) is controlled by the value of editloadfnsflg, which is a dotted pair of two flags, the first of which (i.e., car of editloadfnsflg) controls the loading of the function, and the second the loading of the block. A value of NIL for either flag means "load but ask first," a value of T means "don't ask, just do it" and anything else means "don't ask, don't do it." The initial value of editloadfnsflg is (T), meaning load the function without asking, ask about loading the block. 105 Unless dwimflg=NIL. Spelling correction is performed using the function misspelled?. If fn=NIL, misspelled? returns the last "word" referenced, e.g., by defineq, editf, prettyprint etc. Thus if the user defines foo and then types editf[], the editor will assume he meant foo, type =FOO, and then type EDIT. See Section 17. 9.65 If editf ultimately succeeds in finding a function to edit, i.e., does not exit by calling editv or editp, editf calls the function addspell 106 after editing has been completed. Addspell "notices" fn, i.e., sets lastword to fn, and adds fn to the appropriate spelling lists. If any changes were made, editf also calls the file package to mark the 107 function as being changed, as described in section 14. editv[editvx] nlambda, nospread function, similar to editf, for editing values. car[editvx] specifies the value, cdr[editvx] is an optional list of commands. If car[editvx] is a list, it is evaluated and its value given to edite, e.g., EDITV((CDR (ASSOC (QUOTE FOO) DICTIONARY)))). In this case, the value of editv is T. However, for most applications, car[editvx] is a variable name, i.e., atomic, as in EDITV(FOO). If the value of this variable is NOBIND, editv checks to see if it is the name of a function, and if so, assumes the user meant to call editf, prints =EDITF, calls editf and returns. Otherwise, editv attempts spelling correction using the list 108 userwords. Then editv will call edite on the value of car[editvx] (or the corrected spelling thereof). Thus, if the value of foo is NIL, and the user performs (EDITV FOO), no spelling correction will occur, since foo is the name of a variable in the user's system, i.e., it has a value. However, edite will generate an error, since foo's value is not a list, and hence not editable. If the user performs (EDITV FOOO), where the value of fooo is NOBIND, and foo is on the user's spelling list, the spelling corrector will correct FOOO to FOO. Then edite will be called on the value of foo. Note that this may still result in an error if the value of foo is not a list. When (if) edite returns, editv sets the variable to the value returned, and calls addspell. If any changes were made, editv also calls the file package to mark the variable as being changed. The value of editv is the name of the variable whose value was edited. ------------------------------------------------------------------------ 106 Unless dwimflg=NIL. addspell is described in Section 17. 107 Even though the call to newfile? does not occur until after the editing is completed, nevertheless the function is effectively marked as changed as soon as the first change is performed, so that even if the edit is aborted via control-D, newfile? will still be called. 108 Unless dwimflg=NIL. Misspelled? is also called if car[editvx] is NIL, so that EDITV() will edit lastword. 9.66 editp[x] nlambda, nospread function, similar to editf for editing property lists. If the property list of car[x] is NIL, editp attempts spelling correction using userwords. Then editp calls edite on the property list of car[x], (or the corrected spelling thereof). When (if) edite returns, editp rplacd's car[x] with the value returned, and calls addspell. The value of editp is the atom whose property list was edited. editfns[x] nlambda, nospread function, used to perform the same editing operations on several functions. car[x] is evaluated to obtain a list of 109 functions. cdr[x] is a list of edit commands. editfns maps down the list of functions, prints the name of each function, and calls the editor 110 (via editf) on that function. For example, EDITFNS(FOOFNS (R FIE FUM)) will change every FIE to FUM in each of the functions on foofns. The call to the editor is errorset protected, so that if the editing of one function causes an error, editfns will proceed to the next 111 function. Thus in the above example, if one of the functions did not contain a FIE, the R command would cause an error, but editing would continue with the next function. The value of editfns is NIL. ------------------------------------------------------------------------ 109 If car[x] is atomic, and its value is not a list, and it is the name of a file, filefnslst[car[x]] will be used as the list of functions to be edited. 110 i.e., the definition of editfns might be: [MAPC (EVAL (CAR X)) (FUNCTION (LAMBDA (Y) (APPLY (QUOTE EDITF) (CONS (PRINT Y T) (CDR X] 111 In particular, if an error occurred while editing a function via its EXPR property, the function would not be unsaved. In other words, in the above example, only those functions which contained a FIE, i.e., only those actually changed, would be unsaved. 9.67 edit4e[pat;x;changeflg] is the pattern match routine. Its value is T if pat-matches x. See page 9.16-17 for definition 112 of "match". Note: before each search operation in the editor begins, the entire pattern is scanned for atoms or strings containing alt-modes. These are replaced by patterns of the form (CONS (QUOTE $) (UNPACK atom/string)) for 6a, and (CONS (QUOTE $$) (CONS (NCHARS atom/string) (UNPACK atom/string))), for 113 6b. Thus from the standpoint of edit4e, pattern type 6a is indicated by car[pat] being the atom $ ($ is alt-mode) and pattern type 6b by car[pat] being the atom $$ (double alt-mode). Therefore, if the user wishes to call edit4e directly, he must first convert any patterns which contain atoms or strings ending in alt-modes to the form recognized by edit4e. This is done with the function editfpat. editfpat[pat;flg] makes a copy of pat with all patterns of type 6 114 converted to the form expected by edit4e. editfindp[x;pat;flg] allows a program to use the edit find command as a pure predicate from outside the editor. x is an expression, pat a pattern. The value of editfindp is T if the command F pat would succeed, NIL otherwise. editfindp calls editfpat to convert pat to the form expected by edit4e, unless flg=T. Thus, if the program is applying editfindp to several different expressions using the same pattern, it will be more efficient to call editfpat once, and then call editfindp with the converted pattern and flg=T. ------------------------------------------------------------------------ 112 changeflg is for internal use by the editor. 113 In latter case, atom/string corresponds to the atom or string up to but not including the final two-alt-modes. In both cases, dunpack is used wherever possible. 114 flg=T is used for internal use by the editor. 9.68 115 esubst[x;y;z;errorflg;charflg] equivalent to performing (R y x) with z as the current expression, i.e., the order of arguments is the same as for subst. Note that y and/or x can employ alt-modes. The value of esubst is the modified z. Generates an 116 error if y not found in z. If errorflg=T, also prints an error message of the form y ?. esubst is always undoable. changename[fn;from;to] replaces all occurrences of from by to in the definition of fn. If fn is an expr, changename performs nlsetq[esubst[to;from;getd[fn]]]. If fn is compiled, changename searches the literals of fn (and all of its compiler generated subfunctions), replacing each 117 occurrence of from with to. The value of changename is fn if at least one instance of from was found, otherwise NIL. changename is used by break and advise for changing calls to fn1 to calls to fn1-IN-fn2. editracefn[com] is available to help the user debug complex edit macros, or subroutine calls to the editor. If editracefn is set to T, the function editracefn is called whenever a command that was not typed in by the user is about to be executed, giving it that command as its argument. However, the TRACE and BREAK options described below are probably sufficient for most applications. If editracefn is set to TRACE, the name of the command and the current expression are printed. If editracefn=BREAK, the same information is printed, and the editor goes into a break. The user can then examine the state of the editor. editracefn is initially NIL. ------------------------------------------------------------------------ 115 unless charflg=T, in which case it is equivalent to (RC y x). See page 9.44. 116 of the type that never causes a break. 117 Will succeed even if from is called from fn via a linked call. In this case, the call will also be relinked to call to instead. 9.69