-- RopeEditReplaceImpl.mesa -- written by Bill Paxton, February 1981 -- last edit by Bill Paxton, December 22, 1981 10:23 am DIRECTORY RopeEdit, RopeFrom, Rope, RopeInline; RopeEditReplaceImpl: PROGRAM IMPORTS RopeEdit, RopeInline, RopeFrom EXPORTS RopeEdit SHARES Rope = BEGIN OPEN RopeEdit, RopeInline; FlatMax: Offset = 30; -- if shorter, copy to flat rope -- Edit ReplaceByChar: PUBLIC PROC [ base: ROPE, char: CHAR, start: Offset _ 0, len, baseSize: Offset _ MaxLen] RETURNS [new: ROPE] = { oldPos, newPos, size, xsize: Offset; replace: ROPE; IF baseSize=MaxLen THEN baseSize _ RopeInline.InlineSize[base]; IF start > baseSize THEN start _ baseSize; len _ MIN[len,baseSize-start]; IF (new _ RopeFrom.TryAppendReplaceByChar[base,char,start,len,baseSize]) # NIL THEN RETURN; IF (size _ baseSize+1-len) <= FlatMax THEN RETURN [ RopeFrom.FlatReplaceByChar[base,char,start,len,baseSize,FALSE]]; oldPos _ start+len; newPos _ start+1; IF base # NIL THEN WITH x:base SELECT FROM node => WITH x:x SELECT FROM replace => { xnewPos: Offset _ x.newPos; xstart: Offset _ x.start; xsize _ xnewPos-xstart; IF start = xnewPos THEN { -- appending to the replacement ok: BOOLEAN _ FALSE; IF (new _ RopeFrom.TryFlatAppendChar[x.replace, char, xsize]) # NIL THEN { replace _ new; ok _ TRUE } ELSE IF xsize < FlatMax THEN { replace _ RopeFrom.FlatAppendChar[x.replace, char, xsize, FALSE]; ok _ TRUE }; IF ok THEN { start _ xstart; oldPos _ x.oldPos+len; newPos _ start+xsize+1; base _ x.base }}}; concat => { xpos: Offset _ x.pos; IF start=xpos AND len=0 THEN { ok: BOOLEAN _ FALSE; IF (new _ RopeFrom.TryFlatAppendChar[x.base, char, xpos]) # NIL THEN ok _ TRUE ELSE IF xpos < FlatMax THEN { new _ RopeFrom.FlatAppendChar[x.base, char, xpos, FALSE]; ok _ TRUE }; IF ok THEN RETURN [ RopeFrom.qZone.NEW[Tconcat _ [node[concat[size,new,x.rest,xpos+1, 1+MAX[Depth[new],Depth[x.rest]]]]]]] }}; ENDCASE; ENDCASE; IF replace=NIL THEN replace _ RopeFrom.Character[char]; new _ RopeFrom.qZone.NEW[Treplace _ [node[replace[size,base,replace,start,oldPos,newPos, 1+MAX[Depth[base],Depth[replace]]]]]]}; ReplaceByString: PUBLIC PROC [ base: ROPE, string: REF READONLY TEXT, stringStart: NAT _ 0, stringNum: NAT _ MaxNat, start: Offset _ 0, len, baseSize: Offset _ MaxLen] RETURNS [new: ROPE] = { oldPos, newPos, size, xsize: Offset; replace: ROPE; IF baseSize=MaxLen THEN baseSize _ RopeInline.InlineSize[base]; IF start > baseSize THEN start _ baseSize; len _ MIN[len,baseSize-start]; IF stringNum=MaxNat THEN { stringSize: NAT _ IF string=NIL THEN 0 ELSE string.length; IF stringStart >= stringSize THEN RETURN [Delete[base,start,len,baseSize]]; stringNum _ stringSize-stringStart }; IF (new _ RopeFrom.TryAppendReplaceByString[ base,string,stringStart,stringNum,start,len,baseSize]) # NIL THEN RETURN [new]; IF (size _ baseSize+stringNum-len) <= FlatMax THEN RETURN [ RopeFrom.FlatReplaceByString[ base,string,stringStart,stringNum,start,len,baseSize,FALSE]]; oldPos _ start+len; newPos _ start+stringNum; IF base # NIL THEN WITH x:base SELECT FROM node => WITH x:x SELECT FROM replace => { xnewPos: Offset _ x.newPos; xstart: Offset _ x.start; IF start = xnewPos THEN { -- appending to the replacement ok: BOOLEAN _ FALSE; xsize _ xnewPos-xstart; IF (new _ RopeFrom.TryFlatAppendString[x.replace, string,stringStart,stringNum,xsize]) # NIL THEN { replace _ new; ok _ TRUE} ELSE IF xsize+stringNum <= FlatMax THEN { replace _ RopeFrom.FlatAppendString[x.replace, string,stringStart,stringNum,xsize]; ok _ TRUE }; IF ok THEN { start _ xstart; oldPos _ x.oldPos+len; newPos _ start+xsize+stringNum; base _ x.base}}}; concat => { xpos: Offset _ x.pos; IF start=xpos AND len=0 THEN { ok: BOOLEAN _ FALSE; IF (new _ RopeFrom.TryFlatAppendString[x.base, string,stringStart,stringNum,xpos]) # NIL THEN ok _ TRUE ELSE IF xpos+stringNum <= FlatMax THEN { new _ RopeFrom.FlatAppendString[x.base, string,stringStart,stringNum,xpos,FALSE]; ok _ TRUE }; IF ok THEN RETURN [ RopeFrom.qZone.NEW[Tconcat _ [node[concat[size,new,x.rest,xpos+stringNum, 1+MAX[Depth[new],Depth[x.rest]]]]]]] }}; ENDCASE; ENDCASE; IF replace=NIL THEN replace _ RopeFrom.String[string,stringStart,stringNum]; new _ RopeFrom.qZone.NEW[Treplace _ [node[replace[size,base,replace,start,oldPos,newPos, 1+MAX[Depth[base],Depth[replace]]]]]]}; Replace: PUBLIC PROC [ base: ROPE, start: Offset _ 0, len: Offset _ MaxLen, replace: ROPE _ NIL, baseSize, repSize: Offset _ MaxLen] RETURNS [new: ROPE] = { size, oldPos, newPos, xsize: Offset; IF baseSize=MaxLen THEN baseSize _ RopeInline.InlineSize[base]; IF start >= baseSize THEN RETURN [Concat[base,replace,baseSize,repSize]]; IF len=MaxLen THEN len _ MIN[len,baseSize-start]; IF len=0 AND replace=NIL THEN RETURN[base]; IF repSize=MaxLen THEN repSize _ RopeInline.InlineSize[replace]; size _ baseSize-len+repSize; IF size <= FlatMax THEN RETURN [ RopeFrom.FlatReplace[base,start,len,replace,size,baseSize,repSize]]; oldPos _ start+len; newPos _ start+repSize; WHILE base # NIL DO WITH x:base SELECT FROM node => WITH x:x SELECT FROM replace => { xnewPos: Offset _ x.newPos; xstart: Offset _ x.start; IF start <= xstart AND oldPos >= xnewPos THEN { -- replacing the replacement oldPos _ x.oldPos+(oldPos-xnewPos); len _ oldPos-start; base _ x.base; LOOP} ELSE IF repSize = 0 AND start > xstart AND oldPos = xnewPos -- deleting replacement end AND (xsize_start-xstart) <= FlatMax THEN { replace _ RopeFrom.FlatSubstr[x.replace,0,xsize]; newPos _ start; oldPos _ x.oldPos; start _ xstart; base _ x.base} ELSE IF repSize = 0 AND start = xstart AND oldPos < xnewPos -- deleting start AND (xsize_xnewPos-oldPos) <= FlatMax THEN { replace _ RopeFrom.FlatSubstr[x.replace,len,xsize]; newPos _ start+xsize; oldPos _ x.oldPos; base _ x.base} ELSE IF start = xnewPos THEN { ok: BOOLEAN _ FALSE; xsize _ xnewPos-xstart; IF repSize <= FlatMax AND (new _ RopeFrom.TryAppendConcat[x.replace,replace,xsize,repSize]) # NIL THEN ok _ TRUE ELSE IF xsize+repSize <= FlatMax THEN { new _ RopeFrom.FlatConcat[x.replace,replace,xsize,repSize,FALSE]; ok _ TRUE }; IF ok THEN { replace _ new; new _ NIL; start _ xstart; len _ len+x.oldPos-xstart; oldPos _ start+len; repSize _ xsize+repSize; newPos _ start+repSize; base _ x.base; LOOP }} ELSE IF start+len = xstart AND (xsize_xnewPos-xstart)+repSize <= FlatMax THEN { -- replacing just before replace _ RopeFrom.FlatConcat[replace,x.replace,repSize,xsize]; len _ len+x.oldPos-xstart; oldPos _ start+len; repSize _ xsize+repSize; newPos _ start+repSize; base _ x.base; LOOP }}; concat => { xpos: Offset _ x.pos; IF start=xpos AND len=0 THEN { -- insert between base&rest partSize: Offset; ok: BOOLEAN _ FALSE; -- first try flat concat of x.base&replacement IF repSize <= FlatMax AND (new _ RopeFrom.TryAppendConcat[x.base,replace,xpos,repSize]) # NIL THEN ok _ TRUE ELSE IF (partSize_xpos+repSize) <= FlatMax THEN { new _ RopeFrom.FlatConcat[x.base,replace,xpos,repSize,FALSE]; ok _ TRUE }; IF ok THEN RETURN [ RopeFrom.qZone.NEW[Tconcat _ [node[concat[size,new,x.rest,partSize, 1+MAX[Depth[new],Depth[x.rest]]]]]]]; -- otherwise try concat of replacement&x.rest IF (partSize_x.size-xpos+repSize) <= FlatMax THEN { new _ RopeFrom.FlatConcat[replace,x.rest,repSize,x.size-xpos]; RETURN [RopeFrom.qZone.NEW[Tconcat _ [node[concat[size,x.base, new,xpos,1+MAX[Depth[new],Depth[x.rest]]]]]]]}; }}; ENDCASE; ENDCASE; EXIT; ENDLOOP; IF base=NIL THEN RETURN [replace]; new _ RopeFrom.qZone.NEW[Treplace _ [node[replace[size,base,replace,start,oldPos,newPos, 1+MAX[Depth[base],Depth[replace]]]]]]}; END.