<> <> <> <> <> <> <<>> DIRECTORY Buttons USING [Button, ButtonProc, SetDisplayStyle], EditToolBuilder USING [BuildButton, BuildDataFieldPair, BuildLabel, BuildPair, BuildTriple, DataFieldButton, GetDataNode, HGap, ToMiddle, ToNext], EditToolPrivate USING [anywhere, ChangeState, CycleTriple, DoButton, FixPSel, Info, mainToolInfo, nodes, Register, ReportPatternError, SavePSel, words], Labels USING [Set], Menus USING [MenuProc], MessageWindow USING [Append, Blink], NameSymbolTable USING [MakeName], Rope USING [Concat, ROPE], RunReader USING [Backwards, FreeRunReader, Get, GetRunReader, noLooks, Ref, SetPosition], TEditDocument USING [Selection], TEditInput USING [CloseEvent, CommandProc], TEditInputOps USING [ReloadStyleName], TEditOps USING [GetSelData, SetTextContents], TEditSelection USING [LockSel, UnlockSel], Terminal USING [BlinkBWDisplay, Current], TextEdit USING [ChangeStyle, ChangeType, Size], TextFind USING [Finder, MalformedPattern], TextLooks USING [Looks, noLooks, Runs], TextLooksSupport USING [LooksAND], TextNode USING [MaxLen, NarrowToTextNode, Offset, Ref, RefTextNode], TiogaOps USING [CreateGeneralPattern, Finder, Offset, Pattern, Ref, SearchDir, SelectionSearch], TreeFind USING [Finder], ViewerClasses USING [Viewer], ViewerOps USING [CreateViewer], ViewerSpecs USING [openRightWidth], ViewerTools USING [InhibitUserEdits]; EditToolSearchImpl: CEDAR PROGRAM IMPORTS Buttons, EditToolBuilder, EditToolPrivate, Labels, MessageWindow, NameSymbolTable, Rope, RunReader, TEditOps, Terminal, TextEdit, TextFind, TextLooksSupport, TextNode, TEditInput, TEditInputOps, TEditSelection, TiogaOps, ViewerOps, ViewerSpecs, ViewerTools EXPORTS EditToolPrivate = { OPEN EditToolPrivate, EditToolBuilder; searchForwardAtom: LIST OF REF = Register[$SearchForward,SearchForwardOp]; SearchForwardOp: TEditInput.CommandProc = { Search[forwards,mainToolInfo] }; searchAnywhereAtom: LIST OF REF = Register[$SearchAnywhere,SearchAnywhereOp]; SearchAnywhereOp: TEditInput.CommandProc = { Search[anywhere,mainToolInfo] }; searchBackwardsAtom: LIST OF REF = Register[$SearchBackwards,SearchBackwardsOp]; SearchBackwardsOp: TEditInput.CommandProc = { Search[backwards,mainToolInfo] }; DoSearchMenuButton: PUBLIC Menus.MenuProc = { SELECT mouseButton FROM red => DoButton[searchForwardAtom]; yellow => DoButton[searchAnywhereAtom]; blue => DoButton[searchBackwardsAtom]; ENDCASE => ERROR; }; CheckPSel: PUBLIC PROC [pSel: TEditDocument.Selection, typescriptOK: BOOL _ TRUE] RETURNS [ok: BOOLEAN] = { OPEN MessageWindow; IF pSel#NIL AND pSel.viewer#NIL AND (pSel.viewer.class.flavor=$Text OR (typescriptOK AND pSel.viewer.class.flavor=$Typescript)) THEN RETURN [TRUE]; Append["Please make a text selection.",TRUE]; Blink[]; RETURN [FALSE] }; GetPatternNode: PUBLIC PROC [info: Info] RETURNS [pattern: TextNode.RefTextNode] = { OPEN info; IF ((pattern _ GetDataNode[targetArg])=NIL OR TextEdit.Size[pattern]=0) AND (~ignoreLooks OR ~ignoreText) THEN { OPEN MessageWindow; Append["Please enter a search pattern in the \"target\" field.",TRUE]; Blink[]; RETURN [NIL] }}; Search: PUBLIC PROC [whichDir: TiogaOps.SearchDir, info: Info] = TRUSTED { IF ~TrySearch[whichDir, info] THEN { MessageWindow.Append["Not found.", TRUE]; Terminal.BlinkBWDisplay[Terminal.Current[]]; RETURN }}; TrySearch: PUBLIC PROC [whichDir: TiogaOps.SearchDir, info: Info] RETURNS [found: BOOL] = { OPEN info; where, pattern: TextNode.RefTextNode; pSel: TEditDocument.Selection; searchPattern: TiogaOps.Pattern; IF ignoreText AND ignoreLooks AND ignoreType AND ignoreStyle AND ignoreComment THEN { OPEN MessageWindow; Append["Pick one or more of text/looks/format/style/comment to match.", TRUE]; Blink[]; RETURN }; TEditSelection.LockSel[primary, "TrySearch"]; FixPSel; pSel _ TEditOps.GetSelData[]; IF ~CheckPSel[pSel] OR (pattern _ GetPatternNode[info])=NIL THEN { TEditSelection.UnlockSel[primary]; RETURN }; TRUSTED {searchPattern _ TiogaOps.CreateGeneralPattern[LOOPHOLE[pattern], ~ignoreText, ~ignoreLooks, ~ignoreType, ~ignoreStyle, ~ignoreComment, ~ignoreCase, literal, searchWhere=words, ~looksExact, searchWhere=nodes ! TextFind.MalformedPattern => { ReportPatternError[ec]; GOTO Quit }]}; TRUSTED {finder _ LOOPHOLE[searchPattern.finder, TreeFind.Finder]}; -- need to save this for named subpatterns found _ TiogaOps.SelectionSearch[searchPattern, whichDir, interrupt]; IF ~found THEN GOTO Quit; TEditInput.CloseEvent; where _ TextNode.NarrowToTextNode[pSel.start.pos.node]; varRope _ where.rope; varRuns _ where.runs; -- save in case need for Replace with subpatterns GOTO Quit; EXITS Quit => { TEditSelection.UnlockSel[primary]; RETURN }; }; Extend: PUBLIC PROC [info: Info, forward: BOOLEAN, searchLooks: TextLooks.Looks, where: TextNode.RefTextNode, at, atEnd: TextNode.Offset, last: TextNode.Ref _ NIL, lastLen: TextNode.Offset _ TextNode.MaxLen] RETURNS [newAt, newAtEnd: TextNode.Offset] = { OPEN info; runrdr: RunReader.Ref _ RunReader.GetRunReader[]; looks: TextLooks.Looks; runLen: TextNode.Offset; runs: TextLooks.Runs _ where.runs; IF forward THEN { -- extend toward end of node size: TextNode.Offset _ TextEdit.Size[where]; IF atEnd=size OR size=0 THEN RETURN [at,atEnd]; lastLen _ IF where=last THEN MIN[size,lastLen] ELSE size; RunReader.SetPosition[runrdr,runs,atEnd]; WHILE atEnd < lastLen DO IF runs=NIL THEN { runLen _ size-atEnd; looks _ TextLooks.noLooks } ELSE [runLen,looks] _ RunReader.Get[runrdr]; IF ~looksExact THEN looks _ TextLooksSupport.LooksAND[looks,searchLooks]; IF searchLooks # looks THEN EXIT; atEnd _ atEnd+runLen; ENDLOOP; RunReader.FreeRunReader[runrdr]; RETURN [at,MIN[atEnd,lastLen]] }; IF at=0 THEN RETURN [at,atEnd]; RunReader.SetPosition[runrdr,runs,at]; WHILE at > 0 DO IF runs=NIL THEN { runLen _ at; looks _ TextLooks.noLooks } ELSE [runLen,looks] _ RunReader.Backwards[runrdr]; IF ~looksExact THEN looks _ TextLooksSupport.LooksAND[looks,searchLooks]; IF searchLooks # looks THEN EXIT; at _ at-runLen; ENDLOOP; RunReader.FreeRunReader[runrdr]; RETURN [at,atEnd] }; ---------------------------- BuildSearchButtons: PUBLIC PROC [info: Info] = { BuildSearchChoiceEntries[info]; ToNext[info.layout]; BuildCaseEntry[info]; ToMiddle[info.layout]; BuildWhereEntry[info]; ToNext[info.layout]; BuildLitOrPatternEntry[info]; ToMiddle[info.layout]; BuildLooksMatchEntry[info]; }; ---------------------------- equalLooks: Rope.ROPE = "Equal as Looks Test"; subsetLooks: Rope.ROPE = "Subset as Looks Test"; equalLooksAtom: LIST OF REF = Register[$EqualLooksTest,EqualLooksTestOp]; subsetLooksAtom: LIST OF REF = Register[$SubsetLooksTest,SubsetLooksTestOp]; LooksMatchButton: Buttons.ButtonProc = { ChangeState[mainToolInfo.looksExact, equalLooksAtom,subsetLooksAtom] }; EqualLooksTestOp: TEditInput.CommandProc = { EqualLooksTest[mainToolInfo] }; EqualLooksTest: PROC [info: Info] = { OPEN info; looksExact _ TRUE; Labels.Set[looksMatchLabel,equalLooks] }; SubsetLooksTestOp: TEditInput.CommandProc = { SubsetLooksTest[mainToolInfo] }; SubsetLooksTest: PROC [info: Info] = { OPEN info; looksExact _ FALSE; Labels.Set[looksMatchLabel,subsetLooks] }; BuildLooksMatchEntry: PROC [info: Info] = { OPEN info; looksExact _ FALSE; [looksMatchLabel,] _ BuildPair[layout,LooksMatchButton,looksExact,equalLooks,subsetLooks,info] }; ---------------------------- BuildSearchChoiceEntries: PROC [info: Info] = { OPEN info; [] _ BuildLabel[layout, "Pick one or more: "]; HGap[layout]; textButton _ BuildButton[layout, "Text", MatchTextButton, info, FALSE, FALSE]; SetButton[textButton, ignoreText _ FALSE, FALSE]; looksButton _ BuildButton[layout, "Looks", MatchLooksButton, info, FALSE, FALSE]; SetButton[looksButton, ignoreLooks _ TRUE, FALSE]; typeButton _ BuildButton[layout, "Format", MatchFormatButton, info, FALSE, FALSE]; SetButton[typeButton, ignoreType _ TRUE, FALSE]; styleButton _ BuildButton[layout, "Style", MatchStyleButton, info, FALSE, FALSE]; SetButton[styleButton, ignoreStyle _ TRUE, FALSE]; commentButton _ BuildButton[layout, "Comment", MatchCommentButton, info, FALSE, FALSE]; SetButton[commentButton, ignoreComment _ TRUE, FALSE]; }; SetButton: PROC [viewer: Buttons.Button, ignore: BOOLEAN, paint: BOOLEAN _ TRUE] = { Buttons.SetDisplayStyle[viewer, IF ignore THEN $BlackOnWhite ELSE $WhiteOnBlack, paint] }; ---------------------------- matchTextAtom: LIST OF REF = Register[$MatchText,MatchTextOp]; ignoreTextAtom: LIST OF REF = Register[$IgnoreText,IgnoreTextOp]; MatchTextButton: Buttons.ButtonProc = { ChangeState[mainToolInfo.ignoreText, ignoreTextAtom,matchTextAtom] }; MatchTextOp: TEditInput.CommandProc = { MatchText[mainToolInfo] }; MatchText: PROC [info: Info] = { OPEN info; SetButton[textButton, ignoreText _ FALSE] }; IgnoreTextOp: TEditInput.CommandProc = { IgnoreText[mainToolInfo] }; IgnoreText: PROC [info: Info] = { OPEN info; SetButton[textButton, ignoreText _ TRUE] }; ---------------------------- matchLooksAtom: LIST OF REF = Register[$MatchLooks,MatchLooksOp]; ignoreLooksAtom: LIST OF REF = Register[$IgnoreLooks,IgnoreLooksOp]; MatchLooksButton: Buttons.ButtonProc = { ChangeState[mainToolInfo.ignoreLooks, ignoreLooksAtom,matchLooksAtom] }; MatchLooksOp: TEditInput.CommandProc = { MatchLooks[mainToolInfo] }; MatchLooks: PROC [info: Info] = { OPEN info; SetButton[looksButton, ignoreLooks _ FALSE] }; IgnoreLooksOp: TEditInput.CommandProc = { IgnoreLooks[mainToolInfo] }; IgnoreLooks: PROC [info: Info] = { OPEN info; SetButton[looksButton, ignoreLooks _ TRUE] }; ---------------------------- matchFormatAtom: LIST OF REF = Register[$MatchFormat,MatchFormatOp]; ignoreFormatAtom: LIST OF REF = Register[$IgnoreFormat,IgnoreFormatOp]; MatchFormatButton: Buttons.ButtonProc = { ChangeState[mainToolInfo.ignoreType, ignoreFormatAtom,matchFormatAtom] }; MatchFormatOp: TEditInput.CommandProc = { MatchFormat[mainToolInfo] }; MatchFormat: PROC [info: Info] = { OPEN info; SetButton[typeButton, ignoreType _ FALSE] }; IgnoreFormatOp: TEditInput.CommandProc = { IgnoreFormat[mainToolInfo] }; IgnoreFormat: PROC [info: Info] = { OPEN info; SetButton[typeButton, ignoreType _ TRUE] }; ---------------------------- matchStyleAtom: LIST OF REF = Register[$MatchStyle,MatchStyleOp]; ignoreStyleAtom: LIST OF REF = Register[$IgnoreStyle,IgnoreStyleOp]; MatchStyleButton: Buttons.ButtonProc = { ChangeState[mainToolInfo.ignoreStyle, ignoreStyleAtom,matchStyleAtom] }; MatchStyleOp: TEditInput.CommandProc = { MatchStyle[mainToolInfo] }; MatchStyle: PROC [info: Info] = { OPEN info; SetButton[styleButton, ignoreStyle _ FALSE] }; IgnoreStyleOp: TEditInput.CommandProc = { IgnoreStyle[mainToolInfo] }; IgnoreStyle: PROC [info: Info] = { OPEN info; SetButton[styleButton, ignoreStyle _ TRUE] }; ---------------------------- matchCommentAtom: LIST OF REF = Register[$MatchComment,MatchCommentOp]; ignoreCommentAtom: LIST OF REF = Register[$IgnoreComment,IgnoreCommentOp]; MatchCommentButton: Buttons.ButtonProc = { ChangeState[mainToolInfo.ignoreComment, ignoreCommentAtom,matchCommentAtom] }; MatchCommentOp: TEditInput.CommandProc = { MatchComment[mainToolInfo] }; MatchComment: PROC [info: Info] = { OPEN info; SetButton[commentButton, ignoreComment _ FALSE] }; IgnoreCommentOp: TEditInput.CommandProc = { IgnoreComment[mainToolInfo] }; IgnoreComment: PROC [info: Info] = { OPEN info; SetButton[commentButton, ignoreComment _ TRUE] }; ---------------------------- matchingLiterally: Rope.ROPE = "Match Literally"; matchingAsPattern: Rope.ROPE = "Match as Pattern"; matchLitAtom: LIST OF REF = Register[$MatchLiterally,MatchLitOp]; matchPatternAtom: LIST OF REF = Register[$MatchPattern,MatchPatternOp]; LiteralButton: Buttons.ButtonProc = { ChangeState[mainToolInfo.literal, matchLitAtom,matchPatternAtom] }; MatchLitOp: TEditInput.CommandProc = { MatchLit[mainToolInfo] }; MatchLit: PROC [info: Info] = { OPEN info; literal _ TRUE; Labels.Set[literalLabel,matchingLiterally] }; MatchPatternOp: TEditInput.CommandProc = { MatchPattern[mainToolInfo] }; MatchPattern: PROC [info: Info] = { OPEN info; literal _ FALSE; Labels.Set[literalLabel,matchingAsPattern] }; BuildLitOrPatternEntry: PROC [info: Info] = { OPEN info; literal _ TRUE; [literalLabel,] _ BuildPair[layout,LiteralButton,literal,matchingLiterally,matchingAsPattern,info] }; ---------------------------- numDocRopes: NAT = 18; docRopes: REF ARRAY [0..numDocRopes) OF Rope.ROPE _ NEW[ARRAY [0..numDocRopes) OF Rope.ROPE]; BuildPatternDocEntry: PUBLIC PROC [info: Info] = { OPEN info.layout; lines: CARDINAL = 25; rope: Rope.ROPE; arg: ViewerClasses.Viewer _ ViewerOps.CreateViewer[flavor: $Text, info: [parent: container, border: FALSE, scrollable: TRUE, wx: entryLeft, wy: heightSoFar, ww: ViewerSpecs.openRightWidth-entryLeft-5, wh: entryHeight*lines], paint: FALSE]; heightSoFar _ heightSoFar + entryHeight*lines; FOR i:NAT IN [0..numDocRopes) DO rope _ Rope.Concat[rope, docRopes[i]]; ENDLOOP; TEditOps.SetTextContents[arg, rope] }; numMiniDocRopes: NAT = 4; miniDocRopes: REF ARRAY [0..numMiniDocRopes) OF Rope.ROPE _ NEW[ARRAY [0..numMiniDocRopes) OF Rope.ROPE]; BuildMiniPatternDocEntry: PUBLIC PROC [info: Info] = { OPEN info.layout; lines: CARDINAL = 3; rope: Rope.ROPE; where: TextNode.RefTextNode; height: CARDINAL = numMiniDocRopes*10+3; arg: ViewerClasses.Viewer _ ViewerOps.CreateViewer[flavor: $Text, info: [parent: container, wx: entryLeft, wy: heightSoFar, ww: ViewerSpecs.openRightWidth-entryLeft-5, wh: height, border: FALSE, scrollable: FALSE], paint: FALSE]; heightSoFar _ heightSoFar + height; FOR i:NAT IN [0..numMiniDocRopes) DO rope _ Rope.Concat[rope, miniDocRopes[i]]; ENDLOOP; TEditOps.SetTextContents[arg, rope]; where _ GetDataNode[arg]; TextEdit.ChangeStyle[where,"EditTool"]; TEditInputOps.ReloadStyleName["EditTool"]; TextEdit.ChangeType[where,NameSymbolTable.MakeName["mini"]]; ViewerTools.InhibitUserEdits[arg]; }; ---------------------------- ignoringCase: Rope.ROPE = "Ignore Case"; matchingCase: Rope.ROPE = "Match Case"; ignoreCaseAtom: LIST OF REF = Register[$IgnoreCase,IgnoreCaseOp]; matchCaseAtom: LIST OF REF = Register[$MatchCase,MatchCaseOp]; CaseButton: Buttons.ButtonProc = { ChangeState[mainToolInfo.ignoreCase, ignoreCaseAtom,matchCaseAtom] }; IgnoreCaseOp: TEditInput.CommandProc = { IgnoreCase[mainToolInfo] }; IgnoreCase: PROC [info: Info] = { OPEN info; ignoreCase _ TRUE; Labels.Set[caseLabel,ignoringCase] }; MatchCaseOp: TEditInput.CommandProc = { MatchCase[mainToolInfo] }; MatchCase: PROC [info: Info] = { OPEN info; ignoreCase _ FALSE; Labels.Set[caseLabel,matchingCase] }; BuildCaseEntry: PROC [info: Info] = { OPEN info; ignoreCase _ FALSE; [caseLabel,] _ BuildPair[layout,CaseButton,ignoreCase,ignoringCase,matchingCase,info] }; ---------------------------- matchingWords: Rope.ROPE = "Match Words Only"; matchingAnywhere: Rope.ROPE = "Match Anywhere"; matchingNodes: Rope.ROPE = "Match Entire Nodes Only"; matchWordsAtom: LIST OF REF = Register[$MatchWords,MatchWordsOp]; matchAnywhereAtom: LIST OF REF = Register[$MatchAnywhere,MatchAnywhereOp]; matchNodesAtom: LIST OF REF = Register[$MatchNodes,MatchNodesOp]; WhereButton: Buttons.ButtonProc = { CycleTriple[mainToolInfo.searchWhere, matchAnywhereAtom,matchWordsAtom,matchNodesAtom] }; MatchWordsOp: TEditInput.CommandProc = { MatchWords[mainToolInfo] }; MatchWords: PROC [info: Info] = { OPEN info; searchWhere _ words; Labels.Set[wordLabel,matchingWords] }; MatchNodesOp: TEditInput.CommandProc = { MatchNodes[mainToolInfo] }; MatchNodes: PROC [info: Info] = { OPEN info; searchWhere _ nodes; Labels.Set[wordLabel,matchingNodes] }; MatchAnywhereOp: TEditInput.CommandProc = { MatchAnywhere[mainToolInfo] }; MatchAnywhere: PROC [info: Info] = { OPEN info; searchWhere _ anywhere; Labels.Set[wordLabel,matchingAnywhere] }; BuildWhereEntry: PROC [info: Info] = { OPEN info; searchWhere _ anywhere; [wordLabel,] _ BuildTriple[layout,WhereButton, searchWhere,matchingAnywhere,matchingWords,matchingNodes,info] }; ---------------------------- targetArgAtom: LIST OF REF = Register[$SearchFor,TargetArgOp]; clearTargetArgAtom: LIST OF REF = Register[$ClearSearchFor,ClearTargetArgOp]; TargetButton: Buttons.ButtonProc = { DoButton[targetArgAtom, clearTargetArgAtom, mouseButton=red] }; TargetArgOp: TEditInput.CommandProc = { TargetArg[mainToolInfo] }; TargetArg: PROC [info: Info] = { SavePSel; DataFieldButton[info.targetArg,FALSE] }; ClearTargetArgOp: TEditInput.CommandProc = { ClearTargetArg[mainToolInfo] }; ClearTargetArg: PROC [info: Info] = { SavePSel; DataFieldButton[info.targetArg,TRUE] }; BuildTargetEntry: PUBLIC PROC [info: Info] = { OPEN info; [,targetArg] _ BuildDataFieldPair[layout, "Target:", TargetButton, info, 2] }; ---------------------------- docRopes[0] _ "The following special symbols may be used in search patterns: "; docRopes[1] _ " ' Match the next character in the pattern exactly. "; docRopes[2] _ " ~ Match any character except the next one in the pattern. "; docRopes[3] _ " # Match any single character. "; docRopes[4] _ " * Match any sequence of characters. "; docRopes[5] _ " @ Match any single alphanumeric character (letter or digit). "; docRopes[6] _ " & Match any sequence of alphanumeric characters. "; docRopes[7] _ " ~@ Match any single non-alphanumeric character. "; docRopes[8] _ " ~& Match any sequence of non-alphanumeric characters. "; docRopes[9] _ " % Match any single blank character. "; docRopes[10] _ " $ Match any sequence of blank characters. "; docRopes[11] _ " ~% Match any single non-blank character. "; docRopes[12] _ " ~$ Match any sequence of non-blank characters. "; docRopes[13] _ " | Match start or end of node. "; docRopes[14] _ " { Mark start of resulting selection. "; docRopes[15] _ " } Mark end of resulting selection. "; docRopes[16] _ " < Mark start of named subpattern. "; docRopes[17] _ " > Mark end of named subpattern. "; miniDocRopes[0] _ "single character: # any; @ alpha; ~@ nonalpha; % blank; ~% nonblank; "; miniDocRopes[1] _ "min sequence: * any; & alpha; ~& nonalpha; $ blank; ~$ nonblank; "; miniDocRopes[2] _ "max sequence: ** any; && alpha; ~&~& nonalpha; $$ blank; ~$~$ nonblank; "; miniDocRopes[3] _ "miscellaneous: 'x = use \"x\"; ~x = not x; { } bounds selection; < > named subpattern "; }...