SpellingToolSharedImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Last Edited by: Nix, December 9, 1983 2:52 pm
Michael Plass, January 23, 1986 2:50:21 pm PST
Rick Beach, May 2, 1985 3:10:55 pm PDT
Spreitzer, February 26, 1985 2:37:59 pm PST
DIRECTORY
Ascii USING [Lower],
Rope USING [Fetch, ROPE, Size, Substr],
SpellingLooks USING [Wordlich],
RunReader USING [BumpIndex, Create, GetIndex, MergedBackwards, MergedGet, Ref, SetPosition],
SpellingToolShared,
SpellingWordMap USING [MapWordsInRope, MapWordsInRopeBackward],
TextLooks USING [CreateRun, Looks, noLooks, Runs, Substr],
TextNode USING [NarrowToTextNode, NodeRuns, Ref, RefTextNode],
TiogaOps USING [FirstSibling, GetRope, GetSelection, GetStyle, LastWithin, Lock, LockSel, NoSelection, Root, SelectionGrain, SelectionRoot, StepBackward, StepForward, Unlock, UnlockSel],
TiogaOpsDefs USING [Location, Ref, Viewer];
SpellingToolSharedImpl: CEDAR MONITOR
IMPORTS Ascii, Rope, RunReader, SpellingLooks, SpellingWordMap, TextLooks, TextNode, TiogaOps
EXPORTS SpellingToolShared
=
BEGIN
OPEN SpellingToolShared;
ROPE: TYPE = Rope.ROPE;
CorrectTiogaOpsCallWithLocks:
PUBLIC
PROC [proc:
PROC [root: TiogaOpsDefs.Ref], root: TiogaOpsDefs.Ref ←
NIL] = {
lockedSel, lockedDoc: BOOL ← FALSE;
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 TEXT ← NEW[TEXT[256]];
GetLooks:
PROC [tiogaOpsNode: TiogaOpsDefs.Ref]
RETURNS [runs: TextLooks.Runs] = {
textNode: TextNode.Ref;
refTextNode: TextNode.RefTextNode;
TRUSTED {textNode ←
LOOPHOLE[tiogaOpsNode]};
We know this is OK because TiogaExtraOpsImpl says (TiogaOpsDefs.)NodeBody = TextNode.Body
refTextNode ← TextNode.NarrowToTextNode[textNode];
runs ← IF refTextNode # NIL THEN TextNode.NodeRuns[refTextNode] ELSE NIL;
};
emptyLooks: TextLooks.Runs ← TextLooks.CreateRun[len: 0];
MapWordsInSelection:
PUBLIC
ENTRY
PROC [start, end: TiogaOpsDefs.Location, f:
PROC [
REF
TEXT]
RETURNS [
BOOL], forwards:
BOOL]
RETURNS [premature:
BOOL ←
FALSE, wordStart, wordEnd: TiogaOpsDefs.Location] = {
Maps the given procedure f over the words in the selection, returning as soon as f returns TRUE.
ENABLE UNWIND => NULL;
loc: TiogaOpsDefs.Location ← IF forwards THEN start ELSE end;
nodeLooksReader: RunReader.Ref ← RunReader.Create[];
MapNode:
PROC [start: TiogaOpsDefs.Location,
endPlusOne: INT,
word: REF TEXT,
f: PROC [REF TEXT] RETURNS [BOOL],
forwards: BOOL]
RETURNS [premature:
BOOL ←
FALSE,
wordStart, wordEnd: TiogaOpsDefs.Location] = {
Maps the given procedure f over the words in a single Tioga node, returning as soon as f returns TRUE.
nodeStyle: ROPE ← TiogaOps.GetStyle[start.node];
nodeRope: ROPE ← TiogaOps.GetRope[start.node];
nodeLooks: TextLooks.Runs ← GetLooks[start.node];
index, size, lowest: INT;
IF endPlusOne = -1 THEN endPlusOne ← LAST[INT];
endPlusOne ← MIN[endPlusOne, nodeRope.Size[]];
IF endPlusOne <= start.where THEN RETURN;
size ← endPlusOne - start.where;
IF ~(start.where = 0
AND endPlusOne = nodeRope.Size[])
THEN {
nodeRope ← nodeRope.Substr[start.where, size];
nodeLooks ← nodeLooks.Substr[start.where, size]};
IF forwards THEN index ← 0 ELSE index ← size;
nodeLooksReader.SetPosition[nodeLooks, index];
SELECT forwards
FROM
TRUE =>
DO
length, next: INT;
rope: ROPE;
looks: TextLooks.Looks ← TextLooks.noLooks;
IF nodeLooksReader.GetIndex[] # index THEN ERROR;
IF index >= size THEN EXIT;
IF nodeLooks #
NIL
THEN [length, looks] ← RunReader.MergedGet[nodeLooksReader]
ELSE {length ← size; nodeLooksReader.BumpIndex[size]};
next ← index + length;
rope ← nodeRope.Substr[lowest ← index, length];
IF SpellingLooks.Wordlich[nodeStyle, looks]
THEN {
[premature, wordStart.where, wordEnd.where, word] ← SpellingWordMap.MapWordsInRope[rope, word, f];
IF premature THEN EXIT};
index ← next;
ENDLOOP;
FALSE =>
DO
length, next: INT;
rope: ROPE;
looks: TextLooks.Looks ← TextLooks.noLooks;
IF nodeLooksReader.GetIndex[] # index THEN ERROR;
IF index <= 0 THEN EXIT;
IF nodeLooks #
NIL
THEN [length, looks] ← RunReader.MergedBackwards[nodeLooksReader]
ELSE {length ← size; nodeLooksReader.BumpIndex[-size]};
next ← index - length;
rope ← nodeRope.Substr[lowest ← next, length];
IF SpellingLooks.Wordlich[nodeStyle, looks]
THEN {
[premature, wordStart.where, wordEnd.where, word] ← SpellingWordMap.MapWordsInRopeBackward[rope, word, f];
IF premature THEN EXIT};
index ← next;
ENDLOOP;
ENDCASE => ERROR;
wordStart.node ← start.node;
wordStart.where ← wordStart.where + lowest + start.where;
wordEnd.node ← start.node;
wordEnd.where ← wordEnd.where + lowest + start.where - 1;
};
IF forwards
THEN
DO
[premature, wordStart, wordEnd] ←
MapNode[loc, IF loc.node = end.node THEN end.where+1 ELSE -1, wordBuffer, f, TRUE];
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
[premature, wordStart, wordEnd] ←
MapNode[loc, IF loc.node = end.node THEN end.where+1 ELSE -1, wordBuffer, f, FALSE];
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:
BOOL ←
FALSE, defEOD:
BOOL ←
TRUE, forwards:
BOOL]
RETURNS [s: Selection, wasExtended:
BOOL ←
FALSE] = {
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;
};
};
END.
CHANGE LOG
Spreitzer, February 26, 1985 1:09:03 pm PST
Added looks rule to definition of `word'.
changes to: DIRECTORY, SpellingToolSharedImpl, GetLooks, MapWordsInSelection
Michael Plass, January 23, 1986 2:50:02 pm PST
Fixed off-by-one bug.
changes to: MapWordsInSelection