NewIOMiscImpl.mesa
Last editted: March 28, 1983 4:50 pm by Stewart
Last Edited by: Teitelman, April 20, 1983 3:49 pm
DIRECTORY
AMEvents USING [Debugged, Debugging],
Ascii USING [DEL],
Atom USING [GetPName, GetPropFromList],
IO USING [atom, char, PutChar, PutRope, GetChar, PutF, CharsAvail, STREAM, NewLine, UserAbort, UserAborted],
IOMisc USING [],
Rope USING [Upper, Fetch, ROPE],
Process USING [Pause, MsecToTicks],
ProcessProps USING [GetPropList]
;
IOMiscImpl: CEDAR PROGRAM
IMPORTS AMEvents, Atom, IO, Process, ProcessProps, Rope
EXPORTS IOMisc = BEGIN
defaultKeyList: LIST OF ATOM = LIST[$Yes, $No];
AskUser: PUBLIC PROC [msg: Rope.ROPE, in, out: IO.STREAM, defaultKey: ATOMNIL, keyList: LIST OF ATOMNIL, timeout: INT ← -1] RETURNS [value: ATOM] = {
char: CHAR;
r: REF ANY = Atom.GetPropFromList[ProcessProps.GetPropList[], $AskUser]; -- a way for later packages, e.g. UserExec, to provide a more fancy version of AskUser.
IF r # NIL THEN value ← (NARROW[r, REF PROC [msg: Rope.ROPE, in, out: IO.STREAM, defaultKey: ATOM, keyList: LIST OF ATOM, timeout: INT] RETURNS [value: ATOM]])^[msg, in, out, defaultKey, keyList, timeout !
AMEvents.Debugging, AMEvents.Debugged => REJECT;
UNWIND, IO.UserAborted, ABORTED => NULL;
ANY => CONTINUE
]; -- if anything goes wrong, drop through and use dumb askuser.
IF value # NIL THEN RETURN[value];
UNTIL in.backingStream = NIL DO
in ← in.backingStream;
ENDLOOP;
IF keyList = NIL THEN keyList ← defaultKeyList;
IF timeout > 0 AND timeout < 30 THEN timeout ← timeout * 1000; -- timeout expressed in seconds, should be milliseconds
DO
elapsedTime: INT ← 0;
out.NewLine[];
out.PutRope[msg];
out.PutRope[" (Respond using keyboard) "];
IF timeout # -1 THEN UNTIL elapsedTime > timeout -- timeout is in seconds. -- DO
Process.Pause[Process.MsecToTicks[100]];
elapsedTime ← elapsedTime + 100;
IF in.UserAbort[] THEN ERROR IO.UserAborted[in];
IF in.CharsAvail[] THEN EXIT;
REPEAT
FINISHED => {
out.PutF["...%g\n", IO.atom[defaultKey]];
RETURN[defaultKey];
};
ENDLOOP;
char ← in.GetChar[];
IF char = Ascii.DEL THEN char ← 'N;
timeout ← -1; -- once user types a character, don't timeout.
FOR l: LIST OF ATOM ← keyList, l.rest UNTIL l = NIL DO
r: Rope.ROPE = Atom.GetPName[l.first];
IF char = '\n -- matches first key -- OR Rope.Upper[Rope.Fetch[r, 0]] = Rope.Upper[char] THEN {
out.PutRope[r];
out.PutChar['\n];
RETURN[l.first];
};
REPEAT
FINISHED => { -- didn't match
out.PutChar[char];
out.PutF["\nType one of: "];
FOR l: LIST OF ATOM ← keyList, l.rest UNTIL l = NIL DO
out.PutF["%g, ", IO.char[Rope.Fetch[Atom.GetPName[l.first], 0]]];
ENDLOOP;
};
ENDLOOP;
ENDLOOP;
};
END.