-- EditToolSearchImpl.mesa -- Edited by Paxton on 6-Feb-82 12:00:51 DIRECTORY EditToolPrivate, Buttons, Convert, EditNotify, Inline, IOStream, UndoEvent, Labels, List, Menus, MessageWindow, NodeAddrs, Rope, RopeEdit, RopeReader, RunReader, Runtime, TextEdit, TextFind, TextLooks, TextLooksSupport, TextNode, TEditDocument, TEditInputOps, TEditOps, TreeFind, UserTerminal, ViewerClasses, ViewerOps, ViewerMenus, ViewerSpecs; EditToolSearchImpl: PROGRAM IMPORTS EditToolPrivate, Buttons, Labels, MessageWindow, RunReader, TEditOps, TextEdit, TextFind, TextLooksSupport, TreeFind, UserTerminal, ViewerSpecs EXPORTS EditToolPrivate = { OPEN EditToolPrivate, ViewerSpecs; ---------------------------- forwardButton: Buttons.Button; -- the "Search Forward!" button backwardsButton: Buttons.Button; -- the "Search Backwards!" button searchForwardAtom: ATOM = $EditToolSearchForward; SearchForward: PUBLIC Buttons.ButtonProc = { IF mainEditTool THEN TEditOps.InterpretAtom[button,searchForwardAtom] ELSE [] ← SearchForwardOp[] }; SearchForwardOp: TEditOps.CommandProc = { Search[TRUE] }; searchBackwardsAtom: ATOM = $EditToolSearchBackwards; SearchBackwards: PUBLIC Buttons.ButtonProc = { IF mainEditTool THEN TEditOps.InterpretAtom[button,searchBackwardsAtom] ELSE [] ←SearchBackwardsOp[] }; SearchBackwardsOp: TEditOps.CommandProc = { Search[FALSE] }; CheckPSel: PUBLIC PROC [pSel: TEditDocument.Selection] RETURNS [ok: BOOLEAN] = { IF pSel=NIL OR pSel.viewer=NIL OR pSel.viewer.class.flavor#$Text THEN { OPEN MessageWindow; Append["Please make a text selection.",TRUE]; Blink[]; RETURN [FALSE] }; RETURN [TRUE] }; GetPatternNode: PUBLIC PROC RETURNS [pattern: TextNode.RefTextNode] = { IF (pattern ← GetDataNode[targetArg])=NIL OR TextEdit.Size[pattern]=0 THEN { OPEN MessageWindow; Append["Please enter a search pattern in the Target field.",TRUE]; Blink[]; RETURN [NIL] }}; Search: PUBLIC PROC [forward: BOOLEAN] = { OPEN TreeFind; finder: Finder; found: BOOLEAN; where: TextNode.RefTextNode; pattern: TextNode.RefTextNode; at, atEnd: TextNode.Offset; pSel: TEditDocument.Selection = TEditOps.GetSelData[]; ignoreLooks, lit: BOOLEAN; searchLooks: TextLooks.Looks; IF CheckPSel[pSel]=FALSE OR (pattern ← GetPatternNode[])=NIL THEN RETURN; [pattern,ignoreLooks,lit,searchLooks] ← GetLooksAndPatternInfo[pattern]; { ENABLE TextFind.MalformedPattern => { OPEN MessageWindow; Append[SELECT ec FROM toobig => "Search pattern is too big", endquote => "Search pattern incorrectly ends with quote", boundary => "Search pattern incorrectly has | inside rather than at beginning or end", ENDCASE => "Error in search pattern", TRUE]; Blink[]; GOTO Quit }; finder ← TreeFind.Create[pattern,lit,word,ignoreLooks,ignoreCase]; IF forward THEN [found,where,at,atEnd,,] ← Try[finder: finder, first: pSel.end.pos.node, start: pSel.end.pos.where+1, looksExact:looksExact] ELSE [found,where,at,atEnd,,] ← TryBackwards[finder: finder, first: pSel.start.pos.node, len: pSel.start.pos.where, looksExact: looksExact]; }; IF ~found OR where=NIL THEN { UserTerminal.BlinkDisplay[]; RETURN }; IF looksChoice=looksOnly AND ~word THEN [at,atEnd] ← Extend[forward,searchLooks,where,at,atEnd]; tSel.start.pos ← [where,at]; tSel.end.pos ← tSel.clickPoint ← [where,MAX[0,atEnd-1]]; tSel.granularity ← char; tSel.viewer ← pSel.viewer; tSel.data ← pSel.data; tSel.insertion ← after; TEditOps.SetSelData[tSel]; TEditOps.CloseRepeatSequence[]; TEditOps.AutoScroll[FALSE]; EXITS Quit => RETURN; }; Extend: PUBLIC PROC [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] = { 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] }; BuildSearchEntries: PUBLIC PROC = { forwardButton ← Buttons.Create["Search Forward!", SearchForward, entryLeft, heightSoFar, 0, 0, NIL, FALSE, container, FALSE]; forwardButton.border ← FALSE; backwardsButton ← Buttons.Create["Search Backwards!", SearchBackwards, entryLeft+forwardButton.ww+gapSize*2, heightSoFar, 0, 0, NIL, FALSE, container, FALSE]; backwardsButton.border ← FALSE; heightSoFar ← heightSoFar + entryHeight + entryVSpace; }; ---------------------------- BuildSearchButtons: PUBLIC PROC = { startHeight: CARDINAL ← heightSoFar; initLeft: CARDINAL = entryLeft; BuildCaseEntry[]; BuildWordEntry[]; entryLeft ← (openRightWidth-scrollBarW-40)/2; heightSoFar ← startHeight; BuildLooksEntry[]; BuildLooksMatchEntry[]; entryLeft ← initLeft; BuildLitOrPatternEntry[] }; ---------------------------- ---------------------------- looksMatchButton: Buttons.Button; looksMatchLabel: Labels.Label; looksExact: PUBLIC BOOLEAN ← FALSE; equalLooks: Rope.Ref = "Equal as Looks Test"; subsetLooks: Rope.Ref = "Subset as Looks Test"; equalLooksAtom: ATOM = $EditToolEqualLooksTest; subsetLooksAtom: ATOM = $EditToolSubsetLooksTest; LooksMatchButton: Buttons.ButtonProc = { IF mainEditTool THEN ChangeState[looksMatchLabel,looksExact,equalLooksAtom,subsetLooksAtom] ELSE IF looksExact THEN [] ← SubsetLooksTestOp[] ELSE [] ← EqualLooksTestOp[] }; EqualLooksTestOp: TEditOps.CommandProc = { looksExact ← TRUE; Labels.Set[looksMatchLabel,equalLooks] }; SubsetLooksTestOp: TEditOps.CommandProc = { looksExact ← FALSE; Labels.Set[looksMatchLabel,subsetLooks] }; BuildLooksMatchEntry: PROC = { [looksMatchLabel,looksMatchButton] ← BuildPair[LooksMatchButton,looksExact,equalLooks,subsetLooks] }; ---------------------------- ---------------------------- looksButton: Buttons.Button; looksLabel: Labels.Label; looksChoice: PUBLIC [0..2] ← textAndLooks; textOnlyRope: Rope.Ref = "Text Only"; looksOnlyRope: Rope.Ref = "Looks Only"; textAndLooksRope: Rope.Ref = "Text & Looks"; textOnlyAtom: ATOM = $EditToolTextOnly; looksOnlyAtom: ATOM = $EditToolLooksOnly; textAndLooksAtom: ATOM = $EditToolTextAndLooks; LooksButton: Buttons.ButtonProc = { IF mainEditTool THEN CycleTriple[looksLabel,looksChoice, looksOnlyAtom, textOnlyAtom, textAndLooksAtom] ELSE SELECT looksChoice FROM textOnly => [] ← LooksOnlyOp[]; looksOnly => [] ← TextAndLooksOp[]; textAndLooks => [] ← TextOnlyOp[]; ENDCASE => ERROR }; TextOnlyOp: TEditOps.CommandProc = { looksChoice ← textOnly; Labels.Set[looksLabel,textOnlyRope] }; LooksOnlyOp: TEditOps.CommandProc = { looksChoice ← looksOnly; Labels.Set[looksLabel,looksOnlyRope] }; TextAndLooksOp: TEditOps.CommandProc = { looksChoice ← textAndLooks; Labels.Set[looksLabel,textAndLooksRope] }; BuildLooksEntry: PROC = { [looksLabel,looksButton] ← BuildTriple[LooksButton,looksChoice, looksOnlyRope, textOnlyRope, textAndLooksRope] }; ---------------------------- ---------------------------- literalButton: Buttons.Button; literalLabel: Labels.Label; literal: PUBLIC BOOLEAN ← TRUE; matchingLiterally: Rope.Ref = "Match Literally"; matchingAsPattern: Rope.Ref = "Match as Pattern"; matchLitAtom: ATOM = $EditToolMatchLiterally; matchPatternAtom: ATOM = $EditToolMatchPattern; LiteralButton: Buttons.ButtonProc = { IF mainEditTool THEN ChangeState[literalLabel,literal,matchLitAtom,matchPatternAtom] ELSE IF literal THEN [] ← MatchPatternOp[] ELSE [] ← MatchLitOp[] }; MatchLitOp: TEditOps.CommandProc = { literal ← TRUE; Labels.Set[literalLabel,matchingLiterally] }; MatchPatternOp: TEditOps.CommandProc = { literal ← FALSE; Labels.Set[literalLabel,matchingAsPattern] }; BuildLitOrPatternEntry: PROC = { [literalLabel,literalButton] ← BuildPair[LiteralButton,literal,matchingLiterally,matchingAsPattern] }; ---------------------------- patternDoc1: Rope.Ref = "# = any char; * = any string; 'x = use x literally;"; patternDoc2: Rope.Ref = "& = any alpha string; ~ = any non-alpha string;"; patternDoc3: Rope.Ref = "@ = any alpha char; ! = any non-alpha char;"; patternDoc4: Rope.Ref = "| = node boundary; { } bounds resulting selection"; BuildPatternDocEntry: PUBLIC PROC = { Place: PROC [line: Rope.Ref] = { label: Labels.Label ← Labels.Create[line, container, entryLeft+gapSize*3, heightSoFar, openRightWidth-scrollBarW-5, entryHeight, FALSE]; label.border ← FALSE; heightSoFar ← heightSoFar + entryHeight }; Place[patternDoc1]; Place[patternDoc2]; Place[patternDoc3]; Place[patternDoc4]; heightSoFar ← heightSoFar + entryVSpace }; ---------------------------- caseButton: Buttons.Button; caseLabel: Labels.Label; ignoreCase: PUBLIC BOOLEAN ← FALSE; ignoringCase: Rope.Ref = "Ignore Case"; matchingCase: Rope.Ref = "Match Case"; ignoreCaseAtom: ATOM = $EditToolIgnoreCase; matchCaseAtom: ATOM = $EditToolMatchCase; CaseButton: Buttons.ButtonProc = { IF mainEditTool THEN ChangeState[caseLabel,ignoreCase,ignoreCaseAtom,matchCaseAtom] ELSE IF ignoreCase THEN [] ← MatchCaseOp[] ELSE [] ← IgnoreCaseOp[] }; IgnoreCaseOp: TEditOps.CommandProc = { ignoreCase ← TRUE; Labels.Set[caseLabel,ignoringCase] }; MatchCaseOp: TEditOps.CommandProc = { ignoreCase ← FALSE; Labels.Set[caseLabel,matchingCase] }; BuildCaseEntry: PROC = { [caseLabel,caseButton] ← BuildPair[CaseButton,ignoreCase,ignoringCase,matchingCase] }; ---------------------------- wordButton: Buttons.Button; wordLabel: Labels.Label; word: PUBLIC BOOLEAN ← FALSE; matchingWords: Rope.Ref = "Match Words Only"; matchingAnywhere: Rope.Ref = "Match Anywhere"; matchWordsAtom: ATOM = $EditToolMatchWords; matchAnywhereAtom: ATOM = $EditToolMatchAnywhere; WordButton: Buttons.ButtonProc = { IF mainEditTool THEN ChangeState[wordLabel,word,matchWordsAtom,matchAnywhereAtom] ELSE IF word THEN [] ← MatchAnywhereOp[] ELSE [] ← MatchWordsOp[] }; MatchWordsOp: TEditOps.CommandProc = { word ← TRUE; Labels.Set[wordLabel,matchingWords] }; MatchAnywhereOp: TEditOps.CommandProc = { word ← FALSE; Labels.Set[wordLabel,matchingAnywhere] }; BuildWordEntry: PROC = { [wordLabel,wordButton] ← BuildPair[WordButton,word,matchingWords,matchingAnywhere] }; ---------------------------- targetButton: Buttons.Button; targetArg: PUBLIC ViewerClasses.Viewer; -- the viewer holding the target pattern targetArgAtom: ATOM = $EditToolSearchFor; TargetButton: Buttons.ButtonProc = { IF mainEditTool THEN TEditOps.InterpretAtom[button,targetArgAtom] ELSE [] ← TargetArgOp[] }; TargetArgOp: TEditOps.CommandProc = { DataFieldButton[targetArg] }; BuildTargetEntry: PUBLIC PROC = { [targetButton,targetArg] ← BuildDataFieldPair["Search for:", TargetButton] }; ---------------------------- RegisterSearch: PUBLIC PROC = { TEditOps.Register[searchForwardAtom, SearchForwardOp]; TEditOps.Register[searchBackwardsAtom, SearchBackwardsOp]; TEditOps.Register[targetArgAtom, TargetArgOp]; TEditOps.Register[equalLooksAtom, EqualLooksTestOp]; TEditOps.Register[subsetLooksAtom, SubsetLooksTestOp]; TEditOps.Register[textOnlyAtom, TextOnlyOp]; TEditOps.Register[looksOnlyAtom, LooksOnlyOp]; TEditOps.Register[textAndLooksAtom, TextAndLooksOp]; TEditOps.Register[matchLitAtom, MatchLitOp]; TEditOps.Register[matchPatternAtom, MatchPatternOp]; TEditOps.Register[ignoreCaseAtom, IgnoreCaseOp]; TEditOps.Register[matchCaseAtom, MatchCaseOp]; TEditOps.Register[matchWordsAtom, MatchWordsOp]; TEditOps.Register[matchAnywhereAtom, MatchAnywhereOp]; }; UnRegisterSearch: PUBLIC PROC = { TEditOps.UnRegister[searchForwardAtom]; TEditOps.UnRegister[searchBackwardsAtom]; TEditOps.UnRegister[targetArgAtom]; TEditOps.UnRegister[equalLooksAtom]; TEditOps.UnRegister[subsetLooksAtom]; TEditOps.UnRegister[textOnlyAtom]; TEditOps.UnRegister[looksOnlyAtom]; TEditOps.UnRegister[textAndLooksAtom]; TEditOps.UnRegister[matchLitAtom]; TEditOps.UnRegister[matchPatternAtom]; TEditOps.UnRegister[ignoreCaseAtom]; TEditOps.UnRegister[matchCaseAtom]; TEditOps.UnRegister[matchWordsAtom]; TEditOps.UnRegister[matchAnywhereAtom]; }; }...