DIRECTORY ImagerFont USING [BYTE, XChar], Rope USING [ROPE], Rosary USING [ROSARY], TextLooks USING [Looks, allLooks, noLooks, Runs]; ImmutableTioga: CEDAR DEFINITIONS ~ BEGIN CharSet: TYPE ~ ImagerFont.BYTE; XChar: TYPE ~ ImagerFont.XChar; ROPE: TYPE ~ Rope.ROPE; ROSARY: TYPE ~ Rosary.ROSARY; Runs: TYPE ~ TextLooks.Runs; Looks: TYPE ~ TextLooks.Looks; noLooks: Looks ~ TextLooks.noLooks; allLooks: Looks ~ TextLooks.allLooks; Node: TYPE ~ REF NodeRep; NodeRep: TYPE ~ RECORD [ -- 4 words children: ROSARY --OF Node--, text: Text ]; Text: TYPE ~ REF TextRep; TextRep: TYPE ~ RECORD [ -- 10 words rope: ROPE, runs: Runs, charSets: ROSARY --OF REF CharSet--, charProps: ROSARY --OF PropList--, props: Props ]; Props: TYPE ~ REF PropsRep; PropsRep: TYPE ~ RECORD [ -- 5 words propList: PropList, formatName: ATOM _ NIL, -- name of format for the node comment: BOOL _ FALSE, -- true if node is a comment hasStyleDef: BOOL _ FALSE, -- true if node has StyleDef prop (accelerator) hasPrefix: BOOL _ FALSE, -- true if node has Prefix prop (accelerator) hasPostfix: BOOL _ FALSE, -- true if node has Postfix prop (accelerator) hasArtwork: BOOL _ FALSE -- true if node has Artwork prop (accelerator) ]; PropList: TYPE ~ LIST OF Prop; Prop: TYPE ~ REF PropRep; PropRep: TYPE ~ RECORD [name: ATOM, value: REF]; NodeIndex: TYPE ~ REF NodeIndexRep; NodeIndexRep: TYPE ~ RECORD [depth: NAT, seq: SEQUENCE size: NAT OF INT]; maxLen: INT ~ INT.LAST; Size: PROC [text: Text] RETURNS [INT]; FetchChar: PROC [text: Text, index: INT] RETURNS [XChar]; FetchLooks: PROC [text: Text, index: INT] RETURNS [Looks]; Fetch: PROC [text: Text, index: INT] RETURNS [char: XChar, looks: Looks]; GetProp: PROC [text: Text, name: ATOM] RETURNS [REF]; GetComment: PROC [text: Text] RETURNS [BOOL]; GetFormat: PROC [text: Text] RETURNS [ATOM]; GetPropFromList: PROC [propList: PropList, key: ATOM] RETURNS [value: REF]; PutPropOnList: PROC [propList: PropList, key: ATOM, value: REF] RETURNS [PropList]; ReplaceText: PROC [dest: Text, destStart: INT _ 0, destLen: INT _ maxLen, source: Text _ NIL, sourceStart: INT _ 0, sourceLen: INT _ maxLen] RETURNS [Text]; DeleteText: PROC [dest: Text, destStart: INT _ 0, destLen: INT _ maxLen] RETURNS [Text]; ReplaceByRope: PROC [dest: Text, destStart: INT, destLen: INT, rope: ROPE, inherit: BOOL, looks: Looks, charSet: CharSet] RETURNS [Text]; END. 4ŒImmutableTioga.mesa Copyright c 1986 by Xerox Corporation. All rights reserved. Doug Wyatt, September 15, 1986 4:43:28 pm PDT Types Defined elsewhere Node NodeIndex, Location, Text, Span IndexedNode: PROC [root: Node, index: NodeIndex] RETURNS [Node] ~ { node: Node _ root; FOR k: NAT IN [0..index.depth) DO node _ NthChild[node, index[k]]; ENDLOOP; RETURN[node]; }; nodeItself: INT ~ -1; Location: TYPE ~ RECORD [node: NodeIndex, where: INT _ 0]; where >= length of text means at end where = loc in [0..length) means before that character e.g., where = 0 means at start of text where = nodeItself means location is the node itself rather than in its contents nullLocation: Location ~ [node: NIL, where: nodeItself]; NodeLoc: PROC [n: Node] RETURNS [Location] ~ INLINE { RETURN[[n, nodeItself]] }; Text: TYPE ~ RECORD [content: NodeContent, start: INT _ 0, len: INT _ maxLen]; represents the characters [start..start+len) in content end: PROC [text: Text] RETURNS [INT] ~ INLINE { RETURN[text.start+text.len] }; -- hack so t.start and t.end are uniformly usable Span: TYPE ~ RECORD [start, end: Location _ nullLocation]; start.node can equal end.node in which case either both start.where and end.where = nodeItself, or neither does and start.where <= end.where otherwise, end.node should follow start.node in the tree nodes need not be siblings no restrictions on start.where or end.where nullSpan: Span ~ [nullLocation, nullLocation]; World World: TYPE ~ REF WorldRep; WorldRep: TYPE; Tree operations Parent, Sibling, Child Parent: PROC [n: Node] RETURNS [Node]; returns parent of n returns NIL if n is root Root: PROC [n: Node] RETURNS [Node]; returns root of tree containing n Next: PROC [n: Node] RETURNS [Node]; returns next sibling of n returns NIL if n is last sibling Previous: PROC [n: Node, parent: Node _ NIL] RETURNS [Node]; returns previous sibling of n returns NIL if n is first sibling runs faster if can supply parent IsLastSibling: PROC [n: Node] RETURNS [BOOL]; IsLastSibling[n] == Next[n]=NIL. FirstChild: PROC [n: Node] RETURNS [Node]; Parent[FirstChild[n]] = n; Previous[FirstChild[n]] = NIL. LastChild: PROC [n: Node] RETURNS [Node]; Parent[FirstChild[n]] = n; Next[LastChild[n]] = NIL. FirstSibling: PROC [n: Node] RETURNS [Node]; FirstSibling[n] = FirstChild[Parent[n]] LastSibling: PROC [n: Node] RETURNS [Node]; LastSibling[n] = LastChild[Parent[n]] LastWithin: PROC [n: Node] RETURNS [Node]; returns the last node within the branch i.e., goes to last child of last child of last child ... until no child Level: PROC [n: Node] RETURNS [INT]; Level[Root[x]] == 0; Level[FirstChild[n]]=Level[n]+1 Counting NthChild: PROC [n: Node, index: INT] RETURNS [Node]; NthChild[n, 0] == FirstChild[n]; NthChild[n, k+1] == Next[NthChild[n, k]] NthSibling: PROC [n: Node, index: INT] RETURNS [Node]; CountChildren: PROC [n: Node] RETURNS [count: INT]; CountFollowing: PROC [n: Node] RETURNS [count: INT]; CountToParent: PROC [n: Node] RETURNS [count: INT, parent: Node]; CountToChild: PROC [parent, child: Node] RETURNS [count: INT]; Forward, Backward StepForward: PROC [node: Node] RETURNS [Node]; returns next node in standard tree walk order StepBackward: PROC [node: Node, parent: Node _ NIL] RETURNS [Node]; returns preceding node in standard tree walk order runs faster if can supply parent Forward: PROC [node: Node] RETURNS [nx: Node, levelDelta: INT]; returns next node in standard tree walk order levelDelta is Level[node]-Level[nx], where level is depth in tree levelDelta = 0 if nx and node are siblings levelDelta = 1 if nx is child of node levelDelta < 0 if do Parent* and Next to reach nx from node Backward: PROC [node: Node, parent: Node _ NIL] RETURNS [back, backparent: Node, levelDelta: INT]; for backing through tree runs faster if can supply parent levelDelta same as for Forward ForwardClipped: PROC [node: Node, maxLevel: INT, nodeLevel: INT _ 0] RETURNS [nx: Node, nxLevel: INT]; like Forward, but limits how deep will go in tree if pass nodeLevel=0, correct value will be computed nxLevel = Level[nx] <= MAX[maxLevel,Level[node]] BackwardClipped: PROC [node: Node, maxLevel: INT, parent: Node _ NIL, nodeLevel: INT _ 0] RETURNS [back, backparent: Node, backLevel: INT]; like Backward, but limits how deep will go in tree backLevel = Level[back] <= MAX[maxLevel,Level[node]] Locations BadArgs: ERROR; LocRelative: PROC [location: Location, count: INT, break: INT _ 1, skipCommentNodes: BOOL _ FALSE] RETURNS [Location]; count is interpreted as a character offset from given location returns location corresponding to count adds in break at the end of each text subnode if skipCommentNodes is true, then ignores them in walking the tree LocWithin: PROC [n: Node, count: INT, break: INT _ 1, skipCommentNodes: BOOL _ FALSE] RETURNS [Location]; LocRelative[[n, 0], ...]; count is offset from beginning of given node LocOffset: PROC [loc1, loc2: Location, break: INT _ 1, skipCommentNodes: BOOL _ FALSE] RETURNS [count: INT]; returns character offset of location2 relative to location1 loc1 and loc2 can be in same node but loc2 must not be in node before loc1 or get ERROR BadArgs if skipCommentNodes is true, then ignores them in walking the tree LocNumber: PROC [at: Location, break: INT _ 1, skipCommentNodes: BOOL _ FALSE] RETURNS [count: INT]; returns character offset of location relative to root LastLocWithin: PROC [n: Node] RETURNS [Location]; returns the last location within the branch Node order Order: TYPE ~ { before, same, after, disjoint }; CompareNodeOrder: PROC [node1, node2: Node] RETURNS [Order]; determines relative order in tree of the nodes returns "same" if node1 = node2 returns "before" if node1 comes before node2 returns "after" if node1 comes after node2 returns "disjoint" if nodes are not from the same tree CompareLocOrder: PROC [loc1, loc2: Location] RETURNS [Order]; Node operations Creation NewNode: PROC RETURNS [Node]; CopyNode: PROC [node: Node] RETURNS [Node]; FromRope: PROC [rope: ROPE] RETURNS [Node]; create a text node with looks from a normal rope FromRefText: PROC [text: REF READONLY TEXT] RETURNS [Node]; copies the contents of the text FromString: PROC [string: String] RETURNS [Node]; copies the contents of the string DocFromNode: PROC [child: Node] RETURNS [root: Node]; returns root node which has one child child typically created by FromRope or FromString Size, Chars, Looks fetches the indexed character use rope readers if want characters from contiguous locations returns the looks for the character at the given location use readers if getting looks for sequence of locations fetches the indexed information, except for character properties use rope & looks readers if want info from contiguous locations Properties GetCharProp: PROC [node: Node, index: INT, name: ATOM] RETURNS [REF]; MapPropsAction: TYPE ~ PROC [name: ATOM, value: REF] RETURNS [quit: BOOL _ FALSE]; MapProps: PROC [node: Node, action: MapPropsAction, formatFlag, commentFlag: BOOL _ TRUE] RETURNS [quit: BOOL]; apply the action to each name & value pair for the node returns true if&when an action returns true if commentFlag is false, skips Comment property; ditto for formatFlag hack to accelerate Inherit and PutFile operations MapCharProps: PROC [node: Node, index: INT, action: MapPropsAction] RETURNS [quit: BOOL]; apply the action to each name & value pair for the indexed character Character PropList GetCharPropList: PROC [node: Node, index: INT] RETURNS [PropList]; Read, write, copy props PropReader: TYPE ~ PROC [name: ATOM, specs: ROPE] RETURNS [value: REF]; used when reading files; convert from external specs to internal REF PropWriter: TYPE ~ PROC [name: ATOM, value: REF] RETURNS [specs: ROPE]; used when writing files; convert from internal REF to external specs PropCopier: TYPE ~ PROC [name: ATOM, value: REF] RETURNS [new: REF]; used when copying nodes; copy internal REF ReadProp: PropReader; calls the registered reader for this property name if no reader is registered, returns specs WriteProp: PropWriter; calls the registered writer for this property name if no writer is registered, returns value if it is a rope, NIL otherwise CopyProp: PropCopier; calls the registered copier for this property name if no copier is registered, returns old value NullRead: PropReader; NullWrite: PropWriter; NullCopy: PropCopier; these always return NIL RegisterProp: PROC [name: ATOM, reader: PropReader, writer: PropWriter, copier: PropCopier]; registers procs for given property name they will be called by ReadProp, WriteProp, CopyProp Editing Edit Text replace the dest text by a copy of the source text addrs that are in the replaced text move to destStart addrs that are after the replaced text are adjusted delete the specified range of text addrs that are in the deleted section move to start Replace by Char, Rope, String Edit Spans Place: TYPE ~ { before, after, sibling, child }; these are modifiers for the destination of a Move or Copy or Insert only apply when destination is an entire node (i.e., dest.where = nodeItself) place = before means insert as sibling before dest place = after means insert as sibling after dest; inherit children of dest place = sibling means insert as sibling after dest; don't inherit children of dest place = child means insert as first child of dest Replace: PROC [world: World, destRoot, sourceRoot: Node, dest, source: Span, saveForPaste: BOOL _ TRUE] RETURNS [result: Span]; replace dest span by copy of source span result is the new copy of source Delete: PROC [world: World, root: Node, del: Span, saveForPaste: BOOL _ TRUE]; SaveForPaste: PROC [world: World, span: Span]; SavedForPaste: PROC [world: World] RETURNS [span: Span]; result is last thing deleted or explicitly saved for Paste Copy: PROC [world: World, destRoot, sourceRoot: Node, dest: Location, source: Span, where: Place _ after, nesting: INTEGER _ 0] RETURNS [result: Span]; result is the new copy of source Move: PROC [world: World, destRoot, sourceRoot: Node, dest: Location, source: Span, where: Place _ after, nesting: INTEGER _ 0] RETURNS [result: Span]; dest cannot be within source or get error CannotDoEdit result is moved span nesting is relative to dest e.g., where=after and nesting=1 makes source be child of dest MoveOnto: PROC [world: World, destRoot, sourceRoot: Node, dest, source: Span, saveForPaste: BOOL _ TRUE] RETURNS [result: Span]; like Replace, but moves source instead of copying it result is moved span Transpose: PROC [world: World, alphaRoot, betaRoot: Node, alpha, beta: Span] RETURNS [newAlpha, newBeta: Span]; alpha and beta must not overlap or get error CannotDoEdit newAlpha is new location of alpha span; ditto for newBeta CannotDoEdit: ERROR; Character properties SetCharProp: PROC [world: World, text: Text, name: ATOM, value: REF, root: Node _ NIL]; Places the value on the character property lists of the chars in the specified range. Use value = NIL to remove a character property. SetCharPropList: PROC [world: World, text: Text, propList: PropList, root: Node _ NIL]; ModifyPropsAction: TYPE ~ PROC [value: REF, start: INT, len: INT] RETURNS [quit: BOOL _ FALSE, newValue: REF]; ModifyCharProps: PROC [world: World, text: Text, name: ATOM, action: ModifyPropsAction, root: Node _ NIL] RETURNS [quit: BOOL]; Used for traversing and altering the values of a character property over a range of characters; the action procedure is called for runs of properties, but adjacent runs are not necessarily merged. Node properties SetProp: PROC [world: World, node: Node, name: ATOM, value: REF, root: Node _ NIL]; SetComment: PROC [world: World, node: Node, comment: BOOL, root: Node _ NIL]; Sets the $Comment property of a node. SetFormat: PROC [world: World, node: Node, formatName: ATOM, root: Node _ NIL]; Sets the $Format property of a node. SetStyle: PROC [world: World, node: Node, styleName: ROPE, root: Node _ NIL]; appends style to end of node prefix Insert, Split, Merge, Nest Insert: PROC [world: World, root, old: Node, where: Place _ after, inherit: BOOL _ TRUE] RETURNS [new: Node]; new empty node is inserted in tree in position determined by "where" if inherit, new node inherits properties of old Split: PROC [world: World, root: Node, loc: Location] RETURNS [new: Node]; inserts copy of loc.node is inserted directly before loc.node (as sibling) new adopts children of old (if any) if loc.where # nodeItself and loc.node is a text node, then text after loc.where moves to new node text before loc.where stays in old node returns the new node Merge: PROC [world: World, root, node: Node] RETURNS [loc: Location]; copies text of node to end of previous node then deletes node ChangeNesting: PROC [world: World, root: Node, span: Span, change: INT] RETURNS [Span]; moves all nodes of span, even if entire nodes not selected change>0 is deeper in the tree, change<0 is shallower Looks, Caps ChangeTextLooks: PROC [world: World, root: Node, text: Text, remove, add: Looks]; first remove then add in the given range ChangeLooks: PROC [world: World, root: Node, span: Span, remove, add: Looks]; first remove then add in the given span CapChange: TYPE ~ {allCaps, allLower, initCaps, firstCap}; ChangeTextCaps: PROC [world: World, root: Node, text: Text, how: CapChange _ allCaps]; ChangeCaps: PROC [world: World, root: Node, span: Span, how: CapChange _ allCaps]; Κω˜codešœ™Kšœ Οmœ1™K™——™š‘ œžœžœ™.Kšœ-™-K™—š‘ œžœžœžœ™CKšœ2™2Kšœ ™ K™—š‘œžœžœžœ™?Kšœ-™-šœA™AKšœ*™*Kšœ%™%Kšœ;™;K™——š ‘œžœžœžœ&žœ™cKšœ™Kšœ ™ Kšœ™K™—š ‘œžœžœ žœžœžœ™gKšœ1™1Kšœ4™4Kšœžœ™0K™—š‘œžœžœžœ žœžœ%žœ™‹Kšœ2™2Kšœžœ™4K™——™ šœ žœ™K™—š‘ œžœžœ žœžœžœžœ ™wKšœ>™>Kšœ5™5Kšœ-™-KšœB™BK™—š‘ œžœžœ žœžœžœžœ ™jKšœF™FK™—š‘ œžœžœžœžœžœ žœ™mKšœ;™;Kšœ!™!Kšœ0žœ™=KšœB™BK™—š‘ œžœžœžœžœžœ žœ™eKšœ5™5K™—š‘ œžœ žœ ™1Kšœ,™,K™——™ šœžœ%™0K™—š‘œžœžœ ™™\Kšœ'™'Kšœ4™4K™———™™ š‘ œžœžœžœžœžœžœ žœ˜œKšœ2™2Kšœ5™5Kšœ3™3K™—š ‘ œžœžœžœ žœ˜XKšœ"™"Kšœ3™3K™——™š‘ œžœžœ žœžœ žœ"žœ˜‰K™——™ šœžœ%™0KšœC™CKšœM™MKšœ2™2KšœJ™JKšœR™RKšœ1™1K™—š ‘œžœOžœžœžœ™€Kšœ(™(Kšœ ™ K™—š‘œžœ5žœžœ™NK™—š‘ œžœ™.K™—š‘ œžœžœ™8Kšœ:™:K™—š‘œžœjžœžœ™˜Kšœ ™ K™—š‘œžœjžœžœ™˜Kšœ6™6Kšœ™šœ™Kšœ=™=—K™—š ‘œžœOžœžœžœ™Kšœ4™4Kšœ™K™—š‘ œžœ>žœ™pKšœ9™9Kšœ9™9K™—š‘ œžœ™K™——šœ™š ‘ œžœ"žœ žœžœ™WKšœU™UKšœ žœ ™/K™—š‘œžœ=žœ™WK™—šœžœžœ žœ žœžœžœžœžœ žœ™oK™—š ‘œžœ"žœ*žœžœžœ™K™ΔK™——šœ™š ‘œžœ"žœ žœžœ™SK™—š‘ œžœ%žœžœ™MK™%K™—š‘ œžœ(žœžœ™OK™$K™—š‘œžœ'žœžœ™MKšœ*™*K™——™š ‘œžœAžœžœžœ ™nKšœD™DK™/K™—š‘œžœ+žœ ™JšœJ™JKšœ#™#—šœ;™;Kšœ&™&Kšœ'™'—Kšœ™K™—š‘œžœ"žœ™EKšœ+™+Kšœ™K™—š‘ œžœ0žœžœ™WKšœ:™:K™5K™——™ š‘œžœ<™QKšœ(™(K™—š‘ œžœ<™MKšœ'™'K™—šœ žœ+™:K™—š‘œžœB™VK™—š‘ œžœB™RK™———K˜Kšžœ˜—…— @NΕ