-- RopeEditReplaceImpl.mesa; written by Bill Paxton, February 1981
-- edited by Bill Paxton, July 11, 1983 10:55 am
-- edited by McGregor, March 7, 1983 1:02 pm
-- 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: 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 [
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 ←
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: 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 [
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 ←
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] = 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: 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;
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 [
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 [
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 ←
NEW[Treplace ← [node[replace[size,base,replace,start,oldPos,newPos,
1+MAX[Depth[base],Depth[replace]]]]]]};
END.