<<>> <> <> <> <> <> <> <<>> DIRECTORY Atom USING [GetProp], Buttons USING [Button, ButtonProc, SetDisplayStyle, ReLabel], EditToolBuilder USING [BuildButton, BuildDataFieldPair, BuildLabel, BuildPair, BuildTriple, DataFieldButton, GetDataNode, HGap, ToMiddle, ToNext], EditToolPrivate USING [ChangeState, CycleTriple, DoButton, FixPSel, Info, Pattern, PatternRep, mainToolInfo, editTool, Register, SavePSel, SearchDir, SearchWhere], IO USING [PutFR, rope, int], Labels USING [Set], Menus USING [Menu, MenuProc, MenuEntry, FindEntry, CopyEntry, SetClientData], MessageWindow USING [Append, Clear], NodeProps USING [DoSpecs], NodeStyleOps USING [StyleNameForNode], Rope USING [Concat, ROPE], TEditDocument USING [Selection], TEditInput USING [CloseEvent, CommandProc], TEditInputOps USING [CallWithLocks], TEditOps USING [GetSelData, RememberCurrentPosition, SetTextContents], TEditProfile USING [selectionCaret], TEditRefresh USING [ScrollToEndOfSel], TEditSelection USING [LockSel, UnlockSel, MakeSelection, SetSelLooks], TextEdit, TextFind, TextNode USING [Root, FirstChild], Tioga USING [Node, Location, Looks, noLooks], TiogaFind USING [TargetFromNode, Search, Match], ViewerClasses USING [Viewer], ViewerOps USING [AddProp, BlinkDisplay, CreateViewer], ViewerSpecs USING [openRightWidth], ViewerTools USING [InhibitUserEdits]; EditToolSearchImpl: CEDAR PROGRAM IMPORTS Atom, Buttons, EditToolBuilder, EditToolPrivate, IO, Labels, MessageWindow, Menus, NodeProps, NodeStyleOps, Rope, TEditOps, TextEdit, TextFind, TextNode, TEditInput, TEditInputOps, TEditProfile, TEditRefresh, TEditSelection, TiogaFind, ViewerOps, ViewerSpecs, ViewerTools EXPORTS EditToolPrivate = BEGIN OPEN EditToolPrivate, EditToolBuilder; ROPE: TYPE ~ Rope.ROPE; Node: TYPE ~ Tioga.Node; Location: TYPE ~ Tioga.Location; Report: PROC [msg: Rope.ROPE, blink: BOOL _ TRUE] ~ { IF msg=NIL THEN MessageWindow.Clear[] ELSE { MessageWindow.Append[msg, TRUE]; IF blink THEN ViewerOps.BlinkDisplay[]; }; }; 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: BOOL] = { IF pSel#NIL AND pSel.viewer#NIL AND (pSel.viewer.class.flavor=$Text OR (typescriptOK AND pSel.viewer.class.flavor=$Typescript)) THEN RETURN [TRUE]; Report["Please make a text selection."]; RETURN [FALSE]; }; Search: PUBLIC PROC [whichDir: SearchDir, info: Info] = { found: BOOL ~ TrySearch[whichDir, info]; Report[IF found THEN NIL ELSE "Not found.", TRUE]; }; TrySearch: PUBLIC PROC [whichDir: SearchDir, info: Info] RETURNS [found: BOOL ¬ FALSE] = { IF info.ignoreText AND info.ignoreLooks AND info.ignoreFormat AND info.ignoreStyle AND info.ignoreComment THEN { Report["Pick one or more of text/looks/format/style/comment to match."]; RETURN; }; TEditSelection.LockSel[primary, "TrySearch"]; { ENABLE UNWIND => TEditSelection.UnlockSel[primary]; pSel: TEditDocument.Selection ¬ NIL; pattern: Pattern ¬ NIL; FixPSel[]; pSel ¬ TEditOps.GetSelData[]; IF ~CheckPSel[pSel] OR (pattern ¬ GetPattern[info])=NIL THEN GOTO Quit; [found, info.subs] ¬ DoSearch[whichDir: whichDir, pattern: pattern, interrupt: info.interrupt]; <<>> IF found THEN { <> cmdPtr: REF ANY ¬ Atom.GetProp[$CafeteriaTrayRegistryAtom, $EditToolAddToTray]; IF cmdPtr # NIL THEN { EditToolAddInterfaceProc: TYPE = PROC [operation: ATOM, opList: Rope.ROPE ¬ NIL]; -- same as EditToolCafeteria.EditToolAddInterfaceProc addProcPtr: REF EditToolAddInterfaceProc ¬ NARROW[cmdPtr, REF EditToolAddInterfaceProc]; addProcPtr[$DoSearch]; }; }; EXITS Quit => {}; }; TEditSelection.UnlockSel[primary]; }; matchFromWhere: ARRAY SearchWhere OF TiogaFind.Match ~ [anywhere: any, words: word, nodes: all]; GetPattern: PUBLIC PROC [info: EditToolPrivate.Info] RETURNS [Pattern] ~ { node: Node ~ GetDataNode[info.targetArg]; nodeSize: INT ~ TextEdit.Size[node]; checkText: BOOL ~ NOT info.ignoreText; checkLooks: BOOL ~ NOT info.ignoreLooks; checkComment: BOOL ~ NOT info.ignoreComment; checkFormat: BOOL ~ NOT info.ignoreFormat; checkStyle: BOOL ~ NOT info.ignoreStyle; target: TextFind.Target ¬ NIL; comment: BOOL ¬ FALSE; format: ATOM ¬ NIL; style: ATOM ¬ NIL; IF nodeSize=0 AND (checkText OR checkLooks) THEN { Report["Please enter a search pattern in the \"Target:\" field."]; RETURN[NIL]; }; IF checkText THEN { error: ROPE ¬ NIL; target ¬ TiogaFind.TargetFromNode[node: node, pattern: NOT info.literal ! TextFind.Error => { error ¬ IO.PutFR["Error: %g, at position %g.", IO.rope[reason], IO.int[index]]; CONTINUE }]; IF error#NIL THEN { Report[error]; RETURN[NIL] }; } ELSE IF checkLooks THEN { patternNode: Node ~ TextEdit.FromRope["**#**"]; patternLooks: Tioga.Looks ¬ Tioga.noLooks; FOR i: INT IN [0..nodeSize) DO looks: Tioga.Looks ~ TextEdit.FetchLooks[node, i]; IF i=0 THEN patternLooks ¬ looks ELSE IF looks#patternLooks THEN { Report["Search pattern has nonuniform looks; using looks from first char."]; EXIT; }; ENDLOOP; TextEdit.ChangeLooks[root: NIL, text: patternNode, add: patternLooks]; target ¬ TiogaFind.TargetFromNode[node: patternNode, pattern: TRUE]; }; IF node#NIL THEN { IF checkComment THEN comment ¬ TextEdit.GetComment[node]; IF checkFormat THEN format ¬ TextEdit.GetFormat[node]; IF checkStyle THEN style ¬ NodeStyleOps.StyleNameForNode[node]; }; RETURN[NEW[PatternRep ¬ [target: target, case: NOT info.ignoreCase, match: matchFromWhere[info.searchWhere], checkLooks: checkLooks, looksExact: info.looksExact, checkComment: checkComment, comment: comment, checkFormat: checkFormat, format: format, checkStyle: checkStyle, style: style]]]; }; DoSearch: PROC [whichDir: SearchDir, pattern: Pattern, interrupt: REF BOOL] RETURNS [found: BOOL ¬ FALSE, subs: TextFind.Subs ¬ NIL] ~ { DoSearchLocked: PROC [root: Node, tSel: TEditDocument.Selection] = { where: Node ¬ NIL; at, atEnd: INT ¬ 0; Try: PROC [dir: TextFind.Direction, loc1, loc2: Location] ~ { pat: Pattern ~ pattern; [node: where, matchStart: at, matchEnd: atEnd, subs: subs] ¬ TiogaFind.Search[ direction: dir, loc1: loc1, loc2: loc2, target: pat.target, case: pat.case, match: pat.match, checkLooks: pat.checkLooks, looksExact: pat.looksExact, checkComment: pat.checkComment, comment: pat.comment, checkFormat: pat.checkFormat, format: pat.format, checkStyle: pat.checkStyle, style: pat.style, styleProc: NodeStyleOps.StyleNameForNode, interrupt: interrupt]; }; first: Location ~ [TextNode.FirstChild[root], 0]; loc1: Location ¬ tSel.start.pos; loc2: Location ¬ tSel.end.pos; loc1.where ¬ MIN[MAX[0, loc1.where], TextEdit.Size[loc1.node]]; loc2.where ¬ MIN[MAX[0, loc2.where+1], TextEdit.Size[loc2.node]]; IF interrupt#NIL THEN interrupt­ ¬ FALSE; IF whichDir=backwards THEN Try[backward, first, loc1] ELSE Try[forward, loc2, [NIL, 0]]; IF where=NIL AND whichDir=anywhere AND NOT(interrupt#NIL AND interrupt­) THEN Try[forward, first, [NIL, 0]]; IF where=NIL THEN RETURN ELSE found ¬ TRUE; tSel.start.pos ¬ [where, at]; tSel.end.pos ¬ [where, MAX[0,atEnd-1]]; tSel.granularity ¬ IF pattern.target=NIL OR pattern.match=all THEN node ELSE IF pattern.match=word THEN word ELSE char; tSel.insertion ¬ IF TEditProfile.selectionCaret=before THEN before ELSE after; TEditOps.RememberCurrentPosition[tSel.viewer]; TEditSelection.SetSelLooks[tSel]; TEditSelection.MakeSelection[new: tSel]; TEditInput.CloseEvent[]; TEditRefresh.ScrollToEndOfSel[tSel.viewer, FALSE]; }; TEditInputOps.CallWithLocks[DoSearchLocked, read] }; <<>> SetUpRealText: PROC [info: EditToolPrivate.Info] = { BuildRealSearchChoiceEntries[info]; ToNext[info.layout]; ignoringCase ¬ "IgnoreCase"; matchingCase ¬ "MatchCase"; matchingWords ¬ "MatchWords"; matchingAnywhere ¬ "MatchAnywhere"; matchingNodes ¬ "MatchNodes"; matchingLiterally ¬ "MatchLiterally"; matchingAsPattern ¬ "MatchPattern"; equalLooks ¬ "EqualLooksTest"; subsetLooks ¬ "SubsetLooksTest"; }; SetUpText: PROC [info: EditToolPrivate.Info] = { BuildSearchChoiceEntries[info]; ToNext[info.layout]; ignoringCase ¬ "Ignore Case"; matchingCase ¬ "Match Case"; matchingWords ¬ "Match Words Only"; matchingAnywhere ¬ "Match Anywhere"; matchingNodes ¬ "Match Entire Nodes Only"; matchingLiterally ¬ "Match Literally"; matchingAsPattern ¬ "Match as Pattern"; equalLooks ¬ "Equal as Looks Test"; subsetLooks ¬ "Subset as Looks Test"; }; BuildSearchButtons: PUBLIC PROC [info: EditToolPrivate.Info, realNames: BOOL ¬ FALSE] = { IF realNames THEN SetUpRealText[info] ELSE SetUpText[info]; BuildCaseEntry[info]; ToMiddle[info.layout]; BuildWhereEntry[info]; ToNext[info.layout]; BuildLitOrPatternEntry[info]; ToMiddle[info.layout]; BuildLooksMatchEntry[info]; }; equalLooks: Rope.ROPE; subsetLooks: Rope.ROPE; 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]; }; BuildRealLooksMatchEntry: PROC [info: Info] = { OPEN info; looksExact ¬ FALSE; [looksMatchLabel,] ¬ BuildPair[layout,LooksMatchButton,looksExact,"EqualLooksTest","SubsetLooksTest",info]; }; BuildLooksMatchEntry: PROC [info: Info] = { OPEN info; looksExact ¬ FALSE; [looksMatchLabel,] ¬ BuildPair[layout,LooksMatchButton,looksExact,equalLooks,subsetLooks,info]; }; <<-------------------------->> BuildEntry: PROC [name: Rope.ROPE, info:Info, proc: Buttons.ButtonProc, state: BOOL] RETURNS [new: Buttons.Button] = { new ¬ BuildButton[info.layout, name, proc, info, FALSE, FALSE]; ViewerOps.AddProp[new, $DisableMBFeedback, $DisableMBFeedback]; SetButton[new, state, FALSE]; }; BuildRealSearchChoiceEntries: PROC [info: Info] = { [] ¬ BuildLabel[info.layout, "Pick one or more: "]; HGap[info.layout]; info.textButton ¬ BuildEntry["MatchText", info, MatchTextButton, info.ignoreText ¬ FALSE]; info.looksButton ¬ BuildEntry["IgnoreLooks", info, MatchLooksButton, info.ignoreLooks ¬ TRUE]; info.formatButton ¬ BuildEntry["IgnoreFormat", info, MatchFormatButton, info.ignoreFormat ¬ TRUE]; EditToolBuilder.ToNext[info.layout]; EditToolBuilder.ToMiddle[info.layout]; info.styleButton ¬ BuildEntry["IgnoreStyle", info, MatchStyleButton, info.ignoreStyle ¬ TRUE]; info.commentButton ¬ BuildEntry["IgnoreComment", info, MatchCommentButton, info.ignoreComment ¬ TRUE]; }; BuildSearchChoiceEntries: PROC [info: Info] = { [] ¬ BuildLabel[info.layout, "Pick one or more: "]; HGap[info.layout]; info.textButton ¬ BuildEntry["Text", info, MatchTextButton, info.ignoreText ¬ FALSE]; info.looksButton ¬ BuildEntry["Looks", info, MatchLooksButton, info.ignoreLooks ¬ TRUE]; info.formatButton ¬ BuildEntry["Format", info, MatchFormatButton, info.ignoreFormat ¬ TRUE]; info.styleButton ¬ BuildEntry["Style", info, MatchStyleButton, info.ignoreStyle ¬ TRUE]; info.commentButton ¬ BuildEntry["Comment", info, MatchCommentButton, info.ignoreComment ¬ TRUE]; }; SetButton: PROC [viewer: Buttons.Button, ignore: BOOL, paint: BOOL ¬ 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] = { viewer: ViewerClasses.Viewer ¬ editTool; menu: Menus.Menu ¬ viewer.menu; menuEntry:Menus.MenuEntry ¬ Menus.CopyEntry[ Menus.FindEntry[ menu, "RealOps"] ]; menuClientData: REF ANY¬ Menus.SetClientData[ menuEntry, NIL ]; -- only way to query the clientData without affecting it. data: REF BOOL ¬ NARROW[menuClientData]; usingRealNames: BOOL ¬ data­; <> IF usingRealNames THEN Buttons.ReLabel[ info.textButton, "MatchText", FALSE ]; SetButton[info.textButton, info.ignoreText ¬ FALSE]; }; IgnoreTextOp: TEditInput.CommandProc = { IgnoreText[mainToolInfo] }; IgnoreText: PROC [info: Info] = { viewer: ViewerClasses.Viewer ¬ editTool; menu: Menus.Menu ¬ viewer.menu; menuEntry:Menus.MenuEntry ¬ Menus.CopyEntry[ Menus.FindEntry[ menu, "RealOps"] ]; menuClientData: REF ANY¬ Menus.SetClientData[ menuEntry, NIL ]; -- only way to query the clientData without affecting it. data: REF BOOL ¬ NARROW[menuClientData]; usingRealNames: BOOL ¬ data­; <> IF usingRealNames THEN Buttons.ReLabel[ info.textButton, "IgnoreText", FALSE ]; SetButton[info.textButton, info.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] = { viewer: ViewerClasses.Viewer ¬ editTool; menu: Menus.Menu ¬ viewer.menu; menuEntry:Menus.MenuEntry ¬ Menus.CopyEntry[ Menus.FindEntry[ menu, "RealOps"] ]; menuClientData: REF ANY¬ Menus.SetClientData[ menuEntry, NIL ]; -- only way to query the clientData without affecting it. data: REF BOOL ¬ NARROW[menuClientData]; usingRealNames: BOOL ¬ data­; <> IF usingRealNames THEN Buttons.ReLabel[ info.looksButton, "MatchLooks", FALSE ]; SetButton[info.looksButton, info.ignoreLooks ¬ FALSE]; }; IgnoreLooksOp: TEditInput.CommandProc = { IgnoreLooks[mainToolInfo]; }; IgnoreLooks: PROC [info: Info] = { viewer: ViewerClasses.Viewer ¬ editTool; menu: Menus.Menu ¬ viewer.menu; menuEntry:Menus.MenuEntry ¬ Menus.CopyEntry[ Menus.FindEntry[ menu, "RealOps"] ]; menuClientData: REF ANY¬ Menus.SetClientData[ menuEntry, NIL ]; -- only way to query the clientData without affecting it. data: REF BOOL ¬ NARROW[menuClientData]; usingRealNames: BOOL ¬ data­; <> IF usingRealNames THEN Buttons.ReLabel[ info.looksButton, "IgnoreLooks", FALSE ]; SetButton[info.looksButton, info.ignoreLooks ¬ TRUE]; }; <<-------------------------->> matchFormatAtom: LIST OF REF = Register[$MatchFormat,MatchFormatOp]; ignoreFormatAtom: LIST OF REF = Register[$IgnoreFormat,IgnoreFormatOp]; MatchFormatButton: Buttons.ButtonProc = { ChangeState[mainToolInfo.ignoreFormat, ignoreFormatAtom,matchFormatAtom] }; MatchFormatOp: TEditInput.CommandProc = { MatchFormat[mainToolInfo]; }; MatchFormat: PROC [info: Info] = { viewer: ViewerClasses.Viewer ¬ editTool; menu: Menus.Menu ¬ viewer.menu; menuEntry:Menus.MenuEntry ¬ Menus.CopyEntry[ Menus.FindEntry[ menu, "RealOps"] ]; menuClientData: REF ANY¬ Menus.SetClientData[ menuEntry, NIL ]; -- only way to query the clientData without affecting it. data: REF BOOL ¬ NARROW[menuClientData]; usingRealNames: BOOL ¬ data­; <> IF usingRealNames THEN Buttons.ReLabel[ info.formatButton, "MatchFormat", FALSE ]; SetButton[info.formatButton, info.ignoreFormat ¬ FALSE]; }; IgnoreFormatOp: TEditInput.CommandProc = { IgnoreFormat[mainToolInfo]; }; IgnoreFormat: PROC [info: Info] = { viewer: ViewerClasses.Viewer ¬ editTool; menu: Menus.Menu ¬ viewer.menu; menuEntry:Menus.MenuEntry ¬ Menus.CopyEntry[ Menus.FindEntry[ menu, "RealOps"] ]; menuClientData: REF ANY¬ Menus.SetClientData[ menuEntry, NIL ]; -- only way to query the clientData without affecting it. data: REF BOOL ¬ NARROW[menuClientData]; usingRealNames: BOOL ¬ data­; <> IF usingRealNames THEN Buttons.ReLabel[ info.formatButton, "IgnoreFormat", FALSE ]; SetButton[info.formatButton, info.ignoreFormat ¬ 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] = { viewer: ViewerClasses.Viewer ¬ editTool; menu: Menus.Menu ¬ viewer.menu; menuEntry:Menus.MenuEntry ¬ Menus.CopyEntry[ Menus.FindEntry[ menu, "RealOps"] ]; menuClientData: REF ANY¬ Menus.SetClientData[ menuEntry, NIL ]; -- only way to query the clientData without affecting it. data: REF BOOL ¬ NARROW[menuClientData]; usingRealNames: BOOL ¬ data­; <> IF usingRealNames THEN Buttons.ReLabel[ info.styleButton, "MatchStyle", FALSE ]; SetButton[info.styleButton, info.ignoreStyle ¬ FALSE] }; IgnoreStyleOp: TEditInput.CommandProc = { IgnoreStyle[mainToolInfo] }; IgnoreStyle: PROC [info: Info] = { viewer: ViewerClasses.Viewer ¬ editTool; menu: Menus.Menu ¬ viewer.menu; menuEntry:Menus.MenuEntry ¬ Menus.CopyEntry[ Menus.FindEntry[ menu, "RealOps"] ]; menuClientData: REF ANY¬ Menus.SetClientData[ menuEntry, NIL ]; -- only way to query the clientData without affecting it. data: REF BOOL ¬ NARROW[menuClientData]; usingRealNames: BOOL ¬ data­; <> IF usingRealNames THEN Buttons.ReLabel[ mainToolInfo.styleButton, "IgnoreStyle", FALSE ]; SetButton[info.styleButton, info.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] = { viewer: ViewerClasses.Viewer ¬ editTool; menu: Menus.Menu ¬ viewer.menu; menuEntry:Menus.MenuEntry ¬ Menus.CopyEntry[ Menus.FindEntry[ menu, "RealOps"] ]; menuClientData: REF ANY¬ Menus.SetClientData[ menuEntry, NIL ]; -- only way to query the clientData without affecting it. data: REF BOOL ¬ NARROW[menuClientData]; usingRealNames: BOOL ¬ data­; <> IF usingRealNames THEN Buttons.ReLabel[ info.commentButton, "MatchComment", FALSE ]; SetButton[info.commentButton, info.ignoreComment ¬ FALSE] }; IgnoreCommentOp: TEditInput.CommandProc = { IgnoreComment[mainToolInfo] }; IgnoreComment: PROC [info: Info] = { viewer: ViewerClasses.Viewer ¬ editTool; menu: Menus.Menu ¬ viewer.menu; menuEntry:Menus.MenuEntry ¬ Menus.CopyEntry[ Menus.FindEntry[ menu, "RealOps"] ]; menuClientData: REF ANY¬ Menus.SetClientData[ menuEntry, NIL ]; -- only way to query the clientData without affecting it. data: REF BOOL ¬ NARROW[menuClientData]; usingRealNames: BOOL ¬ data­; <> IF usingRealNames THEN Buttons.ReLabel[ info.commentButton, "IgnoreComment", FALSE ]; SetButton[info.commentButton, info.ignoreComment ¬ TRUE] }; matchingLiterally: Rope.ROPE; matchingAsPattern: Rope.ROPE; 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]; miniDocStyle: Rope.ROPE ~ " BeginStyle (mini) \"for small comment\" { \"TimesRoman\" family 8 pt size 9 pt leading 10 pt topIndent 0 pt bottomIndent 0 leftIndent 5 pt rightIndent } StyleRule EndStyle "; BuildMiniPatternDocEntry: PUBLIC PROC [info: Info] = { OPEN info.layout; rope: Rope.ROPE; where: Node; 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.PutProp[node: TextNode.Root[where], name: $StyleDef, value: NodeProps.DoSpecs[$StyleDef, miniDocStyle]]; TextEdit.PutFormat[where, $mini]; ViewerTools.InhibitUserEdits[arg]; }; <<-------------------------->> ignoringCase: Rope.ROPE; matchingCase: Rope.ROPE; 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; matchingAnywhere: Rope.ROPE; matchingNodes: Rope.ROPE; 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[ORD[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, ORD[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] ¬ "other: 'x = x; ~x = not x; | node boundary; { } selection; < > named subpattern "; END.