DIRECTORY ImmutableTioga, Rope, Rosary, TextLooks; ImmutableTiogaImpl: CEDAR PROGRAM IMPORTS Rope, Rosary, TextLooks EXPORTS ImmutableTioga ~ BEGIN OPEN ImmutableTioga; NChildren: PUBLIC PROC [node: Node] RETURNS [INT] ~ { children: ROSARY ~ node.children; RETURN [IF children=NIL THEN 0 ELSE children.size]; }; NthChild: PUBLIC PROC [node: Node, i: INT] RETURNS [Node] ~ { WITH Rosary.Fetch[node.children, i] SELECT FROM child: Node => RETURN[child]; ENDCASE => RETURN[NIL]; }; PropListGet: PUBLIC PROC [propList: PropList, name: ATOM] RETURNS [value: REF] ~ { FOR list: PropList _ propList, list.rest UNTIL list=NIL DO prop: Prop ~ list.first; IF prop.name=name THEN RETURN[prop.value]; ENDLOOP; RETURN[NIL]; }; PropListRem: PUBLIC PROC [propList: PropList, name: ATOM] RETURNS [PropList] ~ { IF propList=NIL THEN RETURN [NIL] ELSE IF propList.first.name=name THEN RETURN [propList.rest] ELSE { rest: PropList ~ PropListRem[propList.rest, name]; IF rest=propList.rest THEN RETURN [propList] ELSE RETURN [CONS[propList.first, rest]]; }; }; PropListPut: PUBLIC PROC [propList: PropList, name: ATOM, value: REF] RETURNS [PropList] ~ { rest: PropList ~ PropListRem[propList, name]; IF value=NIL THEN RETURN [rest] ELSE RETURN [CONS[NEW[PropRep _ [name, value]], rest]]; }; aComment: ATOM ~ $Comment; aFormat: ATOM ~ $Format; aStyleDef: ATOM ~ $StyleDef; aPrefix: ATOM ~ $Prefix; aPostfix: ATOM ~ $Postfix; aArtwork: ATOM ~ $Artwork; refBool: ARRAY BOOL OF REF BOOL ~ [FALSE: NEW[BOOL _ FALSE], TRUE: NEW[BOOL _ TRUE]]; PropsGet: PROC [props: Props, name: ATOM] RETURNS [value: REF] ~ { SELECT name FROM aComment => value _ refBool[props.comment]; aFormat => value _ props.formatName; ENDCASE => value _ PropListGet[props.propList, name]; }; PropsPut: PROC [props: Props, name: ATOM, value: REF] RETURNS [Props] ~ { propList: PropList _ props.propList; format: ATOM _ props.formatName; comment: BOOL _ props.comment; SELECT name FROM aComment => comment _ WITH value SELECT FROM x: REF BOOL => x^, ENDCASE => FALSE; aFormat => format _ WITH value SELECT FROM x: ATOM => x, ENDCASE => NIL; ENDCASE => propList _ PropListPut[props.propList, name, value]; IF propList#props.propList OR format#props.formatName OR comment#props.comment THEN { new: Props ~ NEW [PropsRep _ [propList: propList, formatName: format, comment: comment, hasStyleDef: props.hasStyleDef, hasPrefix: props.hasPrefix, hasPostfix: props.hasPostfix, hasArtwork: props.hasArtwork]]; IF new.propList#props.propList THEN { hasValue: BOOL ~ (value#NIL); SELECT name FROM aStyleDef => new.hasStyleDef _ hasValue; aPrefix => new.hasPrefix _ hasValue; aPostfix => new.hasPostfix _ hasValue; aArtwork => new.hasArtwork _ hasValue; ENDCASE; }; RETURN[new]; } ELSE RETURN [props]; -- nothing changed }; Size: PUBLIC PROC [text: Text] RETURNS [INT] ~ { RETURN[IF text=NIL THEN 0 ELSE Rope.InlineSize[text.rope]]; }; FetchChar: PUBLIC PROC [text: Text, index: INT] RETURNS [char: XChar _ [0, 0]] ~ { char.code _ ORD[Rope.Fetch[text.rope, index]]; IF text.charSets#NIL THEN WITH Rosary.Fetch[text.charSets, index] SELECT FROM refCharSet: REF CharSet => char.set _ refCharSet^; ENDCASE; }; FetchLooks: PUBLIC PROC [text: Text, index: INT] RETURNS [Looks] = { RETURN [TextLooks.FetchLooks[text.runs, index]]; }; Fetch: PUBLIC PROC [text: Text, index: INT] RETURNS [char: XChar, looks: Looks] ~ { char _ FetchChar[text, index]; looks _ FetchLooks[text, index]; }; GetProp: PUBLIC PROC [text: Text, name: ATOM] RETURNS [REF] ~ { RETURN[PropsGet[text.props, name]]; }; GetCharProp: PUBLIC PROC [text: Text, index: INT, name: ATOM] RETURNS [REF] ~ { RETURN[PropListGet[GetCharPropList[text, index], name]]; }; GetCharPropList: PUBLIC PROC [text: Text, index: INT] RETURNS [PropList] ~ { RETURN[NARROW[Rosary.Fetch[text.charProps, index]]]; }; rosaryOfNil: ROSARY ~ Rosary.FromItem[NIL, maxLen]; RosaryReplace: PROC [dest: ROSARY, destSize: INT, destStart: INT, destLen: INT, source: ROSARY, sourceStart: INT, sourceLen: INT] RETURNS [rosary: ROSARY] ~ { notNil: Rosary.RunActionType ~ { quit _ item#NIL }; d: ROSARY ~ IF dest=NIL THEN rosaryOfNil ELSE dest; d0: INT ~ 0; d1: INT ~ destStart; d2: INT ~ d1+destLen; d3: INT ~ destSize; s: ROSARY ~ IF source=NIL THEN rosaryOfNil ELSE source; s0: INT ~ sourceStart; s1: INT ~ s0+sourceLen; rosary _ Rosary.CatSegments[[d, d0, d1-d0], [s, s0, s1-s0], [d, d2, d3-d2]]; IF NOT Rosary.MapRuns[[rosary], notNil] THEN rosary _ NIL; }; RosaryMapRuns: PROC [rosary: ROSARY, start, len: INT, action: Rosary.RunActionType] ~ { IF rosary=NIL THEN [] _ action[NIL, len] ELSE [] _ Rosary.MapRuns[[rosary, start, len], action]; }; DeleteText: PUBLIC PROC [dest: Text, destStart: INT _ 0, destLen: INT _ maxLen] RETURNS [Text] ~ { destSize: INT ~ Size[dest]; destStart _ MIN[MAX[0, destStart], destSize]; destLen _ MIN[MAX[0, destLen], destSize-destStart]; IF destLen=0 THEN RETURN[dest] -- delete nothing ELSE { new: Text ~ NEW[TextRep _ [rope: NIL, runs: NIL, charSets: NIL, charProps: NIL, props: NIL]]; newSize: INT ~ destSize-destLen; IF newSize#0 THEN { SELECT TRUE FROM (destStart=0) => { -- delete from start new.rope _ Rope.Substr[dest.rope, destLen, newSize]; IF dest.runs#NIL THEN new.runs _ TextLooks.Substr[dest.runs, destLen, newSize]; }; (destStart+destLen=destSize) => { -- delete from end new.rope _ Rope.Substr[dest.rope, 0, newSize]; IF dest.runs#NIL THEN new.runs _ TextLooks.Substr[dest.runs, 0, newSize]; }; ENDCASE => { new.rope _ Rope.Replace[base: dest.rope, start: destStart, len: destLen, with: NIL]; IF dest.runs#NIL THEN new.runs _ TextLooks.Replace[base: dest.runs, start: destStart, len: destLen, replace: NIL, baseSize: destSize, repSize: 0]; }; IF dest.charSets#NIL THEN new.charSets _ RosaryReplace[dest: dest.charSets, destSize: destSize, destStart: destStart, destLen: destLen, source: NIL, sourceStart: 0, sourceLen: 0]; IF dest.charProps#NIL THEN new.charProps _ RosaryReplace[dest: dest.charProps, destSize: destSize, destStart: destStart, destLen: destLen, source: NIL, sourceStart: 0, sourceLen: 0]; }; new.props _ dest.props; RETURN[new]; }; }; ReplaceText: PUBLIC PROC [dest: Text, destStart: INT _ 0, destLen: INT _ maxLen, source: Text _ NIL, sourceStart: INT _ 0, sourceLen: INT _ maxLen] RETURNS [Text] ~ { sourceSize: INT ~ Size[source]; sourceStart _ MIN[MAX[0, sourceStart], sourceSize]; sourceLen _ MIN[MAX[0, sourceLen], sourceSize-sourceStart]; IF sourceLen=0 THEN RETURN DeleteText[dest, destStart, destLen] ELSE { new: Text ~ NEW[TextRep _ [rope: NIL, runs: NIL, charSets: NIL, charProps: NIL, props: NIL]]; replaceRope: ROPE ~ Rope.Substr[source.rope, sourceStart, sourceLen]; replaceRuns: Runs ~ TextLooks.Substr[source.runs, sourceStart, sourceLen]; destSize: INT ~ Size[dest]; destStart _ MIN[MAX[0, destStart], destSize]; destLen _ MIN[MAX[0, destLen], destSize-destStart]; SELECT TRUE FROM (destLen=0 AND destStart=0) => { -- insert at start new.rope _ Rope.Concat[replaceRope, dest.rope]; new.runs _ TextLooks.Concat[replaceRuns, dest.runs, sourceLen, destSize]; }; (destLen=0 AND destStart=destSize) => { -- insert at end new.rope _ Rope.Concat[dest.rope, replaceRope]; new.runs _ TextLooks.Concat[dest.runs, replaceRuns, destSize, sourceLen]; }; ENDCASE => { new.rope _ Rope.Replace[base: dest.rope, start: destStart, len: destLen, with: replaceRope]; new.runs _ TextLooks.Replace[base: dest.runs, start: destStart, len: destLen, replace: replaceRuns, baseSize: destSize, repSize: sourceLen]; }; IF dest.charSets#NIL OR source.charSets#NIL THEN new.charSets _ RosaryReplace[dest: dest.charSets, destSize: destSize, destStart: destStart, destLen: destLen, source: source.charSets, sourceStart: sourceStart, sourceLen: sourceLen]; IF dest.charProps#NIL OR source.charProps#NIL THEN new.charProps _ RosaryReplace[dest: dest.charProps, destSize: destSize, destStart: destStart, destLen: destLen, source: source.charProps, sourceStart: sourceStart, sourceLen: sourceLen]; new.props _ dest.props; RETURN[new]; }; }; CharSetsReplaceByRun: PROC [destCharSets: ROSARY, destSize: INT, destStart: INT, destLen: INT, charSet: CharSet, runSize: INT] RETURNS [ROSARY] ~ { sourceCharSets: ROSARY _ NIL; IF charSet#0 THEN { item: REF CharSet _ NIL; IF destCharSets#NIL THEN { Try: TYPE ~ {before, after}; tries: ARRAY Try OF INT _ [before: destStart-1, after: destStart+destLen]; FOR try: Try IN Try WHILE item=NIL DO i: INT ~ tries[try]; IF i IN [0..destSize) THEN WITH Rosary.Fetch[destCharSets, i] SELECT FROM destItem: REF CharSet => IF destItem^=charSet THEN item _ destItem; ENDCASE; ENDLOOP; }; IF item=NIL THEN item _ NEW[CharSet _ charSet]; sourceCharSets _ Rosary.FromItem[item, runSize]; }; RETURN[RosaryReplace[dest: destCharSets, destSize: destSize, destStart: destStart, destLen: destLen, source: sourceCharSets, sourceStart: 0, sourceLen: runSize]]; }; ReplaceByRope: PUBLIC PROC [dest: Text, destStart: INT, destLen: INT, rope: ROPE, inherit: BOOL, looks: Looks, charSet: CharSet] RETURNS [Text] ~ { ropeSize: INT ~ Rope.Size[rope]; IF ropeSize=0 THEN RETURN DeleteText[dest, destStart, destLen] ELSE { new: Text ~ NEW[TextRep _ [rope: NIL, runs: NIL, charSets: NIL, charProps: NIL, props: NIL]]; destSize: INT ~ Size[dest]; destStart _ MIN[MAX[0, destStart], destSize]; destLen _ MIN[MAX[0, destLen], destSize-destStart]; new.rope _ Rope.Replace[base: dest.rope, start: destStart, len: destLen, with: rope]; new.runs _ TextLooks.ReplaceByRun[dest: dest.runs, start: destStart, len: destLen, runLen: ropeSize, destSize: destSize, inherit: inherit, looks: looks]; IF dest.charSets#NIL OR charSet#0 THEN new.charSets _ CharSetsReplaceByRun[destCharSets: dest.charSets, destSize: destSize, destStart: destStart, destLen: destLen, charSet: charSet, runSize: ropeSize]; IF dest.charProps#NIL THEN new.charProps _ RosaryReplace[dest: dest.charProps, destSize: destSize, destStart: destStart, destLen: destLen, source: NIL, sourceStart: 0, sourceLen: ropeSize]; new.props _ dest.props; RETURN[new]; }; }; SetProp: PUBLIC PROC [text: Text, name: ATOM, value: REF] RETURNS [Text] ~ { newProps: Props ~ PropsPut[text.props, name, value]; IF newProps=text.props THEN RETURN [text] -- no change ELSE RETURN [NEW[TextRep _ [rope: text.rope, runs: text.runs, charSets: text.charSets, charProps: text.charProps, props: newProps]]]; }; END. ΤImmutableTiogaImpl.mesa Copyright c 1986 by Xerox Corporation. All rights reserved. Doug Wyatt, September 15, 1986 6:04:31 pm PDT Try to find a matching item in destCharSets adjacent to the replacement. Κ"˜codešœ™Kšœ Οmœ1™šžœ˜Kš œ žœžœžœ žœ žœ žœ˜]Kšœ žœ˜Kšœ žœžœ˜-Kšœ žœžœ"˜3KšœU˜UKšœ™˜™Kšžœžœžœ žœ£˜ΙKšžœžœžœyžœ'˜½Jšœ˜Jšžœ˜ K˜—˜K˜——š  œžœžœžœ žœžœ ˜LK˜4Kšžœžœžœ‘ ˜6Kšžœžœžœu˜…K˜K˜—K˜Kšžœ˜—…—(:70