{Begin SubSec ASKUSER}
{Title ASKUSER}
{Text

{index *PRIMARY* ASKUSER FN}

DWIM, the compiler, the editor, and many other system packages all use {fn ASKUSER}, an extremely general user interaction package, for their interactions with the user at the terminal.  {fn ASKUSER} takes as its principal argument {arg KEYLST} which is used to drive the interaction.  {arg KEYLST} specifies what the user can type at any given point, how {fn ASKUSER} should respond to the various inputs, what value should be returned by {fn ASKUSER}, and is also used to present the user at any given point with a list of the possible responses.  {fn ASKUSER} also takes other arguments which permit specifying a wait time, a default value, a message to be printed on entry, a flag indicating whether or not typeahead is to be permitted,  a flag indicating whether the transaction is to be stored on the history list ({PageRef Term Programmer's Assistant}), a default set of options, and an (optional) input file/string.


{FnDef {FnName ASKUSER} {FnArgs WAIT DEFAULT MESS KEYLST TYPEAHEAD LISPXPRNTFLG OPTIONSLST FILE}
{Text
{arg WAIT} is either {lisp NIL} or a number (of seconds).  {arg DEFAULT} is a single character or a sequence (list) of characters to be used as the default inputs for the case when {arg WAIT} is not {lisp NIL} and more than {arg WAIT} seconds elapse without any input.  In this case, the character(s) from {arg DEFAULT} are processed exactly as though they had been typed, except that {fn ASKUSER} first types "{lisp ...}".

{arg MESS} is the initial message to be printed by {fn ASKUSER}, if any, and can be a string, or a list.  In the latter case, each element of the list is printed, separated by spaces, and terminated with a " {lisp ? }".  {arg KEYLST} and {arg OPTIONSLST} are described.  {arg TYPEAHEAD} is {lisp T} if the user is permitted to typeahead a response to {fn ASKUSER}.  {lisp NIL} means any typeahead should be cleared and saved.  {arg LISPXPRNTFLG} determines whether or not the interaction is to be recorded on the history list.  {arg FILE} can be either {lisp NIL} (in which case it defaults to the terminal input stream, {lisp T}), a stream, or a string.  If {arg FILE} is a string, and all of its characters are read before {fn ASKUSER} finishes, {arg FILE} will be reset to {lisp T}, and the interaction will continue with {fn ASKUSER} reading from the terminal.


All input operations take place from {arg FILE} until an unacceptable input is encountered, i.e., one that does not conform to the protocol defined by {arg KEYLST}.  At that point, {arg FILE} is set to {lisp T}, {arg DEFAULT} is set to {lisp NIL}, the input buffer is cleared, and a bell is rung.  Unacceptable inputs are not echoed.

The value of {fn ASKUSER} is the result of packing all the keys that were matched, unless the {lisp RETURN} option is specified ({PageRef (Askuser Option) RETURN}).
}}



{FnDef {FnName MAKEKEYLST} {FnArgs LST DEFAULTKEY LCASEFLG AUTOCOMPLETEFLG}
{Text
{arg LST} is a list of atoms or strings.  {fn MAKEKEYLST} returns an {fn ASKUSER} {arg KEYLST} which will permit the user to specify one of the elements on {arg LST} by either typing enough characters to make the choice unambiguous, or else typing a number between 1 and {arg N}, where {arg N} is the length of {arg LST}.


For example, if {fn ASKUSER} is called with {arg KEYLST} = {lisp (MAKEKEYLST '(CONNECT SUPPORT COMPILE))}, then the user can type
{lisp C}-{lisp O}-{lisp N}, {lisp S}, {lisp C}-{lisp O}-{lisp M}, {lisp 1}, {lisp 2}, or {lisp 3} to indicate one of the three choices.


If {arg LCASEFLG}={lisp T}, then echoing of upper case elements will be in lower case (but the value returned will still be one of the elements of {arg LST}). If {arg DEFAULTKEY} is non-{lisp NIL}, it will be the last key on the {arg KEYLST}.  Otherwise, a key which permits the user to indicate "No - none of the above" choices, in which case the value returned by {fn ASKUSER} will be {lisp NIL}.

{arg AUTOCOMPLETEFLG} is used as the value of the {lisp AUTOCOMPLETEFLG} option of the resulting key list.
}}


{Begin SubSec Format of KEYLST}
{Title Format of KEYLST}
{Text

{index KEYLST (ASKUSER argument)}

{arg KEYLST} is a list of elements of the form {lisp ({arg KEY} {arg PROMPTSTRING} . {arg OPTIONS})}, where {arg KEY} is an atom or a string (equivalent), {arg PROMPTSTRING} is an atom or a string, and {arg OPTIONS} a list of options in property list format.  The options are explained below.  If an option is specified in {arg OPTIONS}, the value of the option is the next element.  Otherwise, if the option is specified in the {arg OPTIONSLST} argument to {fn ASKUSER}, its value is the next element on {arg OPTIONSLST}.  Thus, {arg OPTIONSLST} can be used to provide default options for an entire {arg KEYLST}, rather than having to include the option at each level. If an option does not appear on either {arg OPTIONS} or {arg OPTIONSLST}, its value is {lisp NIL}.


For convenience, an entry on {arg KEYLST} of the form
{lisp ({arg KEY} . {arg ATOM/STRING})}, can be used as an abbreviation for {lisp ({arg KEY} {arg ATOM/STRING} CONFIRMFLG T)}, and an entry of just the form {arg KEY}, i.e., a non-list, as an abbreviation for {lisp ({arg KEY} NIL CONFIRMFLG T)}.


As each character is read, it is matched against the currently active keys.  A character matches a key if it is the same character as that in the corresponding position in the key, or, if the character is an alphabetic character, if the characters are the same without regard for upper/lower case differences, i.e. "{lisp A}" matches "{lisp a}" and vice versa (unless the {lisp NOCASEFLG} option is {lisp T}, see {PageRef (Askuser Option) NOCASEFLG}).  In other words, if two characters have already been input and matched, the third character is matched with each active key by comparing it with the third character of that key.  If the character matches with one or more of the keys, the entries on {arg KEYLST} corresponding to the remaining keys are discarded.  If the character does not match with any of the keys, the character is not echoed, and a bell is rung instead.


When a key is complete, {arg PROMPTSTRING} is printed ({lisp NIL} is equivalent to "", the empty string, i.e., nothing will be printed).  Then, if the value of the {lisp CONFIRMFLG} option is {lisp T}, {fn ASKUSER} waits
for confirmation of the key by a carriage return or space.  Otherwise, the key does not require confirmation.


Then, if the value of the {lisp KEYLST} option is not {lisp NIL}, its value becomes the new {arg KEYLST}, and the process recurses.  Otherwise, the key is
a "leaf," i.e., it terminates a particular path through the original, top-level {arg KEYLST}, and {fn ASKUSER} returns the result of packing all the keys that have been matched and completed along the way (unless the {lisp RETURN} option is used to specify some other value, as described below).


For example, when {fn ASKUSER} is called with {arg KEYLST}={lisp NIL}, the following {arg KEYLST} is used as the default:

{lispcode ((Y "es{CRsymbol}") (N "o{CRsymbol}"))}


This {arg KEYLST} specifies that if (as soon as) the user types {lisp Y} (or {lisp y}), {fn ASKUSER} echoes with {lisp Y}, prompts with "{lisp es{CRsymbol}}", and returns {lisp Y} as its value.  Similarly, if the user types {lisp N}, {fn ASKUSER} echoes the {lisp N}, prompts with "{lisp o{CRsymbol}}", and returns {lisp N}.  If the user types {lisp ?}, {fn ASKUSER} prints:

{lispcode
Yes
No}


to indicate his possible responses.  All other inputs are unacceptable, and {fn ASKUSER} will ring the bell and not echo or print anything.


For a more complicated example, the following is the {arg KEYLST} used for the compiler questions ({PageRef Tag CompilerQuestions}):


{lispcode
((ST "ore and redefine " KEYLST ("" (F . "orget exprs"))
 (S . "ame as last time")
 (F . "File only")
 (T . "o terminal")
 1
 2
 (Y . "es")
 (N . "o"))}


When {fn ASKUSER} is called with this {arg KEYLST}, and the user types an {lisp S}, two keys are matched: {lisp ST} and {lisp S}.  The user can then type a {lisp T}, which matches only the {lisp ST} key, or confirm the {lisp S} key by typing a {CRsymbol} or space.  If the user confirms the {lisp S} key, {fn ASKUSER} prompts with "{lisp ame as last time}", and returns {lisp S} as its value.  (Note that the confirming character is not included in the value.)  If the user types a {lisp T}, {fn ASKUSER} prompts with "{lisp ore and redefine}", and makes {lisp ("" (F . "orget exprs"))} be the new {arg KEYLST}, and waits for more input.  The user can then type an {lisp F}, or confirm the "" (which essentially starts out with all of its characters matched).  If he confirms the "", {fn ASKUSER} returns {lisp ST} as its
value the result of packing {lisp ST} and "".  If he types {lisp F}, {fn ASKUSER} prompts with "{lisp orget exprs}", and waits for confirmation again. If the user then confirms, {fn ASKUSER} returns {lisp STF}, the result of packing {lisp ST} and {lisp F}.


At any point the user can type a {lisp ?} and be prompted with the possible responses.  For example, if the user types {lisp S} and then {lisp ?}, {fn ASKUSER} will type:

{lispcode
STore and redefine Forget exprs
STore and redefine
Same as last time}


}{End SubSec Format of KEYLST}



{Begin SubSec Options}
{Title Options}
{Text


{Begin LabeledList Options}

{Label {lisp KEYLST}{index KEYLST (ASKUSER option)}}
{Item
When a key is complete, if the value of the {lisp KEYLST} option is not {lisp NIL}, this value becomes the new {arg KEYLST} and the process recurses. Otherwise, the key terminates a path through the original, top-level {arg KEYLST}, and {fn ASKUSER} returns the indicated value.
}

{Label {lisp CONFIRMFLG}{index CONFIRMFLG (ASKUSER option)}}
{Item
If {lisp T}, the key must be confirmed with either a carriage return or a space.  If the value of {lisp CONFIRMFLG} is a {it list}, the confirming character may be any member of the list.
}

{Label {lisp PROMPTCONFIRMFLG}{index PROMPTCONFIRMFLG (ASKUSER option)}}
{Item
If {lisp T}, whenever confirmation is required, the user is prompted with the string " {lisp [confirm] }".
}

{Label {lisp NOCASEFLG}{index NOCASEFLG (ASKUSER option)}}
{Item
If {lisp T}, says do {it not} perform case independent matching on alphabetic characters.  If {lisp NIL}, do perform case independent matching, i.e. "{lisp A}" matches with "{lisp a}" and vice versa.
}

{Label {lisp RETURN}{index RETURN (ASKUSER option)}}
{Item
If non-{lisp NIL}, {fn EVAL} of the value of the {lisp RETURN} option is returned as the value of {fn ASKUSER}.  Note that different {lisp RETURN} options can be specified for different keys.  The variable {var ANSWER}{index ANSWER Var} is bound in {fn ASKUSER} to the list of keys that have been matched.  In other words, {lisp RETURN (PACK ANSWER)} would be equivalent to what {fn ASKUSER} normally does.
}

{Label {lisp NOECHOFLG}{index NOECHOFLG (ASKUSER option)}}
{Item
If non-{lisp NIL}, characters that are matched (or automatically supplied as a result of typing {lisp $} (escape) or confirming) are not echoed, nor is the confirming character, if any.  The value of {lisp NOECHOFLG} is automatically {lisp NIL} when {fn ASKUSER} is reading from a file or string.  The decision about whether or not to echo a character that matches several keys is determined by the value of the {lisp NOECHOFLG} option for the first key.
}

{Label {lisp EXPLAINSTRING}{index EXPLAINSTRING (ASKUSER option)}}
{Item
If the value of the {lisp EXPLAINSTRING} option is non-{lisp NIL}, its value is printed when the user types a {lisp ?}, rather than {arg KEY} + {arg PROMPTSTRING}.  {lisp EXPLAINSTRING} enables  more elaborate explanations in response to a {lisp ?} than what the user sees when he is prompted as a result of simply completing keys.

For example:  One of the entries on the {arg KEYLST} used by {fn ADDTOFILES?} ({PageRef Fn ADDTOFILES?}) is:

{lispcode
(] "Nowhere{CRsymbol}" NOECHOFLG T
   EXPLAINSTRING "] - nowhere, item is marked as a dummy{CRsymbol}")}

When the user types {lisp ]}, {fn ASKUSER} just prints "{lisp Nowhere}{CRsymbol}", i.e., the {lisp ]} is not echoed.  If the user types {lisp ?}, the explanation corresponding to this entry will be:

{lispcode ] - nowhere, item is marked as a dummy}
}

{Label {lisp KEYSTRING}{index KEYSTRING (ASKUSER option)}}
{Item
If non-{lisp NIL}, characters that are matched are echoed as though the value of {lisp KEYSTRING} were used in place of the key.
{lisp KEYSTRING} is also used for computing the value returned.
The main reason for this feature is to enable echoing in lowercase.
}

{Label {lisp PROMPTON}{index PROMPTON (ASKUSER option)}}
{Item
If non-{lisp NIL}, {arg PROMPTSTRING} is printed {it only} when the
key is confirmed with a member of the value of {lisp PROMPTON}.
}

{Label {lisp COMPLETEON}{index COMPLETEON (ASKUSER option)}}
{Item
When a confirming character is typed, the {arg N} characters that are automatically supplied, as specified in case (4), are echoed {it only} when the key is confirmed with a member of the value of {lisp PROMPTON}.

The {lisp PROMPTON} and {lisp COMPLETEON} options enable the user to construct a {arg KEYLST} which will cause {fn ASKUSER} to emulate the action of the TENEX exec.  The protocol followed by the TENEX exec is that the user can type as many characters as he likes in specifying a command.  The command can be completed with a carriage return or space, in which case no further output is forthcoming, or with a {lisp $} (escape), in which case the rest of the characters in the command are echoed, followed by some prompting information.  The following {arg KEYLST} would handle the TENEX {lisp COPY} and {lisp CONNECT} comands:

{lispcode
((COPY " (FILE LIST) "
		PROMPTON ($)
		COMPLETEON ($)
		CONFIRMFLG ($))
 (CONNECT " (TO DIRECTORY) "
		PROMPTON ($)
		COMPLETEON ($)
		CONFIRMFLG ($)))}

}


{Label {lisp AUTOCOMPLETEFLG}{index AUTOCOMPLETEFLG (ASKUSER option)}}
{Item
If the value of the {lisp AUTOCOMPLETEFLG} option is not {lisp NIL}, {fn ASKUSER} will automatically supply unambiguous characters whenever it can, i.e., {fn ASKUSER} acts as though {lisp $} (escape) were typed after each character (except that it does not ring the bell if there are no unambiguous characters).
}

{Label {lisp MACROCHARS}{index MACROCHARS (ASKUSER option)}}
{Item
value is a list of dotted pairs of form {lisp ({arg CHARACTER} . {arg FORM})}.  When {arg CHARACTER} is typed, and it does not match any of the current keys, {arg FORM} is evaluated and nothing else happens, i.e. the matching process stays where it is.  For example, {lisp ?} could have been implemented using this option.  Essentially {lisp MACROCHARS} provides a read macro facility while inside of {fn ASKUSER} (since {fn ASKUSER} does {fn READC}'s, read macros defined via the readtable are never invoked).
}

{Label {lisp EXPLAINDELIMITER}{index EXPLAINDELIMITER (ASKUSER option)}}
{Item
value is what is printed to delimit explanation in response to {lisp ?}.
Initially a carriage return, but can be reset, e.g. to a comma, for more linear output. 
}

{End LabeledList Options}

}{End SubSec Options}



{Begin SubSec Operation}
{Title Operation}
{Text

All input operations are executed with the terminal table in the variable {var ASKUSERTTBL},{index ASKUSERTTBL Var} in which (1) {lisp (CONTROL T)} has been executed (see {PageRef Fn CONTROL}), so that {fn ASKUSER} can interact with the user after each character is typed; and (2) {lisp (ECHOMODE NIL)} has been executed (see {PageRef Fn ECHOMODE}), so that {fn ASKUSER} can decide {it after} it reads a character whether or not the character should be echoed, and with what, e.g. unacceptable inputs are never echoed.


As each character is typed, it is matched against {arg KEYLST}, and appropriate echoing and/or prompting is performed.  If the user types an unacceptable character, {fn ASKUSER} simply rings the bell and allows him to try again.


At any point, the user can type {lisp ?} and receive a list of acceptable responses at that point (generated from {arg KEYLST}), or type a control-A, control-Q, control-X, or delete, which causes {fn ASKUSER} to reinitialize, and start over.

Note that {lisp ?}, Control-A, Control-Q, and Control-X will not work if they are acceptable inputs, i.e., they match one of the keys on {arg KEYLST}.  Delete will not work if it is an interrupt character, in which case it is not seen by {fn ASKUSER}.

When an acceptable sequence is completed, {fn ASKUSER} returns the
indicated value.


}{End SubSec Operation}



{Begin SubSec Completing a Key}
{Title Completing a Key}
{Text

The decision about when a key is complete is more complicated than simply whether or not all of its characters have been matched.  In the compiler questions example above, all of the characters in the {lisp S} key are matched as soon as the {lisp S} has been typed, but until the next character is typed, {fn ASKUSER} does not know whether the {lisp S} completes the {lisp S} key, or is simply the first character in the {lisp ST} key.  Therefore, a key is considered to be complete when:


{Begin LabeledList key is considered to be complete}

{Label (1)}
{Text
All of its characters have been matched and it is the only key left, i.e., there are no other keys for which this key is a substring.
}

{Label (2)}
{Text
All of its characters have been matched and a confirming character is typed.
}

{Label (3)}
{Text
All of its characters have been matched, and the value of the {lisp CONFIRMFLG} option is {lisp NIL}, and the value of the {lisp KEYLST} option is not {lisp NIL}, and the next character matches one of the keys on the value of the {lisp KEYLST} option.
}

{Label (4)}
{Text
There is only one key left and a confirming character is typed.  Note that if the value of {lisp CONFIRMFLG} is {lisp T}, the key still has to be confirmed, regardless of whether or not it is complete.  For example, if the first entry in the above example were instead 

{lispcode (ST "ore and redefine " CONFIRMFLG T KEYLST ("" (F . "orget exprs"))}

and the user wanted to specify the {lisp STF} path, he would have to type {lisp ST}, {it then} confirm before typing {lisp F},  even though the {lisp ST} completed the {lisp ST} key by the rule in case (1).  However, he would be prompted with  "{lisp ore and redefine}" as soon as he typed the {lisp T}, and completed the {lisp ST} key.
}

{End LabeledList key is considered to be complete}



Case (2) says that confirmation can be used to complete a key in the case where it is a substring of another key, even where the value of {lisp CONFIRMFLG} is {lisp NIL}.  In this case, the confirming character doubles as both an indicator that the key is complete, and also to confirm it, if necessary.  This situation corresponds to typing {lisp S{CRsymbol}} in the above example.


Case (3) says that if there were another entry whose key was {lisp STX} in the above example, so that after the user typed {lisp ST}, two keys, {lisp ST} and {lisp STX}, were still active, then typing {lisp F} would complete the {lisp ST} key, because {lisp F} matches the {lisp (F . "orget exprs")} entry on the value of the {lisp KEYLST} option of the {lisp ST} entry.  In this case, "{lisp ore and redefine}" would be printed {it before} the {lisp F} was echoed.


Finally, case (4) says that the user can use confirmation to specify completion when only one key is left, even when all of its characters have not been matched.  For example, if the first key in the above example were {lisp STORE}, the user could type {lisp ST} and then confirm, and {lisp ORE} would be echoed, followed by whatever prompting was specified.  In this case, the confirming character also confirms the key if necessary, so that no further action is required, even when the value of {lisp CONFIRMFLG} is {lisp T}.


Case (4) permits the user not to have to type every character in a key when the key is the only one left.  Even when there are several active keys, the user can type {lisp $} (escape) to specify the next {arg N}>0 common characters among the currently active keys.  The effect is exactly the same as though these characters had been typed.  If there are no common characters in the active keys at that point, i.e.  {arg N}=0, the {lisp $} is treated as an incorrect input, and the bell is rung.  For example, if {arg KEYLST} is {lisp (CLISPFLG CLISPIFYPACKFLG CLISPIFTRANFLG)}, and the user types {lisp C} followed by {lisp $}, {fn ASKUSER} will supply the {lisp L}, {lisp I}, {lisp S}, and {lisp P}.  The user can then type {lisp F} followed by a carriage return or space to complete and confirm {lisp CLISPFLG}, as per case (4), or type {lisp I}, followed by {lisp $}, and {fn ASKUSER} will supply the {lisp F}, etc.  Note that the characters supplied do not have to correspond to a terminal segment of any of the keys.  Note also that the {lisp $} does not confirm the key, although it may complete it in the case that there is only one key active.


If the user types a confirming character when several keys are left, the next {arg N}>0 common characters are still supplied, the same as with {lisp $}.  However, {fn ASKUSER} assumes the intent was to complete a key, i.e., case (4) is being invoked.  Therefore, after supplying the next {arg N} characters, the bell is rung to indicate that the operation was not  completed. In other words, typing a confirming character has the same effect as typing an {lisp $} in that the next {arg N} common characters are supplied.  Then, if there is only one key left, the key is complete (case 4) and confirmation is not required.  If the key is not the only key left, the bell is rung.

}{End SubSec Completing a Key}



{Begin SubSec Special Keys}
{Title Special Keys}
{Text


{Begin LabeledList Special Keys}

{Label {lisp &}{index & (use in ASKUSER)}}
{Text
This can be used as a key to match with any single character, provided the character does not match with some other key at that level. For the purposes of echoing and returning a value, the effect is the same as though the character that were matched actually appeared as the key.
}

{Label {index $ (escape) (use in ASKUSER)}{index Escape ($) (use in ASKUSER)}{lisp $} (escape)}
{Text
This can be used as a key to match with the result of a single call to {fn READ}.  For example, if the {arg KEYLST} were:

{lispcode
((COPY " (FILE LIST) "
		PROMPTON ($)
		COMPLETEON ($)
		CONFIRMFLG ($)
		KEYLST (($ NIL RETURN ANSWER))))}


then if the user typed {lisp COP FOO{CRsymbol}}, {lisp (COPY FOO)} would be returned as the value of {fn ASKUSER}.  One advantage of using {lisp $}, rather than having the calling program perform the {fn READ}, is that the call to {fn READ} from inside {fn ASKUSER} is {fn ERRORSET} protected, so that the user can back out of this path and reinitialize {fn ASKUSER}, e.g. to change from a {lisp COPY} command to a {lisp CONNECT} command, simply by typing control-E.
}

{Label {lisp $$} (escape, escape){index $$ (escape, escape) (use in ASKUSER)}}
{Text
This can be used as a key to match with the result of a single call to {fn READLINE}.
}

{Label A list}
{Text
A list can be used as a key, in which case the list/form is evaluated and its value "matches" the key.  This feature is provided primarily as an escape hatch for including arbitrary input operations as part of an {fn ASKUSER} sequence.  For example, the effect of {lisp $$} (escape, escape) could be achieved simply by using ({lisp READLINE T}) as a key.
}

{Label {lisp ""}{index "" (use in ASKUSER)}}
{Text
The empty string can be used as a key.  Since it has no characters, all of its characters are automatically matched.  ""  essentially functions as a place marker.  For example, one of the entries on the {arg KEYLST} used by
{fn ADDTOFILES?} is:

{lispcode
("" "File/list:  "
	EXPLAINSTRING "a file name or name of a function list"
	KEYLST ($))}

Thus, if the user types a character that does not match any of the other keys on the {arg KEYLST}, then the character completes the "" key, by virtue of case (4), since the character {it will} match with the {lisp $} in the inner {arg KEYLST}.  {fn ASKUSER} then prints "{lisp File/list:  }" {it before} echoing the character, then calls {fn READ}.  The character will be read as part of the {fn READ}.  The value returned by {fn ASKUSER} will be the value of the {fn READ}.
}

{End LabeledList Special Keys}

Note:  For {lisp $} (escape), {lisp $$} (escape, escape), or a list, if the last character read by the input operation is a separator, the character is treated as a confirming character for the key.  However, if the last character is a break character, it will be matched against the next key.

}{End SubSec Special Keys}



{Begin SubSec Startup Protocol and Typeahead}
{Title Startup Protocol and Typeahead}
{Text

Interlisp permits and encourages the user to typeahead; in actual practice, the user frequently does this.  This presents a problem for {fn ASKUSER}.  When {fn ASKUSER} is entered and there has been typeahead, was the input intended for {fn ASKUSER}, or was the interaction unanticipated, and the user simply typing ahead to some other program, e.g. the programmer's assistant?  Even where there was no typeahead, i.e., the user starts typing {it after} the call to {fn ASKUSER}, the question remains of whether the user had time to see the message from {fn ASKUSER} and react to it, or simply began typing ahead at an inauspicious moment.  Thus, what is needed is an interlock mechanism which warns the user to stop typing, gives him a chance to respond to the warning, and then allows him to begin typing to {fn ASKUSER}.

Therefore, when {fn ASKUSER} is first entered, and the interaction is to take place with a terminal, and typeahead to {fn ASKUSER} is not permitted, the following protocol is observed:


{Begin Labeledlist Startup protocol}

{Label (1)}
{Text
If there is typeahead, {fn ASKUSER} clears and saves the input buffers and rings the bell to warn the user to stop typing.  The buffers will be restored when {fn ASKUSER} completes operation and returns.
}

{Label (2)}
{Text
If {arg MESS}, the message to be printed on entry, is not {lisp NIL} (the typical case), {fn ASKUSER} then prints {arg MESS} if it is a string, otherwise {fn CAR} of {arg MESS}, if {arg MESS} is a list.
}

{Label (3)}
{Text
After printing {arg MESS} or {fn CAR} of {arg MESS}, {fn ASKUSER} waits until the output has actually been printed on the terminal to make sure that the user has actually had a chance to see the output.  This also give the user a chance to react.  {fn ASKUSER} then checks to see if anything additional has been typed in the intervening period since it first warned the user in (1).
If something has been typed, {fn ASKUSER} clears it out and again rings the bell. This latter material, i.e., that typed between the entry to {fn ASKUSER} and this point, is discarded and will not be restored since it is not certain whether the user simply reacted quickly to the first warning (bell) and this input is intended for {fn ASKUSER}, or whether the user was in the process of typing ahead when the call to {fn ASKUSER} occurred, and did not stop typing at the first warning, and therefore this input is a continuation of input intended for another program.

Anything typed after (3)  is considered to be intended for {fn ASKUSER}, i.e., once the user sees {arg MESS} or {fn CAR} of {arg MESS}, he is free to respond.  For example,  {pacom UNDO} ({PageRef PACom UNDO}) calls {fn ASKUSER} when the number of undosaves are exceeded for an event with {arg MESS}={lisp (LIST {arg NUMBER-UNDOSAVES} "undosaves, continue saving")}.  Thus, the user can type a response as soon as {arg NUMBER-UNDOSAVES} is typed.
}

{Label (4)}
{Text
{fn ASKUSER} then types the rest of {arg MESS}, if any.
}

{Label (5)}
{Text
Then {fn ASKUSER} goes into a wait loop until something is typed.  If {arg WAIT}, the wait time, is not {lisp NIL}, and nothing is typed in {arg WAIT} seconds, {fn ASKUSER} will type "{lisp ...}" and treat the elements of {arg DEFAULT}, the default value, as a list of characters, and begin processing them exactly as though they had been typed.  If the user does type anything within {arg WAIT} seconds, he can then wait as long as he likes, i.e.,  once something has been typed, {fn ASKUSER} will not use the default value specified in {arg DEFAULT}.

If the user wants to consider his response for more than {arg WAIT} seconds, and does not want {fn ASKUSER} to default, he can type a carriage return or a space, which are ignored if they are not specified as acceptable inputs by {arg KEYLST} (see below) and they are the first thing typed.


If the calling program knows that the user is expecting an interaction with {fn ASKUSER}, e.g. another interaction preceded this one, it can specify in the call to {fn ASKUSER} that typeahead is permitted.  In this case, {fn ASKUSER} simply notes whether there is any typeahead, then prints {arg MESS} and goes into a wait loop as described above.

If there is typeahead that contains unacceptable input, {fn ASKUSER} will assume that the typeahead was not intended for {fn ASKUSER}, and will restore the typeahead when it completes operation and returns.
}

{Label (6)}
{Text
Finally, if the interaction is not with the terminal, i.e., the optional input file/string is specified, {fn ASKUSER} simply prints {arg MESS} and begins reading from the file/string.
}

{End Labeledlist Startup protocol}


}{End SubSec Startup Protocol and Typeahead}




}{End SubSec ASKUSER}