<> <> <> <> <> 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: BOOLEAN _ FALSE] = { 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; }; }...