EditToolSubsImpl.mesa
Paxton on January 3, 1983 9:49 am
McGregor on August 30, 1982 2:40 pm
Russ Atkinson, September 26, 1983 6:00 pm
Doug Wyatt, January 13, 1984 3:52 pm
DIRECTORY
Buttons USING [ButtonProc],
Convert USING [RopeFromInt],
EditToolBuilder USING [BuildButton, BuildDataFieldPair, BuildPair, BuildTriple, DataFieldButton, GetDataLooks, GetDataNode],
EditToolPrivate USING [afterSel, anywhere, ChangeState, CheckPSel, CycleTriple, DoButton, DoOpsCom, entireDoc, Extend, FixPSel, GetOps, GetPatternNode, Info, mainToolInfo, nodes, Register, ReportPatternError, SavePSel, Search, SubsInfo, SubsInfoRec, withinSel, words],
Labels USING [Set],
Menus USING [MenuProc],
MessageWindow USING [Append, Blink],
NameSymbolTable USING [Name, nullName, RopeFromName],
NodeAddrs USING [GetTextAddr, PutTextAddr, RemTextAddr],
NodeProps USING [false, true],
NodeStyle USING [StyleNameForNode],
Rope USING [Concat, ROPE, RopeRep, Size],
RopeReader USING [Create, Get, GetIndex, ReadOffEnd, Ref, SetPosition],
TEditDocument USING [BeforeAfter, Selection, SelectionGrain, SelectionRec, TEditDocumentData],
TEditInput USING [CommandProc, CurrentEvent, Interpret],
TEditInputOps USING [CheckReadonly],
TEditLocks USING [Lock],
TEditOps USING [GetSelData],
TEditRefresh USING [ScrollToEndOfSel],
TEditSelection USING [Deselect, LockSel, MakeSelection, pSel, SelectionRoot, UnlockDocAndPSel, UnlockSel],
TextEdit USING [ChangeCaps, ChangeLooks, ChangeStyle, ChangeType, DeleteText, FetchChar, FetchLooks, FromRope, PutProp, ReplaceByText, SetLooks, Size],
TextFind USING [Create, MalformedPattern, NameLoc, NameLooks],
TextLooks USING [FetchLooks, Looks, noLooks],
TextNode USING [NarrowToTextNode, NodeItself, nullTypeName, Offset, pZone, Ref, RefTextNode, Root, TypeName],
TreeFind USING [Apply, CommentControl, Create],
UndoEvent USING [Ref],
ViewerClasses USING [Viewer];
EditToolSubsImpl: CEDAR PROGRAM
IMPORTS EditToolPrivate, EditToolBuilder, 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 EditToolBuilder, EditToolPrivate;
----------------------------
Offset: TYPE = TextNode.Offset;
Viewer: TYPE = ViewerClasses.Viewer;
----------------------------
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.RopeFromInt[count],
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;
};
}...