-- EditToolSubsImpl.mesa -- Edited by Paxton on 6-Feb-82 11:56:26 DIRECTORY EditToolPrivate, Buttons, Convert, EditNotify, Inline, IOStream, UndoEvent, Labels, List, Menus, MessageWindow, NodeAddrs, Rope, RopeEdit, RopeReader, RunReader, TextEdit, TextFind, TextLooks, TextLooksSupport, TextNode, TEditDocument, TEditInputOps, TEditOps, TreeFind, UserTerminal, ViewerOps, ViewerClasses, ViewerMenus; EditToolSubsImpl: PROGRAM IMPORTS EditToolPrivate, Buttons, Convert, Inline, IOStream, Labels, List, MessageWindow, NodeAddrs, Rope, TEditInputOps, TEditOps, TextEdit, TextFind, TextNode, TreeFind, UserTerminal, ViewerOps EXPORTS EditToolPrivate = { OPEN ViewerClasses, EditToolPrivate; ---------------------------- ---------------------------- sourceButton: Buttons.Button; sourceArg: PUBLIC ViewerClasses.Viewer; -- the viewer holding the source text sourceArgAtom: ATOM = $EditToolReplaceBy; SourceButton: Buttons.ButtonProc = { IF mainEditTool THEN TEditOps.InterpretAtom[button,sourceArgAtom] ELSE [] ← SourceArgOp[] }; SourceArgOp: TEditOps.CommandProc = { DataFieldButton[sourceArg] }; BuildSourceEntry: PUBLIC PROC = { [sourceButton,sourceArg] ← BuildDataFieldPair["Replace by:", SourceButton] }; ---------------------------- doitButton: Buttons.Button; yesButton: Buttons.Button; noButton: Buttons.Button; substituteButton: Buttons.Button; replaceRope: Rope.Ref = "Replace!"; doitRope: Rope.Ref = "DoOne!"; subsRope: Rope.Ref = "Substitute!"; doallRope: Rope.Ref = "DoAll!"; BuildDoItEntries: PUBLIC PROC = { yesButton ← Buttons.Create["Yes!", DoYes, entryLeft, heightSoFar, 0, 0, NIL, FALSE, container, FALSE]; yesButton.border ← FALSE; noButton ← Buttons.Create["No!", DoNo, entryLeft+gapSize*2+yesButton.ww, heightSoFar, 0, 0, NIL, FALSE, container, FALSE]; noButton.border ← FALSE; substituteButton ← Buttons.Create[subsRope, DoSubstitute, entryLeft+gapSize*4+yesButton.ww+noButton.ww, heightSoFar, 0, 0, NIL, TRUE, container, FALSE]; -- notice that we fork Substitute's substituteButton.border ← FALSE; doitButton ← Buttons.Create[replaceRope, DoIt, entryLeft+gapSize*6+yesButton.ww+noButton.ww+substituteButton.ww, heightSoFar, 0, 0, NIL, FALSE, container, FALSE]; doitButton.border ← FALSE; heightSoFar ← heightSoFar + entryHeight + entryVSpace; }; ---------------------------- operationButton: Buttons.Button; operationLabel: Labels.Label; doReplace: PUBLIC BOOLEAN ← TRUE; replaceOperation: Rope.Ref = "Do Replace"; specifiedOperation: Rope.Ref = "Do Operations Specified Below"; doOpsAtom: ATOM = $EditToolDoOps; doReplaceAtom: ATOM = $EditToolDoReplace; OperationButton: Buttons.ButtonProc = { IF mainEditTool THEN ChangeState[operationLabel,doReplace,doReplaceAtom,doOpsAtom] ELSE IF doReplace THEN [] ← DoOpsOp[] ELSE [] ← DoReplaceOp[] }; DoOpsOp: TEditOps.CommandProc = { doReplace ← FALSE; Labels.Set[operationLabel, specifiedOperation]; Buttons.ReLabel[doitButton, doitRope]; Buttons.ReLabel[substituteButton, doallRope] }; DoReplaceOp: TEditOps.CommandProc = { doReplace ← TRUE; Labels.Set[operationLabel, replaceOperation]; Buttons.ReLabel[doitButton, replaceRope]; Buttons.ReLabel[substituteButton, subsRope] }; BuildOperationEntry: PUBLIC PROC = { [operationLabel,operationButton] ← BuildPair[OperationButton,doReplace,replaceOperation,specifiedOperation] }; ---------------------------- ---------------------------- initCapButton: Buttons.Button; initCapLabel: Labels.Label; forceInitCap: PUBLIC BOOLEAN ← TRUE; forcingInitCap: Rope.Ref = "Capitalize like first replaced char"; ignoringInitCap: Rope.Ref = "Don't change replacement capitalization"; forceInitCapAtom: ATOM = $EditToolChangeInitCap; ignoreInitCapAtom: ATOM = $EditToolLeaveInitCap; InitCapButton: Buttons.ButtonProc = { IF mainEditTool THEN ChangeState[initCapLabel,forceInitCap,forceInitCapAtom,ignoreInitCapAtom] ELSE IF forceInitCap THEN [] ← LeaveInitCapOp[] ELSE [] ← ChangeInitCapOp[] }; ChangeInitCapOp: TEditOps.CommandProc = { forceInitCap ← TRUE; Labels.Set[initCapLabel,forcingInitCap] }; LeaveInitCapOp: TEditOps.CommandProc = { forceInitCap ← FALSE; Labels.Set[initCapLabel,ignoringInitCap] }; BuildInitCapEntry: PUBLIC PROC = { [initCapLabel,initCapButton] ← BuildPair[InitCapButton,forceInitCap,forcingInitCap,ignoringInitCap] }; ---------------------------- opsButton: Buttons.Button; opsArg: ViewerClasses.Viewer; opsAtom: ATOM = $EditToolOperations; OpsButton: Buttons.ButtonProc = { IF mainEditTool THEN TEditOps.InterpretAtom[button,opsAtom] ELSE [] ← OpsArgOp[] }; OpsArgOp: TEditOps.CommandProc = { DataFieldButton[opsArg] }; BuildOperationField: PUBLIC PROC = { [opsButton,opsArg] ← BuildDataFieldPair["Operations:", OpsButton] }; GetOps: PROC RETURNS [list: LIST OF REF ANY] = { OPEN IOStream; rope: Rope.Ref ← TextEdit.GetRope[GetDataNode[opsArg]]; h: Handle ← CreateInputStreamFromRope[rope]; item: REF ANY; WHILE (item ← GetRefAny[h ! EndOfStream => { item ← NIL; CONTINUE}]) # NIL DO WITH item SELECT FROM x: ROPE => item ← LOOPHOLE[Rope.ToString[x], REF TEXT]; -- for now must convert ROPE to REF TEXT ENDCASE; list ← List.Nconc1[list, item]; ENDLOOP; --h.Close[]; }; ---------------------------- ---------------------------- getopsButton: Buttons.Button; setopButton: Buttons.Button; getopButton: Buttons.Button; BuildGetAndSetOpsEntries: PUBLIC PROC = { getopsButton ← Buttons.Create["GetLastOps!", DoGetOps, entryLeft, heightSoFar, 0, 0, NIL, FALSE, container, FALSE]; getopsButton.border ← FALSE; setopButton ← Buttons.Create["SetCom!", DoSetCom, entryLeft+gapSize*2+getopsButton.ww, heightSoFar, 0, 0, NIL, FALSE, container, FALSE]; setopButton.border ← FALSE; getopButton ← Buttons.Create["GetCom!", DoGetCom, entryLeft+gapSize*4+getopsButton.ww+setopButton.ww, heightSoFar, 0, 0, NIL, FALSE, container, FALSE]; getopButton.border ← FALSE; heightSoFar ← heightSoFar + entryHeight + entryVSpace; }; DoGetOps: Buttons.ButtonProc = { ShowOps[TEditOps.GetRepeatSequence[]] }; -- this cannot be a registered TEdit atom since must reenter tedit monitor to get ops ShowOps: PROC [list: LIST OF REF ANY] = { OPEN IOStream; h: IOStream.Handle ← CreateOutputStreamToRope[]; doingChars: BOOLEAN ← FALSE; nospace: BOOLEAN ← TRUE; Space: PROC = { IF doingChars THEN { -- end of string PutChar[h, '"]; doingChars ← FALSE }; IF nospace THEN nospace ← FALSE ELSE PutChar[h,' ] }; AddChar: PROC [c: CHARACTER] = { IF ~doingChars THEN { -- start of string Space[]; PutChar[h, '"]; doingChars ← TRUE }; SELECT c FROM '', '", '\\ => PutChar[h, '\\]; ENDCASE; PutChar[h, c] }; { ENABLE UNWIND => h.Close[]; FOR l: LIST OF REF ANY ← list, l.rest UNTIL l=NIL DO WITH l.first SELECT FROM x: ATOM => { Space[]; Put[h,atom[x]] }; x: REF INT => { Space[]; Put[h,int[x↑]] }; x: REF CHARACTER => AddChar[x↑]; x: ROPE => { AddC: PROC [c: CHAR] RETURNS [BOOL] = { AddChar[c]; RETURN [FALSE] }; [] ← Rope.Map[base: x, action: AddC] }; x: REF TEXT => { FOR i: NAT IN [0..x.length) DO AddChar[x[i]]; ENDLOOP }; ENDCASE; ENDLOOP; IF doingChars THEN PutChar[h, '"]; TEditOps.SetTextContents[opsArg, GetOutputStreamRope[h]]; }}; debugCom: BOOLEAN ← FALSE; SetCom: PROC [num: [0..9]] = { list: LIST OF REF ANY ← GetOps[]; IF debugCom THEN ShowOps[list]; TEditOps.SetCommand[num,list]; }; DoSetCom: Buttons.ButtonProc = { OPEN IOStream; -- this cannot be a registered TEdit atom since must reenter tedit monitor to get ops rope: Rope.Ref ← TextEdit.GetRope[GetDataNode[comArg]]; h: Handle ← CreateInputStreamFromRope[rope]; num: INT ← GetInt[h ! Error => GOTO BadNum]; IF num ~IN [0..9] THEN GOTO BadNum; SetCom[Inline.LowHalf[num]]; EXITS BadNum => { OPEN MessageWindow; Append["Enter number from 0 to 9 in Command Number field", TRUE]; Blink[] } }; DoGetCom: Buttons.ButtonProc = { OPEN IOStream; -- this cannot be a registered TEdit atom since must reenter tedit monitor to get ops rope: Rope.Ref ← TextEdit.GetRope[GetDataNode[comArg]]; h: Handle ← CreateInputStreamFromRope[rope]; num: INT ← GetInt[h ! Error => GOTO BadNum]; IF num ~IN [0..9] THEN GOTO BadNum; ShowOps[TEditOps.GetCommand[Inline.LowHalf[num]]]; EXITS BadNum => { OPEN MessageWindow; Append["Enter number from 0 to 9 in Command Number field", TRUE]; Blink[] } }; ---------------------------- comButton: Buttons.Button; comArg: ViewerClasses.Viewer; comNumAtom: ATOM = $EditToolCommandNumber; ComNumButton: Buttons.ButtonProc = { IF mainEditTool THEN TEditOps.InterpretAtom[button,comNumAtom] ELSE [] ← DoComNumOp[] }; DoComNumOp: TEditOps.CommandProc = { DataFieldButton[comArg] }; BuildComNumField: PUBLIC PROC = { [comButton,comArg] ← BuildDataFieldPair["Command number [0..9]:", ComNumButton, 1]; TEditOps.SetTextContents[comArg, "1 "]; }; ---------------------------- ---------------------------- doItAtom: ATOM = $EditToolDoIt; DoIt: Buttons.ButtonProc = { IF mainEditTool THEN TEditOps.InterpretAtom[button,doItAtom] ELSE [] ← DoItOp[] }; DoItOp: TEditOps.CommandProc = { pSel: TEditDocument.Selection; params: LIST OF REF ANY; IF doReplace THEN { DoReplace[]; RETURN }; IF (pSel ← TEditOps.GetSelData[])=NIL OR pSel.viewer=NIL OR pSel.viewer.class.flavor#$Text OR (params ← GetOps[])=NIL THEN { UserTerminal.BlinkDisplay[]; RETURN }; IF mainEditTool THEN TEditOps.SneakyInterpret[pSel.viewer, params] ELSE TEditOps.InterpretInput[pSel.viewer, params] }; tSel: PUBLIC TEditDocument.Selection ← NEW[TEditDocument.SelectionRec]; DoReplace: PROC = { -- for now do it as a delete followed by a copy -- to do the copy, must make source the secondary selection pSel: TEditDocument.Selection = TEditOps.GetSelData[]; tdd: TEditDocument.TEditDocumentData = NARROW[sourceArg.data]; node: TextNode.RefTextNode ← GetDataNode[sourceArg]; size: TextNode.Offset; runs: TextLooks.Runs; initCap: BOOLEAN; IF pSel=NIL OR pSel.viewer=NIL OR pSel.viewer.class.flavor#$Text THEN { UserTerminal.BlinkDisplay[]; RETURN }; SELECT looksChoice FROM looksOnly => { targetLooks: TextLooks.Looks ← GetDataLooks[targetArg,"Target"]; sourceLooks: TextLooks.Looks ← GetDataLooks[sourceArg,"Source"]; TEditInputOps.ChangeLooks[sourceLooks,targetLooks]; RETURN }; textOnly => IF node#NIL THEN { runs ← node.runs; -- save source looks TextEdit.SetLooks[node,GetSelInitLooks[pSel]] }; textAndLooks => NULL; ENDCASE => ERROR; initCap ← forceInitCap AND IsSelInitCap[pSel]; TEditOps.OpenRepeatSequence[]; TEditInputOps.Delete[]; IF (size ← TextEdit.Size[node]) = 0 THEN RETURN; -- no source tSel.start.pos ← [node,0]; tSel.end.pos ← tSel.clickPoint ← [node,size]; tSel.granularity ← char; tSel.viewer ← sourceArg; tSel.data ← tdd; tSel.insertion ← before; TEditOps.SetSelData[tSel,FALSE]; TEditInputOps.Copy[]; IF looksChoice=textOnly AND node#NIL THEN node.runs ← runs; -- restore source IF initCap AND IsSelInitLower[pSel] THEN TEditInputOps.Capitalise[firstCap]; }; GetSelInitLooks: PROC [pSel: TEditDocument.Selection] RETURNS [TextLooks.Looks] = { node: TextNode.RefTextNode ← TextNode.NarrowToTextNode[pSel.start.pos.node]; loc: TextNode.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: TextNode.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: TextNode.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: ATOM = $EditToolDoYes; DoYes: Buttons.ButtonProc = { IF mainEditTool THEN TEditOps.InterpretAtom[button,doYesAtom] ELSE [] ← DoYesOp[] }; DoYesOp: TEditOps.CommandProc = { [] ← DoItOp[]; Search[TRUE] }; doNoAtom: ATOM = $EditToolDoNo; DoNo: Buttons.ButtonProc = { IF mainEditTool THEN TEditOps.InterpretAtom[button,doNoAtom] ELSE [] ← DoNoOp[] }; DoNoOp: TEditOps.CommandProc = { Search[TRUE] }; ---------------------------- subsRangeButton: Buttons.Button; subsRangeLabel: Labels.Label; subsRange: PUBLIC [0..2] ← withinSel; withinSelRope: Rope.Ref = "Within Selection Only"; afterSelRope: Rope.Ref = "After Selection Only"; entireDocRope: Rope.Ref = "In Entire Document"; withinSelAtom: ATOM = $EditToolSubInSel; afterSelAtom: ATOM = $EditToolSubAfterSel; entireDocAtom: ATOM = $EditToolSubEntireDoc; BuildSubstituteEntry: PUBLIC PROC = { [subsRangeLabel,subsRangeButton] ← BuildTriple[SubsRangeButton, withinSel, withinSelRope, afterSelRope, entireDocRope] }; SubsRangeButton: Buttons.ButtonProc = { IF mainEditTool THEN CycleTriple[subsRangeLabel, subsRange, withinSelAtom, afterSelAtom, entireDocAtom] ELSE SELECT subsRange FROM withinSel => [] ← SubsAfterOp[]; afterSel => [] ← SubsEntireDocOp[]; entireDoc => [] ← SubsWithinOp[]; ENDCASE => ERROR }; SubsWithinOp: TEditOps.CommandProc = { subsRange ← withinSel; Labels.Set[subsRangeLabel,withinSelRope] }; SubsAfterOp: TEditOps.CommandProc = { subsRange ← afterSel; Labels.Set[subsRangeLabel,afterSelRope] }; SubsEntireDocOp: TEditOps.CommandProc = { subsRange ← entireDoc; Labels.Set[subsRangeLabel,entireDocRope] }; GetLooksAndPatternInfo: PUBLIC PROC [pattern: TextNode.RefTextNode] RETURNS [pat: TextNode.RefTextNode, ignoreLooks, lit: BOOLEAN, searchLooks: TextLooks.Looks] = { pat ← pattern; lit ← literal; searchLooks ← TextLooks.noLooks; SELECT looksChoice FROM looksOnly => { size: TextNode.Offset = TextEdit.Size[pattern]; searchLooks ← IF size=0 THEN TextLooks.noLooks ELSE TextEdit.FetchLooks[pattern,0]; FOR i: TextNode.Offset IN [1..size) DO IF TextEdit.FetchLooks[pattern,i]#searchLooks THEN { OPEN MessageWindow; Append["Pattern does not have uniform looks.",TRUE]; Append[" Using looks from first char."]; Blink[]; EXIT }; ENDLOOP; ignoreLooks ← lit ← FALSE; pat ← TextEdit.FromRope["#*"]; TextEdit.SetLooks[pat,searchLooks] }; textOnly => ignoreLooks ← TRUE; textAndLooks => ignoreLooks ← FALSE; ENDCASE => ERROR }; doSubsAtom: ATOM = $EditToolSubstitute; DoSubstitute: Buttons.ButtonProc = { IF mainEditTool THEN TEditOps.InterpretAtom[button,doSubsAtom] ELSE [] ← DoSubstituteOp[] }; DoSubstituteOp: TEditOps.CommandProc = { finder: TreeFind.Finder; first, last, selStart, selEnd: TextNode.Ref; firstText, lastText: TextNode.RefTextNode; lastWhere: TextNode.RefTextNode; pattern: TextNode.RefTextNode; start, lastLen: TextNode.Offset; count: LONG INTEGER; pSel: TEditDocument.Selection = TEditOps.GetSelData[]; vwr: ViewerClasses.Viewer; data: TEditDocument.TEditDocumentData; insertion: TEditDocument.BeforeAfter; granularity: TEditDocument.SelectionGrain; ignoreLooks, lit: BOOLEAN; searchLooks: TextLooks.Looks; IF CheckPSel[pSel]=FALSE OR (pattern ← GetPatternNode[])=NIL THEN RETURN; vwr ← pSel.viewer; [pattern,ignoreLooks,lit,searchLooks] ← GetLooksAndPatternInfo[pattern]; SELECT subsRange FROM withinSel => { first ← pSel.start.pos.node; last ← pSel.end.pos.node; start ← pSel.start.pos.where; lastLen ← pSel.end.pos.where }; 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; IF (firstText ← TextNode.NarrowToTextNode[selStart]) # NIL THEN NodeAddrs.PutTextAddr[firstText,$Start,pSel.start.pos.where]; IF (lastText ← TextNode.NarrowToTextNode[selEnd]) # NIL THEN NodeAddrs.PutTextAddr[lastText,$End,pSel.end.pos.where]; { ENABLE TextFind.MalformedPattern => { OPEN MessageWindow; Append[SELECT ec FROM toobig => "Search pattern is too big", endquote => "Search pattern incorrectly ends with quote", boundary => "Search pattern incorrectly has | inside rather than at beginning or end", ENDCASE => "Error in search pattern", TRUE]; Blink[]; GOTO Quit }; MakeSel: PROC [where: TextNode.RefTextNode, at, atEnd:TextNode.Offset] = { tSel.start.pos ← [where,at]; tSel.end.pos ← [where,MAX[0,atEnd-1]]; tSel.granularity ← char; tSel.viewer ← vwr; tSel.data ← pSel.data; tSel.insertion ← after; TEditOps.SetSelData[tSel]; TEditOps.AutoScroll[FALSE]; }; DoSubs: PROC [where: TextNode.RefTextNode, at, atEnd, before, after: TextNode.Offset] RETURNS [continue, bumpCount: BOOLEAN, from, delta: TextNode.Offset] = { len: TextNode.Offset ← atEnd-at; size: TextNode.Offset ← TextEdit.Size[where]; initCap: BOOLEAN ← forceInitCap AND at < size AND TextEdit.FetchChar[where,at] IN ['A..'Z]; initLooks: TextLooks.Looks; IF interrupt THEN { continue ← FALSE; RETURN }; continue ← bumpCount ← TRUE; SELECT looksChoice FROM looksOnly => { IF looksChoice=looksOnly AND ~word THEN { [at,atEnd] ← Extend[TRUE,searchLooks,where,at,atEnd,last,lastLen]; len ← atEnd-at }; TextEdit.ChangeLooks[where,targetLooks,sourceLooks, at,len,event]; from ← at+len; delta ← 0; RETURN }; textOnly => initLooks ← IF at < size THEN TextEdit.FetchLooks[where,at] ELSE TextLooks.noLooks; textAndLooks => NULL; ENDCASE => ERROR; --MakeSel[where,at,atEnd]; [] ← TextEdit.ReplaceByText[where,at,len, sourceRope,sourceRuns,sourceStart,sourceLen,event]; IF initCap AND sourceLen > 0 AND TextEdit.FetchChar[where,at] IN ['a..'z] THEN TextEdit.ChangeCaps[where,at,1,firstCap,event]; IF looksChoice=textOnly THEN TextEdit.SetLooks[where,initLooks,at,sourceLen,event]; --TEditOps.PaintEdits[pSel]; from ← at+sourceLen; delta ← sourceLen-len }; DoOps: PROC [where: TextNode.RefTextNode, at, atEnd, before, after: TextNode.Offset] RETURNS [continue, bumpCount: BOOLEAN, from, delta: TextNode.Offset] = { len: TextNode.Offset ← atEnd-at; size: TextNode.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]; IF mainEditTool THEN TEditOps.SneakyInterpret[vwr, params] ELSE TEditOps.InterpretInput[vwr, params]; delta ← NodeAddrs.GetTextAddr[where,$After]-atEnd; from ← atEnd+delta; continue ← bumpCount ← TRUE }; source: TextNode.RefTextNode ← GetDataNode[sourceArg]; sourceStart, sourceLen, sourceEnd: TextNode.Offset; sourceRope: Rope.Ref; sourceRuns: TextLooks.Runs; targetLooks, sourceLooks: TextLooks.Looks; size: TextNode.Offset ← TextEdit.Size[source]; event: UndoEvent.Ref ← TEditOps.CurrentEvent[]; params: LIST OF REF ANY; interrupt ← FALSE; IF source # NIL THEN { sourceRope ← source.rope; sourceRuns ← source.runs }; sourceStart ← 0; sourceLen ← size; sourceEnd ← sourceStart+sourceLen; finder ← TreeFind.Create[pattern,lit,word,ignoreLooks,ignoreCase]; IF ~doReplace THEN { IF (params ← GetOps[])=NIL THEN { UserTerminal.BlinkDisplay[]; RETURN }} ELSE IF looksChoice=looksOnly THEN { targetLooks ← GetDataLooks[targetArg,"Target"]; sourceLooks ← GetDataLooks[sourceArg,"Source"] }; TEditOps.OpenRepeatSequence; count ← TreeFind.Apply[finder,first, IF doReplace THEN DoSubs ELSE DoOps, start,last,lastLen,looksExact]; }; -- update the selection tSel.start.pos ← [selStart, IF firstText=NIL THEN TextNode.NodeItself ELSE NodeAddrs.GetTextAddr[firstText,$Start]]; tSel.end.pos ← tSel.clickPoint ← [selEnd, IF lastText=NIL THEN TextNode.NodeItself ELSE NodeAddrs.GetTextAddr[lastText,$End]]; 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; -- repaint IF subsRange=withinSel THEN { TEditOps.SetSelData[tSel,TRUE,FALSE]; TEditOps.PaintEdits[tSel] } ELSE { TEditOps.SetSelData[NIL]; -- clear it ViewerOps.PaintViewer[vwr]; TEditOps.SetSelData[tSel] }; IF count > 0 THEN ViewerOps.SetNewVersion[vwr]; -- display the number of substitutions made MessageWindow.Append[ Rope.Concat[Convert.ValueToRope[[signed[count,10]]], IF count # 1 THEN " substitutions." ELSE " substitution."], TRUE]; EXITS Quit => RETURN; }; RegisterSubs: PUBLIC PROC = { TEditOps.Register[doSubsAtom, DoSubstituteOp]; TEditOps.Register[sourceArgAtom, SourceArgOp]; TEditOps.Register[opsAtom, OpsArgOp]; TEditOps.Register[comNumAtom, DoComNumOp]; TEditOps.Register[doItAtom, DoItOp]; TEditOps.Register[doYesAtom, DoYesOp]; TEditOps.Register[doNoAtom, DoNoOp]; TEditOps.Register[doOpsAtom, DoOpsOp]; TEditOps.Register[doReplaceAtom, DoReplaceOp]; TEditOps.Register[forceInitCapAtom, ChangeInitCapOp]; TEditOps.Register[ignoreInitCapAtom, LeaveInitCapOp]; TEditOps.Register[withinSelAtom, SubsWithinOp]; TEditOps.Register[afterSelAtom, SubsAfterOp]; TEditOps.Register[entireDocAtom, SubsEntireDocOp]; }; UnRegisterSubs: PUBLIC PROC = { TEditOps.UnRegister[doSubsAtom]; TEditOps.UnRegister[sourceArgAtom]; TEditOps.UnRegister[opsAtom]; TEditOps.UnRegister[comNumAtom]; TEditOps.UnRegister[doItAtom]; TEditOps.UnRegister[doYesAtom]; TEditOps.UnRegister[doNoAtom]; TEditOps.UnRegister[doOpsAtom]; TEditOps.UnRegister[doReplaceAtom]; TEditOps.UnRegister[forceInitCapAtom]; TEditOps.UnRegister[ignoreInitCapAtom]; TEditOps.UnRegister[withinSelAtom]; TEditOps.UnRegister[afterSelAtom]; TEditOps.UnRegister[entireDocAtom]; }; }...