-- 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];
};
}...