<<-- TextNode.Mesa>> <<-- written by Bill Paxton. December 1980>> <<-- last written by Paxton. December 21, 1982 9:46 am>> <> DIRECTORY Rope, NameSymbolTable, TextLooks; TextNode: CEDAR DEFINITIONS = BEGIN Offset: TYPE = LONG INTEGER _ 0; MaxLen: Offset = LAST[Offset]; ROPE: TYPE = Rope.ROPE; Ref: TYPE = REF Body; Body: TYPE = RECORD [ next: Ref, -- points to next sibling, or if last=true, to parent child: Ref, -- points to first child, if any, of this node props: NodeProps, -- points to node property list class: REF ANY, -- for Scott to play with typename: TypeName _ nullTypeName, -- name of type for the node last: BOOLEAN _ FALSE, -- true if this is last sibling hasstyledef: BOOLEAN _ FALSE, -- true if node has StyleDef prop (simply an accelerator) hasprefix: BOOLEAN _ FALSE, -- true if node has Prefix prop (simply an accelerator) haspostfix: BOOLEAN _ FALSE, -- true if has Postfix prop (also an accelerator) deleted: BOOLEAN _ FALSE, -- true if has been deleted or is root pending delete dirty: BOOLEAN _ FALSE, -- true if has been edited (contents, or children moved, inserted, ...) new: BOOLEAN _ FALSE, -- true if created during this editing session (i.e., not from file) body: SELECT kind:OfNode FROM text => [ comment: BOOLEAN _ FALSE, -- true if node is a comment count: [0..countMax] _ 0, -- incremented by text edit routines rope: ROPE, runs: TextLooks.Runs ], other => [ variety: ATOM, info: REF ANY ], ENDCASE]; Location: TYPE = RECORD [node: Ref, where: Offset]; <<-- 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>> NodeItself: Offset = -1; nullLocation: Location = [NIL,NodeItself]; MakeNodeLoc: PROC [n: Ref] RETURNS [Location] = INLINE { RETURN [[n,NodeItself]] }; 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 do 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]; MakeNodeSpan: PROC [first, last: Ref] RETURNS [Span] = INLINE { RETURN [[MakeNodeLoc[first],MakeNodeLoc[last]]] }; countMax: NAT=63; -- 6 bits for count OfNode: TYPE = {text,other}; TextBody: TYPE = text Body; RefTextNode: TYPE = REF TextBody; OtherBody: TYPE = other Body; RefOtherNode: TYPE = REF OtherBody; NodeList: TYPE = REF NodeListBody; NodeListBody: TYPE = RECORD [node: Ref, next: NodeList]; NodeProps: TYPE = REF NodePropsBody; NodePropsBody: TYPE; -- exported by NodePropsImpl <<-- here are some access procedures for use with nodes>> NewTextNode: PROC RETURNS [txt: RefTextNode]; NewOtherNode: PROC RETURNS [oth: RefOtherNode]; NarrowToTextNode: PROC [n: Ref] RETURNS [txt: RefTextNode] = TRUSTED INLINE { <<-- returns n as a RefTextNode if possible, else returns NIL>> IF n#NIL THEN WITH x:n SELECT FROM text => txt _ @x; ENDCASE }; NarrowToOtherNode: PROC [n: Ref] RETURNS [othr: RefOtherNode] = TRUSTED INLINE { <<-- returns n as a RefOtherNode if possible, else returns NIL>> IF n#NIL THEN WITH x:n SELECT FROM other => othr _ @x; ENDCASE }; Parent: PROC [n: Ref] RETURNS [Ref]; Root: PROC [n: Ref] RETURNS [Ref]; Next: PROC [n: Ref] RETURNS [Ref]; <<-- returns next sibling of n>> <<-- returns NIL if n is last sibling>> Previous: PROC [n: Ref, parent: Ref _ NIL] RETURNS [nx: Ref]; <<-- returns previous sibling of n>> <<-- returns NIL if n is first sibling>> <<-- runs faster if can supply parent>> StepForward: PROC [node: Ref] RETURNS [nx: Ref] = INLINE { [nx,] _ Forward[node] }; <<-- returns next node in standard tree walk order>> StepBackward: PROC [node: Ref, parent: Ref _ NIL] RETURNS [back: Ref] = INLINE { <<-- returns preceeding node in standard tree walk order>> [back,,] _ Backward[node,parent] }; Forward: PROC [node: Ref] RETURNS [nx: Ref, levelDelta: INTEGER]; <<-- 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: Ref, parent: Ref _ NIL] RETURNS [back, backparent: Ref, levelDelta: INTEGER]; <<-- for backing through tree>> <<-- runs faster if can supply parent>> <<-- levelDelta same as for Forward>> Level: PROC [node: Ref] RETURNS [level: INTEGER]; <<-- Level[Root[x]] == 0; Level[FirstChild[n]]=Level[n]+1>> ForwardClipped: 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]]>> BackwardClipped: 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]]>> LocRelative: PROC [location: Location, count: Offset, break: NAT _ 1, skipCommentNodes: BOOLEAN _ 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: Ref, count: Offset, break: NAT _ 1, skipCommentNodes: BOOLEAN _ FALSE] RETURNS [Location] = INLINE { RETURN [LocRelative[[n,0],count,break,skipCommentNodes]] }; LocOffset: PROC [loc1, loc2: Location, break: NAT _ 1, skipCommentNodes: BOOLEAN _ FALSE] RETURNS [count: Offset]; <<-- 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>> BadArgs: ERROR; LocNumber: PROC [at: Location, break: NAT _ 1, skipCommentNodes: BOOLEAN _ FALSE] RETURNS [count: Offset] = INLINE { RETURN [LocOffset[[Root[at.node],0],at,break,skipCommentNodes]] }; <<-- returns character offset of location relative to root>> FirstSibling: PROC [n: Ref] RETURNS [Ref]; LastSibling: PROC [n: Ref] RETURNS [Ref]; LastWithin: PROC [n: Ref] RETURNS [Ref]; <<-- returns the last node within the branch >> <<-- i.e., goes to last child of last child of last child ... until no child>> LastLocWithin: PROC [n: Ref] RETURNS [Location]; <<-- returns the last location within the branch >> FirstChild: PROC [n: Ref] RETURNS [Ref]; LastChild: PROC [n: Ref] RETURNS [Ref]; NthChild: PROC [n: Ref, location: Offset] RETURNS [child: Ref]; NthSibling: PROC [n: Ref, cnt: Offset] RETURNS [Ref]; CountChildren: PROC [n: Ref] RETURNS [count: Offset]; CountFollowing: PROC [n: Ref] RETURNS [count: Offset]; CountToParent: PROC [n: Ref] RETURNS [count: Offset, parent: Ref]; CountToChild: PROC [parent, child: Ref] RETURNS [count: Offset]; NodeRope: PROC [n: RefTextNode] RETURNS [ROPE]; NodeRuns: PROC [n: RefTextNode] RETURNS [TextLooks.Runs]; Props: PROC [n: Ref] RETURNS [NodeProps]; NodeType: PROC [n: Ref] RETURNS [TypeName]; IsLastSibling: PROC [n: Ref] RETURNS [BOOLEAN]; EndPos: PROC [n: Ref] RETURNS [Offset]; <<-- TypeNames are the same as names in NameSymbolTable>> TypeName: TYPE = NameSymbolTable.Name; nullTypeName: TypeName = NameSymbolTable.nullName; qZone: ZONE; -- quantized zone pZone: ZONE; -- prefix zone <<-- Initialization>> Start: PROC; END.