TerminalIOImpl.mesa
By Ch. Jacobi August 3, 1983 9:54 am
Last edited by Ch. Jacobi November 9, 1983 12:06 pm
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],
ViewerTools USING [SetSelection];
TerminalIOImpl: CEDAR MONITOR
IMPORTS
Commander, EditedStream, Icons, InputFocus, IO, PopUpMenu, Process, Rope, RuntimeError, ViewerIO, ViewerOps, ViewerTools
EXPORTS
TerminalIO =
BEGIN
UserAbort: PUBLIC SIGNAL = CODE; -- Signalyzed allways outside of monitor-lock
terminalParent: ViewerClasses.Viewer←NIL;
messageUsed: BOOLEANFALSE;
in, out, editedIn: IO.STREAMNIL;
terminalIcon: Icons.IconFlavor;
inputIcon: Icons.IconFlavor;
del: CHAR = LOOPHOLE[127, CHAR];
delRope: Rope.ROPE = Rope.FromChar[del];
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
--Terminals own locking procedures
moduleEntered: BOOLEANFALSE;
--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;
terminalParent.icon ← terminalIcon;
END;
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
--input procedures
Done: TYPE = {ok, repeat, intError, abort};
RequestRope: PUBLIC ENTRY PROC [text, text2: Rope.ROPENIL] 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 => {
done�ort; IO.Reset[editedIn]; CONTINUE
};
END;
InternalWriteRope[text];
InternalWriteRope[text2];
InputFocus.PushInputFocus[terminalParent];
ViewerTools.SetSelection[terminalParent];
r ← IO.GetLineRope[editedIn];
InputFocus.PopInputFocus[];
IF Rope.Find[r, delRope]>=0 THEN done�ort;
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.ROPENIL] 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 => {
done�ort; IO.Reset[in]; CONTINUE
};
END;
InternalWriteRope[text];
InternalWriteRope[text2];
InputFocus.PushInputFocus[terminalParent];
ViewerTools.SetSelection[terminalParent];
ch ← IO.GetChar[in]; -- returns immediately, no CR to eat
InputFocus.PopInputFocus[];
IF ch=del THEN done�ort;
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.ROPENIL] 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 => {
done�ort; IO.Reset[editedIn]; CONTINUE
};
END;
ch: CHAR;
InternalWriteRope[text];
InternalWriteRope[text2];
InputFocus.PushInputFocus[terminalParent];
ViewerTools.SetSelection[terminalParent];
i ← IO.GetInt[editedIn];
WHILE IO.CharsAvail[editedIn]>0 DO
[ch] ← IO.GetChar[editedIn];
IF ch=del THEN done�ort;
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.ROPENIL,
choice: LIST OF Rope.ROPE,
text: Rope.ROPENIL,
default: CARDINAL𡤀]
RETURNS [CARDINAL] =
BEGIN
ENABLE UNWIND => UnLock[];
c: CARDINAL ← 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.ROPENIL, default: BOOLEANFALSE] 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.PutFR[format: " %g", v1: 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["/indigo/chipndale/TerminalIO5.1/TerminalIO.icons", 0
! RuntimeError.UNCAUGHT => {terminalIcon←Icons.IconFlavor[unInit]; CONTINUE}];
CONTINUE
}];
inputIcon ← Icons.NewIconFromFile["TerminalIO.icons", 1
! RuntimeError.UNCAUGHT => {
inputIcon←Icons.NewIconFromFile["/indigo/chipndale/TerminalIO5.1/TerminalIO.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.