SpellingToolSharedImpl.mesa
Last Edited by: Nix, December 9, 1983 2:52 pm
DIRECTORY
Ascii USING [Lower],
Rope USING [Fetch, ROPE, Size, Substr],
SpellingToolShared,
SpellingWordMap USING [MapWordsInRope, MapWordsInRopeBackward],
TiogaOps USING [FirstSibling, GetRope, GetSelection, LastWithin, Lock, LockSel, NoSelection, Root, SelectionGrain, SelectionRoot, StepBackward, StepForward, Unlock, UnlockSel],
TiogaOpsDefs USING [Location, Ref, Viewer];
SpellingToolSharedImpl: CEDAR MONITOR
IMPORTS Ascii, Rope, SpellingWordMap, TiogaOps
EXPORTS SpellingToolShared = {
OPEN SpellingToolShared;
ROPE: TYPE = Rope.ROPE;
CorrectTiogaOpsCallWithLocks: PUBLIC PROC [proc: PROC [root: TiogaOpsDefs.Ref], root: TiogaOpsDefs.Ref ← NIL] = {
lockedSel, lockedDoc: BOOLFALSE;
Cleanup: PROC = {
IF lockedSel THEN {
TiogaOps.UnlockSel;
lockedSel ← FALSE;
};
IF lockedDoc THEN {
TiogaOps.Unlock[root];
lockedDoc ← FALSE;
};
};
{
ENABLE UNWIND => Cleanup;
TiogaOps.LockSel; lockedSel ← TRUE;
IF root=NIL AND (root ← TiogaOps.SelectionRoot[])=NIL THEN
ERROR TiogaOps.NoSelection;
TiogaOps.Lock[root]; lockedDoc ← TRUE;
proc[root];
Cleanup[];
};
};
wordBuffer: REF TEXTNEW[TEXT[256]];
MapWordsInSelection: PUBLIC ENTRY PROC [start, end: TiogaOpsDefs.Location, f: PROC [REF TEXT] RETURNS [BOOL], forwards: BOOL] RETURNS [premature: BOOLFALSE, wordStart, wordEnd: TiogaOpsDefs.Location] = {
Maps the given procedure f over the words in the selection, returning as soon as f returns TRUE.
loc: TiogaOpsDefs.Location ← IF forwards THEN start ELSE end;
MapNode: PROC [start: TiogaOpsDefs.Location, endPlusOne: INT, word: REF TEXT, f: PROC [REF TEXT] RETURNS [BOOL]] RETURNS [premature: BOOLFALSE, wordStart, wordEnd: TiogaOpsDefs.Location] = {
Maps the given procedure f over the words in a single Tioga node, returning as soon as f returns TRUE.
theNode: ROPE ← TiogaOps.GetRope[start.node];
IF endPlusOne = -1 THEN endPlusOne ← theNode.Size[];
IF endPlusOne <= start.where THEN RETURN;
IF ~(start.where = 0 AND endPlusOne = theNode.Size[]) THEN
theNode ← theNode.Substr[start.where, endPlusOne-start.where];
[premature, wordStart.where, wordEnd.where, word] ←
SpellingWordMap.MapWordsInRope[theNode, word, f];
wordStart.node ← start.node;
wordStart.where ← wordStart.where + start.where;
wordEnd.node ← start.node;
wordEnd.where ← wordEnd.where + start.where - 1;
};
MapNodeBackward: PROC [loc: TiogaOpsDefs.Location, endPlusOne: INT, word: REF TEXT, f: PROC [REF TEXT] RETURNS [BOOL]] RETURNS [premature: BOOLFALSE, wordStart, wordEnd: TiogaOpsDefs.Location] = {
Maps the given procedure f over the words in a single Tioga node, returning as soon as f returns TRUE.
theNode: ROPE ← TiogaOps.GetRope[loc.node];
IF endPlusOne = -1 THEN endPlusOne ← theNode.Size[];
IF endPlusOne <= loc.where THEN RETURN;
IF ~(loc.where = 0 AND endPlusOne = theNode.Size[]) THEN
theNode ← theNode.Substr[loc.where, endPlusOne-loc.where];
[premature, wordStart.where, wordEnd.where, word] ←
SpellingWordMap.MapWordsInRopeBackward[theNode, word, f];
wordStart.node ← loc.node;
wordStart.where ← wordStart.where + loc.where;
wordEnd.node ← loc.node;
wordEnd.where ← wordEnd.where + loc.where - 1;
};
IF forwards THEN
DO
[premature, wordStart, wordEnd] ←
MapNode[loc, IF loc.node = end.node THEN end.where+1 ELSE -1, wordBuffer, f];
IF premature THEN RETURN;
IF loc.node = end.node OR loc.node = NIL THEN RETURN;
loc.node ← TiogaOps.StepForward[loc.node];
loc.where ← 0;
ENDLOOP
ELSE
DO
IF loc.node = start.node THEN
loc.where ← start.where
ELSE
loc.where ← 0;
[premature, wordStart, wordEnd] ←
MapNodeBackward[loc, IF loc.node = end.node THEN end.where+1 ELSE -1, wordBuffer, f];
IF premature THEN RETURN;
IF loc.node = start.node OR loc.node = NIL THEN RETURN;
loc.node ← TiogaOps.StepBackward[loc.node];
loc.where ← 0;
ENDLOOP
};
ProcessSelection: PUBLIC PROC [forceEOD: BOOLFALSE, defEOD: BOOLTRUE, forwards: BOOL] RETURNS [s: Selection, wasExtended: BOOLFALSE] = {
Analyzes the current selection and returns a selection record that describes it. If forceEOD is true, then the selection record returned always describes a selection from the beginning of the current selection to the end of the document, even if the user only had one word selected. If defEOD is TRUE, then this sort of selection is returned only when the user has a point or single character selection, otherwise the user's actual selection is returned.
selViewer: TiogaOpsDefs.Viewer;
selStart, selEnd: TiogaOpsDefs.Location;
selLevel: TiogaOps.SelectionGrain;
selCaretBefore, selPendingDelete: BOOL;
[selViewer, selStart, selEnd, selLevel, selCaretBefore, selPendingDelete] ← TiogaOps.GetSelection[];
s ← NEW[SelectionRec];
s.viewer ← selViewer;
s.start ← selStart;
s.end ← selEnd;
s.level ← selLevel;
s.caretBefore ← selCaretBefore;
s.pendingDelete ← selPendingDelete;
IF forceEOD OR
(defEOD AND
 (selLevel = point OR ((selLevel = char)
AND (selStart.node = selEnd.node)
AND (selStart.where = selEnd.where)))) THEN {
IF forwards THEN {
s.end.node ← TiogaOps.LastWithin[TiogaOps.Root[s.start.node]];
s.end.where ← (TiogaOps.GetRope[s.end.node]).Size[]-1;
}
ELSE {
s.start.node ← FirstWithin[TiogaOps.Root[s.start.node]];
s.start.where ← 0;
};
CheckMiddleOfWord[s];
wasExtended ← TRUE;
};
};
FirstWithin: PUBLIC PROC [r: TiogaOpsDefs.Ref] RETURNS [first: TiogaOpsDefs.Ref] = {
child: TiogaOpsDefs.Ref;
first ← r;
DO
child ← TiogaOps.FirstSibling[first];
IF child = NIL THEN RETURN;
first ← child;
ENDLOOP;
};
CheckMiddleOfWord: PUBLIC PROC[s: Selection] = {
IF s.start.where > 0 THEN {
r: ROPE ← TiogaOps.GetRope[s.start.node];
IF Ascii.Lower[r.Fetch[s.start.where-1]] IN ['a..'z] THEN
WHILE s.start.where < r.Size[] AND Ascii.Lower[r.Fetch[s.start.where]] IN ['a..'z] DO
s.start.where ← s.start.where + 1;
ENDLOOP;
};
};
}.