-- EditToolSubsImpl.mesa; Edited by Paxton on January 3, 1983 9:49 am
-- Edited by McGregor on August 30, 1982 2:40 pm
DIRECTORY
EditToolPrivate,
EditToolBuilder,
Buttons,
Convert,
EditNotify,
Inline,
IO,
UndoEvent,
Labels,
List,
Menus,
MessageWindow,
NameSymbolTable,
NodeAddrs,
NodeProps,
NodeStyle,
Rope,
RopeEdit,
RopeReader,
RunReader,
TextEdit,
TextFind,
TextLooks,
TextLooksSupport,
TextNode,
TEditDisplay,
TEditDocument,
TEditHistory,
TEditInput,
TEditInputOps,
TEditLocks,
TEditOps,
TEditRefresh,
TEditSelection,
TEditTouchup,
TreeFind,
UserTerminal,
ViewerOps,
ViewerClasses,
ViewerMenus;
EditToolSubsImpl: CEDAR PROGRAM
IMPORTS EditToolPrivate, EditToolBuilder, --Buttons,-- Convert, Labels, MessageWindow, NodeAddrs, NameSymbolTable, NodeProps, NodeStyle, Rope, RopeReader, TEditOps, TextEdit, TextFind, TextNode, TextLooks, TEditInput, TEditInputOps, TEditLocks, TEditRefresh, TEditSelection, TreeFind
EXPORTS EditToolPrivate
SHARES Rope =
{ OPEN ViewerClasses, EditToolBuilder, EditToolPrivate;
----------------------------
Offset: TYPE = TextNode.Offset;
----------------------------
sourceArgAtom: LIST OF REF = Register[$ReplaceBy,SourceArgOp];
clearSourceArgAtom: LIST OF REF = Register[$ClearReplaceBy,ClearSourceArgOp];
SourceButton: Buttons.ButtonProc = {
DoButton[sourceArgAtom, clearSourceArgAtom, mouseButton=red] };
SourceArgOp: TEditInput.CommandProc = { SourceArg[mainToolInfo] };
SourceArg: PROC [info: Info] = { SavePSel; DataFieldButton[info.sourceArg,FALSE] };
ClearSourceArgOp: TEditInput.CommandProc = { ClearSourceArg[mainToolInfo] };
ClearSourceArg: PROC [info: Info] = { SavePSel; DataFieldButton[info.sourceArg,TRUE] };
BuildSourceEntry: PUBLIC PROC [info: Info] = { OPEN info;
[,sourceArg] ← BuildDataFieldPair[layout, "Replacement:", SourceButton, info, 2] };
----------------------------
replaceRope: Rope.ROPE = "Replace";
subsRope: Rope.ROPE = "Substitute";
BuildDoItEntries: PUBLIC PROC [info: Info] = { OPEN info;
substituteButton ← BuildButton[layout, "Substitute", DoSubstitute, info, TRUE];
[] ← BuildButton[layout, "Yes", DoYes, info];
[] ← BuildButton[layout, "No", DoNo, info];
doitButton ← BuildButton[layout, "Replace", DoIt, info];
[] ← BuildButton[layout, "Count", DoCount, info];
};
DoSubstituteMenuButton: PUBLIC Menus.MenuProc = {
DoSubstitute[NARROW[parent], clientData, mouseButton] };
DoYesMenuButton: PUBLIC Menus.MenuProc = {
DoYes[NARROW[parent], clientData, mouseButton] };
DoNoMenuButton: PUBLIC Menus.MenuProc = {
DoNo[NARROW[parent], clientData, mouseButton] };
DoItMenuButton: PUBLIC Menus.MenuProc = {
DoIt[NARROW[parent], clientData, mouseButton] };
DoCountMenuButton: PUBLIC Menus.MenuProc = {
DoCount[NARROW[parent], clientData, mouseButton] };
----------------------------
replaceOperation: Rope.ROPE = "Do Replace";
specifiedOperation: Rope.ROPE = "Do Operations";
doOperationsAtom: LIST OF REF = Register[$DoOperations,DoOperationsOp];
doReplaceAtom: LIST OF REF = Register[$DoReplace,DoReplaceOp];
OperationButton: Buttons.ButtonProc = {
ChangeState[mainToolInfo.doReplace,doReplaceAtom,doOperationsAtom] };
DoOperationsOp: TEditInput.CommandProc = { DoOperations[mainToolInfo] };
DoOperations: PROC [info: Info] = { OPEN info;
doReplace ← FALSE;
Labels.Set[operationLabel, specifiedOperation] };
DoReplaceOp: TEditInput.CommandProc = { DoRep[mainToolInfo] };
DoRep: PROC [info: Info] = { OPEN info;
doReplace ← TRUE;
Labels.Set[operationLabel, replaceOperation] };
BuildOperationEntry: PUBLIC PROC [info: Info] = { OPEN info;
doReplace ← TRUE;
[operationLabel,] ← BuildPair[layout,OperationButton,
doReplace,replaceOperation,specifiedOperation,info] };
----------------------------
----------------------------
forcingInitCap: Rope.ROPE = "First cap like replaced";
ignoringInitCap: Rope.ROPE = "Don't change caps";
forceInitCapAtom: LIST OF REF = Register[$ChangeInitCap,ChangeInitCapOp];
ignoreInitCapAtom: LIST OF REF = Register[$LeaveInitCap,LeaveInitCapOp];
InitCapButton: Buttons.ButtonProc = {
ChangeState[mainToolInfo.forceInitCap,
forceInitCapAtom,ignoreInitCapAtom] };
ChangeInitCapOp: TEditInput.CommandProc = { ChangeInitCap[mainToolInfo] };
ChangeInitCap: PROC [info: Info] = { OPEN info;
forceInitCap ← TRUE;
Labels.Set[initCapLabel,forcingInitCap] };
LeaveInitCapOp: TEditInput.CommandProc = { LeaveInitCap[mainToolInfo] };
LeaveInitCap: PROC [info: Info] = { OPEN info;
forceInitCap ← FALSE;
Labels.Set[initCapLabel,ignoringInitCap] };
BuildInitCapEntry: PUBLIC PROC [info: Info] = { OPEN info;
forceInitCap ← TRUE;
[initCapLabel,] ← BuildPair[layout,InitCapButton,
forceInitCap,forcingInitCap,ignoringInitCap,info] };
doSubsAtom: LIST OF REF = Register[$DoSubstitute,DoSubstituteOp];
DoSubstitute: Buttons.ButtonProc = {
DoButton[doSubsAtom] };
DoSubstituteOp: TEditInput.CommandProc = { DoSubstituteCom[mainToolInfo] };
DoSubstituteCom: PROC [info: Info, countOnly: BOOLEANFALSE] = { OPEN info;
subsinfo: SubsInfo ← TextNode.pZone.NEW[SubsInfoRec];
root: TextNode.Ref;
{ OPEN subsinfo;
first, selStart, selEnd: TextNode.Ref;
firstText, lastText: TextNode.RefTextNode;
lastWhere: TextNode.RefTextNode;
pattern: TextNode.RefTextNode;
commentControl: TreeFind.CommentControl;
type: TextNode.TypeName;
style: NameSymbolTable.Name;
start: Offset;
count: LONG INTEGER;
pSel: TEditDocument.Selection;
vwr: ViewerClasses.Viewer;
data: TEditDocument.TEditDocumentData;
insertion: TEditDocument.BeforeAfter;
granularity: TEditDocument.SelectionGrain;
lit: BOOLEAN;
source: TextNode.RefTextNode ← GetDataNode[sourceArg];
size: Offset ← TextEdit.Size[source];
params: LIST OF REF ANY;
MakeSel: PROC [where: TextNode.RefTextNode, at, atEnd:Offset] = {
tSel.start.pos ← [where,at];
tSel.end.pos ← [where,MAX[0,atEnd-1]];
tSel.granularity ← char;
tSel.viewer ← vwr;
tSel.data ← data;
tSel.insertion ← after;
TEditSelection.MakeSelection[new: tSel];
};
CountOnly: PROC [where: TextNode.RefTextNode, at, atEnd, before, after: Offset]
RETURNS [continue, bumpCount: BOOLEAN, from, delta: Offset] = {
IF interrupt^ THEN { continue ← FALSE; RETURN };
continue ← bumpCount ← TRUE;
from ← atEnd; delta ← 0 };
DoSubs: PROC [where: TextNode.RefTextNode, at, atEnd, before, after: Offset]
RETURNS [continue, bumpCount: BOOLEAN, from, delta: Offset] = {
varRope ← where.rope;
varRuns ← where.runs;
[continue, bumpCount, from, delta] ←
DoOneSubs[info, root, where, at, atEnd, subsinfo, vwr] };
DoOps: PROC [where: TextNode.RefTextNode, at, atEnd, before, after: Offset]
RETURNS [continue, bumpCount: BOOLEAN, from, delta: Offset] = {
len: Offset ← atEnd-at;
size: Offset ← TextEdit.Size[where];
IF interrupt^ THEN { continue ← FALSE; RETURN };
MakeSel[where,at,atEnd];
IF where # lastWhere AND lastWhere # NIL THEN
NodeAddrs.RemTextAddr[lastWhere,$After];
lastWhere ← where;
NodeAddrs.PutTextAddr[where,$After,atEnd];
TEditInput.Interpret[vwr, params];
delta ← NodeAddrs.GetTextAddr[where,$After].location-atEnd;
from ← atEnd+delta; continue ← bumpCount ← TRUE };
event ← TEditInput.CurrentEvent[];
substitute ← TRUE;
TEditSelection.LockSel[primary, "DoSubstituteCom"];
FixPSel[];
pSel ← TEditOps.GetSelData[];
IF (~countOnly AND ~TEditInputOps.CheckReadonly[pSel])
OR (root ← TEditSelection.SelectionRoot[pSel])=NIL
OR CheckForSubs[info,pSel]=FALSE OR (pattern ← GetPatternNode[info])=NIL
THEN { TEditSelection.UnlockSel[primary]; RETURN };
vwr ← pSel.viewer;
[pattern,lit,searchLooks,type,style,commentControl] ←
GetLooksAndPatternInfo[pattern,info];
SELECT subsRange FROM
withinSel => {
first ← pSel.start.pos.node;
last ← pSel.end.pos.node;
start ← pSel.start.pos.where;
lastLen ← pSel.end.pos.where+1 };
afterSel => {
first ← pSel.end.pos.node;
last ← NIL;
start ← pSel.end.pos.where+1;
lastLen ← 0 };
entireDoc => {
first ← TextNode.Root[pSel.start.pos.node];
last ← NIL;
start ← 0;
lastLen ← 0 };
ENDCASE => ERROR;
data ← pSel.data;
insertion ← pSel.insertion;
granularity ← pSel.granularity;
selStart ← pSel.start.pos.node;
selEnd ← pSel.end.pos.node;
tSel^ ← pSel^;
[] ← TEditLocks.Lock[root, "DoSubstituteCom"];
IF (firstText ← TextNode.NarrowToTextNode[selStart]) # NIL THEN
NodeAddrs.PutTextAddr[firstText,$Start,tSel.start.pos.where];
IF (lastText ← TextNode.NarrowToTextNode[selEnd]) # NIL THEN
NodeAddrs.PutTextAddr[lastText,$End,tSel.end.pos.where+1];
interrupt^ ← FALSE;
IF source # NIL AND ~countOnly AND doReplace THEN {
sourceType ← source.typename;
IF ~ignoreStyle THEN sourceStyle ← NodeStyle.StyleNameForNode[source];
sourceComment ← source.comment;
sourceRope ← source.rope;
sourceRuns ← source.runs };
sourceLen ← size;
IF ~ignoreLooks OR ~ignoreText THEN -- create a description of the pattern
finder ← TreeFind.Create[
pattern,lit,searchWhere=words,ignoreLooks,ignoreCase,searchWhere=nodes !
TextFind.MalformedPattern => { ReportPatternError[ec]; GOTO Quit }];
IF ~countOnly AND ~doReplace THEN { -- doing specified operations
IF (params ← GetOps[info])=NIL THEN { OPEN MessageWindow;
Append["Specify operations to be performed.", TRUE];
Blink[]; TEditSelection.UnlockDocAndPSel[root]; RETURN }}
ELSE IF doReplace AND ignoreText AND ~ignoreLooks THEN {
targetLooks ← GetDataLooks[targetArg,"\"Search for\" field"];
IF ~countOnly THEN sourceLooks ← GetDataLooks[sourceArg,"\"Replace by\" field"] };
IF ~countOnly THEN {
TEditSelection.Deselect[]; -- clear selection
IF doReplace AND ~literal THEN rdr ← RopeReader.Create[] };
IF ~countOnly AND ~doReplace THEN TEditSelection.LockSel[primary , "DoSubstituteCom"];
count ← TreeFind.Apply[finder,first,
IF countOnly THEN CountOnly ELSE IF doReplace THEN DoSubs ELSE DoOps,
start,last,lastLen,looksExact,commentControl,~ignoreType,type,
~ignoreStyle,style,NodeStyle.StyleNameForNode];
IF ~countOnly AND ~doReplace THEN TEditSelection.UnlockSel[primary];
-- update the selection
tSel.start.pos ← [selStart,
IF firstText=NIL THEN TextNode.NodeItself
ELSE NodeAddrs.GetTextAddr[firstText,$Start].location];
tSel.end.pos ← [selEnd,
IF lastText=NIL THEN TextNode.NodeItself
ELSE MAX[NodeAddrs.GetTextAddr[lastText,$End].location,1]-1];
IF selStart=selEnd THEN tSel.end.pos.where ← MAX[tSel.start.pos.where, tSel.end.pos.where];
IF firstText#NIL THEN NodeAddrs.RemTextAddr[firstText,$Start];
IF lastText#NIL THEN NodeAddrs.RemTextAddr[lastText,$End];
IF lastWhere#NIL THEN NodeAddrs.RemTextAddr[lastWhere,$After];
tSel.granularity ← granularity;
tSel.viewer ← vwr;
tSel.data ← data;
tSel.insertion ← insertion;
IF ~countOnly THEN TEditSelection.MakeSelection[new: tSel]; -- restore selection
TEditSelection.UnlockDocAndPSel[root];
-- display the number of substitutions made
MessageWindow.Append[
Rope.Concat[Convert.ValueToRope[[signed[count,10]]],
IF countOnly THEN IF count # 1 THEN " matches." ELSE " match."
ELSE IF count # 1 THEN " substitutions." ELSE " substitution."], TRUE];
EXITS Quit => { TEditSelection.UnlockDocAndPSel[root]; RETURN };
}};
DoOneSubs: PROC [info: Info, root: TextNode.Ref, where: TextNode.RefTextNode, at, atEnd: Offset,
subsinfo: SubsInfo, viewer: ViewerClasses.Viewer]
RETURNS [continue, bumpCount: BOOLEAN, from, delta: Offset] = { OPEN info, subsinfo;
len: Offset ← atEnd-at;
size: Offset ← TextEdit.Size[where];
initCap: BOOLEAN ← forceInitCap AND
at < size AND TextEdit.FetchChar[where,at] IN ['A..'Z];
initLower: BOOLEAN ← forceInitCap AND
at < size AND TextEdit.FetchChar[where,at] IN ['a..'z];
initLooks: TextLooks.Looks;
DoType: PROC = {
IF ~ignoreType AND where.typename # sourceType THEN
TextEdit.ChangeType[where,sourceType,event,root];
};
DoStyle: PROC = {
IF ~ignoreStyle AND NodeStyle.StyleNameForNode[where] # sourceStyle THEN {
styleRope ← NameSymbolTable.RopeFromName[sourceStyle];
TextEdit.ChangeStyle[where,styleRope,event,root] };
};
DoComment: PROC = {
IF ~ignoreComment AND where.comment # sourceComment THEN
TextEdit.PutProp[where, "Comment",
IF sourceComment THEN NodeProps.true ELSE NodeProps.false, event, root];
};
IF interrupt^ THEN { continue ← FALSE; RETURN };
continue ← bumpCount ← TRUE; from ← atEnd; delta ← 0;
SELECT TRUE FROM
ignoreText AND ~ignoreLooks => { -- looks only
IF searchWhere=anywhere AND substitute THEN { -- need to extend to include entire run
[at,atEnd] ← Extend[info,TRUE,searchLooks,where,at,atEnd,last,lastLen];
len ← atEnd-at };
TextEdit.ChangeLooks[root,where,targetLooks,sourceLooks,at,len,event];
from ← at+len;
DoType; DoStyle; DoComment;
RETURN };
ignoreLooks AND ~ignoreText => initLooks ← IF at < size THEN
TextEdit.FetchLooks[where,at] ELSE TextLooks.noLooks;
ENDCASE;
IF ~ignoreText OR ~ignoreLooks THEN {
sLen: Offset ← sourceLen;
IF ~literal THEN { -- treat source as pattern
end, dest: Offset ← at+len; -- insert after the text to be deleted
litstart: Offset ← 0;
InsertLit: PROC [after: Offset] = {
litlen: Offset ← after-litstart;
IF litlen <= 0 THEN RETURN;
[] ← TextEdit.ReplaceByText[root,where,dest,0,
sourceRope,sourceRuns,litstart,litlen,event];
dest ← dest+litlen };
RopeReader.SetPosition[rdr,sourceRope,0];
DO-- read the source
char: CHAR ← RopeReader.Get[rdr ! RopeReader.ReadOffEnd => EXIT];
SELECT char FROM
'' => { -- treat next as literal
loc: Offset ← RopeReader.GetIndex[rdr]; -- after the quote
InsertLit[loc-1]; -- to take care of stuff up to the quote
litstart ← loc;
[] ← RopeReader.Get[rdr ! RopeReader.ReadOffEnd => EXIT] };
'< => { -- read name, insert value
loc: Offset ← RopeReader.GetIndex[rdr]; -- after the <
at, atEnd, after: Offset;
addLooks: TextLooks.Looks;
IF ~ignoreLooks THEN -- read looks from the < at the start of the name
addLooks ← TextLooks.FetchLooks[sourceRuns, RopeReader.GetIndex[rdr]-1];
InsertLit[loc-1]; -- to take care of stuff up to the <
DO-- read to >
IF RopeReader.Get[rdr ! RopeReader.ReadOffEnd => EXIT]
= '> THEN EXIT;
ENDLOOP;
after ← RopeReader.GetIndex[rdr]; -- after the >
IF nameRope = NIL THEN
nameRope ← TextNode.pZone.NEW[substr node Rope.RopeRep];
nameRope.size ← after-loc-1;
nameRope.base ← sourceRope;
nameRope.start ← loc;
[at,atEnd] ← TextFind.NameLoc[finder,nameRope];
atEnd ← MIN[atEnd,Rope.Size[varRope]];
IF at < atEnd THEN {
len: Offset ← atEnd-at;
[] ← TextEdit.ReplaceByText[root,where,dest,0,varRope,varRuns,at,len,event];
IF ~ignoreLooks THEN { -- change the looks for the subpattern
remLooks: TextLooks.Looks = TextFind.NameLooks[finder, nameRope];
TextEdit.ChangeLooks[root,where,remLooks,addLooks,dest,len,event] };
dest ← dest+len };
litstart ← after;
LOOP };
ENDCASE;
ENDLOOP;
InsertLit[sourceLen];
sLen ← dest-end; -- the length of the replacement text
TextEdit.DeleteText[root,where,at,len,event]
-- delete last to keep selection addrs correct -- }
ELSE [] ← TextEdit.ReplaceByText[root,where,at,len,
sourceRope,sourceRuns,0,sourceLen,event];
IF initCap AND sourceLen > 0 AND TextEdit.FetchChar[where,at] IN ['a..'z] THEN
TextEdit.ChangeCaps[root,where,at,1,allCaps,event]
ELSE IF initLower AND sourceLen > 0 AND TextEdit.FetchChar[where,at] IN ['A..'Z] THEN
TextEdit.ChangeCaps[root,where,at,1,allLower,event];
IF ignoreLooks THEN -- just changing the text, so now restore the looks
TextEdit.SetLooks[root,where,initLooks,at,sLen,event];
from ← at+sLen; delta ← sLen-len };
DoType; DoStyle; DoComment };
----------------------------
----------------------------
doItAtom: LIST OF REF = Register[$DoIt,DoItOp];
DoIt: Buttons.ButtonProc = {
DoButton[doItAtom] };
DoItOp: TEditInput.CommandProc = { DoItCom[mainToolInfo] };
DoItCom: PROC [info: Info] = {
FixPSel[];
IF info.doReplace THEN DoReplaceCom[info] ELSE DoOpsCom[info] };
tSel: PUBLIC TEditDocument.Selection ← NEW[TEditDocument.SelectionRec];
CheckForSubs: PROC [info: Info, pSel: TEditDocument.Selection] RETURNS [ok: BOOLEAN] = { OPEN info;
IF ignoreText AND ignoreLooks AND ignoreType
AND ignoreStyle AND ignoreComment THEN { OPEN MessageWindow;
Append["Pick one or more of text/looks/type/style/comment to replace.", TRUE];
Blink[]; RETURN [FALSE] };
IF ~CheckPSel[pSel] THEN RETURN [FALSE];
RETURN [TRUE] };
DoReplaceCom: PROC [info: Info] = { OPEN info;
subsinfo: SubsInfo;
pSel: TEditDocument.Selection;
source: TextNode.RefTextNode ← GetDataNode[sourceArg];
where: TextNode.RefTextNode;
root: TextNode.Ref;
at, atEnd, delta: TextNode.Offset;
TEditSelection.LockSel[primary, "DoReplaceCom"];
FixPSel[];
pSel ← TEditOps.GetSelData[];
IF ~TEditInputOps.CheckReadonly[pSel]
OR (root ← TEditSelection.SelectionRoot[pSel])=NIL
OR CheckForSubs[info,pSel]=FALSE
THEN { TEditSelection.UnlockSel[primary]; RETURN };
IF (where ← TextNode.NarrowToTextNode[pSel.start.pos.node]) # pSel.end.pos.node THEN {
OPEN MessageWindow;
Append["Selection to replace must be within a single node.", TRUE];
Blink[]; TEditSelection.UnlockSel[primary]; RETURN };
at ← pSel.start.pos.where;
atEnd ← pSel.end.pos.where+1;
subsinfo ← TextNode.pZone.NEW[SubsInfoRec];
{ OPEN subsinfo; 
event ← TEditInput.CurrentEvent[];
substitute ← FALSE;
sourceLen ← TextEdit.Size[source];
IF source # NIL THEN {
sourceType ← source.typename;
IF ~ignoreStyle THEN sourceStyle ← NodeStyle.StyleNameForNode[source];
sourceComment ← source.comment;
sourceRope ← source.rope;
sourceRuns ← source.runs };
rdr ← RopeReader.Create[];
IF ignoreText AND ~ignoreLooks THEN { -- looks only
targetLooks ← GetDataLooks[targetArg,"\"Search for\" field"];
sourceLooks ← GetDataLooks[sourceArg,"\"Replace by\" field"] };
tSel^ ← pSel^;
[] ← TEditLocks.Lock[root, "DoReplaceCom"];
TEditSelection.Deselect[]; -- remove the selection
delta ← DoOneSubs[info,root,
where,at,atEnd,subsinfo,tSel.viewer].delta;
tSel.end.pos.where ← tSel.end.pos.where + delta;
IF tSel.start.pos.node = tSel.end.pos.node AND tSel.start.pos.where > tSel.end.pos.where THEN {
tSel.end.pos.where ← tSel.start.pos.where;
tSel.granularity ← point;
tSel.insertion ← before };
TEditSelection.MakeSelection[new: tSel];
TEditRefresh.ScrollToEndOfSel[tSel.viewer, FALSE];
TEditSelection.UnlockDocAndPSel[root];
}};
GetSelInitLooks: PROC [pSel: TEditDocument.Selection] RETURNS [TextLooks.Looks] = {
node: TextNode.RefTextNode ← TextNode.NarrowToTextNode[pSel.start.pos.node];
loc: Offset ← pSel.start.pos.where;
IF node=NIL OR loc=TextNode.NodeItself OR loc=TextEdit.Size[node]
THEN RETURN [TextLooks.noLooks];
RETURN [TextEdit.FetchLooks[node,loc]] };
IsSelInitCap: PROC [pSel: TEditDocument.Selection] RETURNS [BOOLEAN] = {
node: TextNode.RefTextNode ← TextNode.NarrowToTextNode[pSel.start.pos.node];
loc: Offset ← pSel.start.pos.where;
IF node=NIL OR loc=TextNode.NodeItself OR loc=TextEdit.Size[node]
THEN RETURN [FALSE];
RETURN [TextEdit.FetchChar[node,loc] IN ['A..'Z]] };
IsSelInitLower: PROC [pSel: TEditDocument.Selection] RETURNS [BOOLEAN] = {
node: TextNode.RefTextNode ← TextNode.NarrowToTextNode[pSel.start.pos.node];
loc: Offset ← pSel.start.pos.where;
IF node=NIL OR loc=TextNode.NodeItself OR loc=TextEdit.Size[node]
THEN RETURN [FALSE];
RETURN [TextEdit.FetchChar[node,loc] IN ['a..'z]] };
doYesAtom: LIST OF REF = Register[$DoYes,DoYesOp];
doYesBackAtom: LIST OF REF = Register[$DoYesBack,DoYesBackOp];
DoYes: Buttons.ButtonProc = {
DoButton[doYesAtom, doYesBackAtom, mouseButton=red] };
DoYesOp: TEditInput.CommandProc = { DoYesCom[mainToolInfo] };
DoYesCom: PROC [info: Info] = { DoItCom[info]; Search[forwards,info] };
DoYesBackOp: TEditInput.CommandProc = { DoYesBackCom[mainToolInfo] };
DoYesBackCom: PROC [info: Info] = { DoItCom[info]; Search[backwards,info] };
doNoAtom: LIST OF REF = Register[$DoNo,DoNoOp];
doNoBackAtom: LIST OF REF = Register[$DoNoBack,DoNoBackOp];
DoNo: Buttons.ButtonProc = {
DoButton[doNoAtom, doNoBackAtom, mouseButton=red] };
DoNoOp: TEditInput.CommandProc = { DoNoCom[mainToolInfo] };
DoNoCom: PROC [info: Info] = { FixPSel[]; Search[forwards,info] };
DoNoBackOp: TEditInput.CommandProc = { DoNoBackCom[mainToolInfo] };
DoNoBackCom: PROC [info: Info] = { FixPSel[]; Search[backwards,info] };
----------------------------
doCountAtom: LIST OF REF = Register[$DoCount,DoCountOp];
DoCount: Buttons.ButtonProc = {
DoButton[doCountAtom] };
DoCountOp: TEditInput.CommandProc = { DoCountCom[mainToolInfo] };
DoCountCom: PROC [info: Info] = { DoSubstituteCom[info,TRUE] };
----------------------------
withinSelRope: Rope.ROPE = "Within Selection Only";
afterSelRope: Rope.ROPE = "After Selection Only";
entireDocRope: Rope.ROPE = "In Entire Document";
withinSelAtom: LIST OF REF = Register[$SubstituteInSel,SubsWithinOp];
afterSelAtom: LIST OF REF = Register[$SubstituteAfterSel,SubsAfterOp];
entireDocAtom: LIST OF REF = Register[$SubstituteInEntireDoc,SubsEntireDocOp];
BuildSubstituteEntry: PUBLIC PROC [info: Info] = { OPEN info;
subsRange ← entireDoc;
[subsRangeLabel,] ← BuildTriple[layout, SubsRangeButton, subsRange,
withinSelRope, afterSelRope, entireDocRope, info] };
SubsRangeButton: Buttons.ButtonProc = {
CycleTriple[mainToolInfo.subsRange, withinSelAtom, afterSelAtom, entireDocAtom] };
SubsWithinOp: TEditInput.CommandProc = { SubsWithin[mainToolInfo] };
SubsWithin: PROC [info: Info] = { OPEN info;
subsRange ← withinSel;
Labels.Set[subsRangeLabel,withinSelRope] };
SubsAfterOp: TEditInput.CommandProc = { SubsAfter[mainToolInfo] };
SubsAfter: PROC [info: Info] = { OPEN info;
subsRange ← afterSel;
Labels.Set[subsRangeLabel,afterSelRope] };
SubsEntireDocOp: TEditInput.CommandProc = { SubsEntireDoc[mainToolInfo] };
SubsEntireDoc: PROC [info: Info] = { OPEN info;
subsRange ← entireDoc;
Labels.Set[subsRangeLabel,entireDocRope] };
GetLooksAndPatternInfo: PUBLIC PROC [pattern: TextNode.RefTextNode, info: Info]
RETURNS [pat: TextNode.RefTextNode,
lit: BOOLEAN,
searchLooks: TextLooks.Looks,
type: TextNode.TypeName,
style: NameSymbolTable.Name,
commentControl: TreeFind.CommentControl] = { OPEN info;
pat ← pattern; lit ← literal; searchLooks ← TextLooks.noLooks;
IF ignoreText AND ~ignoreLooks THEN { -- make a phony search pattern and get the looks
size: Offset = TextEdit.Size[pattern];
searchLooks ← IF size=0 THEN TextLooks.noLooks
ELSE TextEdit.FetchLooks[pattern,0];
FOR i: Offset IN [1..size) DO
IF TextEdit.FetchLooks[pattern,i]#searchLooks THEN {
OPEN MessageWindow;
Append["Search pattern does not have uniform looks.",TRUE];
Append[" Using looks from first char."];
Blink[]; EXIT };
ENDLOOP;
lit ← FALSE;
pat ← TextEdit.FromRope["#*"];
TextEdit.SetLooks[NIL,pat,searchLooks] };
type ← IF pattern # NIL THEN pat.typename ELSE TextNode.nullTypeName;
style ← IF ignoreStyle THEN NameSymbolTable.nullName
ELSE NodeStyle.StyleNameForNode[pattern];
commentControl ← IF ignoreComment THEN includeComments
ELSE IF pattern # NIL AND pattern.comment THEN commentsOnly
ELSE excludeComments;
};
}...