TerminalIOImpl.mesa
Copyright © 1983, 1985 by Xerox Corporation. All rights reserved.
By Ch. Jacobi August 3, 1983 9:54 am
Last edited by Ch. Jacobi July 10, 1985 11:55:27 am PDT
DIRECTORY
Commander USING [CommandProc, Register],
EditedStream,
Icons USING [IconFlavor, NewIconFromFile],
InputFocus USING [PopInputFocus, PushInputFocus],
IO,
PopUpMenu,
Process,
Rope,
RuntimeError USING [UNCAUGHT],
TerminalIO,
ViewerClasses USING [Viewer],
ViewerIO USING [CreateViewerStreams, GetViewerFromStream],
ViewerOps USING [PaintViewer, OpenIcon],
ViewerTools USING [SetSelection];
TerminalIOImpl: CEDAR MONITOR
IMPORTS
Commander, EditedStream, Icons, InputFocus, IO, PopUpMenu, Process, Rope, RuntimeError, ViewerIO, ViewerOps, ViewerTools
BEGIN
UserAbort: PUBLIC SIGNAL = CODE; -- Signalyzed allways outside of monitor-lock
terminalParent: ViewerClasses.Viewer←NIL;
messageUsed: BOOLEAN ← FALSE;
in, out, editedIn: IO.STREAM ← NIL;
terminalIcon: Icons.IconFlavor;
inputIcon: Icons.IconFlavor;
del: CHAR = LOOPHOLE[127, CHAR];
delRope: Rope.ROPE = Rope.FromChar[del];
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
--Terminals own locking procedures
moduleEntered:
BOOLEAN ←
FALSE;
--is set if process releases the monitorlock but waits still for input
next: CONDITION; -- the next module might enter the "moduleEntered" region
MyLock:
INTERNAL
PROC [] =
BEGIN
ENABLE UNWIND => NULL;
WHILE moduleEntered
DO
WAIT next;
ENDLOOP;
moduleEntered ← TRUE;
terminalParent.icon ← inputIcon;
terminalParent.name ← "Terminal [Input Expected]";
ViewerOps.PaintViewer[terminalParent, caption];
END;
MyUnLock:
INTERNAL
PROC [] =
BEGIN
ENABLE UNWIND => NULL;
moduleEntered ← FALSE;
NOTIFY next;
terminalParent.icon ← terminalIcon;
terminalParent.name ← "Terminal";
ViewerOps.PaintViewer[terminalParent, caption];
--conveniant to be here since in all places where UnLock is called
terminalParent.inhibitDestroy ← FALSE;
END;
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
--Lock, UnLock mechanism
LockList: TYPE = LIST OF PROC;
lockList: LockList←NIL;
unLockList: LockList←NIL;
AddLock:
PUBLIC
ENTRY
PROC [lock, unLock:
PROC] =
BEGIN
ENABLE UNWIND => NULL;
lockList ← CONS[lock, lockList];
IF unLockList=NIL THEN unLockList ← LIST[unLock]
ELSE
FOR l: LockList ← unLockList, l.rest
DO
IF l.rest=NIL THEN {l.rest←LIST[unLock]; EXIT}
ENDLOOP;
END;
Lock:
INTERNAL
PROC =
BEGIN
FOR l: LockList ← lockList, l.rest
WHILE l#
NIL
DO
l.first[! RuntimeError.UNCAUGHT => CONTINUE]
ENDLOOP
END;
UnLock:
INTERNAL
PROC =
BEGIN
FOR l: LockList ← unLockList, l.rest
WHILE l#
NIL
DO
l.first[! RuntimeError.UNCAUGHT => CONTINUE]
ENDLOOP
END;
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
--creation of viewer
InternalCreateTerminal:
INTERNAL
PROC [] =
BEGIN
[in: in, out: out] ← ViewerIO.CreateViewerStreams[
name: "Terminal",
viewer: NIL,
editedStream: FALSE];
[editedIn] ← EditedStream.Create[in: in, echoTo: out];
terminalParent ← ViewerIO.GetViewerFromStream[out];
IF terminalParent=NIL THEN ERROR;
IF terminalParent.iconic
THEN {
terminalParent.column ← right;
ViewerOps.OpenIcon[terminalParent];
};
terminalParent.icon ← terminalIcon;
END;
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
--input procedures
Done: TYPE = {ok, repeat, intError, abort};
PrepareRequest:
INTERNAL PROC [text, text2: Rope.
ROPE ←
NIL] =
BEGIN
InternalWriteRope[text];
InternalWriteRope[text2];
IF terminalParent.iconic
THEN {
terminalParent.column ← right;
ViewerOps.OpenIcon[terminalParent];
};
InputFocus.PushInputFocus[terminalParent];
ViewerTools.SetSelection[terminalParent];
END;
RequestRope:
PUBLIC
ENTRY
PROC [text, text2: Rope.
ROPE ←
NIL]
RETURNS [Rope.
ROPE] =
BEGIN
ENABLE UNWIND => UnLock[];
done: Done;
r: Rope.ROPE;
DoIt:
INTERNAL
PROC [] =
BEGIN
ENABLE
BEGIN
IO.Error =>
IF ec=StreamClosed
THEN {
done←repeat; IO.Reset[editedIn]; CONTINUE
}
ELSE REJECT;
EditedStream.Rubout => {
doneort; IO.Reset[editedIn]; CONTINUE
};
END;
PrepareRequest[text, text2];
r ← IO.GetLineRope[editedIn];
InputFocus.PopInputFocus[];
IF Rope.Find[r, delRope]>=0 THEN doneort;
END;
--RequestRope
Lock[];
DO
done ← ok;
DoIt[];
IF done=ok THEN {UnLock[]; RETURN [r]}
ELSE IF done=repeat THEN {InternalWriteRope["XXX\n"]}
ELSE {InternalWriteRope[" ..user abort\n"]; SIGNAL UserAbort}
ENDLOOP;
END;
RequestChar:
PUBLIC
ENTRY
PROC [text, text2: Rope.
ROPE ←
NIL]
RETURNS [
CHAR] =
BEGIN
ENABLE UNWIND => UnLock[];
done: Done;
ch: CHAR;
DoIt:
INTERNAL
PROC [] =
BEGIN
ENABLE
BEGIN
IO.Error =>
IF ec=StreamClosed THEN {done←repeat; CONTINUE}
ELSE REJECT;
EditedStream.Rubout => {
doneort; IO.Reset[in]; CONTINUE
};
END;
PrepareRequest[text, text2];
ch ← IO.GetChar[in]; -- returns immediately, no CR to eat
InputFocus.PopInputFocus[];
IF ch=del THEN doneort;
END;
--RequestChar
Lock[];
DO
done ← ok;
DoIt[];
IF done=ok THEN {UnLock[]; RETURN[ch]}
ELSE IF done=repeat THEN {InternalWriteRope["XXX\n"]}
ELSE {
InternalWriteRope[" ..user abortion\n"];
SIGNAL UserAbort
};
ENDLOOP;
END;
RequestInt:
PUBLIC
ENTRY
PROC [text, text2: Rope.
ROPE ←
NIL]
RETURNS [
INT] =
BEGIN
ENABLE UNWIND => UnLock[];
done: Done;
i: INT;
DoIt:
INTERNAL
PROC [] =
BEGIN
ENABLE
BEGIN
IO.Error =>
IF ec=StreamClosed THEN {done←repeat; CONTINUE}
ELSE IF ec=Overflow THEN {done←intError; CONTINUE}
ELSE IF ec=SyntaxError THEN {done←intError; CONTINUE}
ELSE REJECT;
EditedStream.Rubout => {
doneort; IO.Reset[editedIn]; CONTINUE
};
END;
ch: CHAR;
PrepareRequest[text, text2];
i ← IO.GetInt[editedIn];
WHILE
IO.CharsAvail[editedIn]>0
DO
[ch] ← IO.GetChar[editedIn];
IF ch=del THEN doneort;
IF ch#15C AND done#abort THEN done←intError
ENDLOOP;
InputFocus.PopInputFocus[];
END;
--RequestInt
Lock[];
DO
done ← ok;
DoIt[];
IF done=ok THEN {UnLock[]; RETURN[i]}
ELSE IF done=repeat THEN {InternalWriteRope["XXX\n"]}
ELSE IF done=intError THEN {InternalWriteRope[" ?? (integer), please repeat: \n"]}
ELSE {InternalWriteRope[" ..user abortion\n"]; SIGNAL UserAbort}
ENDLOOP;
END;
ChoiceError: ERROR = CODE;
RequestSelection:
PUBLIC
ENTRY
PROC [
label: Rope.ROPE ← NIL,
choice: LIST OF Rope.ROPE,
text: Rope.ROPE ← NIL,
default:
NAT𡤀]
RETURNS [NAT] =
BEGIN
ENABLE UNWIND => UnLock[];
c: NAT ← 0;
IF (choice=NIL) OR (choice.first=NIL) THEN RETURN WITH ERROR ChoiceError;
Lock[];
IF text#NIL THEN InternalWriteRope[text];
IO.Flush[out ! RuntimeError.UNCAUGHT => CONTINUE];
--SILLY FLUSH DOESN'T WORK
Process.Pause[Process.MsecToTicks[5]];
c ← PopUpMenu.RequestSelection[label, choice, default];
UnLock[];
RETURN [c];
END;
UserSaysYes:
PUBLIC
PROC [label, text: Rope.
ROPE ←
NIL, default:
BOOLEAN←
FALSE]
RETURNS [
BOOLEAN] =
BEGIN
RETURN [
SELECT
RequestSelection[label,
LIST["yes", "no"], text, (
IF default
THEN 1
ELSE 2)]
FROM
1 => TRUE,
2 => FALSE
ENDCASE => default];
END;
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
--output procedures
InternalWriteRope:
INTERNAL
PROC [text: Rope.
ROPE] =
BEGIN
IF out=NIL THEN InternalCreateTerminal[];
IO.PutRope[out, text !
IO.Error => {
IF ec=StreamClosed
THEN {
InternalCreateTerminal[];
IO.PutRope[out, text];
CONTINUE
}
ELSE REJECT
}];
END;
WriteRope:
PUBLIC
ENTRY
PROC [text: Rope.
ROPE] =
BEGIN
ENABLE UNWIND => NULL;
InternalWriteRope[text];
--terminalParent.inhibitDestroy ← FALSE;
END;
WriteLn:
PUBLIC
PROC [] =
BEGIN
WriteRope["\n"];
END;
WriteChar:
PUBLIC
PROC [ch:
CHAR] =
BEGIN
WriteRope[Rope.FromChar[ch]];
END;
WriteInt:
PUBLIC
PROC [i:
INT] =
BEGIN
WriteRope[IO.PutFR1[format: " %g", value: IO.int[i]]];
END;
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
CreateTerminal:
ENTRY Commander.CommandProc =
BEGIN
ENABLE UNWIND => NULL;
InternalCreateTerminal[];
END;
Init:
PROC [] =
BEGIN
terminalIcon ← Icons.NewIconFromFile["TerminalIO.icons", 0
! RuntimeError.
UNCAUGHT => {
terminalIcon ← Icons.NewIconFromFile["/Cedar/ChipNDale/6.0/TerminalIO/TerminalIO.icons", 0
! RuntimeError.
UNCAUGHT => {
terminalIcon←Icons.IconFlavor[unInit];
CONTINUE
}
];
CONTINUE
}];
inputIcon ← Icons.NewIconFromFile["TerminalIO.icons", 1
! RuntimeError.
UNCAUGHT => {
inputIcon ← Icons.NewIconFromFile["/Cedar/ChipNDale/6.0/TerminalIO/TerminalIO.icons.icons", 1
! RuntimeError.
UNCAUGHT => {
inputIcon ← terminalIcon;
CONTINUE
}
];
CONTINUE
}];
AddLock[MyLock, MyUnLock];
Commander.Register[
key: "Terminal",
proc: CreateTerminal,
doc: "Create terminal viewer if it does not yet exist"
];
END;
Init[];
END.