{Begin SubSec EDITDEFAULT}
{Title EDITDEFAULT}
{Text


{index *BEGIN* EDITDEFAULT FN}
{index *PRIMARY* EDITDEFAULT FN}

Whenever a command is not recognized, i.e., is not "built in" or defined as a macro, the editor calls an internal function, {fn EDITDEFAULT}, to determine what action to take.{foot 
Since {fn 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 {index EDITUSERFN Var}{var EDITUSERFN}.  If the value of the variable {var EDITUSERFN} is {lisp T}, {fn EDITDEFAULT} calls the function {lisp EDITUSERFN} giving it the command as an argument.  If {lisp EDITUSERFN} returns a non-{lisp NIL} value, its value is interpreted as a single command and executed.  Otherwise, the error correction procedure described below is performed.
}{comment endfootnote}
If a location specification is being executed, an internal flag informs {fn EDITDEFAULT} to treat the command as though it had been preceded by an {lisp F}.


If the command is a list, an attempt is made to perform spelling correction on
{fn CAR} of the command{foot 
unless {index DWIMFLG Var}{var DWIMFLG}={lisp NIL}.
}{comment endfootnote}
using {index spelling lists}{index spelling correction}{index *PRIMARY* EDITCOMSL Var}{var EDITCOMSL}, a list of all list edit commands.{foot 
When a macro is defined via the {editcom M} command, the command name is added to {index EDITCOMSA Var}{index spelling lists}{var EDITCOMSA} or {index EDITCOMSL Var}{var EDITCOMSL}, depending on whether it is an atomic or list command.  The {index USERMACROS FileCom}{filecom USERMACROS} file package command is aware of this, and provides for restoring {var EDITCOMSA} and {var EDITCOMSL}.
}{comment endfootnote}
If spelling correction is successful, the correct command name is {fn RPLACA}ed into the command, and the editor continues by executing the command.
In other words, if the user types {lisp (LP F PRINT (MBBD AND (NULL FLG)))}, only one spelling correction will be necessary to change {lisp MBBD} to {lisp MBD}.  If spelling correction is not successful, an error is generated.


If the command is atomic, the procedure followed is a little more elaborate.


{Begin LabeledList If the command is atomic}

{Indent 10percent}

{Name (1)}
{Text
If the command is one of the list commands, i.e., a member of {var EDITCOMSL}, and there is additional input on the same terminal line, treat the entire line as a single list command.{foot
The line is read using {index READLINE FN}{fn READLINE} ({PageRef Fn READLINE}).  Thus the line can be terminated by a square bracket, or by a carriage return not preceded by a space.
}{comment endfootnote}
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. {editcom NX}, {editcom BK}.  For example,

{lispcode
*P
(COND (& &) (T &))
*XTR 3 2]
*MOVE TO AFTER LP
*}

If the command is on the list {index EDITCOMSL Var}{var EDITCOMSL} but no additional input is on the terminal line, an error is generated, e.g.

{lispcode
*P
(COND (& &) (T &))
*MOVE

MOVE ?
*}

If the command is on {var EDITCOMSL}, and {it not} typed in directly, e.g., it appears as one of the commands in a {editcom LP} command, the procedure is similar, with the rest of the command stream at that level being treated as "the terminal line", e.g. {lisp (LP F (COND (T &)) XTR 2 2)}.{foot 
Note that if the command is being executed in location context,
{fn EDITDEFAULT} does not get this far, e.g., {lisp (MOVE TO AFTER COND XTR 3)} will search for {lisp XTR}, {it not} execute it.  However, {lisp (MOVE TO AFTER COND (XTR 3))} will work.
}{comment endfootnote}
}



{Name (2)}
{Text
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 {index 8 (instead of left parenthesis)}and the rest of the line as the arguments to the command, e.g.,

{lispcode
*P
(COND (& &) (T &))
*8-2 (Y (RETURN Z)))
=(-2
*P
(COND (Y &) (& &) (T &))}
}



{Name (3)}
{Text
If the command was typed in, is the name of a function, and is
followed by {lisp NIL} or a list {fn CAR} of which is not an edit command, assume the user forgot to type {editcom E} and means to apply the function to its arguments, type {lisp =E}{index =E (Printed by Editor)} and the function name, and perform the indicated computation, e.g.

{lispcode
*BREAK(FOO)
=E BREAK
(FOO)
*}

}



{Name (4)}
{Text
If the last character in the command is {lisp P}, and the first {arg N}-1 characters comprise a number, assume that the user intended two commands, e.g.,

{lispcode
*P
(COND (& &) (T &))
*0P
=0 P
(SETQ X (COND & &))}
}




{Name (5)}
{Text
Attempt spelling correction{index spelling correction}{index spelling lists} using {index *PRIMARY* EDITCOMSA Var}{var EDITCOMSA}, and if successful, execute the corrected command.
}




{Name (6)}
{Text
If there is additional input on the same line, or command stream, spelling correct using {index spelling lists}{index spelling correction}{index EDITCOMSL Var}{var EDITCOMSL} as a spelling list, e.g.,

{lispcode
*MBBD SETQ X
=MBD
*}
}




{Name (6)}
{Text
Otherwise, generate an error.
}


{End LabeledList If the command is atomic}


{index *END* EDITDEFAULT FN}


}{End SubSec EDITDEFAULT}





