DIRECTORY Atom USING [MakeAtom], NodeProps USING [GetProp], RefTab USING [Create, Delete, EachPairAction, Fetch, Pairs, Ref, Store], Rope USING [InlineSize, ROPE, Size], TextNode USING [Location, MaxLen, NodeItself, Node, NodeProps, NodeRep, Span], TextNodeRegistry USING [ProcSet]; TextNodeImpl: CEDAR PROGRAM IMPORTS Atom, NP: NodeProps, RefTab, Rope EXPORTS TextNode, TextNodeRegistry = BEGIN OPEN TextNode; ROPE: TYPE ~ Rope.ROPE; ProcSet: TYPE ~ TextNodeRegistry.ProcSet; registrationTable: RefTab.Ref = RefTab.Create[]; Register: PUBLIC PROC [activity: ATOM, procs: ProcSet] RETURNS [] ~ { [] _ RefTab.Store[registrationTable, activity, procs]; }; UnRegister: PUBLIC PROC [activity: ATOM] RETURNS [] ~ { [] _ RefTab.Delete[registrationTable, activity]; }; GetProcs: PUBLIC PROC [activity: ATOM] RETURNS [procs: ProcSet] ~ { RETURN[NARROW[RefTab.Fetch[registrationTable, activity].val]]; }; ActivityOn: PUBLIC PROC [activity: ATOM, on: BOOL _ TRUE] RETURNS [wasOn: BOOL] ~ { SetActivity: RefTab.EachPairAction = { procs: ProcSet = NARROW[val]; IF procs#NIL THEN { wasOn _ procs.activityOn; procs.activityOn _ on; IF wasOn#on AND procs.activityProc#NIL THEN procs.activityProc[on, procs.activityProcData]; }; }; wasOn _ FALSE; IF activity#NIL THEN [] _ SetActivity[activity, RefTab.Fetch[registrationTable, activity].val] ELSE [] _ RefTab.Pairs[registrationTable, SetActivity]; }; DoTransform: PUBLIC PROC [activity: ATOM, node: Node, parent: Node _ NIL, wantFirst: BOOL _ TRUE] RETURNS [new: Node] ~ { procs: ProcSet = NARROW[RefTab.Fetch[registrationTable, activity].val]; new _ IF procs=NIL OR NOT procs.activityOn OR procs.transformProc=NIL THEN node ELSE procs.transformProc[node, parent, wantFirst, procs.transformProcData]; }; GetSize: PUBLIC PROC [activity: ATOM, node: Node] RETURNS [size: INT] ~ { procs: ProcSet = NARROW[RefTab.Fetch[registrationTable, activity].val]; size _ IF procs=NIL OR NOT procs.activityOn OR procs.sizeProc=NIL THEN Rope.Size[node.rope] ELSE procs.sizeProc[node, procs.sizeProcData]; }; PTransform: PROC [node: Node, parent: Node, wantFirst: BOOL] RETURNS [Node] ~ { activity: ROPE ~ NARROW[NP.GetProp[node, activeAtom]]; RETURN [DoTransform[activity: Atom.MakeAtom[activity], node: node, parent: parent, wantFirst: wantFirst]]; }; PSize: PROC [node: Node] RETURNS [INT] ~ { activity: ROPE ~ NARROW[NP.GetProp[node, activeAtom]]; RETURN [GetSize[activity: Atom.MakeAtom[activity], node: node]]; }; activeAtom: ATOM ~ $Active; Transform: PROC [node: Node, parent: Node _ NIL, wantFirst: BOOL _ TRUE] RETURNS [Node] ~ INLINE { IF node = NIL OR node.props = NIL OR NP.GetProp[node, activeAtom] = NIL THEN RETURN [node]; RETURN [PTransform[node: node, parent: parent, wantFirst: wantFirst]]; }; Size: PROC [node: Node] RETURNS [INT] ~ INLINE { IF node.props = NIL OR NP.GetProp[node, activeAtom] = NIL THEN RETURN [Rope.InlineSize[node.rope]]; RETURN [PSize[node: node]]; }; MakeNodeLoc: PUBLIC PROC [n: Node] RETURNS [Location] = { RETURN [[node: n, where: NodeItself]] }; MakeNodeSpan: PUBLIC PROC [first, last: Node] RETURNS [Span] = { RETURN [[MakeNodeLoc[first], MakeNodeLoc[last]]] }; NarrowToTextNode: PUBLIC PROC [n: Node] RETURNS [txt: Node] ~ {RETURN [n]}; NewTextNode: PUBLIC PROC RETURNS [txt: Node] = { txt _ NEW[NodeRep]; txt.last _ TRUE }; InlineParent: PROC [n: Node] RETURNS [Node] = INLINE { DO IF n=NIL OR n.deleted THEN RETURN [NIL]; IF n.last THEN RETURN [n.next]; n _ n.next; ENDLOOP; }; Parent: PUBLIC PROC [n: Node] RETURNS [Node] = { RETURN [Transform[node: InlineParent[n], wantFirst: FALSE]] }; Root: PUBLIC PROC [n: Node] RETURNS [Node] = { p: Node; 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: Node] RETURNS [Node] = { RETURN[IF n=NIL OR n.last OR n.deleted THEN NIL ELSE Transform[node: n.next, wantFirst: TRUE]]; }; Previous: PUBLIC PROC [n: Node, parent: Node _ NIL] RETURNS [nx: Node] = { nx2: Node; 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: Node] RETURNS [nx: Node, levelDelta: INTEGER] = { [nx, levelDelta] _ InlineForward[node]; nx _ Transform[node: nx, wantFirst: TRUE]; }; InlineForward: PROC [node: Node] RETURNS [nx: Node, levelDelta: INTEGER] = INLINE { child: Node; 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: Node, parent: Node _ NIL] RETURNS [back, backparent: Node, levelDelta: INTEGER] = { child, child2: Node; 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: Node] RETURNS [Node] = { RETURN[Forward[node].nx] }; StepBackward: PUBLIC PROC [node: Node, parent: Node _ NIL] RETURNS [Node] = { RETURN[Backward[node, parent].back] }; Level: PUBLIC PROC [node: Node] RETURNS [level: INTEGER] = { level _ 0; UNTIL (node _ InlineParent[node])=NIL DO level _ level+1 ENDLOOP; }; ForwardClipped: PUBLIC PROC [ node: Node, maxLevel: INTEGER, nodeLevel: INTEGER _ 0] RETURNS [nx: Node, nxLevel: INTEGER] = { child: Node; 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: Node, maxLevel: INTEGER, parent: Node _ NIL, nodeLevel: INTEGER _ 0] RETURNS [back, backparent: Node, backLevel: INTEGER] = { child, child2: Node; 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: Node _ location.node; size, lastSize, where: INT _ 0; init: Node _ n; lastTxt: Node; 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: Node, 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: Node _ loc2.node; n: Node _ 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: Node] RETURNS [Node] = { RETURN[FirstChild[Parent[n]]]; }; LastSibling: PUBLIC PROC [n: Node] RETURNS [Node] = { IF n=NIL THEN RETURN [NIL]; UNTIL n.last DO n _ n.next ENDLOOP; RETURN[Transform[node: n, wantFirst: FALSE]]; }; FirstChild: PUBLIC PROC [n: Node] RETURNS [Node] = { RETURN[IF n=NIL THEN NIL ELSE Transform[node: n.child, parent: n, wantFirst: TRUE]]; }; LastChild: PUBLIC PROC [n: Node] RETURNS [Node] = { RETURN[LastSibling[FirstChild[n]]]; }; LastWithin: PUBLIC PROC [n: Node] RETURNS [Node] = { nxt: Node; 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: Node] RETURNS [Location] = { last: Node _ LastWithin[n]; where: INT _ IF last # NIL THEN Rope.Size[last.rope] ELSE NodeItself; RETURN [[last, where]]; }; NthChild: PUBLIC PROC [n: Node, location: INT _ 0] RETURNS [child: Node] = { 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: Node, cnt: INT _ 0] RETURNS [Node] = { 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: Node] RETURNS [count: INT _ 0] = { child: Node; 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: Node] 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: Node] RETURNS [count: INT _ 0, parent: Node] = { 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: Node] RETURNS [count: INT _ 0] = { n: Node; 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; }; NodeFormat: PUBLIC PROC [n: Node] RETURNS [ATOM] = { RETURN[IF n=NIL THEN NIL ELSE n.formatName]; }; IsLastSibling: PUBLIC PROC [n: Node] RETURNS [BOOL] = { RETURN[IF n=NIL THEN FALSE ELSE n.last]; }; EndPos: PUBLIC PROC [n: Node] RETURNS [INT] = { IF n=NIL THEN RETURN [0]; RETURN [MAX[Rope.Size[n.rope], 1]-1]; }; END. TextNodeImpl.mesa Copyright Σ 1985, 1986, 1987, 1988 by Xerox Corporation. All rights reserved. written by Bill Paxton, March 1981 last edit by Bill Paxton, August 11, 1982 9:51 am Rick Beach, March 27, 1985 10:13:12 am PST Michael Plass, July 27, 1987 9:21:44 am PDT Doug Terry, June 25, 1987 2:18:19 pm PDT Doug Wyatt, February 17, 1988 6:06:44 pm PST This is a modified version (by Doug Terry) 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 (in Transform and Size). This change was not made since modifying TextNode.mesa triggers lots of recompilations. TextNodeRegistryImpl The given TransformProc will hereafter be applied to all nodes having an active property with value=activity. Removes the procedures associated with the given activity. Return the procedures associated with the given activity. Determines whether or not the registered transformations should be currently applied; if activity=NIL then activity is turned on/off for all registered clients. Registered clients are informed via callbacks when this switch is toggled so they can take appropriate action. [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOL _ FALSE] Force the TransformProc associated with the given activity to be applied to the node. (This is intended primarily for use by TextNodeImpl.) Computes or estimates the size that the given node will be AFTER it is transformed by the specified activity. (This is intended primarily for use by TextNodeImpl.) Routines to check for and generate registered activities The rest of TextNodeImpl 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 Κ'˜codešœ™KšœN™NKšœ"™"Kšœ1™1K™*Kšœ+™+K™(Kšœ,™,—K™šœΕ™ΕK™K™ΎK™K™Ϊ—K™šΟk ˜ Kšœœ ˜Kšœ œ ˜Kšœœ<˜HKšœœœ ˜%Kšœ œ@˜NKšœœ ˜!—K˜KšΠln œœ˜Kšœœ˜)Kšœ˜"šœœœ ˜K˜Kšœœœ˜K˜—™K˜Kšœ œ˜)K˜Jšœ0˜0J˜š Οnœœœ œœ˜EKšœm™mJšœ6˜6K˜K™—š Ÿ œœœ œœ˜7K™:Jšœ0˜0K˜K™—š Ÿœœœ œœ˜CJšœ9™9Jšœœ1˜>K˜J™—šŸ œœœ œœœœ œ˜SKšœbœ«™•StartOfExpansionC -- [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOL _ FALSE]šŸ œ˜&Kšœ#œœœ™?Kšœœ˜šœœœ˜Kšœ˜Kšœ˜šœ œœ˜+Kšœ/˜/—K˜—K˜—Kšœœ˜šœ ˜KšœJ˜NKšœ3˜7—K˜K™—šŸ œœœ œœ œœœ˜yKšœŒ™ŒKšœœ0˜GKšœœœœœœœœœG˜›K˜K™—š Ÿœœœ œ œœ˜IKšœ€™€Kšœœ0˜GKšœœœœœœœœœ*˜ŠK˜J˜—K™—™8K˜šŸ œœ'œœ ˜OKšœ œœœ˜6Kšœd˜jK˜K˜—šŸœœœœ˜*Kšœ œœœ˜6Kšœ:˜@K˜K˜—šœ œ ˜K˜—šŸ œœœ œœœ œ˜bKšœœœœœœœœœ˜[Kšœ@˜FK˜K˜—š Ÿœœœœœ˜0Kšœœœœœœœ˜cKšœ˜K˜K˜—K˜—™K™šŸ œœœ œ ˜5Kšœœ"˜,K˜—šŸ œœœœ˜Kš œœœœœ˜FK˜Kšœœ˜K˜K˜Kšœ œœ˜'Kšœ ˜9Kšœœ #˜Cšœœ˜šœœœœœœ œ˜=Kšœ˜Kš œ#œœ!œœ˜mK˜ K˜K˜—Kšœ˜K˜ Kšœ˜—Kš œ œœœ'œ ˜oKšœ ˜K˜—K˜šŸ œœœœ œœœœ ˜oKšœœ8˜BK˜—Kšœ œœœ˜šŸ œœœœœœœ œ ˜zKšœ;™;K˜K˜Kšœœœ œ˜:Kšœœ˜#šœ /˜2šœ˜ Kšœœ˜Kšœœ ˜Kšœ˜ —š œœœœœœ ˜;Kšœ˜—Kšœ˜Kšœ˜—K˜—K˜šŸ œœœœœœœ œ˜jKšœœ?˜IKšœ5™5K˜—šŸ œœœ œ ˜6Kšœ˜K˜—K˜šŸ œœœ œ ˜5Kš œœœœœ˜Kšœœ œ˜#Kšœœ˜-K˜—K˜šŸ œœœ œ ˜4Kšœœœœœœ0œ˜TK˜—K˜šŸ œœœ œ ˜3Kšœ˜#K˜—K˜šŸ œœœ œ ˜4K˜ Kš œœœœœ˜Kšœœœœ˜'K˜šœ &˜)šœœ˜Kš œœœœ œ˜JK˜K˜—Kšœ ˜Kšœ˜—K˜—K˜šŸ œœœ œ˜;K˜Kš œœœœœœ ˜EKšœ˜K˜—K˜š Ÿœœœœœ˜LKšœK™KKš œœœœœœ˜.š œœ œœ$œ˜GKšœ*œ˜0Kšœ œœœ˜ K˜Kšœ˜Kšœ˜—K˜—K˜š Ÿ œœœœœ ˜BKšœE™EKš œœœœœ˜š œœœœ œ˜>Kšœ"œ˜(Kšœœœœ˜K˜ Kšœ ˜ Kšœ˜—K˜—K˜š Ÿ œœœ œ œ ˜AK˜ Kšœœœœ˜+šœ˜Kšœ*œ˜0Kšœ œœ˜K˜Kšœ˜—K˜—K˜š Ÿœœœ œ œ ˜BKšœœœœ˜šœ˜K˜ K˜Kšœ"œ˜(Kšœ˜—K˜—K˜š Ÿ œœœ œ œ˜OKšœœœœ˜šœ˜K˜ K˜Kšœ"œ˜(Kšœ˜—K˜Kšœ,œ˜3K˜—K˜š Ÿ œœœœ œ ˜LKšœ1™1K˜Kš œœœœœœ˜'Kšœ-œ˜3šœœ˜Kšœ œ ˜Kšœœ ˜Kšœ˜Kšœ ˜ K˜Kšœ˜—K˜—K˜K˜š Ÿ œœœ œœ˜4Kš œœœœœœ˜,K˜—K˜š Ÿ œœœ œœ˜7Kš œœœœœœ ˜(K˜—K˜š Ÿœœœ œœ˜/Kšœœœœ˜Kšœœ˜%K˜—K˜—Kšœ˜K˜—…—/TN—