<> <> <> <> <> <> <> <<>> DIRECTORY Rope USING [ROPE], TextEdit USING [Size], TextFind USING [Create, CreateFromRope, Finder, Try, TryBackwards], TextLooks USING [], TextNode USING [Backward, Offset, Ref, RefTextNode, StepForward], TreeFind USING [ApplyProc, CommentControl]; TreeFindImpl: CEDAR PROGRAM IMPORTS TextFind, TextNode, TextEdit EXPORTS TreeFind = BEGIN OPEN TreeFind; Finder: TYPE ~ TextFind.Finder; ROPE: TYPE = Rope.ROPE; RefTextNode: TYPE = TextNode.RefTextNode; Create: PUBLIC PROC [ pattern: TextNode.RefTextNode, literal, word, ignoreLooks, ignoreCase, addBounds: BOOL _ FALSE, patternStart: INT _ 0, patternLen: INT _ LAST[INT]] RETURNS [Finder] = { RETURN [TextFind.Create[ pattern, literal, word, ignoreLooks, ignoreCase, addBounds, patternStart, patternLen]] }; CreateFromRope: PUBLIC PROC [pattern: ROPE, literal, word, ignoreCase, addBounds: BOOL _ FALSE, patternStart: INT _ 0, patternLen: INT _ LAST[INT]] RETURNS [Finder] = { RETURN [ TextFind.CreateFromRope[pattern, literal, word, ignoreCase, addBounds, patternStart, patternLen] ] }; Try: PUBLIC PROC [ finder: Finder, first: TextNode.Ref, start: TextNode.Offset _ 0, last: TextNode.Ref _ NIL, lastLen: TextNode.Offset _ LAST[INT], looksExact: BOOLEAN _ FALSE, commentControl: CommentControl _ includeComments, checkFormat: BOOLEAN _ FALSE, format: ATOM _ NIL, checkStyle: BOOLEAN _ FALSE, style: ATOM _ NIL, styleProc: PROC [TextNode.Ref] RETURNS [ATOM] _ NIL, interrupt: REF BOOL _ NIL] RETURNS [found: BOOLEAN, where: TextNode.RefTextNode, at, atEnd, before, after: TextNode.Offset] = { node: TextNode.Ref; found _ FALSE; IF (node _ first)=NIL THEN RETURN; DO -- test new node each time through the loop IF checkFormat AND node.formatName # format THEN NULL ELSE IF checkStyle AND styleProc[node] # style THEN NULL ELSE { IF (SELECT commentControl FROM excludeComments => ~node.comment, commentsOnly => node.comment, ENDCASE => TRUE) THEN { IF finder # NIL THEN [found, at, atEnd, before, after] _ TextFind.Try[finder, node, start, IF node=last THEN lastLen-start ELSE LAST[INT], looksExact, interrupt] ELSE { found _ TRUE; at _ before _ 0; atEnd _ after _ TextEdit.Size[node]; }; IF found THEN { where _ node; RETURN }; }; }; <> start _ 0; IF node=last THEN RETURN; IF (node _ TextNode.StepForward[node])=NIL THEN RETURN; ENDLOOP }; TryBackwards: PUBLIC PROC [ finder: TextFind.Finder, first: TextNode.Ref, len: TextNode.Offset _ LAST[INT], last: TextNode.Ref _ NIL, lastStart: TextNode.Offset _ 0, looksExact: BOOLEAN _ FALSE, commentControl: CommentControl _ includeComments, checkFormat: BOOLEAN _ FALSE, format: ATOM _ NIL, checkStyle: BOOLEAN _ FALSE, style: ATOM _ NIL, styleProc: PROC [TextNode.Ref] RETURNS [ATOM] _ NIL, interrupt: REF BOOL _ NIL] RETURNS [found: BOOLEAN, where: TextNode.RefTextNode, at, atEnd, before, after: TextNode.Offset] = { node, parent: TextNode.Ref; found _ FALSE; IF (node _ first)=NIL THEN RETURN; DO -- test new node each time through the loop IF checkFormat AND node.formatName # format THEN NULL ELSE IF checkStyle AND styleProc[node] # style THEN NULL ELSE { IF (SELECT commentControl FROM excludeComments => ~node.comment, commentsOnly => node.comment, ENDCASE => TRUE) THEN { IF finder # NIL THEN [found, at, atEnd, before, after] _ TextFind.TryBackwards[finder, node, IF node=last THEN lastStart ELSE 0, len, looksExact, interrupt] ELSE { found _ TRUE; at _ before _ 0; atEnd _ after _ TextEdit.Size[node]; }; IF found THEN { where _ node; RETURN } }; }; <> len _ LAST[INT]; IF node=last THEN RETURN; [node, parent] _ TextNode.Backward[node, parent]; IF node=NIL THEN RETURN; ENDLOOP }; Apply: PUBLIC PROC [ finder: Finder, first: TextNode.Ref, proc: ApplyProc, start: TextNode.Offset _ 0, last: TextNode.Ref _ NIL, lastLen: TextNode.Offset _ LAST[INT], looksExact: BOOLEAN _ FALSE, commentControl: CommentControl _ includeComments, checkFormat: BOOLEAN _ FALSE, format: ATOM _ NIL, checkStyle: BOOLEAN _ FALSE, style: ATOM _ NIL, styleProc: PROC [TextNode.Ref] RETURNS [ATOM] _ NIL] RETURNS [count: LONG INTEGER] = { where: TextNode.RefTextNode; node: TextNode.Ref; at, atEnd, before, after, from, delta: TextNode.Offset; found, continue, bumpCount: BOOLEAN; count _ 0; node _ first; UNTIL node=NIL DO IF node=last AND start >= lastLen THEN RETURN; [found, where, at, atEnd, before, after] _ Try[finder, node, start, last, lastLen, looksExact, commentControl, checkFormat, format, checkStyle, style, styleProc]; IF ~found THEN RETURN; [continue, bumpCount, from, delta] _ proc[where, at, atEnd, before, after]; IF bumpCount THEN count _ count+1; IF ~continue THEN RETURN; IF where=last AND lastLen < LAST[INT] THEN lastLen _ lastLen+delta; IF finder # NIL THEN { node _ where; start _ from } ELSE { node _ TextNode.StepForward[node]; start _ 0 }; ENDLOOP }; END.