PipalTextMutant.mesa 
Copyright Ó 1988 by Xerox Corporation. All rights reserved.
Barth, February 9, 1988 10:25:30 am PST
Bertrand Serlet February 16, 1988 6:07:51 pm PST
DIRECTORY Pipal, PipalInt, PipalReal;
PipalTextMutant: CEDAR DEFINITIONS = BEGIN
Theory
The Pipal text mutant. The look and feel is stolen from Tioga.
Text Class
pipalTextClass: Pipal.Class;
PipalText: TYPE = REF PipalTextRec;
PipalTextRec: TYPE = RECORD [
rope: Pipal.ROPENIL,
size: PipalReal.Size ← PipalReal.emptySize];
Location: TYPE = INT;
CreatePipalText: PROC [rope: Pipal.ROPE, size: PipalReal.Size ← PipalReal.emptySize] RETURNS [text: PipalText];
GetSelectionInterval: PROC [text: PipalText, position: PipalReal.Position, grain: SelectionGrain] RETURNS [interval: PipalInt.Interval, closerRight: BOOL];
Convert a 2D position and grain specification into a selection interval and a boolean which indicates if the position was closer the right edge of the selection bounding box than the left edge.
Text Mutant Class
textMutantClass: Pipal.Class;
TextMutant: TYPE = REF TextMutantRec;
TextMutantRec: TYPE = RECORD [
text: PipalText,
selections: ARRAY Selections OF Selection,
paste: Pipal.ROPENIL];
Selections: TYPE = {primary, secondary};
Selection: TYPE = RECORD [
valid: BOOLFALSE,
interval: PipalInt.Interval ← [0, 0],
pendingDelete: BOOLFALSE,
caretAfter: BOOLFALSE, -- invariant: caretAfter => interval.base<Rope.Size[text.rope]
granularity: SelectionGrain ← point]; -- invariant: point => interval.size=0
SelectionGrain: TYPE = {point, char, word};
Manipulation
InsertRope: PROC [tm: TextMutant, characters: Pipal.ROPE] RETURNS [message: Pipal.ROPE, newtm: TextMutant];
Insert the characters at the primary selection caret location. If pending delete then delete the primary selection, put it into the paste buffer, and reduce the primary selection size to 0.
Errors: noPrimarySelection
InsertChar: PROC [tm: TextMutant, character: CHAR] RETURNS [message: Pipal.ROPE, newtm: TextMutant];
Insert the character at the primary selection caret location. If pending delete then delete the primary selection, put it into the paste buffer, and reduce the primary selection size to 0.
Errors: noPrimarySelection
Copy: PROC [tm: TextMutant] RETURNS [message: Pipal.ROPE, newtm: TextMutant];
Copy the secondary selection to the primary selection caret location. If primary pending delete then delete the primary selection, put it into the paste buffer, and reduce the primary selection size to 0. If secondary pending delete then delete the secondary selection and reduce the secondary selection size to 0.
Errors: noPrimarySelection, noSecondarySelection
Transpose: PROC [tm: TextMutant] RETURNS [message: Pipal.ROPE, newtm: TextMutant];
Transpose the primary and secondary selections.
Errors: noPrimarySelection, noSecondarySelection
Delete: PROC [tm: TextMutant] RETURNS [message: Pipal.ROPE, newtm: TextMutant];
Delete the primary selection, put it into the paste buffer, and reduce the primary selection size to 0.
Errors: noPrimarySelection
Paste: PROC [tm: TextMutant] RETURNS [message: Pipal.ROPE, newtm: TextMutant];
Insert the paste buffer at the primary selection caret location.
Errors: noPrimarySelection
Erase: PROC [tm: TextMutant] RETURNS [message: Pipal.ROPE, newtm: TextMutant];
Delete the character before the primary selection caret.
Errors: noPrimarySelection, noCharacterToErase
Selection
SetSelection: PROC [tm: TextMutant, interval: PipalInt.Interval, selection: Selections ← primary, pendingDelete: BOOLFALSE, caretAfter: BOOLFALSE, granularity: SelectionGrain ← char] RETURNS [message: Pipal.ROPE, newtm: TextMutant];
CancelSelection: PROC [tm: TextMutant, selection: Selections ← primary] RETURNS [message: Pipal.ROPE, newtm: TextMutant];
Invalidate the selection.
END.