TEditBufferedInputImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Russ Atkinson (RRA) June 10, 1985 10:37:44 pm PDT
Michael Plass, October 19, 1987 5:31:35 pm PDT
Doug Wyatt, June 22, 1985 1:03:47 pm PDT
DIRECTORY
Process USING [Detach, MsecToTicks, SetTimeout, Ticks],
Rope USING [Concat, Fetch, FromRefText, Length, ROPE],
TextEdit USING [InsertRope, InsertString],
TextNode USING [Location, 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 Process, Rope, TextEdit, TEditInput, TEditInputOps, TEditLocks, TEditRefresh, TEditSelection
EXPORTS TEditInputOps
=
BEGIN
OPEN TEditSelection;
repainting: BOOL ← FALSE;
editRepaintProcess: PROCESS ← NIL;
repaintDone: CONDITION;
bufferMaxlen: CARDINAL ← 32;
inputBuffer: REF TEXT ← NEW[TEXT[bufferMaxlen]];
inputRope: Rope.ROPE;
aLittleWhile: Process.Ticks = Process.MsecToTicks[50];
untilTimesOutInALittleWhile: CONDITION;
bufferClear: CONDITION;
BufferedInsertChar:
PUBLIC
ENTRY
PROC [char:
CHAR] = {
ENABLE UNWIND => NULL; -- release lock
count: INTEGER ← 0;
WHILE inputBuffer.length >= bufferMaxlen
DO
-- buffer full
IF (count ← count+1) > 10
THEN {
-- waited long enough
inputRope ← Rope.Concat[inputRope, Rope.FromRefText[inputBuffer]];
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
NOT repainting
THEN {
TRUSTED { Process.Detach[editRepaintProcess ← FORK Repaint[]] };
repainting ← TRUE;
};
};
BufferedInsertText:
PUBLIC
PROC [text: Rope.
ROPE] = {
FOR n:
INT
IN [0..Rope.Length[text])
DO
BufferedInsertChar[Rope.Fetch[text, n]];
ENDLOOP;
};
WaitForInsertToFinish:
PUBLIC
ENTRY
PROC = {
ENABLE UNWIND => NULL; -- release lock
WHILE repainting DO WAIT repaintDone; ENDLOOP;
};
NoteRepaintDone:
ENTRY
PROC = {
editRepaintProcess ← NIL;
repainting ← FALSE;
BROADCAST repaintDone;
};
Repaint:
PROC = {
root: TextNode.Ref;
docLock: BOOL ← FALSE;
tSel: TEditDocument.Selection;
Cleanup:
PROC = {
TEditSelection.UnlockSel[primary];
IF docLock THEN TEditLocks.Unlock[root];
IF tSel # NIL THEN Free[tSel];
NoteRepaintDone[];
};
{
ENABLE {
UNWIND => Cleanup[];
ABORTED => GOTO Quit;
};
DoInsertions:
ENTRY
PROC = {
caretVisible: BOOL ← TEditSelection.CaretVisible[];
WHILE MakeEdits[root, tSel, caretVisible]
DO
IF inputRope=
NIL
AND inputBuffer.length<bufferMaxlen
THEN
WAIT untilTimesOutInALittleWhile;
ENDLOOP;
};
TEditSelection.LockSel[primary, "TEditBufferedInputImplRepaint"];
IF NOT TEditInputOps.CheckReadonly[pSel] THEN GO TO Quit;
IF (root ← TEditSelection.SelectionRoot[pSel]) = NIL THEN GO TO Quit;
tSel ← Alloc[];
[] ← TEditLocks.Lock[root, "TEditBufferedInputImplMakeEdits"];
docLock ← TRUE;
DoInsertions[];
GO TO Quit;
EXITS Quit => Cleanup[];
};
};
MakeEdits:
INTERNAL
PROC [root: TextNode.Ref, tSel: TEditDocument.Selection, caretVisible:
BOOL]
RETURNS [
BOOL] = {
Get document and selection locks outside of monitor to avoid deadlock with someone doing an insert char while holding a lock.
ENABLE UNWIND => NULL;
pos: TextNode.Location ← InsertionPoint[pSel];
IF root=NIL OR pos.node=NIL OR (inputRope=NIL AND inputBuffer.length=0) THEN RETURN[FALSE];
Copy[source: pSel, dest: tSel];
[] ← TextEdit.InsertString[root: root, dest: 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: 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];
};
TRUSTED {
Process.SetTimeout[@untilTimesOutInALittleWhile, aLittleWhile];
Process.SetTimeout[@bufferClear, aLittleWhile];
};
END.