{Begin SubSec Commands That Modify Structure} {Title Commands That Modify Structure} {Text {index *BEGIN* structure modification commands (in Editor) Term} The basic structure modification commands in the editor are: {Def {Type EditCom} {Name N} {PrintName {lisp ({arg N})} ({arg N}{ge}1)} {Text Deletes the corresponding element from the current expression. }} {Def {Type EditCom} {Name N} {Args E{sub 1} {ellipsis} E{sub M}} {PrintName {lisp ({arg N} {arg E{sub 1}} {ellipsis} {arg E{sub M}})} ({arg N}{ge}1)} {Text Replaces the {arg N}th element in the current expression with {arg E{sub 1}} {ellipsis} {arg E{sub M}}. }} {Def {Type EditCom} {Name N} {Args E{sub 1} {ellipsis} E{sub M}} {PrintName {lisp (-{arg N} {arg E{sub 1}} {ellipsis} {arg E{sub M}})} ({arg N}{ge}1)} {text Inserts {arg E{sub 1}} {ellipsis} {arg E{sub M}} before the {arg N}th element in the current expression. }} {index *PRIMARY* N EditCom} {Def {Type EditCom} {name N} {Args E{sub 1} {ellipsis} E{sub M}} {Text Attaches {arg E{sub 1}} {ellipsis} {arg E{sub M}} at the end of the current expression. }} As mentioned earlier: {it all structure modification done by the editor is destructive, i.e., the editor uses {fn RPLACA} and {fn RPLACD} to physically change the structure it was given.} However, all structure modification is undoable,{index undoing (in Editor)} see {EditCom UNDO} ({PageRef EditCom UNDO}). 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 {arg N} elements. In addition, the command {lisp (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 {lisp NIL}) which cannot be done. However, the command {index DELETE EditCom}{editcom DELETE} will work even if there is only one element in the current expression, since it will ascend to a point where it {it can} do the deletion. {Tag EditorChangeMarks} If the value of {index CHANGESARRAY Var}{var CHANGESARRAY} is a hash array, the editor will mark all structures that are changed by doing {lisp (PUTHASH {arg STRUCTURE} {arg FN} {var CHANGESARRAY})}, where {arg 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. (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. {var CHANGESARRAY} is primarily for use by {fn PRETTYPRINT} ({PageRef Fn PRETTYPRINT}). When the value of {var CHANGECHAR}{index CHANGECHAR Var} is non-{lisp NIL}, {fn PRETTYPRINT}, when printing to a file or display terminal, prints {var CHANGECHAR} in the right margin while printing an expression marked as having been changed. {var CHANGECHAR} is initially {lisp |}{index | (change character)}. {Begin Note} Date: 24-Sep-82 11:34:32 PDT (Friday) From: Masinter at PARC-MAXC You can set CHANGESARRAY to (LIST (HARRAY nn)); I've found that generally the change-bar mechanism didn't work well (EVERY function wound up with most things marked, formatting often looked wrong), slowed things down (too many things didn't get GC'd; prettyprinting was much slower) and so turned it OFF as a system default. This should be changed in the manual also. Date: 25 Sep 1982 1320-PDT From: Clancey at SUMEX-AIM We generally find the change bars to be useful when "system" functions are involved because an individual's changes tend to be local and are marked clearly. {End Note} {Begin SubSec Implementation of Structure Modification Commands} {Title Implementation of Structure Modification Commands} {Text {it 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, unless the command was typed in directly to the editor,{foot Some editor commands take as arguments a list of edit commands, e.g., {lisp (LP F FOO (1 (CAR FOO)))}. In this case, the command {lisp (1 (CAR FOO))} is not considered to have been "typed in" even though the {lisp LP} command itself may have been typed in. Similarly, commands originating from macros, or commands given to the editor as arguments to {fn EDITF}, {fn EDITV}, et al, e.g., {lisp EDITF(FOO F COND (N --))} are not considered typed in. }{comment endfootnote} {it 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 {lisp (1 (A B C))} e.g., via {lisp (LIST 1 FOO)}, and gives this command to the editor, the {lisp (A B C)} used for the replacement will {it not} be {fn EQ} to {lisp FOO}.{foot The user can circumvent this by using the {editcom I} command ({PageRef EditCom I}), which computes the structure to be used. In the above example, the form of the command would be {lisp (I 1 FOO)}, which would replace the first element with the value of {lisp FOO} itself. }{comment endfootnote} 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 {lisp FOO} is {fn CDR} of the current expression, what will the commands {lisp (2)}, {lisp (3)}, {lisp (2 X Y Z)}, {lisp (-2 X Y Z)}, etc. do to {lisp 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 {lisp FOO} is {fn EQ} to the current expression which is {lisp (A B C D)}, and {lisp FIE} is {fn CDR} of {lisp FOO}, after executing the command {lisp (1)}, {lisp FOO} will be {lisp (B C D)} (which is {fn EQUAL} but not {fn EQ} to {lisp FIE}). However, under the same initial conditions, after executing {lisp (2)} {lisp FIE} will be unchanged, i.e., {lisp FIE} will still be {lisp (B C D)} even though the current expression and {lisp FOO} are now {lisp (A C D)}.{foot A general solution of the problem just isn't possible, as it would require being able to make two lists {fn EQ} to each other that were originally different. Thus if {lisp FIE} is {fn CDR} of the current expression, and {lisp FUM} is {fn CDDR} of the current expression, performing {lisp (2)} would have to make {lisp FIE} be {fn EQ} to {lisp FUM} if all subsequent operations were to update both {lisp FIE} and {lisp FUM} correctly. }{comment endfootnote} Both replacement and insertion are accomplished by smashing both {fn CAR} and {fn CDR} of the corresponding tail. Thus, if {lisp FOO} were {fn EQ} to the current expression, {lisp (A B C D)}, after {lisp (1 X Y Z)}, {lisp FOO} would be {lisp (X Y Z B C D)}. Similarly, if {lisp FOO} were {fn EQ} to the current expression, {lisp (A B C D)}, then after {lisp (-1 X Y Z)}, {lisp FOO} would be {lisp (X Y Z A B C D)}. The {editcom N} command is accomplished by smashing the last {fn CDR} of the current expression a la {fn NCONC}. Thus if {lisp FOO} were {fn EQ} to any tail of the current expression, after executing an {editcom N} command, the corresponding expressions would also appear at the end of {lisp FOO}. In summary, the only situation in which an edit operation will {it not} change an external pointer occurs when the external pointer is to a {it proper tail} of the data structure, i.e., to {fn CDR} of some node in the structure, and the operation is deletion. If all external pointers are to {it elements} of the structure, i.e., to {fn CAR} of some node, or if only insertions, replacements, or attachments are performed, the edit operation will {it always} have the same effect on an external pointer as it does on the current expression. }{End SubSec Implementation of Structure Modification Commands} {Begin SubSec The A, B, and : Commands} {Title The A, B, and : Commands} {Text In the {lisp ({arg N})}, {lisp ({arg N} {arg E{sub 1}} {ellipsis} {arg E{sub M}})}, and {lisp (-{arg N} {arg E{sub 1}} {ellipsis} {arg E{sub M}})} 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 {editcom N} command). Similarly, the user cannot specify deletion or replacement of the {arg N}th element from the end of a list without first converting {arg N} to the corresponding positive integer. Accordingly, we have: {Def {Type EditCom} {Name B} {Args E{sub 1} {ellipsis} E{sub M}} {Text Inserts {arg E{sub 1}} {ellipsis} {arg E{sub M}} before the current expression. Equivalent to {editcom UP} followed by {lisp (-1 {arg E{sub 1}} {ellipsis} {arg E{sub M}})}. }} For example, to insert {lisp FOO} before the last element in the current expression, perform {lisp -1} and then {lisp (B FOO)}. {Def {Type EditCom} {Name A} {Args E{sub 1} {ellipsis} E{sub M}} {Text Inserts {arg E{sub 1}} {ellipsis} {arg E{sub M}} after the current expression. Equivalent to {editcom UP} followed by {lisp (-2 {arg E{sub 1}} {ellipsis} {arg E{sub M}})} or {lisp (N {arg E{sub 1}} {ellipsis} {arg E{sub M}})}, whichever is appropriate. }} {Def {Type EditCom} {Name :} {Args E{sub 1} {ellipsis} E{sub M}} {Text Replaces the current expression by {arg E{sub 1}} {ellipsis} {arg E{sub M}}. Equivalent to {editcom UP} followed by {lisp (1 {arg E{sub 1}} {ellipsis} {arg E{sub M}})}. }} {index *PRIMARY* DELETE EditCom} {Def {Type EditCom} {Name DELETE}} {Def {Type EditCom} {Name :} {Parens} {Text Deletes the current expression. }} {editcom DELETE} first tries to delete the current expression by performing an {editcom UP} and then a {lisp (1)}. This works in most cases. However, if after performing {editcom UP}, the new current expression contains only one element, the command {lisp (1)} will not work. Therefore, {editcom DELETE} starts over and performs a {editcom BK}, followed by {editcom UP}, followed by {lisp (2)}. For example, if the current expression is {lisp (COND ((MEMB X Y)) (T Y))}, and the user performs {lisp -1}, and then {editcom DELETE}, the {lisp BK-UP-(2)} method is used, and the new current expression will be {lisp ... ((MEMB X Y)))}. However, if the next higher expression contains only one element, {editcom BK} will not work. So in this case, {index DELETE EditCom}{editcom DELETE} performs {editcom UP}, followed by {lisp (: NIL)}, i.e., it {it replaces} the higher expression by {lisp NIL}. For example, if the current expression is {lisp (COND ((MEMB X Y)) (T Y))} and the user performs {lisp F MEMB} and then {editcom DELETE}, the new current expression will be {lisp ... NIL (T Y))} and the original expression would now be {lisp (COND NIL (T Y))}. The rationale behind this is that deleting {lisp (MEMB X Y)} from {lisp ((MEMB X Y))} changes a list of one element to a list of no elements, i.e., {lisp ()} or {lisp NIL}. If the current expression is a tail, then {editcom B}, {editcom A}, {editcom :}, and {index DELETE EditCom}{editcom DELETE} all work exactly the same as though the current expression were the first element in that tail. Thus if the current expression were {lisp ... (PRINT Y) (PRINT Z))}, {lisp (B (PRINT X))} would insert {lisp (PRINT X)} before {lisp (PRINT Y)}, leaving the current expression {lisp ... (PRINT X) (PRINT Y) (PRINT Z))}. The following forms of the {editcom A}, {editcom B}, and {editcom :} commands incorporate a location specification: {index *PRIMARY* INSERT EditCom} {Def {Type EditCom} {Name INSERT} {Args E{sub 1} {ellipsis} E{sub M}} {PrintName {lisp (INSERT {arg E{sub 1}} {ellipsis} {arg E{sub M}} BEFORE . @)}} {Text {index BEFORE (in INSERT command) (in Editor)}({lisp @} is {lisp (CDR (MEMBER 'BEFORE {arg COMMAND}))}) Similar to {lisp (LC .@)} followed by {lisp (B {arg E{sub 1}} {ellipsis} {arg E{sub M}})}. Warning: If {lisp @} causes an error, the location process does {it not} continue as described on {PageRef Tag EditorLocationSpecification}. For example if {lisp @}={lisp (COND 3)} and the next {lisp COND} does not have a 3rd element, the search stops and the {editcom INSERT} fails. Note that the user can always write {lisp (LC COND 3)} if he intends the search to continue. }} {lispcode *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) ( {it user typed control-E} *} Current edit chain is not changed, but {index UNFIND Var}{var UNFIND} is set to the edit chain after the {editcom B} was performed, i.e., {index \ EditCom}{editcom \} will make the edit chain be that chain where the insertion was performed. {Def {Type EditCom} {Name INSERT} {Args E{sub 1} {ellipsis} E{sub M}} {PrintName {lisp (INSERT {arg E{sub 1}} {ellipsis} {arg E{sub M}} AFTER . @)}} {Text {index AFTER (in INSERT command) (in Editor)}Similar to {lisp INSERT BEFORE} except uses {editcom A} instead of {editcom B}. }} {Def {Type EditCom} {Name INSERT} {Args E{sub 1} {ellipsis} E{sub M}} {PrintName {lisp (INSERT {arg E{sub 1}} {ellipsis} {arg E{sub M}} FOR . @)}} {Text {index FOR (in INSERT command) (in Editor)}Similar to {lisp INSERT BEFORE} except uses {editcom :} for {editcom B}. }} {Def {Type EditCom} {Name REPLACE} {Args E{sub 1} {ellipsis} E{sub M}} {PrintName {lisp (REPLACE @ BY {arg E{sub 1}} {ellipsis} {arg E{sub M}})}} } {Def {Type EditCom} {Name REPLACE} {Args E{sub 1} {ellipsis} E{sub M}} {PrintName {lisp (REPLACE @ WITH {arg E{sub 1}} {ellipsis} {arg E{sub M}})}} {Text {index WITH (in REPLACE command) (in Editor)}{index BY (in REPLACE command) (in Editor)}Here {lisp @} is the {it segment} of the command between {lisp REPLACE} and {index WITH (in REPLACE command) (in Editor)}{lisp WITH}. Same as {lisp (INSERT {arg E{sub 1}} {ellipsis} {arg E{sub M}} FOR . @)}. Example: {lisp (REPLACE COND -1 WITH (T (RETURN L)))} }} {Def {Type EditCom} {Name CHANGE} {Args E{sub 1} {ellipsis} E{sub M}} {PrintName {lisp (CHANGE @ TO {arg E{sub 1}} {ellipsis} {arg E{sub M}})}} {Text Same as {lisp REPLACE WITH}. }} {Def {Type EditCom} {Name DELETE} {PrintName {lisp (DELETE . @)}} {Text Does a {lisp (LC . @)} followed by {lisp DELETE}.{foot See warning about {editcom INSERT}, {PageRef EditCom INSERT}. }{comment endfootnote} The current edit chain is not changed, but {index UNFIND Var}{var UNFIND} is set to the edit chain after the {lisp DELETE} was performed. Note: the edit chain will be changed if the current expression is no longer a part of the expression being edited, e.g., if the current expression is {lisp ... C)} and the user performs {lisp (DELETE 1)}, the tail, {lisp (C)}, will have been cut off. Similarly, if the current expression is {lisp (CDR Y)} and the user performs {lisp (REPLACE WITH (CAR X))}. Example: {lisp (DELETE -1)}, {lisp (DELETE COND 3)} }} {it Note: if {lisp @} is {lisp NIL} (i.e., empty), the corresponding operation is performed on the current edit chain. } For example, {lisp (REPLACE WITH (CAR X))} is equivalent to {lisp (: (CAR X))}. For added readability, {index HERE (in edit command)}{lisp HERE} is also permitted, e.g., {lisp (INSERT (PRINT X) BEFORE HERE)} will insert {lisp (PRINT X)} before the current expression (but not change the edit chain). {it Note: {lisp @} does not have to specify a location {it within} the current expression, i.e., it is perfectly legal to ascend to {lisp INSERT}, {lisp REPLACE}, or {lisp DELETE} } For example, {lisp (INSERT (RETURN) AFTER ^ PROG -1)} will go to the top, find the first {lisp PROG}, and insert a {lisp (RETURN)} at its end, and not change the current edit chain. {Tag EditorAchecks} The {editcom A}, {editcom B}, and {editcom :} commands, commands, (and consequently {editcom INSERT}, {editcom REPLACE}, and {editcom CHANGE}), all make special checks in {arg E{sub 1}} thru {arg E{sub M}} for expressions of the form {lisp (## . {arg COMS})}.{index ## (in INSERT, REPLACE, and CHANGE commands)} In this case, the expression used for inserting or replacing is a {it copy} of the current expression after executing {arg COMS}, a list of edit commands (the execution of {arg COMS} does not change the current edit chain). For example, {lisp (INSERT (## F COND -1 -1) AFTER 3)} will make a copy of the last form in the last clause of the next {lisp COND}, and insert it after the third element of the current expression. Note that this is not the same as {lisp (INSERT F COND -1 (## -1) AFTER 3)}, which inserts four elements after the third element, namely {lisp F}, {lisp COND}, {lisp -1}, and a copy of the last element in the current expression. }{End SubSec The A, B, and : Commands} {Begin SubSec Form Oriented Editing and the Role of UP} {Title Form Oriented Editing and the Role of UP} {Text {Tag FormOrientedEditing} The {index UP EditCom}{editcom UP} that is performed before {editcom A}, {editcom B}, and {editcom :} commands{foot and therefore in {editcom INSERT}, {editcom CHANGE}, {editcom REPLACE}, and {editcom DELETE} commands after the location portion of the operation has been performed. }{comment endfootnote} makes these operations form-oriented. For example, if the user types {lisp F SETQ}, and then {lisp DELETE}, or simply {lisp (DELETE SETQ)}, he will delete the entire {lisp SETQ} expression, whereas {lisp (DELETE X)} if {lisp X} is a variable, deletes just the variable {lisp X}. In both cases, the operation is performed on the corresponding {it form}, and in both cases is probably what the user intended. Similarly, if the user types {lisp (INSERT (RETURN Y) BEFORE SETQ)}, he means before the {lisp SETQ} expression, not before the atom {lisp SETQ}.{foot There is some ambiguity in {lisp (INSERT {arg EXPR} AFTER {arg FUNCTIONNAME})}, as the user might mean make {arg EXPR} be the function's first argument. Similarly, the user cannot write {lisp (REPLACE SETQ WITH SETQQ)} meaning change the name of the function. The user must in these cases write {lisp (INSERT {arg EXPR} AFTER {arg FUNCTIONNAME} 1)}, and {lisp (REPLACE SETQ 1 WITH SETQQ)}. }{comment endfootnote} A consequent of this procedure is that a pattern of the form {lisp (SETQ Y --)} can be viewed as simply an elaboration and further refinement of the pattern {lisp SETQ}. Thus {lisp (INSERT (RETURN Y) BEFORE SETQ)} and {lisp (INSERT (RETURN Y) BEFORE (SETQ Y --))} perform the same operation{foot assuming the next {lisp SETQ} is of the form {lisp (SETQ Y --)}. }{comment endfootnote} and, in fact, this is one of the motivations behind making the current expression after {lisp F SETQ}, and {lisp 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 {fn CAR} of a list, versus those appearing elsewhere in a list. In general, the user may not even {it know} whether a particular atom is at the head of a list or not. Thus, when he writes {lisp (INSERT {arg EXPR} BEFORE FOO)}, he means before the atom {lisp FOO}, whether or not it is {fn CAR} of a list. By setting the variable {index *PRIMARY* UPFINDFLG Var}{var UPFINDFLG} to {lisp NIL} (initially {lisp T}), the user can suppress the implicit {editcom UP} that follows searches for atoms, and thus achieve the desired effect. With {var UPFINDFLG}={lisp NIL}, following {lisp F FOO}, for example, the current expression will be the atom {lisp FOO}. In this case, the {editcom A}, {editcom B}, and {editcom :} operations will operate with respect to the atom {lisp FOO}. If the user intends the operation to refer to the list which {lisp FOO} heads, he simply uses instead the pattern {lisp (FOO --)}. }{End SubSec Form Oriented Editing and the Role of UP} {Begin SubSec Extract and Embed} {Title Extract and Embed} {Text Extraction involves replacing the current expression with one of its subexpressions (from any depth). {Def {Type EditCom} {name XTR} {PrintName {lisp (XTR . @)}} {Text Replaces the original current expression with the expression that is current after performing {lisp (LCL . @)}.{foot See warning about {editcom INSERT}, {PageRef EditCom INSERT}. }{comment endfootnote} If the current expression after {lisp (LCL . @)} is a {it tail} of a higher expression, its first element is used. If the extracted expression is a list, then after {editcom XTR} has finished, the current expression will be that list. If the extracted expression is not a list, the new current expression will be a tail whose first element is that non-list. }} For example, if the current expression is {lisp (COND ((NULL X) (PRINT Y)))}, {lisp (XTR PRINT)}, or {lisp (XTR 2 2)} will replace the {fn COND} by the {fn PRINT}. The current expression after the {editcom XTR} would be {lisp (PRINT Y)}. If the current expression is {lisp (COND ((NULL X) Y) (T Z))}, then {lisp (XTR Y)} will replace the {fn COND} with {lisp Y}, even though the current expression after performing {lisp (LCL Y)} is {lisp ... Y)}. The current expression after the {editcom XTR} would be {lisp ... Y} followed by whatever followed the {lisp COND}. If the current expression {it 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 {lisp ... (COND ((NULL X) (PRINT Y))) (RETURN Z))}, then {lisp (XTR PRINT)} will replace the {fn COND} by the {fn PRINT}, leaving {lisp (PRINT Y)} as the current expression. The extract command can also incorporate a location specification: {Def {Type EditCom} {name EXTRACT} {Args {lisp @{sub 1} FROM . @{sub 2}}} {PrintName {lisp (EXTRACT @{sub 1} FROM . @{sub 2})}} {Text ({lisp @{sub 1}} is the {it segment} between {lisp EXTRACT} and {lisp FROM}.) {index FROM (in EXTRACT command) (in Editor)}Performs {lisp (LC . @{sub 2})}{foot See warning about {editcom INSERT}, {PageRef EditCom INSERT}. }{comment endfootnote} and then {lisp (XTR . @{sub 1})}. The current edit chain is not changed, but {index UNFIND Var}{var UNFIND} is set to the edit chain after the {editcom XTR} was performed. }} For example: If the current expression is {lisp (PRINT (COND ((NULL X) Y) (T Z)))} then following {lisp (EXTRACT Y FROM COND)}, the current expression will be {lisp (PRINT Y)}. {lisp (EXTRACT 2 -1 FROM COND)}, {lisp (EXTRACT Y FROM 2)}, and {lisp (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 it} as a subexpression. {Def {Type EditCom} {name MBD} {Args E{sub 1} {ellipsis} E{sub M}} {Text {editcom MBD} substitutes the current expression for all instances of the atom {index & (in MBD command)}{lisp &} in {arg E{sub 1}} {ellipsis} {arg E{sub M}}, and replaces the current expression with the result of that substitution. As with {fn SUBST}, a fresh copy is used for each substitution. If {lisp &} does not appear in {arg E{sub 1}} {ellipsis} {arg E{sub M}}, the {editcom MBD} is interpreted as {lisp (MBD ({arg E{sub 1}} {ellipsis} {arg E{sub M}} &))}. {editcom MBD} leaves the edit chain so that the larger expression is the new current expression. }} Examples: If the current expression is {lisp (PRINT Y)}, {lisp (MBD (COND ((NULL X) &) ((NULL (CAR Y)) & (GO LP))))} would replace {lisp (PRINT Y)} with {lisp (COND ((NULL X) (PRINT Y)) ((NULL (CAR Y)) (PRINT Y) (GO LP)))}. If the current expression is {lisp (RETURN X)}, {lisp (MBD (PRINT Y) (AND FLG &))} would replace it with the {it two} expressions {lisp (PRINT Y)} and {lisp (AND FLG (RETURN X))} i.e., if the {lisp (RETURN X)} appeared in the cond clause {lisp (T (RETURN X))}, after the {editcom MBD}, the clause would be {lisp (T (PRINT Y) (AND FLG (RETURN X)))}. If the current expression is {lisp (PRINT Y)}, then {lisp (MBD SETQ X)} will replace it with {lisp (SETQ X (PRINT Y))}. If the current expression is {lisp (PRINT Y)}, {lisp (MBD RETURN)} will replace it with {lisp (RETURN (PRINT Y))}. If the current expression {it 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 {lisp ... (PRINT Y) (PRINT Z))}, {lisp (MBD SETQ X)} would replace {lisp (PRINT Y)} with {lisp (SETQ X (PRINT Y))}. The embed command can also incorporate a location specification: {Def {Type EditCom} {name EMBED} {Args X} {PrintName {lisp (EMBED @ IN . {arg X})}} {Text {index IN (in EMBED command) (in Editor)}({lisp @} is the segment between {lisp EMBED} and {lisp IN}.) Does {lisp (LC . @)}{foot See warning about {editcom INSERT}, {PageRef EditCom INSERT}. }{comment endfootnote} and then {lisp (MBD . {arg X})}. Edit chain is not changed, but {index UNFIND Var}{var UNFIND} is set to the edit chain after the {editcom MBD} was performed. }} Examples: {lisp (EMBED PRINT IN SETQ X)}, {lisp (EMBED 3 2 IN RETURN)}, {lisp (EMBED COND 3 1 IN (OR & (NULL X)))}. {lisp WITH} can be used for {lisp IN}, and {lisp SURROUND} can be used for {lisp EMBED}, e.g., {lisp (SURROUND NUMBERP WITH (AND & (MINUSP X)))}.{index WITH (in SURROUND command) (in Editor)}{index SURROUND EditCom} {VarDef {Name EDITEMBEDTOKEN} {Text The special atom used in the {editcom MBD} and {editcom EMBED} commands is the value of this variable, initially {lisp &}.{index & (in MBD command)} }} {Begin Note} Date: 19 June 1982 4:57 am PDT (Saturday) From: JonL.PA EMBED and MBD don't do the right thing when * is the final CDR of a (pattern) list, and the frob being embedded is atomic. {End Note} }{End SubSec Extract and Embed} {Begin SubSec The MOVE Command} {Title The MOVE Command} {Text {index *BEGIN* MOVE EditCom} The {editcom 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. {Def {Type EditCom} {name MOVE} {Args @{sub 1} COM @{sub 2}} {PrintName {lisp (MOVE @{sub 1} TO {arg COM} . @{sub 2})}} {Text ({lisp @{sub 1}} is the segment between {lisp MOVE} and {lisp TO}.) {arg COM} is {index BEFORE (in MOVE command) (in Editor)}{lisp BEFORE}, {index AFTER (in MOVE command) (in Editor)}{lisp AFTER}, or the name of a list command, e.g., {editcom :}, {editcom N}, etc. Performs {lisp (LC . @{sub 1})},{foot See warning about {editcom INSERT}, {PageRef EditCom INSERT}. }{comment endfootnote} and obtains the current expression there (or its first element, if it is a tail), which we will call {arg EXPR}; {editcom MOVE} then goes back to the original edit chain, performs {lisp (LC . @{sub 2})} followed by {lisp ({arg COM} {arg EXPR})} (setting an internal flag so {arg EXPR} is not copied), then goes back to {lisp @{sub 1}} and deletes {arg EXPR}. The edit chain is not changed. {index UNFIND Var}{var UNFIND} is set to the edit chain after {lisp ({arg COM} {arg EXPR})} was performed. If {lisp @{sub 2}} specifies a location {it inside of the expression to be moved,} a message is printed and an error is generated, e.g., {lisp (MOVE 2 TO AFTER X)}, where {lisp X} is contained inside of the second element.{index DESTINATION IS INSIDE EXPRESSION BEING MOVED (Printed by Editor)} }} For example, if the current expression is {lisp (A B C D)}, {lisp (MOVE 2 TO AFTER 4)} will make the new current expression be {lisp (A C D B)}. Note that {lisp 4} was executed as of the original edit chain, and that the second element had not yet been removed. {Begin Note} Date: 19 June 1982 4:57 am PDT (Saturday) From: JonL.PA Subject: A few EDITF/P problems It would sure be nice to have a COPY command, which has syntax like MOVE. I've just put a macro for it in my personal "utilities" file. E.g. (COPY 3 1 TO AFTER COND), and (COPY GO TO N COND -1) [also have IFY for turning COND's to IF's] Date: 19 JUN 1982 2224-PDT From: MASINTER.PA COPY can be achieved with using ## in A or B or INSERT etc. This may need better explaination, or maybe COPY is a better abstraction. {End Note} As the following examples taken from actual editing will show, the {editcom MOVE} command is an extremely versatile and powerful feature of the editor. {lispcode *? (PROG ((L L)) (EDLOC (CDDR C)) (RETURN (CAR L))) *(MOVE 3 TO : CAR) *? (PROG ((L L)) (RETURN (EDLOC (CDDR C)))) *} {lispcode *P ... (SELECTQ OBJPR & &) (RETURN &) LP2 (COND & &)) *(MOVE 2 TO N 1) *P ... (SELECTQ OBJPR & & &) LP2 (COND & &)) *} {lispcode *P (OR (EQ X LASTAIL) (NOT &) (AND & & &)) *(MOVE 4 TO AFTER (BELOW COND)) *P (OR (EQ X LASTAIL) (NOT &)) *\ P ... (& &) (AND & & &) (T & &)) *} {lispcode *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 {lisp PROG} label {lisp NXT} and moved the {fn COND} in one operation by performing {lisp (MOVE 4 TO N (_ PROG) (N NXT))}. Similarly, in the next example, in the course of specifying {lisp @{sub 2}}, the location where the expression was to be moved to, the user also performs a structure modification, via {lisp (N (T))}, thus creating the structure that will receive the expression being moved. {lispcode *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 {lisp @{sub 2}} is {lisp NIL}, or {lisp (HERE)}, the current position specifies where the operation is to take place. In this case, {index UNFIND Var}{var UNFIND} is set to where the expression that was moved was originally located, i.e., {lisp @{sub 1}}. For example: {lispcode *P (TENEX) *(MOVE ^ F APPLY TO N HERE) *P (TENEX (APPLY & &)) *} {lispcode *P (PROG (& & & ATM IND VAL) (OR & &) **COMMENT** (OR & &) (PRIN1 & T) ( PRIN1 & T) (SETQ IND {it user typed control-E} *(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 {lisp @{sub 1}} is {lisp NIL}, the {editcom MOVE} command allows the user to specify where the {it 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; {index UNFIND Var}{var UNFIND} is set to where it was. {lispcode *P (SELECTQ OBJPR (&) (PROGN & &)) *(MOVE TO BEFORE LOOP) *P ... (SELECTQ OBJPR & &) LOOP (FRPLACA DFPRP &) (FRPLACD DFPRP &) (SELECTQ {it user typed control-E} *} {index *END* MOVE EditCom} }{End SubSec The MOVE Command} {Begin SubSec Commands That Move Parentheses} {Title Commands That Move Parentheses} {Text {index *BEGIN* commands that move parentheses (in Editor) Term} 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 {fn PRINT}. Thus, no command can insert or remove just one parenthesis, but this is suggestive of what actually happens. In all six commands, {arg N} and {arg M} are used to specify an element of a list, usually of the current expression. In practice, {arg N} and {arg M} are usually positive or negative integers with the obvious interpretation. However, all six commands use the generalized {editcom NTH} command {lisp (NTH {arg COM})} to find their element(s), so that {arg N}th element means the first element of the tail found by performing {lisp (NTH {arg N})}. In other words, if the current expression is {lisp (LIST (CAR X) (SETQ Y (CONS W Z)))}, then {lisp (BI 2 CONS)}, {lisp (BI X -1)}, and {lisp (BI X Z)} all specify the exact same operation. All six commands generate an error if the element is not found, i.e., the {editcom NTH} fails. All are undoable. {Def {Type EditCom} {name BI} {Args N M} {Text "Both In". Inserts a left parentheses before the {arg N}th element and after the {arg M}th element in the current expression. Generates an error if the {arg M}th element is not contained in the {arg N}th tail, i.e., the {arg M}th element must be "to the right" of the {arg N}th element. }} Example: If the current expression is {lisp (A B (C D E) F G)}, then {lisp (BI 2 4)} will modify it to be {lisp (A (B (C D E) F) G)}. {Def {Type EditCom} {name BI} {Args N} {Text Same as {lisp (BI {arg N} {arg N})}. }} Example: If the current expression is {lisp (A B (C D E) F G)}, then {lisp (BI -2)} will modify it to be {lisp (A B (C D E) (F) G)}. {Def {Type EditCom} {name BO} {Args N} {Text "Both Out". Removes both parentheses from the {arg N}th element. Generates an error if {arg N}th element is not a list. }} Example: If the current expression is {lisp (A B (C D E) F G)}, then {lisp (BO D)} will modify it to be {lisp (A B C D E F G)}. {Def {Type EditCom} {name LI} {Args N} {Text "Left In". Inserts a left parenthesis before the {arg N}th element (and a matching right parenthesis at the end of the current expression), i.e. equivalent to {lisp (BI {arg N} -1)}. }} Example: if the current expression is {lisp (A B (C D E) F G)}, then {lisp (LI 2)} will modify it to be {lisp (A (B (C D E) F G))}. {Def {Type EditCom} {name LO} {Args N} {Text "Left Out". Removes a left parenthesis from the {arg N}th element. {it All elements following the {arg N}th element are deleted.} Generates an error if {arg N}th element is not a list. }} Example: If the current expression is {lisp (A B (C D E) F G)}, then {lisp (LO 3)} will modify it to be {lisp (A B C D E)}. {Def {Type EditCom} {name RI} {Args N M} {Text "Right In". Inserts a right parenthesis after the {arg M}th element of the {arg N}th element. The rest of the {arg N}th element is brought up to the level of the current expression. }} Example: If the current expression is {lisp (A (B C D E) F G)}, {lisp (RI 2 2)} will modify it to be {lisp (A (B C) D E F G)}. Another way of thinking about {editcom RI} is to read it as "move the right parenthesis at the end of the {arg N}th element {it in} to after its {arg N}th element." {Def {Type EditCom} {name RO} {Args N} {Text "Right Out". Removes the right parenthesis from the {arg N}th element, moving it to the end of the current expression. All elements following the {arg N}th element are moved inside of the {arg N}th element. Generates an error if {arg N}th element is not a list. }} Example: If the current expression is {lisp (A B (C D E) F G)}, {lisp (RO 3)} will modify it to be {lisp (A B (C D E F G))}. Another way of thinking about {editcom RO} is to read it as "move the right parenthesis at the end of the {arg N}th element {it out} to the end of the current expression." {index *END* commands that move parentheses (in Editor) Term} }{End SubSec Commands That Move Parentheses} {Begin SubSec TO and THRU} {Title TO and THRU} {Text {index *BEGIN* TO EditCom} {index *BEGIN* THRU EditCom} {editcom EXTRACT}, {editcom EMBED}, {editcom DELETE}, {editcom REPLACE}, and {editcom 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 {editcom TO} or {editcom THRU} command. {index *PRIMARY* THRU EditCom} {Def {Type EditCom} {name THRU} {PrintName {lisp (@{sub 1} THRU @{sub 2})}} {Text Does a {lisp (LC . @{sub 1})}, followed by an {editcom UP}, and then a {lisp (BI 1 @{sub 2})}, thereby grouping the segment into a single element, and finally does a {lisp 1}, making the final current expression be that element. }} For example, if the current expression is {lisp (A (B (C D) (E) (F G H) I) J K)}, following {lisp (C THRU G)}, the current expression will be {lisp ((C D) (E) (F G H))}. {index *PRIMARY* TO EditCom} {Def {Type EditCom} {name TO} {PrintName {lisp (@{sub 1} TO @{sub 2})}} {Text Same as {editcom THRU} except the last element not included, i.e., after the {editcom BI}, an {lisp (RI 1 -2)} is performed. }} If both {lisp @{sub 1}} and {lisp @{sub 2}} are numbers, and {lisp @{sub 2}} is greater than {lisp @{sub 1}}, then {lisp @{sub 2}} counts from the beginning of the current expression, the same as {lisp @{sub 1}}. In other words, if the current expression is {lisp (A B C D E F G)}, {lisp (3 THRU 5)} means {lisp (C THRU E)} not {lisp (C THRU G)}. In this case, the corresponding {editcom BI} command is {lisp (BI 1 @{sub 2}-@{sub 1}+1)}. {editcom THRU} and {editcom TO} are not very useful commands by themselves; they are intended to be used in conjunction with {editcom EXTRACT}, {editcom EMBED}, {editcom DELETE}, {editcom REPLACE}, and {editcom MOVE}. After {editcom THRU} and {editcom 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: {lispcode *P (PROG (& & ATM IND VAL WORD) (PRIN1 & T) (PRIN1 & T) (SETQ IND &) (SETQ VAL &) **COMMENT** (SETQQ {it user typed control-E} *(MOVE (3 THRU 4) TO BEFORE 7) *P (PROG (& & ATM IND VAL WORD) (SETQ IND &) (SETQ VAL &) (PRIN1 & T) (PRIN1 & T) **COMMENT** {it user typed control-E} *} {lispcode *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 {it user typed control-E} *} {lispcode *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 &)) *} {lispcode *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 & & {it user typed control-E} *} {editcom TO} and {editcom THRU} can also be used directly with {editcom XTR}, because {editcom XTR} involves a location specification while {editcom A}, {editcom B}, {editcom :}, and {editcom MBD} do not. Thus in the previous example, if the current expression had been the {lisp COND}, e.g., the user had first performed {lisp F COND}, he could have used {lisp (XTR (SETQ THRU CADR))} to perform the extraction. {Def {Type EditCom} {name TO} {PrintName {lisp (@{sub 1} TO)}} } {Def {Type EditCom} {name THRU} {PrintName {lisp (@{sub 1} THRU)}} {Text Both are the same as {lisp (@{sub 1} THRU -1)}, i.e., from {lisp @{sub 1}} through the end of the list. }} Examples: {lispcode *P (VALUE (RPLACA DEPRP &) (RPLACD &) (RPLACA VARSWORD &) (RETURN)) *(MOVE (2 TO) TO N (_ PROG)) *(N (GO VAR)) *P (VALUE (GO VAR))} {lispcode *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 &)) *} {lispcode *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] *} {index *END* TO EditCom} {index *END* THRU EditCom} }{End SubSec TO and THRU} {Begin SubSec The R Command} {Title The R Command} {Text {Def {Type EditCom} {Name R} {Args X Y} {Text Replaces all instances of {arg X} by {arg Y} in the current expression, e.g., {lisp (R CAADR CADAR)}. Generates an error if there is not at least one instance. }} The {editcom R} command operates in conjunction with the search mechanism of the editor. The search proceeds as described on {PageRef Tag EditorSearchAlgorithm}, and {arg X} can employ any of the patterns on {PageRef Tag EditPattern}. Each time {arg X} matches an element of the structure, the element is replaced by (a copy of) {arg Y}; each time {arg X} matches a tail of the structure, the tail is replaced by (a copy of) {arg Y}. For example, if the current expression is {lisp (A (B C) (B . C))}, {lisp (R C D)} will change it to {lisp (A (B D) (B . D))}, {lisp (R (... . C) D)} will change it to {lisp (A (B C) (B . D))}, {lisp (R C (D E))} will change it to {lisp (A (B (D E)) (B D E))}, and {lisp (R (... . NIL) D)} will change it to {lisp (A (B C . D) (B . C) . D)}. If {arg X} is an atom or string containing {lisp $}s (s), {lisp $}s appearing in {arg Y} stand for the characters matched by the corresponding {lisp $} in {arg X}.{index $ () (in R command) (in Editor)} For example, {lisp (R FOO$ FIE$)} means for all atoms or strings that begin with {lisp FOO}, replace the characters "{lisp FOO}" by "{lisp FIE}".{foot If {arg X} matches a string, it will be replaced by a string. Note that it does not matter whether {arg X} or {arg Y} themselves are strings, i.e. {lisp (R $D$ $A$)}, {lisp (R "$D$" $A$)}, {lisp (R $D$ "$A$")}, and {lisp (R "$D$" "$A$")} are equivalent. Note also that {arg X} will never match with a number, i.e., {lisp (R $1 $2)} will not change 11 to 12. }{comment endfootnote} Applied to the list {lisp (FOO FOO2 XFOO1)}, {arg (R FOO$ FIE$)} would produce {lisp (FIE FIE2 XFOO1)}, and {lisp (R $FOO$ $FIE$)} would produce {lisp (FIE FIE2 XFIE1)}. Similarly, {lisp (R $D$ $A$)} will change {lisp (LIST (CADR X) (CADDR Y))} to {lisp (LIST (CAAR X) (CAADR))}. Note that {lisp CADDR} was {it not} changed to {lisp CAAAR}, i.e., {lisp (R $D$ $A$)} does not mean replace every {lisp D} with {lisp A}, but replace the first {lisp D} in every atom or string by {lisp A}. If the user wanted to replace every {lisp D} by {lisp A}, he could perform {lisp (LP (R $D$ $A$))}. The user will be informed of all such {lisp $} replacements by a message of the form {lisp {arg X}->{arg Y}}, e.g., {lisp CADR->CAAR}.{index -> (Printed by Editor)} Note that the {lisp $} feature can be used to delete or add characters, as well as replace them. For example, {lisp (R $1 $)} will delete the terminating {lisp 1}'s from all literal atoms and strings. Similarly, if an {lisp $} in {arg X} does not have a mate in {arg Y}, the characters matched by the {lisp $} are effectively deleted.{index $ (, in R command) (in Editor)} For example, {lisp (R $/$ $)} will change {lisp AND/OR} to {lisp AND}.{foot There is no similar operation for changing {lisp AND/OR} to {lisp OR}, since the first {lisp $} in {arg Y} always corresponds to the first {lisp $} in {arg X}, the second {lisp $} in {arg Y} to the second in {arg X}, etc. }{comment endfootnote} {arg Y} can also be a list containing {lisp $}s, e.g., {lisp (R $1 (CAR $))} will change {lisp FOO1} to {lisp (CAR FOO)}, {lisp FIE1} to {lisp (CAR FIE)}. If {arg X} does not contain {lisp $}s, {lisp $} appearing in {arg Y} refers to the {it entire} expression matched by {arg X}, e.g., {lisp (R LONGATOM '$)} changes {lisp LONGATOM} to {lisp 'LONGATOM}, {lisp (R (SETQ X &) (PRINT $))} changes every {lisp (SETQ X &)} to {lisp (PRINT (SETQ X &))}.{foot If {arg X} is a pattern containing an {lisp $} pattern somewhere {it within} it, the characters matched by the {lisp $}s are not available, and for the purposes of replacement, the effect is the same as though {arg X} did not contain any {lisp $}s. For example, if the user types {lisp (R (CAR F$) (PRINT $))}, the second {lisp $} will refer to the entire expression matched by {lisp (CAR F$)}. }{comment endfootnote} Since {lisp (R ${arg X}$ ${arg Y}$)} is a frequently used operation for {lisp R}eplacing {lisp C}haracters, the following command is provided: {Def {Type EditCom} {name RC} {Args X Y} {text Equivalent to {lisp (R ${arg X}$ ${arg Y}$)} }} {Begin Note} Date: 19 June 1982 4:57 am PDT (Saturday) From: JonL.PA Subject: A few EDITF/P problems You can't do RC on a litatom -- why not? the editor could do the same thing that the : command does, namely go UP then (1 ...) Date: 19 JUN 1982 2224-PDT From: MASINTER.PA RC on litatoms: yes, unimplemented. {End Note} {editcom R} and {editcom RC} change all instances of {arg X} to {arg Y}. The commands {editcom R1} and {editcom RC1} are available for changing just one, (i.e., the first) instance of {arg X} to {arg Y}. {Def {Type EditCom} {name R1} {Args X Y} {text Find the first instance of {arg X} and replace it by {arg Y}. }} {Def {Type EditCom} {name RC1} {Args X Y} {text {lisp (R1 ${arg X}$ ${arg Y}$)}. }} In addition, while {editcom R} and {editcom RC} only operate within the current expression, {editcom R1} and {editcom RC1} will continue searching, a la the {editcom F} command, until they find an instance of {arg x}, even if the search carries them beyond the current expression. {Def {Type EditCom} {name SW} {Args N M} {text Switches the {arg N}th and {arg M}th elements of the current expression. }} For example, if the current expression is {lisp (LIST (CONS (CAR X) (CAR Y)) (CONS (CDR X) (CDR Y)))}, {lisp (SW 2 3)} will modify it to be {lisp (LIST (CONS (CDR X) (CDR Y)) (CONS (CAR X) (CAR Y)))}. The relative order of {arg N} and {arg M} is not important, i.e., {lisp (SW 3 2)} and {lisp (SW 2 3)} are equivalent. {editcom SW} uses the generalized {editcom NTH} command {lisp (NTH {arg COM})} to find the {arg N}th and {arg M}th elements, a la the {editcom BI}-{editcom BO} commands. Thus in the previous example, {lisp (SW CAR CDR)} would produce the same result. {Def {Type EditCom} {name SWAP} {PrintName {lisp (SWAP @{sub 1} @{sub 2})}} {text Like {editcom SW} except switches the expressions specified by {lisp @{sub 1}} and {lisp @{sub 2}}, not the corresponding elements of the current expression, i.e. {lisp @{sub 1}} and {lisp @{sub 2}} can be at different levels in current expression, or one or both be outside of current expression. }} Thus, using the previous example, {lisp (SWAP CAR CDR)} would result in {lisp (LIST (CONS (CDR X) (CAR Y)) (CONS (CAR X) (CDR Y)))}. }{End SubSec The R Command} {index *END* structure modification commands (in Editor) Term} }{End SubSec Commands That Modify Structure}