1 PROMPTFORWORD

PROMPTFORWORD is a function that reads in a sequence of characters,
generally from the keyboard, without involving READ-like syntax or
Process-related problems, and generally echoing the characters being
typed-in to a specified stream (e.g., (TTYDISPLAYSTREAM) or PROMPTWINDOW).
The intent is to mimic the prompted-READ used by the Alto Exec when asking
for login names, passwords etc.  Thus a user can supply a prompting string,
as well as a "candidate" string, which will be printed and used if the user
types only a word terminator character (or doesn't type anything before a
given time limit).  As soon as any characters are typed the "candidate"
string is erased and the new input takes its place.

PROMPTFORWORD accepts user type-in until one of the "word terminator"
characters is typed.  Normally, the word terminator characters are EOL,
ESCAPE, LF, SPACE, or TAB.  This list can be changed using the
TERMINCHAR.LST argument to PROMPTFORWORD, for example if it is desirable to
allow the user to input lines including spaces.

PROMPTFORWORD also recognizes the following special characters:


          Control-A, BS, or DELAny of these characters will delete the last
          character typed and appropriately erase it from the echo stream
          if it is a displaystream.
          Control-W or Control-QWill erase all the type-in so far.


          Control-RReprints the accumulated string.  When echoing to
          display streams, it reprints "in place".
          ?Calls up a "help" facility.  The action taken is defined by the
          GENERATE?LIST.FN argument to PROMPTFORWORD (see below).
          Normally, this will print a list of possible candidates.
          Control-VAfter typing Control-V, the next character typed will be
          added to the accumulated string, regardless of any special
          meaning it has.  Allows the user to include editing characters
          and word terminator characters in the accumulated string.

(PROMPTFORWORD PROMPT.STR CANDIDATE.STR GENERATE?LIST.FN ECHO.CHANNEL
DONTECHOTYPEIN.FLG TIMELIMIT.secs TERMINCHARS.LST KEYBD.CHANNEL OLDSTRING)


PROMPTFORWORD has a multiplicity of features, which are specified through a
rather large number of input arguments, but the default settings for them
(i.e., when they aren't given, or are given as NIL) is such to minimize the
number needed in the average case, and an attempt has been made to order
the more frequently non-defaulted arguments at the first of the argument
list.  When the default input channel is taken (NIL, meaning the keyboard)
then the various system buffers (linbuf and sysbuf) are saved-and-restored
so as not to interact with the "word" being read in; the terminal table in
effect during input allows most control characters to be INDICATE'd, and
all terminal interrupt characters are temporarily disabled.

PROMPTFORWORD returns NIL if a null string is typed; this would occur when
no candidate is given and only a terminator is typed, or when the candidate
is erased and a terminator is typed with no other input still un-erased.
In all other cases, PROMPTFORWORD returns a string.

PROMPTFORWORD uses a MONITORLOCK (see page X.XX) so that a second call
cannot be started before the first one finished; primarily this is to limit
confusion between multiple processes that might try to access the keyboard
at the same time, or print in the prompt window "at the same time"

PROMPTFORWORD is controlled through the following arguments:


    PROMPT.STRIf non-NIL, this is coerced to a string and used for
    prompting; an additional space will be output after this string.
    CANDIDATE.STRIf non-NIL, this is coerced to a string and offered as
    initial contents of the input buffer.
    GENERATE?LIST.FNIf non-NIL, this is either a string to be printed out
    for help, or a function to be applied to PROMPT.STR and CANDIDATE.STR
    (after both have been coerced to strings), and which should return a
    list of potential candidates.  The help string or list of potential
    candidates will then be printed on a separate line, the prompt will be
    restarted, and any type-in will be re-echoed.

    Note: If GENERATE?LIST.FN is a function, its value list will be
    "cached" so that it will be run at most once per call to PROMPTFORWORD.


    ECHO.CHANNELCoerced to an output stream; NIL and T both mean the
    current (TTYDISPLAYSTREAM).  To achieve echoing to the "current output
    file", use (GETSTREAM NIL 'OUTPUT).  Any display stream will also have
    a flashing caret showing where the next input is to be echoed.
    DONTECHOTYPEIN.FLGIf non-NIL, there wil be no echoing of the input
    characters.  However, a non-NIL prompt will still be visible.
    TIMELIMIT.secsIf non-NIL, this is the number of seconds (as an integer)
    that the caller is is willing to wait with no input from KEYBD.CHANNEL
    (see below); if timeout is reached, then CANDIDATE.WORD is returned,
    regardless of any other type-in activity.
    TERMINCHAR.LSTThis is list of "word terminators".  If NIL, this
    defaults to (CHARCODE (EOL ESCAPE LF SPACE TAB)).


    KEYBD.CHANNELIf non-NIL, this will be coerced to a stream, and the
    input bytes will be taken from that stream.  If this is NIL, the
    default is to take in characters typed on the real keyboard, with any
    "typeahead" saved-and-restored.  Note that supplying T for this arg
    will generally not do what you want -- it will turn into the LINEBUFFER
    stream which has an entirely independent input buffering mechanism, and
    which will probably be at the "end of file" anyway, thereby forcing the
    candidate result to be returned.  Use the (global) variable
    \KEYBOARD.STREAM to supply a stream which reads from the keyboard, but
    with no special processing or cognizance of that fact (e.g, it "eats"
    typeahead rather than saving it).
    OLDSTRINGIf non-NIL, this must be a string, which will be destructively
    used to return the answer.

Examples:

(PROMPTFORWORD
   "What is your FOO word?" 'Mumble
   (FUNCTION (LAMBDA () '(Grumble Bletch)))
   PROMPTWINDOW  NIL 30)

This will first prompt the user for input by printing the first argument as
a prompt into PROMPTWINDOW; then the proffered default answer, "Mumble",
will be printed out and the caret will be flashing just after it to
indicate that the upcoming input will be echoed there.  If the user fails
to complete a word within 30 seconds, then the result will be the string
"Mumble".

(FRESHLINE T)
(LIST
   (PROMPTFORWORD
      (CONCAT "{"  HOST  "} Login:")
      (USERNAME NIL NIL T))
   (PROMPTFORWORD
      " (password)" NIL NIL NIL 'DONTECHO))

This will first prompt in whatever window is currently (TTYDISPLAYSTREAM),
and then take in a username; the second call will take in another word (the
password) without proffering a candidate, without echoing any of the
typed-in characters, and without re-adjusting the caret to the left edge of
the window.  However, the second call will still issue the prompt "
(password)" into the (TTYDISPLAYSTREAM), for the fourth argument designates
the echostream, and both NIL and T default to (TTYDISPLAYSTREAM).

Caution: because of the dynamics of multiple processes, and the
above-mentioned input-buffer saving, a multiple use of PROMPTFORWORD is not
quite as simple as this "motivating" example.  See discussion of
KEYBD.CHANNEL above.