{Begin SubSec EDITDEFAULT}
{Title EDITDEFAULT}
{Text


{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.  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.


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 the {fn CAR} of the command (unless {index DWIMFLG Var}{var DWIMFLG}={lisp NIL}) using {index spelling lists}{index spelling correction}{index *PRIMARY* EDITCOMSL Var}{var EDITCOMSL}, a list of all list edit commands.  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.

Note:  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}.

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


{Begin LabeledList If the command is atomic}

{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.  The line is read using {index READLINE FN}{fn READLINE} ({PageRef Fn READLINE}), so the line can be terminated by a square bracket, or by a carriage return not preceded by a space.  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)}.

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.
}



{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}



}{End SubSec EDITDEFAULT}





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

{FnDef {FnName EDIT} {FnArgs NAME {anonarg}}
{Text
General purpose function for calling the editor.  Figures out what type of definition {arg NAME} has (function, variable, macro, etc.), and calls the editor to edit it.  If {arg NAME} has more than one definition of different types, the user is prompted for which type of definition to edit.
}}


{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.  {fn EDITF} returns {arg NAME}.

If {arg NAME} is {lisp NIL}, it defaults to the value of {var LASTWORD} ({PageRef Var LASTWORD}), the last function or variable referred to by the user.

Note:  {fn EDITF} initially calls {fn HASDEF} ({PageRef Fn HASDEF}), which does spelling correction on {arg NAME} using the spelling list {index USERWORDS Var}{var USERWORDS} (unless {index DWIMFLG Var}{var DWIMFLG}={lisp NIL}).
}}


The action of {fn EDITF} is somewhat complicated, because the function may be broken or advised, the expr definition of the function may be saved on the property list of {arg NAME}, the function may need to be loaded from a file, etc.  There are many special cases that have to be handled differently.  When {fn EDITF} is called, it tries the following, in order:

{Begin LabeledList The action of EDITF}

{Name (1)}
{Text
In the most common case, if the definition of {arg NAME} is an expr definition (not as a result of its being broken or advised), {fn EDITE} ({PageRef Fn EDITE}) is called to edit the function definition. 
}


{Name (2)}
{Text
If {arg NAME} has an expr definition by virtue of its being broken or advised, and the original definition is also an expr definition, 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 (e.g. "{lisp Note: you are editing a BROKEN definition}") is printed to alert the user that the function definition is surrounded by a call to {fn BREAK1} or {fn ADV-PROG}.
}


{Name (3)}
{Text
If {arg NAME} has an expr definition by virtue of its being broken or advised, the original definition is not an expr definition, 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 expr definition of {arg NAME} is loaded onto its property list as described below, and the editor proceeds to the next possibility.  Otherwise, a warning message is printed (e.g. "{lisp Note: you are editing a BROKEN compiled definition}"), and the edit proceeds, e.g., the user may have called the editor to examine the advice on a compiled function.
}


{Name (4)}
{Text
If {arg NAME} has an expr definition 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 the editor proceeds to the next possibility.
}


