<> <> 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: 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]]; MapWordsInSelection: PUBLIC ENTRY PROC [start, end: TiogaOpsDefs.Location, f: PROC [REF TEXT] RETURNS [BOOL], forwards: BOOL] RETURNS [premature: BOOL _ FALSE, wordStart, wordEnd: TiogaOpsDefs.Location] = { <> <<>> 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: BOOL _ FALSE, wordStart, wordEnd: TiogaOpsDefs.Location] = { <> 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: BOOL _ FALSE, wordStart, wordEnd: TiogaOpsDefs.Location] = { <> 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: BOOL _ FALSE, defEOD: BOOL _ TRUE, forwards: BOOL] RETURNS [s: Selection, wasExtended: BOOL _ FALSE] = { <> 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; }; }; }.