<<-- TEditBufferedInputImpl.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], TextNode USING [NarrowToTextNode, Location, pZone, Ref], TEditDocument USING [Selection], TEditInput USING [currentEvent], TEditInputOps, TEditLocks USING [Lock, Unlock], TEditRefresh USING [ScrollToEndOfSel], TEditSelection USING [Alloc, Free, CaretVisible, Copy, InsertionPoint, LockSel, MakePointSelection, pSel, SelectionRoot, UnlockSel]; TEditBufferedInputImpl: CEDAR MONITOR IMPORTS ImplErrors, Process, Rope, TextEdit, TextNode, TEditInput, TEditInputOps, TEditLocks, TEditRefresh, TEditSelection EXPORTS TEditInputOps SHARES TEditInputOps = BEGIN OPEN TEditSelection; editRepaintProcess: PROCESS _ NIL; repaintDone: CONDITION; bufferMaxlen: CARDINAL _ 32; inputBuffer: REF TEXT _ TextNode.pZone.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 = { TEditSelection.UnlockSel[primary]; IF docLock THEN TEditLocks.Unlock[root]; IF tSel # NIL THEN Free[tSel]; NotifyDone }; root: TextNode.Ref; docLock, caretVisible: BOOL _ FALSE; tSel: TEditDocument.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; TEditSelection.LockSel[primary, "TEditBufferedInputImplRepaint"]; caretVisible _ TEditSelection.CaretVisible[]; IF ~TEditInputOps.CheckReadonly[pSel] OR (root _ TEditSelection.SelectionRoot[pSel])=NIL THEN { Cleanup[]; RETURN }; [] _ TEditLocks.Lock[root, "TEditBufferedInputImplMakeEdits"]; 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: TextNode.Ref, tSel: TEditDocument.Selection, caretVisible: BOOL] <> RETURNS [BOOLEAN] = BEGIN ENABLE UNWIND => NULL; pos: TextNode.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: TextNode.NarrowToTextNode[pos.node], string: inputBuffer, destLoc: pos.where, inherit: FALSE, looks: tSel.looks, event: TEditInput.currentEvent]; IF inputRope#NIL THEN -- insert it in front of the inputBuffer string [] _ TextEdit.InsertRope[ root: root, dest: TextNode.NarrowToTextNode[pos.node], rope: inputRope, destLoc: pos.where, inherit: FALSE, looks: tSel.looks, event: TEditInput.currentEvent]; pos.where _ pos.where+inputBuffer.length+Rope.Length[inputRope]; TEditSelection.MakePointSelection[tSel, pos]; IF caretVisible THEN -- after repaint finishes, do an autoscroll TEditRefresh.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.