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
DIRECTORY
Buttons,
Convert,
EditNotify,
EditToolBuilder,
EditToolPrivate,
IO,
Labels,
List,
Menus,
MessageWindow,
NameSymbolTable,
NodeAddrs,
NodeStyle,
Rope,
RopeEdit,
RopeReader,
RunReader,
TEditDocument,
TEditInputOps,
TEditSelection,
TEditRefresh,
TEditInput,
TEditOps,
Terminal,
TextEdit,
TextFind,
TextLooks,
TextLooksSupport,
TextNode,
TiogaOps,
TreeFind,
UndoEvent,
ViewerClasses,
ViewerMenus,
ViewerOps,
ViewerSpecs,
ViewerTools;
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, ViewerSpecs;
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: 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: 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
";
}...