{Name (5)}
{Text
If {arg NAME} does not have an expr definition, but has an {index EXPR Prop}{prop EXPR} property, {fn EDITF} prints {index prop (Printed by Editor)}{lisp prop}, and calls {fn EDITE} ({PageRef Fn EDITE} to edit this saved expr definition.  In this case, if the edit completes and no changes have been made, {fn EDITE} prints {index not changed, so not unsaved (Printed by Editor)}"{lisp not changed, so not unsaved}."  If changes were made, but the value of {var DFNFLG}{index DFNFLG Var} ({PageRef Var DFNFLG}) is {lisp PROP}, {fn EDITE} prints {index changed, but not unsaved (Printed by Editor)}"{lisp changed, but not unsaved}."  Otherwise if changes were made, {fn EDITE} prints {index unsaved (Printed by Editor)}{lisp unsaved} and does an {fn UNSAVEDEF} ({PageRef Fn UNSAVEDEF}).
}


{Name (6)}
{Text
If {arg NAME} neither has an expr definition nor an {prop EXPR} property, and the file package "knows" which file {arg NAME} is contained in (see {fn EDITLOADFNS?}, {PageRef Fn EDITLOADFNS?}), the expr definition of {arg NAME} is automatically loaded (using {fn LOADFNS}, {PageRef Fn LOADFNS}) onto the {prop EXPR} property, and {fn EDITE} proceeds as described above.  Because of the existence of file maps ({PageRef Tag FileMaps}), this operation is extremely fast, essentially requiring only the time to perform the {lisp READ} to obtain the actual definition.  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.

The editor's behaviour in this case is controlled by the value of {var EDITLOADFNSFLG}{index *PRIMARY* 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.
}


{Name (7)}
{Text
If {arg NAME} has neither an expr definition nor an {prop EXPR} property, but it does have a macro definition, that definition is edited.
}

{Name (8)}
{Text
If {arg NAME} has neither an expr definition nor an {prop EXPR} property nor a macro definition, the user is prompted with "{lisp No FNS defn for {arg NAME}.  Do you wish to edit a dummy defn?}".  If the user confirms by typing {lisp Yes}, a "blank" definition (stored on the variable {index *PRIMARY* DUMMY-EDIT-FUNCTION-BODY Var}{var DUMMY-EDIT-FUNCTION-BODY}) is edited.  If any changes are made, on exit from the editor, the definition will be installed as the name's function definition.  Exiting the editor with the {lisp STOP} command will prevent any changes to the function definition.
}


{Name (9)}
{Text
Otherwise, the editor generates an {index not editable Error}{lisp {arg NAME} 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.  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.

{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 ({PageRef Fn ERRORSET}), 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.  {arg NAME} is the name of the variable, {arg COM{sub 1}}, {arg COM{sub 2}}, {ellipsis}, {arg COM{sub n}} are (optional)  edit commands.

If {arg NAME} is {lisp NIL}, it defaults to the value of {var LASTWORD} ({PageRef Var LASTWORD}), the last function or variable referred to by the user.

If {arg NAME} is bound as a variable on the stack, {fn EDITV} edits its value, otherwise if {arg NAME} has a top-level variable binding, {fn EDITV} edits the top-level value.  {fn EDITV} returns {arg NAME} if it is bound or has a top-level value, {lisp NIL} otherwise.

{fn EDITV} calls {fn EDITE} ({PageRef Fn EDITE}) to edit the value of the variable.  Note that if the value of the variable is not a list, this causes an error: "{lisp {arg EXPR} not editable}."

Note:  {fn EDITV} initially calls {fn HASDEF} ({PageRef Fn HASDEF}), which does spelling correction on {arg NAME} using the spelling list {index USERWORDS Var}{var USERWORDS} (unless {index DWIMFLG Var}{var DWIMFLG}={lisp NIL}).
}}


{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} (unless {index DWIMFLG Var}{var DWIMFLG}={lisp NIL}).  Then {fn EDITP} calls {fn EDITE} on the property list of {arg NAME}, (or the corrected spelling thereof), with {arg TYPE}={lisp PROPLST}.

{fn EDITP} returns 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}"{lisp {arg EXPR} not editable}."

{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, 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}.)

Note:  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}.
}}



{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.  {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.

{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 read table.  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 matching in the 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 matching in the 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} if no file is found.

{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 {fn WHEREIS} returns more than one file, {fn EDITLOADFNS?} asks the user to indicate which file to use.

If the file has been {fn LOAD}ed or {fn LOADFROM}ed, the file name saved on the {lisp FILEDATES} property ({PageRef Prop FILEDATES}) of the file is checked by calling {fn INFILEP}.  If not found, {fn FINDFILE} is called to find the file.  If a file is found, the file date (see {fn FILEDATE}, {PageRef Fn FILEDATE}) is compared to the file date saved on the {lisp FILEDATES} property of the file, to determine whether this file is the one that was {it originally} loaded.  If not, {fn EDITLOADFNS?} prints {index *** note:  FILENAME dated DATE isn't current version; FILENAME dated DATE is. (printed by EDITLOADFNS?)}"{lisp *** note:  {arg FILENAME} dated {arg DATE} isn't current version; {arg FILENAME} dated {arg DATE} is.}" and then uses the file found.

In the case that {arg FILES}={lisp T} and the WHEREIS library package has been loaded, 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.

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 NIL} and {arg STR}={lisp NIL}, {fn EDITLOADFNS?} prints "{lisp loading definition of {arg FN} from {arg FILENAME}}."

If {arg ASKFLG}={lisp T}, {fn EDITLOADFNS?} calls {fn ASKUSER} ({PageRef Fn ASKUSER}) giving {lisp (LIST {arg FN} {arg STR} {arg FILENAME})} as the message to be printed.  If {fn ASKUSER} returns {lisp Y}, {fn EDITLOADFNS?} returns the filename.
}}


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



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, 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.

{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.
}}



{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}.
}}






{VarDef {Name EDITRACEFN}
{Text
This variable 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 {lisp EDITRACEFN} (initially undefined) 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 *PRIMARY* 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 ({PageRef Term Greeting}), 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}