TEditBufferedInputImpl.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
Russ Atkinson (RRA) June 10, 1985 10:37:44 pm PDT
Michael Plass, March 29, 1985 3:51:11 pm PST
Doug Wyatt, September 2, 1986 2:16:11 pm PDT
DIRECTORY
Process USING [Detach, MsecToTicks, SetTimeout, Ticks],
Rope USING [Concat, Fetch, FromProc, Length, ROPE],
TextEdit USING [InsertRope, InsertString],
TextNode USING [Location, Node],
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
SHARES 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
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
NOT repainting
THEN {
TRUSTED { Process.Detach[editRepaintProcess ← FORK Repaint[]] };
repainting ← TRUE;
};
};
BufferedInsertText:
PUBLIC
PROC [text: Rope.
ROPE] = {
FOR n:
LONG
INTEGER
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.Node;
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 ~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.Node, 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.