{Begin SubSec Editor Functions}
{Title Editor Functions}
{Text


{FnDef {FnName EDITF}
{FnArgs NAME COM{SUB 1} COM{SUB 2} {ellipsis} COM{SUB N}}
{Type NOSPREAD NLAMBDA}
{Text
Nlambda, nospread function for {lisp EDIT}ing a {lisp F}unction.  {arg NAME} is the name of the function, {arg COM{sub 1}}, {arg COM{sub 2}}, {ellipsis}, {arg COM{sub n}}  are (optional)  edit commands.

The value of {fn EDITF} is {arg NAME}.
}}


The action of {fn EDITF} is somewhat complicated:

{Begin LabeledList The action of EDITF}

{Indent 10percent}

{Name (1)}
{Text
In the most common case, if the definition of {arg NAME} is an {lisp EXPR} (not as a result of its being broken or advised), and {fn EDITF} simply performs {lisp (PUTD {arg NAME} (EDITE (GETD '{arg NAME}) (LIST '{arg COM{SUB 1}} '{arg COM{SUB 2}} {ellipsis} '{arg COM{SUB N}}) '{arg NAME} 'FNS))}. 
}


{Name (2)}
{Text
If {arg NAME} is an {lisp EXPR} by virtue of its being broken or advised, and the original definition is also an {lisp EXPR}, then the broken/advised definition is given to {fn 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 {lisp (-3 --)}, {lisp (N --)}, etc.
}


{Name (3)}
{Text
If {arg NAME} is an {lisp EXPR} by virtue of its being broken or advised, the original definition is not an {lisp EXPR}, there is no {prop EXPR} property, and the file package "knows" which file {arg NAME} is contained in (see {fn EDITLOADFNS?}, {PageRef Fn EDITLOADFNS?}), then the {lisp EXPR} definition of {arg NAME} is loaded onto its property list as described below, and the {fn EDITF} proceeds to the next possibility.  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 {lisp SUBR}.
}


{Name (4)}
{Text
If {arg NAME} is an {lisp EXPR} by virtue of its being broken or advised, the original definition is not an {lisp EXPR}, and there is an {prop 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 {fn EDITF} proceeds to the next possibility.
}


{Name (5)}
{Text
If {arg NAME} is not an {lisp EXPR}, but has an {index EXPR Prop}{prop EXPR} property, {fn EDITF} prints {index PROP (Printed by Editor)}{lisp PROP}, and performs {lisp (EDITE (GETPROP '{arg NAME} 'EXPR) (LIST '{arg COM{SUB 1}} '{arg COM{SUB 2}} {ellipsis} '{arg COM{SUB N}}) '{arg NAME} 'PROP)}.  In this case, if the edit completes and no changes have been made, {fn EDITE} prints {lisp NOT CHANGED, SO NOT UNSAVED}.{index NOT CHANGED, SO NOT UNSAVED (Printed by Editor)}  If changes were made, but the value of {var DFNFLG}{index DFNFLG Var} ({PageRef Var DFNFLG}) is {lisp PROP}, {fn EDITE} prints {lisp CHANGED, BUT NOT UNSAVED}.{index CHANGED, BUT NOT UNSAVED (Printed by Editor)}  Otherwise if changes were made, {fn EDITE} prints {lisp UNSAVED} and does an {fn UNSAVEDEF}.
}


{Name (6)}
{Text
If {arg NAME} is neither an {lisp EXPR} nor has an {prop EXPR} property, and the file package "knows" which file {arg NAME} is contained in (see {fn EDITLOADFNS?}, {PageRef Fn EDITLOADFNS?}), the {lisp EXPR} definition of {arg NAME} is automatically loaded (using {fn LOADFNS}) onto the {prop EXPR} property, and {fn EDITE} proceeds as described above.{foot 
Because of the existence of the file map (see {PageRef Tag FileMaps}), this operation is extremely fast, essentially requiring only the time to perform the {lisp READ} to obtain the actual definition.
}{comment endfootnote}
In addition, if {arg NAME} is a member of a block, the user will be asked whether he wishes the rest of the functions in the block to be loaded at the same time.{foot 
The editor's behaviour in this case is controlled by the value of {var EDITLOADFNSFLG}{index EDITLOADFNSFLG Var}, which is a dotted pair of two flags.  The {fn CAR} of {var EDITLOADFNSFLG} controls the loading of the function, and the {fn CDR} controls the loading of the block.  A value of {lisp NIL} for either flag means "load but ask first," a value of {lisp T} means "don't ask, just do it" and anything else means "don't ask, don't do it." The initial value of {var EDITLOADFNSFLG} is {lisp (T . NIL)}, meaning to load the function without asking, and ask about loading the block.
}{comment endfootnote}
}




{Name (7)}
{Text
If {arg NAME} is neither an {lisp EXPR} nor has an {prop EXPR} property, but it does have a definition, {fn EDITF} generates an {lisp {arg NAME} NOT EDITABLE} error.{index NOT EDITABLE Error}
}



{Name (8)}
{Text
If {arg NAME} is neither defined, nor has an {index EXPR Prop}{prop EXPR} property, but its top level value is a list, {fn EDITF} assumes the user meant to call {fn EDITV}, prints {lisp =EDITV},{index =EDITV (Printed by Editor)} calls {fn EDITV} and returns.  Similarly, if {arg NAME} has a non-{lisp NIL} property list, {fn EDITF} prints {lisp =EDITP},{index =EDITP (Printed by Editor)} calls {fn EDITP} and returns.
}


{Name (9)}
{Text
If {arg NAME} is neither a function, nor has an {index EXPR Prop}{prop EXPR} property, nor a top level value that is a list, nor a non-{lisp NIL}
property list, {index EDITF FN}{fn EDITF} attempts spelling correction using the spelling list {index spelling lists}{index spelling correction}{index USERWORDS Var}{var USERWORDS},{foot 
Unless {index DWIMFLG Var}{var DWIMFLG}={lisp NIL}.  Spelling correction is performed using the function {fn MISSPELLED?} ({PageRef Fn MISSPELLED?}).  If {arg NAME}={lisp NIL}, {fn MISSPELLED?} returns the last "word" referenced, e.g., by {fn DEFINEQ}, {fn EDITF}, {fn PRETTYPRINT} etc.  Thus if the user defines {lisp FOO} and then types {lisp (EDITF)}, the editor will assume he meant {lisp FOO}, type {lisp =FOO}, and then type {lisp EDIT}.
}{comment endfootnote}
and, if successful, goes back to the beginning.
}


{Name (10)}
{Text
Otherwise, {fn EDITF} generates an {lisp {arg NAME} NOT EDITABLE} error.{index NOT EDITABLE Error}
}


{End LabeledList The action of EDITF}


In all cases, if a function is edited, and changes were made, the function is time-stamped (by {fn EDITE}), which consists of inserting a comment of the form {lisp (* {arg USERS-INITIALS} {arg DATE})} (see {PageRef Tag TimeStamps}).  If the function was already time-stamped, then only the date is changed.



{FnDef {FnName EDITFNS}
{FnArgs NAME COM{SUB 1} COM{SUB 2} {ellipsis} COM{SUB N}}
{Type NOSPREAD NLAMBDA}
{Text
An nlambda, nospread function, used to perform the same editing operations on several functions.  {arg NAME} is evaluated to obtain a list of functions.{foot
If {arg NAME} is atomic, and its value is not a list, and it is the name of a file, {lisp (FILEFNSLST '{arg NAME})} will be used as the list of functions to be edited.
}{comment endfootnote}
{arg COM{sub 1}}, {arg COM{sub 2}}, {ellipsis}, {arg COM{sub N}} are (optional) edit commands.  {fn EDITFNS} maps down the list of functions, prints the name of each function, and calls the editor (via {fn EDITF}) on that function.  The value of {fn EDITFNS} is {lisp NIL}.


For example, {lisp (EDITFNS FOOFNS (R FIE FUM))} will change every {lisp FIE} to {lisp FUM} in each of the functions on {lisp FOOFNS}.


The call to the editor is {fn ERRORSET} protected, so that if the editing of one function causes an error, {index EDITFNS FN}{fn EDITFNS} will proceed to the next function.  In particular, if an error occurred while editing a function via its {index EXPR Prop}{prop EXPR} property, the function would not be unsaved.  Thus in the above example, if one of the functions did not contain a {lisp FIE}, the {editcom R} command would cause an error, it would not be unsaved, and editing would continue with the next function.
}}



{FnDef {FnName EDITV} {FnArgs NAME COM{SUB 1} COM{SUB 2} {ellipsis} COM{SUB N}}
{Type NOSPREAD NLAMBDA}
{Text
Similar to {fn EDITF}, for editing values of variables.

The value of {fn EDITV} is the name of the variable whose value was edited.
}}


If {arg NAME} is a list, it is evaluated and its value given to {fn EDITE}, e.g., {lisp (EDITV (CDR (ASSOC 'FOO DICTIONARY)))}.  In this case, the value of {fn EDITV} is {lisp T}.


However, for most applications, {arg NAME} is a variable name, i.e., atomic, as in {lisp EDITV(FOO)}.  If the value of this variable is {index NOBIND Litatom}{lisp NOBIND}, {fn EDITV} checks to see if it is the name of a function, and if so, assumes the user meant to call {index EDITF FN}{fn EDITF}, prints {lisp =EDITF},{index =EDITF (Printed by Editor)} calls {fn EDITF} and returns.  Otherwise, {index EDITV FN}{fn EDITV} attempts spelling correction using the list {index USERWORDS Var}{var USERWORDS}.{foot 
Unless {index DWIMFLG Var}{var DWIMFLG}={lisp NIL}.  {fn MISSPELLED?} is also called if {arg NAME} is {lisp NIL}, so that {lisp (EDITV)} will edit {index LASTWORD Var}{var LASTWORD}.
}{comment endfootnote}
Then {fn EDITV} will call {index EDITE FN}{fn EDITE} on the value of {arg NAME} (or the corrected spelling thereof), and {arg TYPE}={lisp VARS}.
Thus, if the value of {lisp FOO} is {lisp NIL}, and the user performs {lisp (EDITV FOO)}, no spelling correction{index spelling correction} will occur,
since {lisp FOO} is the name of a variable in the user's system, i.e., it has a value.  However, {fn EDITE} will generate an error, since {lisp FOO}'s value is not a list, and hence not editable.  If the user performs {lisp (EDITV FOOO)}, where the value of {lisp FOOO} is {lisp NOBIND}, and {lisp FOO} is on the user's spelling list, the spelling corrector will correct {lisp FOOO} to {lisp FOO}.
Then {fn EDITE} will be called on the value of {lisp FOO}.  Note that this may still result in an error if the value of {lisp FOO} is not a list.




{FnDef {FnName EDITP} {FnArgs NAME COM{SUB 1} COM{SUB 2} {ellipsis} COM{SUB N}}
{Type NOSPREAD NLAMBDA}
{Text
Similar to {fn EDITF} for editing property lists.  If the property list of {arg NAME} is {lisp NIL}, {fn EDITP} attempts spelling correction using {index USERWORDS Var}{var USERWORDS}.  Then {fn EDITP} calls {index EDITE FN}{fn EDITE} on the property list of {arg NAME}, (or the corrected spelling thereof), with {arg TYPE}={lisp PROPLST}.  When (if) {fn EDITE} returns, {fn EDITP} calls {fn SETPROPLIST} on {arg NAME} with the value returned.

The value of {fn EDITP} is the atom whose property list was edited.
}}



{FnDef {FnName EDITE} {FnArgs EXPR COMS ATM TYPE IFCHANGEDFN}
{Text
Edits the expression, {arg EXPR}, by calling {fn EDITL} on {lisp (LIST {arg EXPR})} and returning the last element of the value returned by {fn EDITL}.  Generates an error if {arg EXPR} is not a list.{index NOT EDITABLE Error}

{arg ATM} and {arg TYPE} are for use in conjunction with the file package.  If supplied, {arg ATM} is the {it name} of the object that {arg EXPR} is associated with, and {arg TYPE} describes the association (i.e., {arg TYPE} corresponds to the {arg TYPE} argument of {fn MARKASCHANGED}, {PageRef Fn MARKASCHANGED}.)  For example, if {arg EXPR} is the definition of {lisp FOO}, {arg ATM}={lisp FOO} and {arg TYPE}={lisp FNS}.  When {fn EDITE} is called from {fn EDITP}, {arg EXPR} is the property list of {arg ATM}, and {arg TYPE}={lisp PROPLST}, etc..

{fn EDITE} calls {fn EDITL} to do the editing (described below).  Upon return, if both {arg ATM} and {arg TYPE} are non-{lisp NIL}, {fn ADDSPELL} is called to add {arg ATM} to the appropriate spelling list.  Then, if {arg EXPR} was changed,{foot
For {arg TYPE}={lisp FNS} or {arg TYPE}={lisp PROP}, i.e., calls from {fn EDITF}, {fn EDITE} performs some additional operations as described earlier under {fn EDITF}.
}{comment endfootnote}
and the value of {arg IFCHANGEDFN} is not {lisp NIL}, the value of {arg IFCHANGEDFN} is applied to the arguments {arg ATM}, {arg EXPR}, {arg TYPE}, and a flag which is {lisp T} for normal edits from editor, {lisp NIL} for calls that were aborted via control-D or {lisp STOP}.  Otherwise, if {arg EXPR} was changed, and the value of {arg IFCHANGEDFN} is {lisp NIL}, and {arg TYPE} is not {lisp NIL}, {fn MARKASCHANGED} ({PageRef Fn MARKASCHANGED}) is called on {arg ATM} and {arg TYPE}.  {fn EDITE} uses {fn RESETSAVE} to insure that {arg IFCHANGEDFN} and {fn MARKASCHANGED} are called if any change was made even if editing is subsequently aborted via control-D.  (In this case, the fourth argument to {arg IFCHANGEDFN} will be {lisp NIL}.)
}}



{FnDef {FnName EDITL} {FnArgs L COMS ATM MESS EDITCHANGES}
{Text
{fn EDITL} {it is} the editor.  Its first argument is the edit chain, and its value
is an edit chain, namely the value of {arg L} at the time {fn EDITL} is exited.{foot 
{arg L} is a {lisp SPECVAR}, and so can be examined or set by edit commands.
For example, {editcom ↑} is equivalent to {lisp (E (SETQ L (LAST L)) T)}.
However, the user should only manipulate or examine {arg L} directly as a last resort, and then with caution.
}{comment endfootnote}

{arg COMS} is an optional list of commands.  For interactive editing, coms is {lisp NIL}.  In this case, {fn EDITL} types {index EDIT (Printed by Editor)}{lisp EDIT} (or {arg MESS}, if it not {lisp NIL}) and then waits for input from terminal.  All input is done with {var EDITRDTBL}{index EDITRDTBL Var} as the readtable.  Exit occurs only via an {index OK EditCom}{editcom OK}, {index STOP EditCom}{editcom STOP}, or {index SAVE EditCom}{editcom SAVE} command.

If {arg COMS} is {it not} {lisp NIL}, no message is typed, and each member of {arg 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 {fn EDITL} exits with an error, i.e., the effect is the same as though a {index STOP EditCom}{editcom STOP} command had been executed.  If all commands execute successfully, {fn EDITL} returns the current value of {arg L}.

{arg ATM} is optional.  On calls from {fn EDITF}, it is the name of the function being edited; on calls from {fn EDITV}, the name of the variable, and calls from {fn EDITP}, the atom whose property list is being edited.  The property list of {arg ATM} is used by the {index SAVE EditCom}{editcom SAVE} command for saving the state of the edit.  Thus {editcom SAVE} will not save anything if {arg ATM}={lisp NIL}, i.e., when editing arbitrary expressions via {fn EDITE} or {fn EDITL} directly.  

{arg EDITCHANGES} is used for communicating with {fn EDITE}.
}}



{FnDef {FnName EDITL0} {FnArgs L COMS MESS {anonarg}}
{Text
Like {fn EDITL}, except it does not rebind or initialize the editor's various state variables, such as {index LASTAIL Var}{var LASTAIL}, {index UNFIND Var}{var UNFIND}, {index UNDOLST Var}{var UNDOLST}, {index MARKLST Var}{var MARKLST}, etc.  Should only be called when already under a call to {fn EDITL}.
}}



{FnDef {FnName EDIT4E} {FnArgs PAT X {anonarg}}
{Text
The editor's pattern match routine.{index pattern match (in Editor)}  Returns {lisp T}, if {arg PAT} matches {arg X}.  See {PageRef Tag EditPattern} for definition of "match".
}}


Note:  Before each search operation in the editor begins, the entire pattern is scanned for atoms or strings containing {lisp $}s (<esc>s).  Atoms or strings containing {lisp $}s are replaced by lists of the form {lisp ($ {ellipsis})}, and atoms or strings ending in double {lisp $}s are replaced by lists of the form {lisp ($$ {ellipsis})}.  Thus from the standpoint of {fn EDIT4E}, single and double {lisp $} patterns are detected by {lisp (CAR {arg PAT})} being the atom {lisp $} (<esc>) or the atom {lisp $$} (<esc><esc>).  Therefore, if the user wishes to call {fn EDIT4E} directly, he must first convert any patterns which contain atoms or strings containing {lisp $}s to the form recognized by {fn EDIT4E}.  This is done with the function {fn EDITFPAT}:



{note info about form of ($ ...) and ($$ ...) lists taken out, because it was a crock, it wasn't entirely true, and it didn't seem that people needed to know this anyway.  Currently, atoms with single $s get translated into ($ . <UNPACK of atom/string>), and atoms or strings ending with $$s get translated into ($$ <#chars (not including $$)> <#doubleletters??> . <CHCON of atom/string (not including $$)>)}



{FnDef {FnName EDITFPAT} {FnArgs PAT {anonarg}}
{Text
Makes a copy of {arg PAT} with all atoms or strings containing {lisp $}s (<esc>s) converted to the form expected by {fn EDIT4E}.
}}



{FnDef {FnName EDITFINDP} {FnArgs X PAT FLG}
{Text
Allows a program to use the edit find command as a pure predicate from outside the editor.{index pattern match (in Editor)}  {arg X} is an expression, {arg PAT} a pattern.  The value of {fn EDITFINDP} is {lisp T} if the command {lisp F {arg PAT}} {it would} succeed, {lisp NIL} otherwise.  {fn EDITFINDP} calls {fn EDITFPAT} to convert {arg PAT} to the form expected by {fn EDIT4E}, unless {arg FLG}={lisp T}.  Thus, if the program is applying {fn EDITFINDP} to several different expressions using the same pattern, it will be more efficient to call {fn EDITFPAT} once, and then call {fn EDITFINDP} with the converted pattern and {arg FLG}={lisp T}.
}}



{FnDef {FnName ESUBST} {FnArgs NEW OLD EXPR ERRORFLG CHARFLG}
{Text
Equivalent to performing {lisp (R {arg OLD} {arg NEW})} with {arg EXPR} as the current expression, i.e., the order of arguments is the same as for {fn SUBST}.  Note that {arg OLD} and/or {arg NEW} can employ {lisp $}s (<esc>s).  The value of {fn ESUBST} is the modified {arg EXPR}.  Generates an error if {arg OLD} not found in {arg EXPR}.  If {arg ERRORFLG}={lisp T}, also prints an error message of the form {lisp {arg OLD} ?}.

If {arg CHARFLG}={lisp T} and no {lisp $}s (<esc>s) are specified in {arg NEW} or {arg OLD}, it is equivalent to {lisp (RC {arg OLD} {arg NEW})}.  In other words, if {arg CHARFLG}={lisp T}, and no {lisp $}s appear, {fn ESUBST} will supply them.

{fn ESUBST} is always undoable.
}}



{FnDef {FnName EDITLOADFNS?} {FnArgs FN STR ASKFLG FILES}
{Text
{arg FN} is the name of a function.  {fn EDITLOADFNS?} returns the name of file {arg FN} is contained in, or {lisp NIL}.

{fn EDITLOADFNS?} performs {lisp (WHEREIS {arg FN} FNS {arg FILES})} to obtain the name of the file(s) containing {arg FN}, if any (see {PageRef Fn WHEREIS}).  If there is more than one file, {fn EDITLOADFNS?} asks the user to indicate which file.  It then checks the {prop FILEDATES} property for each file to see if the version that was originally loaded still exists.{foot
In the case that {arg FILES}={lisp T} and the WHEREIS package has been loaded ({PageRef Tag WHEREISpackage}), files(s) may be found that have not been loaded or otherwise noticed, and thus will not have {prop FILEDATES} property.
In this case, {fn EDITLOADFNS?} does not do any version checks, but simply uses the latest version.
}{comment endfootnote}
If the file that was {it originally} loaded no longer exists, but there is a different version of the file on that directory, {fn EDITLOADFNS?} prints "{lisp ****can't find {arg FILENAME}}",{index ****can't find (printed by EDITLOADFNS?)} and then uses the version that it could find.  Similarly, if the original version {it is} found, but a newer version is also found, {fn EDITLOADFNS?} prints {lisp "****Note:  {arg FILENAME} is not the newest version"} and then uses the newest version.{index ****Note:  FN is not the newest version (printed by EDITLOADFNS?)}

Having decided which file the function is on, if {arg ASKFLG}={lisp NIL}, {fn EDITLOADFNS?} prints the value of {arg STR} followed by the name of the file, and returns the name of the file.  If {arg ASKFLG}={lisp T}, {fn EDITLOADFNS?} calls {fn ASKUSER} giving {lisp (LIST {arg FN} {arg STR} {arg FILENAME})} as {arg MESS}, the message to be printed.  If {fn ASKUSER} returns {lisp Y}, {fn EDITLOADFNS?} returns the filename.  If {arg STR}={lisp NIL}, {lisp "loading from"} is used.
}}


{fn EDITLOADFNS?} is used by the editor, {fn LOADFNS} (when the file name is not supplied), by {fn PRETTYPRINT}, and by {fn DWIM}.


{FnDef {FnName CHANGENAME} {FnArgs FN FROM TO}
{Text
Replaces all occurrences of {arg FROM} by {arg TO} in the definition of {arg FN}.  If {arg FN} is an {lisp EXPR}, {fn CHANGENAME} performs {lisp (NLSETQ (ESUBST {arg TO} {arg FROM} (GETD {arg FN})))}.  If {arg FN} is {it compiled,} {index editing compiled code} {fn CHANGENAME} searches the literals of {arg FN} (and all of its compiler generated subfunctions), replacing each occurrence of {arg FROM} with {arg TO}.  This will succeed even if {arg FROM} is called from {arg FN} via a linked call.  In this case, the call will also be relinked to call {arg TO} instead.

The value of {fn CHANGENAME} is {arg FN} if at least one instance of {arg FROM} was found, otherwise {lisp NIL}.
}}


{fn CHANGENAME} is used by {fn BREAK} and {fn ADVISE} for changing calls to {arg FN{sub 1}} to calls to {lisp {arg FN{sub 1}}-IN-{arg FN{sub 2}}}.




The function {fn EDITCALLERS} provides a way of rapidly searching a file or entire set of files, even files not loaded into Interlisp or "noticed" by the file package, for the appearance of one or more key words (atoms) anywhere in the file.

{note {fn EDITCALLERS} was written by L. M. Masinter.}


{FnDef {FnName EDITCALLERS} {FnArgs ATOMS FILES COMS}
{Text
Uses {fn FFILEPOS} to search the file(s) {arg FILES} for occurrences of the atom(s) {arg ATOMS}.  It then calls {fn EDITE} on each of those objects,{foot {fn EDITCALLERS} uses {fn GETDEF} ({PageRef Fn GETDEF}) to obtain the "definition" for each object. When {fn EDITE} returns, if a change was made, {fn PUTDEF} is called to store the changed object.
}{comment endfootnote}
performing the edit commands {arg COMS}.  If {arg COMS}={lisp NIL}, then {lisp (EXAM . {arg ATOMS})} is used.  Both {arg ATOMS} and {arg FILES} may be single atoms.  If {arg FILES} is {lisp NIL}, {var FILELST} is used.  Elements on {arg ATOMS} may contain $s (<esc>s).

{fn EDITCALLERS} prints the name of each file as it searches it, and when it finds an occurrence of one of {arg ATOMS}, it prints out either the name of the containing function or, if the atom occurred outside a function definition, it prints out the byte position at which the atom was found.

{fn EDITCALLERS} will read in and use the filemap of the file. In the case that the editor is actually called, {fn EDITCALLERS} will {fn LOADFROM} the file if the file has not previously been noticed.
}}



{FnDef {FnName FINDCALLERS} {FnArgs ATOMS FILES}
{Text
Like {fn EDITCALLERS}, except does not call the editor, but instead simply returns the list of files that contain one of {arg ATOMS}.
}}






{FnDef {FnName EDITRACEFN} {FnArgs COM}
{Text
Is available to help the user debug complex edit macros, or subroutine calls to the editor.  If {var EDITRACEFN} is set to {lisp T}, the function {fn 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 {lisp TRACE} and {lisp BREAK} options described below are probably sufficient for most applications.

If {var EDITRACEFN} is set to {lisp TRACE}, the name of the command and the current expression are printed.  If {var EDITRACEFN}={lisp BREAK}, the same information is printed, and the editor goes into a break.  The user can then examine the state of the editor.

{var EDITRACEFN} is initially {lisp NIL}.
}}




{FnDef {FnName SETTERMCHARS} {FnArgs NEXTCHAR BKCHAR LASTCHAR UNQUOTECHAR 2CHAR PPCHAR}
{Text
Used to set up the immediate read macros used by the editor, as well as the control-Y{index control-Y} read macro ({PageRef Tag control-YReadMacro}).  {arg NEXTCHAR}, {arg BKCHAR}, {arg LASTCHAR}, {arg 2CHAR} and {arg PPCHAR} specify which control character should perform the edit commands {lisp NXP}, {lisp BKP}, {lisp -1P}, {lisp 2P} and {lisp PP*}, respectively; {arg UNQUOTECHAR} corresponds to control-Y.  For each non-{lisp NIL} argument, {fn SETTERMCHARS} makes the corresponding control character have the indicated function.  The arguments to {fn SETTERMCHARS} can be character codes, the control characters themselves, or the alphabetic letters corresponding to the control characters.  
}}

If an argument to {fn SETTERMCHARS} is currently assigned as an interrupt character, it cannot be a read macro (since the reader will never see it); {fn SETTERMCHARS} prints a message to that effect and makes no change to the control character.  However, if {fn SETTERMCHARS} is given a list as one of its arguments, it uses {fn CAR} of the list even if the character is an interrupt.  In this case, if {fn CADR} of the list is non-{lisp NIL}, {fn SETTERMCHARS} reassigns the interrupt function to {fn CADR}.  For example, if control-X is an interrupt, {lisp (SETTERMCHARS '(X W))} assigns control-W the interrupt control-X had, and makes control-X be the {arg NEXTCHAR} operator.


As part of the greeting operation, {fn SETTERMCHARS} is applied to the value of {index EDITCHARACTERS Var}{var EDITCHARACTERS}, which is initially {lisp (J X Z Y N)} in Interlisp-D and in Interlisp-10 under Tenex, {lisp (J A L Y K)} under Tops-20 (control-J is line-feed).
{fn SETTERMCHARS} is called {it after} the user's init file is loaded, so it works to reset {var EDITCHARACTERS} in the init file; alternatively, {fn SETTERMCHARS} can be called explicitly.



}{End SubSec Editor Functions}






{Begin SubSec Time Stamps}
{Title Time Stamps}
{Text

{index *PRIMARY* time stamps}

{Tag TimeStamps}

Whenever a function is edited, and changes were made, the function is time-stamped (by {fn EDITE}), which consists of inserting a comment of the form {lisp (* {arg USERS-INITIALS} {arg DATE})}.  {arg USERS-INITIALS} is the value of the variable {index INITIALS Var}{var INITIALS}.  After greeting, or following a {fn SYSIN}, the function {fn SETINITIALS}{index SETINITIALS Var} is called.  {fn SETINITIALS} searches {var INITIALSLST}{index *PRIMARY* INITIALSLST Var}, a list of elements of the form {lisp ({arg USERNAME} . {arg INITIALS})} or {lisp ({arg USERNAME} {arg FIRSTNAME} {arg INITIALS})}.  If the user's name is found, {var INITIALS} is set accordingly.  If the user's name is {it not} found on {var INITIALSLST}, {var INITIALS} is set to the value of {var DEFAULTINITIALS}{index DEFAULTINITIALS Var}, initially {lisp edited:}.  Thus, the default is to always time stamp.  To suppress time stamping, the user must either include an entry of the form {lisp ({arg USERNAME})} on {var INITIALSLST}, or set {var DEFAULTINITIALS} to {lisp NIL} before greeting, i.e. in his user profile, or else, {it after} greeting, explicitly set {var INITIALS} to {lisp NIL}.



If the user wishes his functions to be time stamped with his initials when edited, he should include a file package command command of the form {lisp (ADDVARS (INITIALSLST ({arg USERNAME} . {arg INITIALS})))} in the user's {lisp INIT.LISP} file (see {PageRef Fn GREET}).


The following three functions may be of use for specialized applications with respect to time-stamping: {index *PRIMARY* FIXEDITDATE FN}{lisp (FIXEDITDATE {arg EXPR})} which, given a lambda expression, inserts or smashes a time-stamp comment; {index *PRIMARY* EDITDATE? FN}{lisp (EDITDATE? {arg COMMENT})} which returns {lisp T} if {arg COMMENT} is a time stamp; and {index *PRIMARY* EDITDATE FN}{lisp (EDITDATE {arg OLDATE} {arg INITLS})} which returns a new time-stamp comment.
If {arg OLDATE} is a time-stamp comment, it will be reused.



}{End SubSec Time Stamps}