{Begin SubSec Commands That Print} {Title Commands That Print} {Text {Def {Type EditCom} {name PP} {text Prettyprints the current expression. }} {index *PRIMARY* P EditCom} {Def {Type EditCom} {name P} {text Prints the current expression as though {fn PRINTLEVEL} ({PageRef Fn PRINTLEVEL}) were set to 2. }} {Def {Type EditCom} {name P} {Args M} {text Prints the {arg M}th element of the current expression as though {fn PRINTLEVEL} were set to 2. }} {Def {Type EditCom} {name P} {Args {lisp 0}} {text Same as {editcom P}. }} {Def {Type EditCom} {name P} {Args M N} {text Prints the {arg M}th element of the current expression as though {fn PRINTLEVEL} were set to {arg N}. }} {Def {Type EditCom} {name P} {Args {lisp 0} N} {text Prints the current expression as though {fn PRINTLEVEL} were set to {arg N}. }} {Def {Type EditCom} {name ?} {text Same as {lisp (P 0 100)}. }} Both {lisp (P {arg M})} and {lisp (P {arg M} {arg N})} use the generalized {editcom NTH} command {lisp (NTH {arg COM})} to obtain the corresponding element, so that {arg M} does not have to be a number, e.g., {lisp (P COND 3)} will work. {editcom PP} causes all comments to be printed as {index **COMMENT** (Printed by Editor)}{lisp **COMMENT**} (see {PageRef Var **COMMENT**FLG}). {editcom P} and {editcom ?} print as {lisp **COMMENT**} only those comments that are (top level) elements of the current expression. Lower expressions are not really seen by the editor; the printing command simply sets {fn PRINTLEVEL} and calls {fn PRINT}. {Def {Type EditCom} {name PP*} {text Prettyprints current expression, {it including} comments. {editcom PP*} is equivalent to {editcom PP} except that it first resets {var **COMMENT**FLG}{index **COMMENT**FLG Var} to {lisp NIL} (see {PageRef Var **COMMENT**FLG}). }} {Begin Note} Date: 19 Jun 1979 2344-EDT Sender: LEWIS at BBN-TENEXD Subject: something for the bottom of your queue If I have FOO defined as a "comment", I can easily get it to prettyprint to the terminal as **Foo** by defining a prettyprintmacro where the fn rebinds **comment**flg. But there is no way to get it to do the same when I give a P command to the editor. Such a thing might be nice. eg, the timestamp stuff could be changed do something like (Edited: 1-27-80 by Teitelman), and then in the editor it could appear as **timestamp**. Then there would be no question of what is a timestamp and what is a real comment. {End Note} {Def {Type EditCom} {name PPV} {text Prettyprints the current expression as a variable, i.e., no special treatment for {lisp LAMBDA}, {lisp COND}, {lisp SETQ}, etc., or for CLISP. }} {Def {Type EditCom} {name PPT} {text Prettyprints the current expression, printing CLISP translations, if any. }} {Def {Type EditCom} {name ?=} {text Prints the argument names and corresponding values for the current expression. Analagous to the {Breakcom ?=} break command ({PageRef BreakCom ?=}). For example, {lispcode *P (STRPOS "A0???" X N (QUOTE ?) T) *?= X = "A0???" Y = X START = N SKIP = (QUOTE ?) ANCHOR = T TAIL =} }} The command {editcom MAKE} ({PageRef EditCom MAKE}) is an imperative form of {editcom ?=}. It allows the user to specify a change to the element of the current expression that corresponds to a particular argument name. All printing functions print to the {index terminal}terminal, regardless of the primary output file. All use the readtable {lisp T}. No printing function ever changes the edit chain. All record the current edit chain for use by {index \P EditCom}{editcom \P} ({PageRef EditCom \P}). All can be aborted with control-E. }{End SubSec Commands That Print} {Begin SubSec Commands for Leaving the Editor} {Title Commands for Leaving the Editor} {Text {Def {Type EditCom} {name OK} {Text Exits from the editor. }} {Def {Type EditCom} {name STOP} {Text Exits from the editor with an error. Mainly for use in conjunction with {editcom TTY:} commands ({PageRef EditCom TTY:}) that the user wants to abort. }} Since all of the commands in the editor are errorset protected, the user must exit from the editor via a command. {editcom 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 {lisp (MOVE 3 TO AFTER COND TTY:)}, and he exits from the lower editor with an {editcom OK}, the {editcom MOVE} command will then complete its operation. If the user wants to abort the {editcom MOVE} command, he must make the {index TTY: EditCom}{editcom TTY:} command generate an error. He does this by exiting from the lower editor with a {index STOP EditCom}{editcom STOP} command. In this case, the higher editor's edit chain will not be changed by the {editcom TTY:} command. Actually, it is also possible to exit the editor by typing {index control-D}control-D. {index STOP EditCom}{editcom STOP} is preferred even if the user is editing at the {fn EVALQT} level, as it will perform the necessary "wrapup" to insure that the changes made while editing will be undoable. {Def {Type EditCom} {name SAVE} {Text 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 {index EDIT-SAVE Prop}{prop 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 {index UNFIND Var}{var UNFIND} and {index UNDOLST Var}{var UNDOLST} are restored. }} For example: {lispcode *P (NULL X) *F COND P (COND (& &) (T &)) *SAVE FOO ← . . . ←EDITF(FOO) EDIT *P (COND (& &) (T &)) *\ P (NULL X) *} {editcom SAVE} is necessary only if the user is editing many different expressions; an exit from the editor via {editcom OK} always saves the state of the edit of that call to the editor on the property list of the atom {lisp EDIT},{index EDIT Litatom} under the property name {index LASTVALUE Prop}{prop LASTVALUE}. {editcom OK} also remprops {index EDIT-SAVE Prop}{prop EDIT-SAVE} from the property list of the function or variable being edited. {index *BEGIN* continuing an edit session} 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 and {index UNDOLST Var}{var UNDOLST}, and sets {index UNFIND Var}{var UNFIND} to be the edit chain as of the previous exit from the editor. For example: {lispcode ←EDITF(FOO) EDIT *P (LAMBDA (X) (PROG & & LP & & & &)) . . . *P (COND & &) *OK FOO ← . . {it any number of {fn LISPX} inputs} . {it except for calls to the editor} ←EDITF(FOO) EDIT *P (LAMBDA (X) (PROG & & LP & & & &)) *\ P (COND & &) *} Furthermore, as a result of the history feature, if the editor is called on the same expression within a certain number of {index LISPX FN}{fn LISPX} inputs,{foot Namely, the size of the history list, which can be changed with {fn CHANGESLICE}, ({PageRef Fn CHANGESLICE}). }{comment endfootnote} the state of the edit of that expression is restored, regardless of how many other expressions may have been edited in the meantime. For example: {lispcode ←EDITF(FOO) EDIT * . . . *P (COND (& &) (& &) (&) (T &)) *OK FOO . {it a small number of {fn LISPX} inputs,} . {it 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 session (since saving takes place at {it exit} time, intervening calls that were aborted via control-D or exited via {editcom STOP} will not affect the editor's memory); or (2) That session was "sufficiently" recent; or (3) It was ended with a {index SAVE EditCom}{editcom SAVE} command. {index *END* continuing an edit session} }{End SubSec Commands for Leaving the Editor} {Begin SubSec Nested Calls to Editor} {Title Nested Calls to Editor} {Text {Def {Type EditCom} {Name TTY:} {Text Calls the editor recursively. The user can then type in commands, and have them executed. The {editcom TTY:} command is completed when the user exits from the lower editor. (see {editcom OK} and {editcom STOP} above). }} The {editcom 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 {lisp (MOVE 3 TO AFTER COND 3 P TTY:)} allows the user to interact, in effect, {it within} the {editcom MOVE} command. Thus he can verify for himself that the correct location has been found, or complete the specification "by hand." In effect, {editcom TTY:} says "I'll tell you what you should do when you get there." The {index TTY: EditCom}{editcom TTY:} command operates by printing {index TTY: (Printed by Editor)}{editcom 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 {editcom TTY:} command was entered. Until the user exits from the lower editor, any attention changing commands he executes only affect the lower editor's edit chain. Of course, if the user performs any structure modification commands while under a {editcom TTY:} command, these will modify the structure in both editors, since it is the same structure. When the {editcom TTY:} command finishes, the lower editor's edit chain becomes the edit chain of the higher editor. {Def {Type EditCom} {Name EF}} {Def {Type EditCom} {Name EV}} {Def {Type EditCom} {Name EP} {Text Calls {fn EDITF} or {fn EDITV} or {fn EDITP} on {fn CAR} of current expression. }} }{End SubSec Nested Calls to Editor} {Begin SubSec Manipulating the Characters of an Atom or String} {Title Manipulating the Characters of an Atom or String} {Text {index *PRIMARY* RAISE EditCom} {Def {Type EditCom} {Name RAISE} {Text An edit macro defined as {editcom UP} followed by {lisp (I 1 (U-CASE (## 1)))},{index U-CASE FN} i.e., it raises to upper-case the current expression, or if a tail, the first element of the current expression. }} {index *PRIMARY* LOWER EditCom} {Def {Type EditCom} {Name LOWER} {Text Similar to {editcom RAISE}, except uses {fn L-CASE}.{index L-CASE FN} }} {Def {Type EditCom} {Name CAP} {Text First does a {editcom RAISE}, and then lowers all but the first character, i.e., the first character is left capitalized. }} Note: {editcom RAISE}, {editcom LOWER}, and {editcom CAP} are all no-ops if the corresponding atom or string is already in that state. {Def {Type EditCom} {Name RAISE} {Args X} {Text Equivalent to {lisp (I R (L-CASE {arg X}) {arg X})}, i.e., changes every lower-case {arg X} to upper-case in the current expression. }} {Def {Type EditCom} {Name LOWER} {Args X} {Text Similar to {editcom RAISE}, except performs {lisp (I R {arg X} (L-CASE {arg X}))}. }} Note that in both {lisp (RAISE {arg X})} and {lisp (LOWER {arg X})}, {arg X} should be typed in upper case. {index *PRIMARY* REPACK EditCom} {Def {Type EditCom} {Name REPACK} {Text Permits the "editing" of an atom or string. {editcom REPACK} operates by calling the editor recursively on {fn UNPACK} of the current expression, or if it is a list, on {fn UNPACK} of its first element. If the lower editor is exited successfully, i.e., via {index OK EditCom}{editcom OK} as opposed to {index STOP EditCom}{editcom 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. }} Example: {lispcode *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 "THIS IS A LONG STRING" *} Note that this could also have been accomplished by {lisp (R $GN$ $NG$)} or simply {lisp (RC GN NG)}. {Def {Type EditCom} {Name REPACK} {PrintName {lisp (REPACK @)}} {Text Does {lisp (LC . @)} followed by {editcom REPACK}, e.g. {lisp (REPACK THIS$)}. }} }{End SubSec Manipulating the Characters of an Atom or String} {Begin SubSec Manipulating Predicates and Conditional Expressions} {Title Manipulating Predicates and Conditional Expressions} {Text {Def {Type EditCom} {Name JOINC} {Text Used to join two neighboring {lisp COND}'s together, e.g. {lisp (COND {arg CLAUSE{sub 1}} {arg CLAUSE{sub 2}})} followed by {lisp (COND {arg CLAUSE{sub 3}} {arg CLAUSE{sub 4}})} becomes {lisp (COND {arg CLAUSE{sub 1}} {arg CLAUSE{sub 2}} {arg CLAUSE{sub 3}} {arg CLAUSE{sub 4}})}. {editcom JOINC} does an {lisp (F COND T)} first so that you don't have to be at the first {lisp COND}. }} {Def {Type EditCom} {Name SPLITC} {Args X} {Text Splits one {lisp COND} into two. {arg X} specifies the last clause in the first {lisp COND}, e.g. {lisp (SPLITC 3)} splits {lisp (COND {arg CLAUSE{sub 1}} {arg CLAUSE{sub 2}} {arg CLAUSE{sub 3}} {arg CLAUSE{sub 4}})} into {lisp (COND {arg CLAUSE{sub 1}} {arg CLAUSE{sub 2}})} {lisp (COND {arg CLAUSE{sub 3}} {arg CLAUSE{sub 4}})}. Uses the generalized {editcom NTH} command {lisp (NTH {arg COM})}, so that {arg X} does not have to be a number, e.g., the user can say {lisp (SPLITC RETURN)}, meaning split after the clause containing {lisp RETURN}. {editcom SPLITC} also does an {lisp (F COND T)} first. }} {Def {Type EditCom} {Name NEGATE} {Text Negates the current expression, i.e. performs {lisp (MBD NOT)}, except that is smart about simplifying. For example, if the current expression is: {lisp (OR (NULL X) (LISTP X))}, {editcom NEGATE} would change it to {lisp (AND X (NLISTP X))}. {editcom NEGATE} is implemented via the function {fn NEGATE} ({PageRef Fn NEGATE}).{index NEGATE FN} }} {Def {Type EditCom} {Name SWAPC} {Text Takes a conditional expression of the form {lisp (COND (A B)(T C))} and rearranges it to an equivalent {lisp (COND ((NOT A) C)(T B))}, or {lisp (COND (A B) (C D))} to {lisp (COND ((NOT A) (COND (C D))) (T B))}. }} {editcom SWAPC} is smart about negations (uses {editcom NEGATE}) and simplifying {fn COND}s. It always produces an equivalent expression. It is useful for those cases where one wants to insert extra clauses or tests. }{End SubSec Manipulating Predicates and Conditional Expressions} {Begin SubSec History commands in the editor} {Title History commands in the editor} {Text As described on {PageRef Var EDITHISTORY}, all of the user's inputs to the editor are stored on {var EDITHISTORY}, the editor's history list, and all of the programmer's assistant commands for manipulating the history list, e.g. {pacom REDO}, {pacom USE}, {pacom FIX}, {pacom NAME}, etc., are available for use on events on {var EDITHISTORY}. In addition, the following four history commands are recognized specially by the editor. They always operate on the last, i.e. most recent, event. {Def {Type EditCom} {Name DO} {Args COM} {Noparens} {Text Allows the user to supply the command name when it was omitted. {pacom USE} is useful when a command name is {it incorrect}. }} For example, suppose the user wants to perform {lisp (-2 (SETQ X (LIST Y Z)))} but instead types just {lisp (SETQ X (LIST Y Z))}. The editor will type {lisp SETQ ?}, whereupon the user can type {lisp DO -2}. The effect is the same as though the user had typed {pacom FIX}, followed by {lisp (LI 1)}, {lisp (-1 -2)}, and {lisp OK}, i.e., the command {lisp (-2 (SETQ X (LIST Y Z)))} is executed. {editcom DO} also works if the command is a line command. {Def {Type EditCom} {Name !F} {Text Same as {lisp DO F}. }} In the case of {editcom !F}, the previous command is always treated as though it were a line command, e.g., if the user types {lisp (SETQ X &)} and then {lisp !F}, the effect is the same as though he had typed {lisp F (SETQ X &)}, not {lisp (F (SETQ X &))}. {Def {Type EditCom} {Name !E} {Text Same as {lisp DO E}. }} {Def {Type EditCom} {Name !N} {Text Same as {lisp DO N}. }} }{End SubSec History commands in the editor} {Begin SubSec Miscellaneous Commands} {Title Miscellaneous Commands} {Text {Def {Type EditCom} {Name NIL} {Text Unless preceded by {editcom F} or {editcom BF}, is always a no-op. Thus extra right parentheses or square brackets at the ends of commands are ignored. }} {Def {Type EditCom} {Name CL} {Text Clispifies the current expression (see {PageRef Fn CLISPIFY}). }} {Def {Type EditCom} {Name DW} {Text Dwimifies the current expression (see {PageRef Fn DWIMIFY}). }} {Def {Type EditCom} {Name GET*} {Text If the current expression is a {index comment pointers}comment pointer (see {PageRef Tag CommentPointer}), reads in the full text of the comment, and replaces the current expression by it. }} {Def {Type EditCom} {Name *} {Args X} {PrintName {lisp (* . {arg X})}} {Text {arg X} is the text of a comment. {editcom *} ascends the edit chain looking for a "safe" place to insert the comment, e.g., in a {fn COND} clause, after a {fn PROG} statement, etc., and inserts {lisp (* . {arg X})} {it after} that point, if possible, otherwise before. For example, if the current expression is {lisp (FACT (SUB1 N))} in {lispcode [COND ((ZEROP N) 1) (T (ITIMES N (FACT (SUB1 N]} {lisp (* CALL FACT RECURSIVELY)} would insert {lisp (* CALL FACT RECURSIVELY)} {it before} the {fn ITIMES} expression.{foot If inserted after the {fn ITIMES}, the comment would then be (incorrectly) returned as the value of the {fn COND}. However, if the {fn COND} was itself a {fn PROG} statement, and hence its value was not being used, the comment could be (and would be) inserted after the {fn ITIMES} expression. }{comment endfootnote} {editcom *} does not change the edit chain, but {index UNFIND Var}{var UNFIND} is set to where the comment was actually inserted. }} {Def {Type EditCom} {Name GETD} {Text Essentially "expands" the current expression in line: (1) if ({fn CAR} of) the current expression is the name of a macro, expands the macro in line; (2) if a CLISP word, translates the current expression and replaces it with the translation; (3) if {fn CAR} is the name of a function for which the editor can obtain a symbolic definition, either in-core or from a file, substitutes the argument expressions for the corresponding argument names in the body of the definition and replaces the current expression with the result; (4) if {fn CAR} of the current expression is an open lambda, substitutes the arguments for the corresponding argument names in the body of the lambda, and then removes the lambda and argument list. }} {Def {Type EditCom} {Name MAKEFN} {Args FN ACTUALARGS ARGLIST N{sub 1} N{sub 2}} {PrintName {lisp (MAKEFN ({arg FN} . {arg ACTUALARGS}) {arg ARGLIST} {arg N{sub 1}} {arg N{sub 2}})}} {Text The inverse of {editcom GETD}: makes the current expression into a function. {arg FN} is the function name, {arg ARGLIST} its arguments. The argument names are substituted for the corresponding argument values in {arg ACTUALARGS}, and the result becomes the body of the function definition for {arg FN}. The current expression is then replaced with {lisp ({arg FN} . {arg ACTUALARGS})}. If {arg N{sub 1}} and {arg N{sub 2}} are supplied, {lisp ({arg N{sub 1}} THRU {arg N{sub 2}})} is used rather than the current expression; if just {arg N{sub 1}} is supplied, {lisp ({arg N{sub 1}} THRU -1)} is used. If {arg ARGLIST} is omitted, {editcom MAKEFN} will make up some arguments, using elements of {arg ACTUALARGS}, if they are literal atoms, otherwise arguments selected from {lisp (X Y Z A B C ...)}, avoiding duplicate argument names. }} Example: If the current expression is {lisp (COND ((CAR X) (PRINT Y T)) (T (HELP)))}, then {lisp (MAKEFN (FOO (CAR X) Y) (A B))} will define {lisp FOO} as {lisp (LAMBDA (A B) (COND (A (PRINT B T)) (T (HELP))))} and then replace the current expression with {lisp (FOO (CAR X) Y)}. {Def {Type EditCom} {Name MAKE} {Args ARGNAME EXP} {Text Makes the value of {arg ARGNAME} be {arg EXP} in the call which is the current expression, i.e. a {editcom ?=} command following a {editcom MAKE} will always print {arg ARGNAME}={arg EXP}. For example: {lispcode *P (JSYS) *?= JSYS[N;AC1,AC2,AC3,RESULTAC] *(MAKE N 10) *(MAKE RESULTAC 3) *P (JSYS 10 NIL NIL NIL 3)} }} {Def {Type EditCom} {Name Q} {Text Quotes the current expression, i.e. {lisp MBD QUOTE}. }} {Def {Type EditCom} {Name D} {Text Deletes the current expression, then prints new current expression, i.e. {lisp (:) I P}. }} }{End SubSec Miscellaneous Commands} {Begin SubSec Commands That Evaluate} {Title Commands That Evaluate} {Text {index *PRIMARY* E EditCom} {Def {Type EditCom} {Name E} {Text Causes the editor to call the Interlisp executive {index LISPX FN}{fn LISPX} giving it the next input as argument. Example: {lispcode *E BREAK(FIE FUM) (FIE FUM) *E (FOO) (FIE BROKEN) :} Note: {editcom E} only works when when typed in, e.g, {lisp (INSERT D BEFORE E)} will treat {lisp E} as a pattern, and search for {lisp E}. }} {Def {Type EditCom} {Name E} {Args X} {Text Evaluates {arg X}, i.e., performs {lisp (EVAL {arg X})}, and prints the result on the terminal. }} {Def {Type EditCom} {Name E} {Args X {lisp T}} {Text Same as {lisp (E {arg x})} but does not print. }} The {lisp (E {arg X})} and {lisp (E {arg 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) {editcom E} command. {Def {Type EditCom} {Name I} {Args C X{sub 1} {ellipsis} X{sub N}} {Text Executes the {it editor command} {lisp ({arg C} {arg Y{sub 1}} {ellipsis} {arg Y{sub N}})} where {arg Y{sub i}} = {lisp (EVAL {arg X{sub i}})}. If {arg C} is not an atom, {arg C} is evaluated also. Examples: {lisp (I 3 (GETD 'FOO))} will replace the 3rd element of the current expression with the definition of {lisp FOO}. {lisp (I N FOO (CAR FIE))} will attach the value of {lisp FOO} and {lisp CAR} of the value of {lisp FIE} to the end of the current expression. {lisp (I F= FOO T)} will search for an expression {fn EQ} to the value of {lisp FOO}. {lisp (I (COND ((NULL FLG) '-1) (T 1)) FOO)}, if {lisp FLG} is {lisp NIL}, inserts the value of {lisp FOO} before the first element of the current expression, otherwise replaces the first element by the value of {lisp FOO}. The {editcom I} command sets an internal flag to indicate to the structure modification commands {it not} to copy expression(s) when inserting, replacing, or attaching. }} {Def {Type EditCom} {Name EVAL} {Text Does an {fn EVAL} of the current expression. }} Note that {editcom EVAL}, line-feed, and the {editcom GO} command together effectively allow the user to "single-step" {index single-stepping a program}a program through its symbolic definition. {Def {Type EditCom} {Name GETVAL} {Text Replaces the current expression by the result of evaluating it. }} {FnDef {FnName ##} {FnArgs COM{sub 1} COM{sub 2} {ellipsis} COM{sub N}} {Type NLAMBDA NOSPREAD} {Text An nlambda, nospread function (not a command). Its value is what the current expression would be after executing the edit commands {arg COM{SUB 1}} {ellipsis} {arg COM{SUB N}} starting from the present edit chain. Generates an error if any of {arg COM{SUB 1}} thru COM{SUB N} cause errors. The current edit chain is never changed.{foot The {editcom A}, {editcom B}, {editcom :}, {editcom INSERT}, {editcom REPLACE}, and {editcom CHANGE} commands make special checks for ## forms in the expressions used for inserting or replacing, and use a copy of ## form instead (see {PageRef Tag EditorAchecks}). Thus, {lisp (INSERT (## 3 2) AFTER 1)} is equivalent to {lisp (I INSERT (COPY (## 3 2)) 'AFTER 1)}. }{comment endfootnote} }} Example: {lisp (I R 'X (## (CONS .. Z)))} replaces all {lisp X}'s in the current expression by the first {fn CONS} containing a {lisp Z}. The {editcom I} command is not very convenient for computing an {it entire} edit command for execution, since it computes the command name and its arguments separately. Also, the {editcom I} command cannot be used to compute an atomic command. The following two commands provide more general ways of computing commands. {Def {Type EditCom} {Name COMS} {Args X{sub 1} {ellipsis} X{sub M}} {Text Each {arg X{sub i}} is evaluated and its value is executed as a command. }} For example, {lisp (COMS (COND (X (LIST 1 X))))} will replace the first element of the current expression with the value of {lisp X} if non-{lisp NIL}, otherwise do nothing.{foot The editor command {index NIL EditCom}{editcom NIL} is a no-op, see {PageRef EditCom NIL}. }{comment endfootnote} {Def {Type EditCom} {Name COMSQ} {Args COM{sub 1} {ellipsis} COM{sub N}} {Text Executes {arg COM{sub 1}} {ellipsis} {arg COM{sub N}}. }} {editcom COMSQ} is mainly useful in conjunction with the {editcom 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 {editcom COMS} command. He would then write {lisp (COMS (CONS 'COMSQ {arg X}))} where {arg X} computed the list of commands, e.g., {lisp (COMS (CONS 'COMSQ (GETP FOO 'COMMANDS)))}. }{End SubSec Commands That Evaluate} {Begin SubSec Commands That Test} {Title Commands That Test} {Text {index edit commands that test} {index *PRIMARY* IF EditCom} {Def {Type EditCom} {name IF} {Args X} {Text Generates an error {it unless} the value of {lisp (EVAL {arg X})} is true. In other words, if {lisp (EVAL {arg X})} causes an error or {lisp (EVAL {arg X})}={lisp NIL}, {editcom 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 {fn COND} uses {lisp NIL} and non-{lisp NIL}. For example, an error condition in a location specification may simply mean "not this one, try the next." Thus the location specification{index location specification (in Editor)} {lisp (IPLUS (E (OR (NUMBERP (## 3)) (ERROR!)) T))} specifies the first {lisp IPLUS} whose second argument is a number. The {editcom IF} command, by equating {lisp NIL} to error, provides a more natural way of accomplishing the same result. Thus, an equivalent location specification is {lisp (IPLUS (IF (NUMBERP (## 3))))}. The {editcom IF} command can also be used to select between two alternate lists of commands for execution. {Def {Type EditCom} {name IF} {Args X COMS{sub 1} COMS{sub 2}} {Text If {lisp (EVAL {arg X})} is true, execute {arg COMS{sub 1}}; if {lisp (EVAL {arg X})} causes an error or is equal to {lisp NIL}, execute {arg COMS{sub 2}}. Thus {editcom IF} is equivalent to {lispcode (COMS (CONS 'COMSQ (COND ((CAR (NLSETQ (EVAL X))) {arg COMS{sub 1}}) (T {arg COMS{sub 2}}))))} }} For example, the command {lisp (IF (READP T) NIL (P))} will print the current expression provided the input buffer is empty. {Def {Type EditCom} {name IF} {Args X COMS{sub 1}} {Text If {lisp (EVAL {arg X})} is true, execute {arg COMS{sub 1}}; otherwise generate an error. }} {Def {Type EditCom} {name LP} {Args COMS{sub 1} {ellipsis} COMS{sub N}} {Text Repeatedly executes {arg COMS{sub 1}} {ellipsis} {arg COMS{sub N}} until an error occurs. For example, {lisp (LP F PRINT (N T))} will attach a {lisp T} at the end of every {fn PRINT} expression. {lisp (LP F PRINT (IF (## 3) NIL ((N T))))} will attach a {lisp T} at the end of each print expression which does not already have a second argument.{foot The form {lisp (## 3)} will cause an error if the edit command {lisp 3} causes an error, thereby selecting {lisp ((N T))} as the list of commands to be executed. The {editcom IF} could also be written as {lisp (IF (CDDR (##)) NIL ((N T)))}. }{comment endfootnote} When an error occurs, {editcom LP} prints {lisp {arg N} OCCURRENCES}{index OCCURRENCES (Printed by Editor)} where {arg N} is the number of times the commands were successfully executed. The edit chain is left as of the last complete successful execution of {arg COMS{sub 1}} {ellipsis} {arg COMS{sub N}}. }} {Def {Type EditCom} {name LPQ} {Args COMS{sub 1} {ellipsis} COMS{sub N}} {Text Same as {editcom LP} but does not print the message {lisp {arg N} OCCURRENCES}. }} In order to prevent non-terminating loops, both {index LP EditCom}{editcom LP} and {index LPQ EditCom}{editcom LPQ} terminate when the number of iterations reaches {index MAXLOOP Var}{var MAXLOOP}, initially set to 30.{index MAXLOOP EXCEEDED (Printed by Editor)} {var MAXLOOP} can be set to {lisp NIL}, which is equivalent to setting it to infinity. Since the edit chain is left as of the last successful completion of the loop, the user can simply continue the {editcom LP} command with {pacom REDO} ({PageRef PACom REDO}). {Def {Type EditCom} {name SHOW} {Args X} {Text {arg X} is a list of patterns. {editcom SHOW} does a {editcom LPQ} printing all instances of the indicated expression(s), e.g. {lisp (SHOW FOO (SETQ FIE &))} will print all {lisp FOO}'s and all {lisp (SETQ FIE &)}'s. Generates an error if there aren't any instances of the expression(s). }} {Def {Type EditCom} {name EXAM} {Args X} {Text Like {editcom SHOW} except calls the editor recursively (via the {index TTY: EditCom}{editcom TTY:} command, see {PageRef EditCom TTY:}) on each instance of the indicated espression(s) so that the user can examine and/or change them. }} {Def {Type EditCom} {name ORR} {Args COMS{sub 1} {ellipsis} COMS{sub N}} {Text {editcom ORR} begins by executing {arg COMS{sub 1}}, a list of commands. If no error occurs, {editcom ORR} is finished. Otherwise, {editcom ORR} restores the edit chain to its original value, and continues by executing {arg COMS{sub 2}}, etc. If none of the command lists execute without errors, i.e., the {editcom ORR} "drops off the end", {editcom ORR} generates an error. Otherwise, the edit chain is left as of the completion of the first command list which executes without an error. {lisp NIL} as a command list is perfectly legal, and will always execute successfully. Thus, making the last "argument" to {editcom ORR} be {lisp NIL} will insure that the {editcom ORR} never causes an error. Any other atom is treated as {lisp ({arg ATOM})}, i.e., the above example could be written as {lisp (ORR NX !NX NIL)}. }} For example, {lisp (ORR (NX) (!NX) NIL)} will perform a {editcom NX}, if possible, otherwise a {editcom !NX}, if possible, otherwise do nothing. Similarly, {lisp DELETE} could be written as {lisp (ORR (UP (1)) (BK UP (2)) (UP (: NIL)))}. }{End SubSec Commands That Test} {Begin SubSec Edit Macros} {Title Edit Macros} {Text {index *BEGIN* macros (in Editor)} {index *BEGIN* edit macros} {Tag EditMacros} Many of the more sophisticated branching commands in the editor, such as {editcom ORR}, {editcom IF}, etc., are most often used in conjunction with edit macros. The macro feature permits the user to define new commands and thereby expand the editor's repertoire, or redefine existing commands.{foot To refer to the original definition of a built-in command when redefining it via a macro, use the {editcom ORIGINAL} command ({PageRef EditCom ORIGINAL}). }{comment endfootnote} Macros are defined by using the {editcom M} command: {index *PRIMARY* M EditCom} {Def {Type EditCom} {name M} {Args C COMS{sub 1} {ellipsis} COMS{sub N}} {Text For {arg C} an atom, {editcom M} defines {arg C} as an atomic command. If a macro is redefined, its new definition replaces its old. Executing {arg C} is then the same as executing the list of commands {arg COMS{sub 1}} {ellipsis} {arg COMS{sub N}}. }} For example, {lisp (M BP BK UP P)} will define {lisp BP} as an atomic command which does three things, a {lisp BK}, and {lisp UP}, and a {lisp P}. Macros can use commands defined by macros as well as built in commands in their definitions. For example, suppose {lisp Z} is defined by {lisp (M Z -1 (IF (READP T) NIL (P)))}, i.e., {lisp Z} does a {lisp -1}, and then if nothing has been typed, a {lisp P}. Now we can define {lisp ZZ} by {lisp (M ZZ -1 Z)}, and {lisp ZZZ} by {lisp (M ZZZ -1 -1 Z)} or {lisp (M ZZZ -1 ZZ)}. Macros can also define list commands, i.e., commands that take arguments. {Def {Type EditCom} {name M} {Args C ARG{sub 1} {ellipsis} ARG{sub N} COMS{sub 1} {ellipsis} COMS{sub M}} {PrintName {lisp (M ({arg C}) ({arg ARG{sub 1}} {ellipsis} {arg ARG{sub N}}) {arg COMS{sub 1}} {ellipsis} {arg COMS{sub M}})}} {Text {arg C} an atom. {editcom M} defines {arg C} as a list command. Executing {lisp ({arg C} {arg E{sub 1}} {ellipsis} {arg E{sub N}})} is then performed by substituting {arg E{sub 1}} for {arg ARG{sub 1}}, {ellipsis} {arg E{sub N}} for {arg ARG{sub N}} throughout {arg COMS{sub 1}} {ellipsis} {arg COMS{sub M}}, and then executing {arg COMS{sub 1}} {ellipsis} {arg COMS{sub M}}. }} For example, we could define a more general {lisp BP} by {lisp (M (BP) (N) (BK N) UP P)}. Thus, {lisp (BP 3)} would perform {lisp (BK 3)}, followed by an {lisp UP}, followed by a {lisp 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 {it atomic}, the command takes an indefinite number of arguments. {Def {Type EditCom} {name M} {Args C ARG COMS{sub 1} {ellipsis} COMS{sub M}} {PrintName {lisp (M ({arg C}) {arg ARG} {arg COMS{sub 1}} {ellipsis} {arg COMS{sub M}})}} {Text If {arg C}, {arg ARG} are both atoms, this defines {arg C} as a list command. Executing {lisp ({arg C} {arg E{sub 1}} {ellipsis} {arg E{sub N}})} is performed by substituting {lisp ({arg E{sub 1}} {ellipsis} {arg E{sub N}})}, i.e., {fn CDR} of the command, for {arg ARG} throughout {arg COMS{sub 1}} {ellipsis} {arg COMS{sub M}}, and then executing {arg COMS{sub 1}} {ellipsis} {arg COMS{sub M}}. }} For example, the command {editcom 2ND} ({PageRef EditCom 2ND}), could be defined as a macro by {lisp (M (2ND) X (ORR ((LC . X) (LC . X))))}. Note that for all editor commands, "built in" commands as well as commands defined by macros as atomic commands and list definitions are {it completely} independent. In other words, the existence of an atomic definition for {arg C} in {it no} way affects the treatment of {arg C} when it appears as {fn CAR} of a list command, and the existence of a list definition for {arg C} in {it no} way affects the treatment of {arg C} when it appears as an atom. In particular, {arg 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 {arg C} is defined as an atomic command via a macro definition, it will {it not} be searched for when used in a location specification, unless it is preceded by an {editcom F}. Thus {lisp (INSERT -- BEFORE BP)} would not search for {lisp BP}, but instead perform a {lisp BK}, and {lisp UP}, and a {lisp P}, and then do the insertion. The corresponding also holds true for list commands. Occasionally, the user will want to employ the {editcom S} command in a macro to save some temporary result. For example, the {editcom SW} command could be defined as: {lispcode (M (SW) (N M) (NTH N) (S FOO 1) MARK 0 (NTH M) (S FIE 1) (I 1 FOO) ←← (I 1 FIE))} {note 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.} Since this version of {editcom SW} sets {lisp FOO} and {lisp FIE}, using {editcom 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 {editcom BIND} command solves both problems. {Def {Type EditCom} {name BIND} {Args COMS{sub 1} {ellipsis} COMS{sub N}} {Text Binds three dummy variables {lisp #1}, {lisp #2}, {lisp #3}, (initialized to {lisp NIL}), and then executes the edit commands {arg COMS{sub 1}} {ellipsis} {arg COMS{sub N}}. {editcom BIND} uses a {lisp PROG} to make these bindings, so they are only in effect while the commands are being executed and {editcom BIND}s can be used recursively; the variables {lisp #1}, {lisp #2}, and {lisp #3} will be rebound each time {editcom BIND} is invoked. }} Thus, we can write {editcom SW} safely as: {lispcode (M (SW) (N M) (BIND (NTH N) (S #1 1) MARK 0 (NTH M) (S #2 1) (I 1 #1) ←← (I 1 #2)))} {Def {Type EditCom} {name ORIGINAL} {Args COMS{sub 1} {ellipsis} COMS{sub N}} {Text Executes {arg COMS{sub 1}} {ellipsis} {arg COMS{sub N}} without regard to macro definitions. Useful for redefining a built in command in terms of itself., i.e. effectively allows user to "advise" edit commands. }} User macros are stored on a list {index *PRIMARY* USERMACROS Var}{var USERMACROS}. The file package command {index USERMACROS FileCom}{filecom USERMACROS} ({PageRef FileCom USERMACROS}), is available for dumping all or selected user macros. {index *END* macros (in Editor)} {index *END* edit macros} }{End SubSec Edit Macros} {Begin SubSec Undo} {Title Undo} {Text {index *PRIMARY* undoing (in Editor)} Each command that causes structure modification automatically adds an entry to the front of {index *PRIMARY* UNDOLST Var}{var UNDOLST} that contains the information required to restore all pointers that were changed by that command. {index *PRIMARY* UNDO EditCom} {Def {Type EditCom} {Name UNDO} {Text Undoes the last, i.e., most recent, structure modification command that has not yet been undone, and prints the name of that command, e.g., {index UNDONE (Printed by Editor)}{lisp MBD UNDONE}. The edit chain is then {it exactly} what it was before the "undone" command had been performed. If there are no commands to undo, {editcom UNDO} types {lisp NOTHING SAVED}.{index NOTHING SAVED (Printed by Editor)} }} {Def {Type EditCom} {Name !UNDO} {Text 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 {editcom UNDO}. If there is nothing to be undone, {editcom !UNDO} prints {lisp NOTHING SAVED}.{index NOTHING SAVED (Printed by Editor)} }} Undoing an event containing an {editcom I}, {editcom E}, or {editcom S} command will also undo the side effects of the evaluation(s), e.g., undoing {lisp (I 3 (/NCONC FOO FIE))} will not only restore the 3rd element but also restore {lisp FOO}. Similarly, undoing an {editcom S} command will undo the set. See the discussion of {pacom UNDO} in {PageRef PAcom UNDO}. (Note that if the {editcom I} command was typed directly to the editor, {lisp /NCONC} would automatically be substituted for {lisp NCONC} as described in {PageRef Tag SlashifyingTypedInFns}.) Since {editcom UNDO} and {editcom !UNDO} cause structure modification, they also add an entry to {index UNDOLST Var}{var UNDOLST}. However, {lisp UNDO} and {lisp !UNDO} entries are skipped by {editcom UNDO}, e.g., if the user performs an {editcom INSERT}, and then an {editcom MBD}, the first {editcom UNDO} will undo the {editcom MBD}, and the second will undo the {editcom INSERT}. However, the user can also specify precisely which commands he wants undone by identifying the corresponding entry on the history list.{index history list} In this case, he can undo an {editcom UNDO} command, e.g., by typing {lisp UNDO UNDO}, or undo a {editcom !UNDO} command, or undo a command other than that most recently performed. Whenever the user {it continues} an editing session, the undo information of the previous session is protected by inserting a special blip, called an undo-block, on the front of {index UNDOLST Var}{var UNDOLST}. This undo-block will terminate the operation of a {editcom !UNDO}, thereby confining its effect to the current session, and will similarly prevent an {editcom 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 {editcom UNDO} or {editcom !UNDO}, the editor will type {index BLOCKED (Printed by Editor)}{lisp BLOCKED} instead of {lisp NOTHING SAVED}. Similarly, if the user executes several commands and then undoes them all, another {editcom UNDO} or {editcom !UNDO} will also cause {lisp BLOCKED} to be typed. {Def {Type EditCom} {Name UNBLOCK} {Text Removes an undo-block. If executed at a non-blocked state, i.e., if {editcom UNDO} or {editcom !UNDO} {it could} operate, types {lisp NOT BLOCKED}.{index NOT BLOCKED (Printed by Editor)} }} {Def {Type EditCom} {Name TEST} {Text Adds an undo-block at the front of {index UNDOLST Var}{var UNDOLST}. }} Note that {editcom TEST} together with {editcom !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 {editcom !UNDO} command. {Def {Type EditCom} {Name UNDO} {Args EventSpec} {Text {arg EventSpec} is an event specification (see {PageRef Tag EventAddress}). Undoes the indicated event on the history list. In this case, the event does not have to be in the current editing session, even if the previous session has not been unblocked as described above. However, the user does have to be editing the same expression as was being edited in the indicated event. If the expressions differ, the editor types the warning message "{lisp different expression}",{index different expression (Printed by Editor)} and does not undo the event. The editor enforces this to avoid the user accidentally undoing a random command by giving the wrong event specification. }} }{End SubSec Undo}