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:
BOOL ←
TRUE]
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:
BOOLEAN ←
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] = {
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
";
}...