<> <> <> 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: 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; terminalParent.icon _ terminalIcon; END; <<-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -->> <<--input procedures>> Done: TYPE = {ok, repeat, intError, abort}; 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 => { done_abort; 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_abort; 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 => { done_abort; 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_abort; 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 => { done_abort; 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_abort; 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: CARDINAL_0] 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.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.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.