<<-- TextNodeImpl.mesa>> <<-- written by Bill Paxton, March 1981>> <<-- last edit by Bill Paxton, August 11, 1982 9:51 am>> <> DIRECTORY TextNode, TextLooks, Rope, RopeEdit, SafeStorage; TextNodeImpl: CEDAR PROGRAM IMPORTS SafeStorage, RopeEdit, TextNode EXPORTS TextNode = BEGIN OPEN TextNode; <<-- ***** Declarations>> qZone: PUBLIC ZONE _ SafeStorage.NewZone[quantized]; -- quantized zone pZone: PUBLIC ZONE _ SafeStorage.NewZone[prefixed]; -- prefix zone <<-- ***** Operations>> NewTextNode: PUBLIC PROC RETURNS [txt: RefTextNode] = { txt _ qZone.NEW[TextBody]; txt.last _ TRUE }; NewOtherNode: PUBLIC PROC RETURNS [oth: RefOtherNode] = { oth _ qZone.NEW[OtherBody]; oth.last _ TRUE }; Parent: PUBLIC PROC [n: Ref] RETURNS [Ref] = { RETURN [InlineParent[n]] }; 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] = { <<-- applies Parent repeatedly until reaches root>> p: Ref; DO IF (p _ InlineParent[n])=NIL THEN RETURN [IF n=NIL OR n.deleted THEN NIL ELSE n]; n _ p; ENDLOOP }; Next: PUBLIC PROC [n: Ref] RETURNS [Ref] = { RETURN[IF n=NIL OR n.last OR n.deleted THEN NIL ELSE n.next] }; 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; nx _ nx2; ENDLOOP }; Forward: PUBLIC PROC [node: Ref] RETURNS [nx: Ref, levelDelta: INTEGER] = { [nx, levelDelta] _ InlineForward[node] }; InlineForward: PROC [node: Ref] RETURNS [nx: Ref, levelDelta: INTEGER] = INLINE { <<-- returns next node in standard tree walk order>> 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 ~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] = { <<-- returns preceeding node in standard tree walk order>> 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 [parent,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; DO IF (child2 _ LastChild[child]) = NIL THEN RETURN [child,parent,levelDelta]; levelDelta _ levelDelta+1; parent _ child; child _ child2; ENDLOOP }; Level: PUBLIC PROC [node: Ref] RETURNS [level: INTEGER] = { <<-- Level[Root[x]] == 0; Level[FirstChild[n]]=Level[n]+1>> 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] = { <<-- 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]]>> 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 [child,nodeLevel+1]; -- return the child DO -- move to next node, sibling or up* then sibling IF ~node.last THEN RETURN [node.next,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] = { <<-- like Backward, but limits how deep will go in tree>> <<-- backLevel = Level[back] <= MAX[maxLevel,Level[node]]>> 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 [parent,InlineParent[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; 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: Offset, break: NAT _ 1, skipCommentNodes: BOOLEAN _ FALSE] RETURNS [Location] = { n: Ref _ location.node; size, lastSize, where: Offset; init: Ref _ n; txt, 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 txt _ NarrowToTextNode[n]; IF txt # NIL AND (~skipCommentNodes OR ~txt.comment) THEN { lastSize _ size _ RopeEdit.Size[txt.rope]; IF (count _ count-(size-where)) <= 0 THEN RETURN [[n,MAX[0,count+size]]]; lastTxt _ txt; count _ count-break }; [n,] _ InlineForward[n]; where _ 0; ENDLOOP; IF lastTxt # NIL THEN RETURN [[lastTxt,lastSize]]; -- end of last text node RETURN [[init,0]] }; BadArgs: PUBLIC ERROR = CODE; LocOffset: PUBLIC PROC [loc1, loc2: Location, break: NAT _ 1, skipCommentNodes: BOOLEAN _ FALSE] RETURNS [count: Offset] = { <<-- returns character offset of location2 relative to location1>> node: Ref _ loc2.node; n: Ref _ loc1.node; txt: RefTextNode; 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; txt _ NarrowToTextNode[n]; IF txt # NIL AND (~skipCommentNodes OR ~txt.comment) THEN count _ count+RopeEdit.Size[txt.rope]+break; [n,] _ InlineForward[n]; ENDLOOP }; FirstSibling: PUBLIC PROC [n: Ref] RETURNS [Ref] = { RETURN[FirstChild[Parent[n]]]}; LastSibling: PUBLIC PROC [n: Ref] RETURNS [Ref] = { IF n=NIL THEN RETURN [NIL]; DO IF n.last THEN RETURN [n]; n _ n.next; ENDLOOP }; FirstChild: PUBLIC PROC [n: Ref] RETURNS [Ref] = { RETURN[IF n=NIL THEN NIL ELSE n.child]}; 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 [n]; n _ nxt } ELSE n _ n.next; ENDLOOP }; LastLocWithin: PUBLIC PROC [n: Ref] RETURNS [Location] = { last: Ref _ LastWithin[n]; lastText: RefTextNode _ NarrowToTextNode[last]; where: Offset _ IF lastText # NIL THEN RopeEdit.Size[lastText.rope] ELSE NodeItself; RETURN [[last,where]] }; NthChild: PUBLIC PROC [n: Ref, location: Offset] RETURNS [child: Ref] = { <<-- note: NthChild[n,0]==FirstChild[n]; NthChild[n,k+1]==Next[NthChild[n,k]]>> IF n=NIL OR (child _ n.child)=NIL THEN RETURN; DO IF location=0 THEN RETURN [child]; IF child.last THEN RETURN [NIL]; child _ child.next; location _ location-1; ENDLOOP }; NthSibling: PUBLIC PROC [n: Ref, cnt: Offset] RETURNS [Ref] = { <<-- note: NthSibling[n,0]==n; NthSibling[n,k+1]==Next[NthSibling[n,k]]>> IF n=NIL THEN RETURN [NIL]; DO IF cnt=0 THEN RETURN [n]; IF n.last THEN RETURN [NIL]; n _ n.next; cnt _ cnt-1; ENDLOOP }; CountChildren: PUBLIC PROC [n: Ref] RETURNS [count: Offset] = { child: Ref; count _ 0; IF (child _ FirstChild[n])=NIL THEN RETURN; DO count _ count+1; IF child.last THEN RETURN; child _ child.next; ENDLOOP }; CountFollowing: PUBLIC PROC [n: Ref] RETURNS [count: Offset] = { count _ 0; IF n=NIL THEN RETURN; DO IF n.last THEN RETURN; n _ n.next; count _ count+1; ENDLOOP }; CountToParent: PUBLIC PROC [n: Ref] RETURNS [count: Offset, parent: Ref] = { count _ 0; IF n=NIL THEN RETURN; DO IF n.last THEN EXIT; n _ n.next; count _ count+1; ENDLOOP; parent _ n.next }; CountToChild: PUBLIC PROC [parent, child: Ref] RETURNS [count: Offset] = { <<-- note: CountToChild[parent,FirstChild[parent]]==0>> n: Ref; count _ 0; IF parent=NIL OR child=NIL THEN RETURN; n _ parent.child; 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]}; NodeType: PUBLIC PROC [n: Ref] RETURNS [TypeName] = { RETURN[IF n=NIL THEN nullTypeName ELSE n.typename]}; IsLastSibling: PUBLIC PROC [n: Ref] RETURNS [BOOLEAN] = { RETURN[IF n=NIL THEN FALSE ELSE n.last] }; EndPos: PUBLIC PROC [n: Ref] RETURNS [Offset] = { node: RefTextNode = NarrowToTextNode[n]; IF node=NIL THEN RETURN [0]; RETURN [MAX[RopeEdit.Size[node.rope],1]-1] }; <<-- ***** Initialization>> Start: PUBLIC PROC = { }; END.