EditToolSearchImpl.mesa
Paxton on February 24, 1983 12:53 pm
McGregor on August 30, 1982 2:21 pm
Maxwell, January 6, 1983 12:17 pm
Russ Atkinson, September 26, 1983 5:58 pm
Doug Wyatt, January 13, 1984 2:54 pm
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: BOOLTRUE]
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: BOOLEANTRUE] = {
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
";
}...