-- RopeEditReplaceImpl.mesa
-- written by Bill Paxton, February 1981
-- last edit by Bill Paxton, May 20, 1982 9:38 am
Last Edited by: Maxwell, January 5, 1983 12:04 pm
DIRECTORY
RopeEdit,
RopeFrom,
Rope,
RopeInline;
RopeEditReplaceImpl: CEDAR 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] = TRUSTED {
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: BOOLEANFALSE;
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: BOOLEANFALSE;
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] = TRUSTED {
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: NATIF 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: BOOLEANFALSE;
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: BOOLEANFALSE;
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: ROPENIL,
baseSize, repSize: Offset ← MaxLen]
RETURNS [new: ROPE] = TRUSTED {
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: BOOLEANFALSE;
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: BOOLEANFALSE;
partSize←xpos+repSize; -- 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 <= 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.