<<-- TiogaBufferedInputImpl.mesa Edited by Paxton on November 24, 1982 9:50 am>> <> DIRECTORY ImplErrors USING [UserErrorQuery], Process USING [Detach, GetCurrent, MsecToTicks, SetTimeout, Ticks], Rope USING [Concat, Fetch, FromProc, Length, ROPE], TextEdit USING [InsertRope, InsertString], TiogaNode USING [Location, RefBranchNode], TiogaNodeOps USING [NarrowToTextNode], TiogaDocument USING [Selection], TiogaInput USING [currentEvent], TiogaInputOps, TiogaLocks USING [Lock, Unlock], TiogaRefresh USING [ScrollToEndOfSel], TiogaSelection USING [Alloc, Free, CaretVisible, Copy, InsertionPoint, LockSel, MakePointSelection, pSel, SelectionRoot, UnlockSel]; TiogaBufferedInputImpl: CEDAR MONITOR IMPORTS ImplErrors, Process, Rope, TextEdit, TiogaNodeOps, TiogaInput, TiogaInputOps, TiogaLocks, TiogaRefresh, TiogaSelection EXPORTS TiogaInputOps SHARES TiogaInputOps = BEGIN OPEN TiogaSelection; editRepaintProcess: PROCESS _ NIL; repaintDone: CONDITION; bufferMaxlen: CARDINAL _ 32; inputBuffer: REF TEXT _ NEW[TEXT[bufferMaxlen]]; inputRope: Rope.ROPE; BufferedInsertChar: PUBLIC ENTRY PROCEDURE [char: CHARACTER] = BEGIN ENABLE UNWIND => NULL; -- release lock count: INTEGER _ 0; WHILE inputBuffer.length >= bufferMaxlen DO -- buffer full IF (count _ count+1) > 10 THEN { -- waited long enough i: CARDINAL _ 0; Char: PROC RETURNS [c: CHAR] = { c _ inputBuffer[i]; i _ i+1 }; rope: Rope.ROPE _ Rope.FromProc[inputBuffer.length, Char]; inputRope _ Rope.Concat[inputRope, rope]; inputBuffer.length _ 0; EXIT }; BROADCAST untilTimesOutInALittleWhile; -- wake up the repaint process WAIT bufferClear; -- this will time out if repaint fails to empty the buffer ENDLOOP; inputBuffer[inputBuffer.length] _ char; inputBuffer.length _ inputBuffer.length + 1; IF editRepaintProcess=NIL THEN TRUSTED { Process.Detach[editRepaintProcess _ FORK Repaint[]] }; END; BufferedInsertText: PUBLIC PROCEDURE [text: Rope.ROPE] = BEGIN FOR n: LONG INTEGER IN [0..Rope.Length[text]) DO BufferedInsertChar[Rope.Fetch[text, n]]; ENDLOOP; END; WaitForInsertToFinish: PUBLIC ENTRY PROCEDURE = BEGIN ENABLE UNWIND => NULL; -- release lock WHILE editRepaintProcess # NIL DO WAIT repaintDone; ENDLOOP; END; Repaint: PROCEDURE = BEGIN Cleanup: PROC = { TiogaSelection.UnlockSel[primary]; IF docLock THEN TiogaLocks.Unlock[root]; IF tSel # NIL THEN Free[tSel]; NotifyDone }; root: TiogaNode.RefBranchNode; docLock, caretVisible: BOOL _ FALSE; tSel: TiogaDocument.Selection; BEGIN ENABLE BEGIN UNWIND => Cleanup; ABORTED => GOTO Quit; ANY => IF ImplErrors.UserErrorQuery[] THEN CONTINUE; END; WaitForMoreInput: ENTRY PROCEDURE = BEGIN ENABLE UNWIND => NULL; -- release lock WAIT untilTimesOutInALittleWhile; END; TiogaSelection.LockSel[primary, "TiogaBufferedInputImplRepaint"]; caretVisible _ TiogaSelection.CaretVisible[]; IF ~TiogaInputOps.CheckReadonly[pSel] OR (root _ TiogaSelection.SelectionRoot[pSel])=NIL THEN { Cleanup[]; RETURN }; [] _ TiogaLocks.Lock[root, "TiogaBufferedInputImplMakeEdits"]; docLock _ TRUE; tSel _ Alloc[]; WHILE MakeEdits[root, tSel, caretVisible] DO IF inputRope=NIL AND inputBuffer.length Cleanup; END END; NotifyDone: ENTRY PROC = TRUSTED INLINE { IF Process.GetCurrent[]=editRepaintProcess THEN editRepaintProcess _ NIL; BROADCAST repaintDone}; MakeEdits: ENTRY PROCEDURE [ root: TiogaNode.RefBranchNode, tSel: TiogaDocument.Selection, caretVisible: BOOL] <> RETURNS [BOOLEAN] = BEGIN ENABLE UNWIND => NULL; pos: TiogaNode.Location _ InsertionPoint[pSel]; IF root=NIL OR pos.node=NIL OR (inputRope=NIL AND inputBuffer.length=0) THEN {editRepaintProcess _ NIL; RETURN[FALSE]}; -- done Copy[source: pSel, dest: tSel]; [] _ TextEdit.InsertString[ root: root, dest: TiogaNodeOps.NarrowToTextNode[pos.node], string: inputBuffer, destLoc: pos.where, inherit: FALSE, looks: tSel.looks, event: TiogaInput.currentEvent]; IF inputRope#NIL THEN -- insert it in front of the inputBuffer string [] _ TextEdit.InsertRope[ root: root, dest: TiogaNodeOps.NarrowToTextNode[pos.node], rope: inputRope, destLoc: pos.where, inherit: FALSE, looks: tSel.looks, event: TiogaInput.currentEvent]; pos.where _ pos.where+inputBuffer.length+Rope.Length[inputRope]; TiogaSelection.MakePointSelection[tSel, pos]; IF caretVisible THEN -- after repaint finishes, do an autoscroll TiogaRefresh.ScrollToEndOfSel[tSel.viewer, TRUE]; inputBuffer.length _ 0; inputRope _ NIL; BROADCAST bufferClear; RETURN[TRUE]; END; aLittleWhile: Process.Ticks = Process.MsecToTicks[50]; untilTimesOutInALittleWhile, bufferClear: CONDITION; TRUSTED {Process.SetTimeout[@untilTimesOutInALittleWhile, aLittleWhile]}; TRUSTED {Process.SetTimeout[@bufferClear, aLittleWhile]}; END.