ImmutableTioga.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Doug Wyatt, September 16, 1986 4:46:35 pm PDT
DIRECTORY
ImagerFont USING [BYTE, XChar],
Rope USING [ROPE],
Rosary USING [ROSARY],
TextLooks USING [Looks, allLooks, noLooks, Runs];
ImmutableTioga: CEDAR DEFINITIONS
~ BEGIN
Types
Defined elsewhere
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;
PropList
Prop: TYPE ~ REF PropRep;
PropRep: TYPE ~ RECORD [name: ATOM, value: REF];
PropList: TYPE ~ LIST OF Prop;
MapPropsAction: TYPE ~ PROC [name: ATOM, value: REF] RETURNS [quit: BOOLFALSE];
Node
Node: TYPE ~ REF NodeRep; -- immutable
NodeRep: TYPE ~ RECORD [
text: Text,
children: ROSARY --OF Node--,
depth: INT
];
Text: TYPE ~ REF TextRep; -- immutable
TextRep: TYPE ~ RECORD [
rope: ROPE,
runs: Runs,
charSets: ROSARY --OF REF CharSet--,
charProps: ROSARY --OF PropList--,
props: Props
];
Props: TYPE ~ REF PropsRep; -- immutable
PropsRep: TYPE ~ RECORD [
propList: PropList ← NIL,
formatName: ATOMNIL, -- value of $Format property
comment: BOOLFALSE, -- value of $Comment property
hasStyleDef: BOOLFALSE, -- true if propList has $StyleDef prop (accelerator)
hasPrefix: BOOLFALSE, -- true if propList has $Prefix prop (accelerator)
hasPostfix: BOOLFALSE, -- true if propList has $Postfix prop (accelerator)
hasArtwork: BOOLFALSE -- true if propList has $Artwork prop (accelerator)
];
Location, Span
maxLen: INT ~ INT.LAST;
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]] };
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
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: BOOLFALSE] RETURNS [Location];
count is interpreted as a character offset from given location
returns <node,offset> 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: BOOLFALSE] RETURNS [Location];
LocRelative[[n, 0], ...]; count is offset from beginning of given node
LocOffset: PROC [loc1, loc2: Location, break: INT ← 1,
skipCommentNodes: BOOLFALSE] 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: BOOLFALSE] 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
NewText: PROC [props: Props ← NIL] RETURNS [Text];
TextFromRope: PROC [rope: ROPE, looks: Looks ← noLooks] RETURNS [Text];
create a text node 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
Properties
PropListGet: PROC [propList: PropList, name: ATOM] RETURNS [value: REF];
PropListPut: PROC [propList: PropList, name: ATOM, value: REF] RETURNS [PropList];
PropListMap: PROC [propList: PropList, action: MapPropsAction] RETURNS [BOOL];
PropsGet: PROC [props: Props, name: ATOM] RETURNS [value: REF];
PropsPut: PROC [props: Props, name: ATOM, value: REF] RETURNS [Props];
PropsMap: PROC [props: Props, action: MapPropsAction] RETURNS [BOOL];
Read, Write 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
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
RegisterProp: PROC [name: ATOM, reader: PropReader, writer: PropWriter];
registers procs for given property name
they will be called by ReadProp, WriteProp, CopyProp
Fetch Text information
Size: PROC [text: Text] RETURNS [INT];
FetchChar: PROC [text: Text, index: INT] RETURNS [XChar];
fetches the indexed character
use rope readers if want characters from contiguous locations
FetchLooks: PROC [text: Text, index: INT] RETURNS [Looks];
returns the looks for the character at the given location
use readers if getting looks for sequence of locations
Fetch: PROC [text: Text, index: INT] RETURNS [char: XChar, looks: Looks];
fetches the indexed information, except for character properties
use rope & looks readers if want info from contiguous locations
GetProp: PROC [text: Text, name: ATOM] RETURNS [REF];
GetComment: PROC [text: Text] RETURNS [BOOL];
GetFormat: PROC [text: Text] RETURNS [ATOM];
MapProps: PROC [node: Node, action: MapPropsAction] RETURNS [quit: BOOL];
apply the action to each name & value pair for the node
returns true if&when an action returns true
GetCharProp: PROC [text: Text, index: INT, name: ATOM] RETURNS [value: REF];
GetCharPropList: PROC [text: Text, index: INT] RETURNS [PropList];
MapCharProps: PROC [node: Node, index: INT, action: MapPropsAction] RETURNS [BOOL];
apply the action to each name & value pair for the indexed character
Editing
Edit Text
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: BOOLTRUE, looks: Looks ← noLooks, charSet: CharSet ← 0] RETURNS [Text];
SetProp: PROC [text: Text, name: ATOM, value: REF] RETURNS [Text];
SetComment: PROC [text: Text, comment: BOOL] RETURNS [Text];
Sets the $Comment property of a node.
SetFormat: PROC [text: Text, formatName: ATOM] RETURNS [Text];
Sets the $Format property of a node.
SetCharProp: PROC [text: Text, start: INT ← 0, len: INT ← maxLen, name: ATOM, value: REF] RETURNS [Text];
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 [text: Text, start: INT ← 0, len: INT ← maxLen, propList: PropList] RETURNS [Text];
ModifyPropsAction: TYPE ~ PROC [value: REF, start: INT, len: INT]
RETURNS
[quit: BOOLFALSE, 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.
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: BOOLTRUE] 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: BOOLTRUE];
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: BOOLTRUE] 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;
Node properties
SetStyle: PROC [world: World, node: Node, styleName: ROPE, root: Node ← NIL];
appends <name> style to end of node prefix
Insert, Split, Merge, Nest
Insert: PROC [world: World, root, old: Node, where: Place ← after,
inherit: BOOLTRUE] 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];
END.