<> <> <> <> <> <> 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]}; <> 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] = { <> 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] = { <> 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 ELSE loc.where _ 0; [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] = { <> 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. <<>> <> <<>> <> <> <> <> <> <> <<>>