DIRECTORY Atom USING [MakeAtom], NodeProps USING [GetProp], Rope USING [ROPE, Size], TextLooks USING [Runs], TextNode USING [Body, Location, MaxLen, NodeItself, NodeProps, Ref, RefTextNode, Span], TextNodeRegistry USING [DoTransform, GetSize]; ActiveTextNodeImpl: CEDAR PROGRAM IMPORTS Atom, NP: NodeProps, Rope, TextNodeRegistry EXPORTS TextNode = BEGIN OPEN TextNode; ROPE: TYPE ~ Rope.ROPE; MakeNodeLoc: PUBLIC PROC [n: Ref] RETURNS [Location] = { RETURN [[node: n, where: NodeItself]] }; MakeNodeSpan: PUBLIC PROC [first, last: Ref] RETURNS [Span] = { RETURN [[MakeNodeLoc[first], MakeNodeLoc[last]]] }; NarrowToTextNode: PUBLIC PROC [n: Ref] RETURNS [txt: RefTextNode] ~ {RETURN [n]}; NewTextNode: PUBLIC PROC RETURNS [txt: RefTextNode] = { txt _ NEW[Body]; txt.last _ TRUE }; Parent: PUBLIC PROC [n: Ref] RETURNS [Ref] = { RETURN [Transform[node: InlineParent[n], wantFirst: FALSE]] }; InlineParent: PROC [n: Ref] RETURNS [Ref] = INLINE { DO IF n=NIL OR n.deleted THEN RETURN [NIL]; IF n.last THEN RETURN [n.next]; n _ n.next; ENDLOOP; }; Root: PUBLIC PROC [n: Ref] RETURNS [Ref] = { p: Ref; DO IF (p _ InlineParent[n])=NIL THEN RETURN [IF n=NIL OR n.deleted THEN NIL ELSE Transform[node: n, wantFirst: TRUE]]; n _ p; ENDLOOP; }; Next: PUBLIC PROC [n: Ref] RETURNS [Ref] = { RETURN[IF n=NIL OR n.last OR n.deleted THEN NIL ELSE Transform[node: n.next, wantFirst: TRUE]]; }; Previous: PUBLIC PROC [n: Ref, parent: Ref _ NIL] RETURNS [nx: Ref] = { nx2: Ref; IF parent=NIL THEN parent _ InlineParent[n]; IF n=NIL OR parent=NIL OR (nx _ parent.child)=n THEN RETURN [NIL]; DO IF (nx2_nx.next)=n THEN RETURN [Transform[node: nx, wantFirst: FALSE]]; nx _ nx2; ENDLOOP; }; Forward: PUBLIC PROC [node: Ref] RETURNS [nx: Ref, levelDelta: INTEGER] = { [nx, levelDelta] _ InlineForward[node]; nx _ Transform[node: nx, wantFirst: TRUE]; }; InlineForward: PROC [node: Ref] RETURNS [nx: Ref, levelDelta: INTEGER] = INLINE { child: Ref; IF node=NIL THEN RETURN [NIL, 0]; IF (child _ node.child) # NIL THEN RETURN [child, 1]; -- descend in the tree levelDelta _ 0; DO -- move to next node, sibling or up* then sibling IF NOT node.last THEN RETURN [node.next, levelDelta]; -- the sibling IF (node _ node.next) = NIL THEN RETURN [NIL, levelDelta]; -- the parent levelDelta _ levelDelta-1; ENDLOOP; }; Backward: PUBLIC PROC [node: Ref, parent: Ref _ NIL] RETURNS [back, backparent: Ref, levelDelta: INTEGER] = { child, child2: Ref; IF parent = NIL THEN parent _ InlineParent[node]; IF parent = NIL OR node = NIL THEN RETURN [NIL, NIL, 0]; IF (child _ parent.child) = node THEN RETURN [Transform[node: parent, wantFirst: FALSE], Parent[parent], -1]; DO IF child.last THEN ERROR; -- incorrect value supplied for parent IF (child2 _ child.next)=node THEN EXIT; child _ child2; ENDLOOP; levelDelta _ 0; child _ Transform[node: child, parent: parent, wantFirst: FALSE]; DO IF (child2 _ LastChild[child]) = NIL THEN RETURN [child, parent, levelDelta]; levelDelta _ levelDelta+1; parent _ child; child _ child2; ENDLOOP; }; StepForward: PUBLIC PROC [node: Ref] RETURNS [Ref] = { RETURN[Forward[node].nx] }; StepBackward: PUBLIC PROC [node: Ref, parent: Ref _ NIL] RETURNS [Ref] = { RETURN[Backward[node, parent].back] }; Level: PUBLIC PROC [node: Ref] RETURNS [level: INTEGER] = { level _ 0; UNTIL (node _ InlineParent[node])=NIL DO level _ level+1 ENDLOOP; }; ForwardClipped: PUBLIC PROC [ node: Ref, maxLevel: INTEGER, nodeLevel: INTEGER _ 0] RETURNS [nx: Ref, nxLevel: INTEGER] = { child: Ref; IF node=NIL THEN RETURN [NIL, 0]; IF nodeLevel <= 0 THEN nodeLevel _ Level[node]; IF nodeLevel < maxLevel AND (child _ node.child) # NIL THEN RETURN [Transform[node: child, parent: node, wantFirst: TRUE], nodeLevel+1]; -- return the child DO -- move to next node, sibling or up* then sibling IF NOT node.last THEN RETURN [Transform[node: node.next, wantFirst: TRUE], nodeLevel]; -- return the sibling IF (node _ node.next) = NIL THEN RETURN [NIL, 0]; -- go to the parent nodeLevel _ nodeLevel-1; ENDLOOP; }; BackwardClipped: PUBLIC PROC [ node: Ref, maxLevel: INTEGER, parent: Ref _ NIL, nodeLevel: INTEGER _ 0] RETURNS [back, backparent: Ref, backLevel: INTEGER] = { child, child2: Ref; IF parent = NIL THEN parent _ InlineParent[node]; IF parent = NIL OR node = NIL THEN RETURN [NIL, NIL, 0]; IF nodeLevel <= 0 THEN nodeLevel _ Level[node]; IF (child _ parent.child) = node THEN RETURN [Transform[node: parent, wantFirst: FALSE], Parent[parent], nodeLevel-1]; DO -- search for sibling just before node IF child.last THEN ERROR; -- incorrect value supplied for parent IF (child2 _ child.next)=node THEN EXIT; child _ child2; ENDLOOP; child _ Transform[node: child, parent: parent, wantFirst: FALSE]; DO -- go deeper in tree until reach maxLevel IF nodeLevel >= maxLevel OR (child2 _ LastChild[child]) = NIL THEN RETURN [child, parent, nodeLevel]; nodeLevel _ nodeLevel+1; parent _ child; child _ child2; ENDLOOP; }; LocRelative: PUBLIC PROC [location: Location, count: INT _ 0, break: NAT _ 1, skipCommentNodes: BOOL _ FALSE] RETURNS [Location] = { n: Ref _ location.node; size, lastSize, where: INT _ 0; init: Ref _ n; lastTxt: RefTextNode; IF count=0 AND InlineParent[n]=NIL THEN RETURN [[FirstChild[n], 0]]; -- avoid returning root node where _ MAX[location.where, 0]; -- where we are in the current node WHILE n # NIL DO IF n # NIL AND (NOT skipCommentNodes OR NOT n.comment) THEN { lastSize _ size _ Size[n]; IF (count _ count-(size-where)) <= 0 THEN RETURN [[Transform[node: n, wantFirst: TRUE], MAX[0, count+size]]]; lastTxt _ n; count _ count-break; }; [n, ] _ InlineForward[n]; where _ 0; ENDLOOP; IF lastTxt # NIL THEN RETURN [[Transform[node: lastTxt, wantFirst: FALSE], lastSize]]; -- end of last text node RETURN [[init, 0]]; }; LocWithin: PUBLIC PROC [n: Ref, count: INT, break: NAT _ 1, skipCommentNodes: BOOL _ FALSE] RETURNS [Location] = { RETURN[LocRelative[[n, 0], count, break, skipCommentNodes]] }; BadArgs: PUBLIC ERROR = CODE; LocOffset: PUBLIC PROC [loc1, loc2: Location, break: NAT _ 1, skipCommentNodes: BOOL _ FALSE] RETURNS [count: INT _ 0] = { node: Ref _ loc2.node; n: Ref _ loc1.node; count _ IF loc2.where # NodeItself THEN loc2.where ELSE 0; count _ count - MAX[loc1.where, 0]; DO -- add in counts for text nodes before location SELECT n FROM node => RETURN; NIL => ERROR BadArgs; ENDCASE; IF n # NIL AND (NOT skipCommentNodes OR NOT n.comment) THEN count _ count+Size[n]+break; [n, ] _ InlineForward[n]; ENDLOOP; }; LocNumber: PUBLIC PROC [at: Location, break: NAT _ 1, skipCommentNodes: BOOL _ FALSE] RETURNS [count: INT] = { RETURN[LocOffset[[Root[at.node], 0], at, break, skipCommentNodes]] }; FirstSibling: PUBLIC PROC [n: Ref] RETURNS [Ref] = { RETURN[FirstChild[Parent[n]]]; }; LastSibling: PUBLIC PROC [n: Ref] RETURNS [Ref] = { IF n=NIL THEN RETURN [NIL]; UNTIL n.last DO n _ n.next ENDLOOP; RETURN[Transform[node: n, wantFirst: FALSE]]; }; FirstChild: PUBLIC PROC [n: Ref] RETURNS [Ref] = { RETURN[IF n=NIL THEN NIL ELSE Transform[node: n.child, parent: n, wantFirst: TRUE]]; }; LastChild: PUBLIC PROC [n: Ref] RETURNS [Ref] = { RETURN[LastSibling[FirstChild[n]]]; }; LastWithin: PUBLIC PROC [n: Ref] RETURNS [Ref] = { nxt: Ref; IF n=NIL THEN RETURN [NIL]; IF (nxt _ n.child)=NIL THEN RETURN [n]; n _ nxt; DO -- keep going to child of last sibling IF n.last THEN { IF (nxt _ n.child)=NIL THEN RETURN [Transform[node: n, wantFirst: FALSE]]; n _ nxt } ELSE n _ n.next; ENDLOOP; }; LastLocWithin: PUBLIC PROC [n: Ref] RETURNS [Location] = { last: Ref _ LastWithin[n]; where: INT _ IF last # NIL THEN Rope.Size[last.rope] ELSE NodeItself; RETURN [[last, where]]; }; NthChild: PUBLIC PROC [n: Ref, location: INT _ 0] RETURNS [child: Ref] = { IF n=NIL OR (child _ n.child)=NIL THEN RETURN; DO IF location=0 THEN RETURN [Transform[node: child, wantFirst: TRUE]]; child _ Transform[node: child, wantFirst: TRUE]; IF child.last THEN RETURN [NIL]; child _ child.next; location _ location-1; ENDLOOP; }; NthSibling: PUBLIC PROC [n: Ref, cnt: INT _ 0] RETURNS [Ref] = { IF n=NIL THEN RETURN [NIL]; DO IF cnt=0 THEN RETURN [Transform[node: n, wantFirst: TRUE]]; n _ Transform[node: n, wantFirst: TRUE]; IF n.last THEN RETURN [NIL]; n _ n.next; cnt _ cnt-1; ENDLOOP; }; CountChildren: PUBLIC PROC [n: Ref] RETURNS [count: INT _ 0] = { child: Ref; IF (child _ FirstChild[n])=NIL THEN RETURN; DO count _ count+1; child _ Transform[node: child, wantFirst: TRUE]; IF child.last THEN RETURN; child _ child.next; ENDLOOP; }; CountFollowing: PUBLIC PROC [n: Ref] RETURNS [count: INT _ 0] = { IF n=NIL THEN RETURN; UNTIL n.last DO n _ n.next; count _ count+1; n _ Transform[node: n, wantFirst: TRUE]; ENDLOOP; }; CountToParent: PUBLIC PROC [n: Ref] RETURNS [count: INT _ 0, parent: Ref] = { IF n=NIL THEN RETURN; UNTIL n.last DO n _ n.next; count _ count+1; n _ Transform[node: n, wantFirst: TRUE]; ENDLOOP; parent _ n.next; parent _ Transform[node: parent, wantFirst: FALSE]; }; CountToChild: PUBLIC PROC [parent, child: Ref] RETURNS [count: INT _ 0] = { n: Ref; IF parent=NIL OR child=NIL THEN RETURN; n _ Transform[node: parent.child, wantFirst: TRUE]; DO SELECT n FROM child => RETURN [count]; NIL => RETURN [MaxLen]; ENDCASE; n _ Next[n]; count _ count+1; ENDLOOP; }; NodeRope: PUBLIC PROC [n: RefTextNode] RETURNS [ROPE] = { RETURN[IF n=NIL THEN NIL ELSE n.rope]; }; NodeRuns: PUBLIC PROC [n: RefTextNode] RETURNS [TextLooks.Runs] = { RETURN[IF n=NIL THEN NIL ELSE n.runs]; }; Props: PUBLIC PROC [n: Ref] RETURNS [NodeProps] = { RETURN[IF n=NIL THEN NIL ELSE n.props]; }; NodeFormat: PUBLIC PROC [n: Ref] RETURNS [ATOM] = { RETURN[IF n=NIL THEN NIL ELSE n.formatName]; }; IsLastSibling: PUBLIC PROC [n: Ref] RETURNS [BOOL] = { RETURN[IF n=NIL THEN FALSE ELSE n.last]; }; EndPos: PUBLIC PROC [n: Ref] RETURNS [INT] = { IF n=NIL THEN RETURN [0]; RETURN [MAX[Rope.Size[n.rope], 1]-1]; }; Transform: PROC [node: Ref, parent: Ref _ NIL, wantFirst: BOOLEAN _ TRUE] RETURNS [new: Ref] ~ INLINE { activity: ROPE _ NARROW[NP.GetProp[node, $Active]]; new _ IF activity=NIL THEN node ELSE TextNodeRegistry.DoTransform[activity: Atom.MakeAtom[activity], node: node, parent: parent, wantFirst: wantFirst]; }; Size: PROC [node: Ref] RETURNS [size: INT] ~ INLINE { activity: ROPE _ NARROW[NP.GetProp[node, $Active]]; size _ IF activity=NIL THEN Rope.Size[node.rope] ELSE TextNodeRegistry.GetSize[activity: Atom.MakeAtom[activity], node: node]; }; END. PActiveTextNodeImpl.mesa Copyright Σ 1985, 1986 by Xerox Corporation. All rights reserved. written by Bill Paxton, March 1981 last edit by Bill Paxton, August 11, 1982 9:51 am Doug Wyatt, March 3, 1985 3:01:39 pm PST Michael Plass, March 27, 1985 3:50:32 pm PST Rick Beach, March 27, 1985 10:13:12 am PST Doug Terry, June 25, 1987 2:18:19 pm PDT This is a modified version of TextNodeImpl.mesa that performs transformations on "active" nodes as they are requested. Active nodes as those with the "Active" property; the value associated with this property identifies a particular transformation. Transformations must be registered using TextNodeRegistry. Note: All of the public procedures in this module assume that any nodes passed as inputs are regular text nodes (i.e. do not need to be transformed) and ensure that any nodes returned as results are regular text nodes. Strange behavior might result if the transformation of an active node yields another active node. Note: TextNode.Ref should have a field, "hasactive", to accelerate the checking for the active property. This change was not made since modifying TextNode.mesa triggers lots of recompilations. For backwards compatability. applies Parent repeatedly until reaches root returns next node in standard tree walk order returns preceeding node in standard tree walk order returns next node in standard tree walk order returns preceding node in standard tree walk order Level[Root[x]] == 0; Level[FirstChild[n]]=Level[n]+1 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]] like Backward, but limits how deep will go in tree backLevel = Level[back] <= MAX[maxLevel, Level[node]] returns character offset of location2 relative to location1 returns character offset of location relative to root note: NthChild[n, 0]==FirstChild[n]; NthChild[n, k+1]==Next[NthChild[n, k]] note: NthSibling[n, 0]==n; NthSibling[n, k+1]==Next[NthSibling[n, k]] note: CountToChild[parent, FirstChild[parent]]==0 Routines to check for and generate registered activities Κ₯˜codešœ™KšœB™BKšœ"™"Kšœ1™1Kšœ(™(Kšœ,™,K™*K™(—K™šœ΅™΅K™K™ΎK™K™Β—K™šΟk ˜ Kšœœ ˜Kšœ œ ˜Kšœœœ ˜Kšœ œ ˜Kšœ œI˜WKšœœ˜.—K˜KšΠblœœ˜!Kšœ,˜3Kšœ ˜šœœœ ˜K˜šœœœ˜K˜—šΟn œœœ œ ˜4Kšœœ"˜,K˜—šŸ œœœœ˜;Kšœœ-˜7K˜—š Ÿœœœ œœ˜QK™K˜—šŸ œœœœ˜7Kšœœœ˜!K˜—K˜Kš Ÿœœœ œ œ.œ˜mšŸ œœ œ œ˜5šœœœœ œœœ˜+Kšœœœ ˜K˜ Kšœ˜—K˜—K˜šŸœœœ œ ˜-Kšœ,™,K˜šœœœœœœœœ œœœœ˜vK˜Kšœ˜—K˜—K˜šŸœœœ œ ˜,Kšœœœœœ œœœ$œ˜_K˜—K˜š Ÿœœœœœ˜GK˜ Kšœœœ˜,Kšœœœœœœœœ˜BKš œœœœ!œœ˜]K˜—K˜š Ÿœœœ œœ˜KK˜'Kšœ$œ˜*K˜—K˜š Ÿ œœ œœœ˜QKšœ-™-K˜ Kš œœœœœ˜!Kš œœœœ Οc˜LK˜šœ œ ˜4Kš œœ œœ ˜DKš œœœœœ  ˜HK˜Kšœ˜—K˜K˜—šŸœœœœ˜4Kšœ%œ˜8Kšœ3™3K˜Kšœ œœ˜1Kšœ œœœœœœœ˜8Kšœœœ%œ˜mš œœ œœ &˜CKšœœœ˜(K˜Kšœ˜—K˜Kšœ:œ˜Aš œœœœœ˜PK˜Kšœ˜Kšœ˜—K˜—K˜šŸ œœœ œ˜2Kšœœ˜Kšœ-™-K˜—š Ÿ œœœœœ˜FKšœœ ˜*Kšœ2™2K˜—š Ÿœœœ œ œ˜;Kšœ4™4Kšœ ˜ Kšœœœœ˜AK˜—K˜šŸœœœ˜Kšœœ œ˜5Kšœœ˜'Kšœ1™1Kšœ4™4Kšœ1™1K˜ Kš œœœœœ˜!Kšœœ˜/šœœœ˜;Kšœ2œ ˜`—šœ œ ˜4Kš œœ œœ(œ ˜lKš œœœœœ ˜EK˜Kšœ˜—K˜—K˜šŸœœœ˜Kšœœœ œ˜HKšœ$œ˜7Kšœ2™2Kšœ5™5K˜Kšœ œœ˜1Kšœ œœœœœœœ˜8Kšœœ˜/Kšœœœ%œ ˜všœ &˜)Kšœ œœ &˜@Kšœœœ˜(K˜Kšœ˜—Kšœ:œ˜Ašœ )˜,Kšœœœ˜BKšœ˜"K˜K˜K˜Kšœ˜—K˜—K˜šŸ œœœœ˜>Kš œœœœœ˜FK˜Kšœœ˜K˜K˜Kšœ œœ˜'Kšœ ˜9Kšœœ #˜Cšœœ˜šœœœœœœ œ˜=Kšœ˜Kš œ#œœ!œœ˜mK˜ K˜K˜—Kšœ˜K˜ Kšœ˜—Kš œ œœœ'œ ˜oKšœ ˜K˜—K˜šŸ œœœœ œœœœ ˜nKšœœ8˜BK˜—Kšœ œœœ˜šŸ œœœœœœœ œ ˜zKšœ;™;K˜K˜Kšœœœ œ˜:Kšœœ˜#šœ /˜2šœ˜ Kšœœ˜Kšœœ ˜Kšœ˜ —š œœœœœœ ˜;Kšœ˜—Kšœ˜Kšœ˜—K˜—K˜šŸ œœœœœœœ œ˜jKšœœ?˜IKšœ5™5K˜—šŸ œœœ œ ˜4Kšœ˜K˜—K˜šŸ œœœ œ ˜3Kš œœœœœ˜Kšœœ œ˜#Kšœœ˜-K˜—K˜šŸ œœœ œ ˜2Kšœœœœœœ0œ˜TK˜—K˜šŸ œœœ œ ˜1Kšœ˜#K˜—K˜šŸ œœœ œ ˜2K˜ Kš œœœœœ˜Kšœœœœ˜'K˜šœ &˜)šœœ˜Kš œœœœ œ˜JK˜K˜—Kšœ ˜Kšœ˜—K˜—K˜šŸ œœœ œ˜:K˜Kš œœœœœœ ˜EKšœ˜K˜—K˜š Ÿœœœœœ˜JKšœK™KKš œœœœœœ˜.š œœ œœ$œ˜GKšœ*œ˜0Kšœ œœœ˜ K˜Kšœ˜Kšœ˜—K˜—K˜š Ÿ œœœœœ ˜@KšœE™EKš œœœœœ˜š œœœœ œ˜>Kšœ"œ˜(Kšœœœœ˜K˜ Kšœ ˜ Kšœ˜—K˜—K˜š Ÿ œœœ œ œ ˜@K˜ Kšœœœœ˜+šœ˜Kšœ*œ˜0Kšœ œœ˜K˜Kšœ˜—K˜—K˜š Ÿœœœ œ œ ˜AKšœœœœ˜šœ˜K˜ K˜Kšœ"œ˜(Kšœ˜—K˜—K˜š Ÿ œœœ œ œ˜MKšœœœœ˜šœ˜K˜ K˜Kšœ"œ˜(Kšœ˜—K˜Kšœ,œ˜3K˜—K˜š Ÿ œœœœ œ ˜KKšœ1™1K˜Kš œœœœœœ˜'Kšœ-œ˜3šœœ˜Kšœ œ ˜Kšœœ ˜Kšœ˜Kšœ ˜ K˜Kšœ˜—K˜—K˜š Ÿœœœœœ˜9Kš œœœœœœ ˜&K˜—K˜šŸœœœœ˜CKš œœœœœœ ˜&K˜—K˜šŸœœœ œ˜3Kš œœœœœœ ˜'K˜—K˜š Ÿ œœœ œœ˜3Kš œœœœœœ˜,K˜—K˜š Ÿ œœœ œœ˜6Kš œœœœœœ ˜(K˜—K˜š Ÿœœœ œœ˜.Kšœœœœ˜Kšœœ˜%K˜—K˜K™8K˜šŸ œœœ œœœœ˜gKšœ œœ˜3šœœ œœ˜ Kšœs˜w—K˜K˜—š Ÿœœ œœœ˜5Kšœ œœ˜3Kš œœ œœœI˜~K˜K˜——Kšœ˜K˜—…—(žA“