Insert:
PUBLIC
PROC [root: RefBranchNode, old: Ref, where: Place ← after, event: Event ←
NIL]
RETURNS [new: Ref] = TRUSTED {
empty copy of old node is inserted in tree in position determined by "where"
IF old=NIL THEN RETURN [NIL];
new ←
WITH old
SELECT
FROM
br: RefBranchNode => TiogaNodeOps.NewBranchNode[],
tx: RefTextNode => TiogaNodeOps.NewTextNode[tx.class],
bx: TiogaNode.RefBoxNode => TiogaNodeOps.NewBoxNode[bx.class],
ls: TiogaNode.RefListNode => TiogaNodeOps.NewListNode[ls.class],
bs: TiogaNode.RefBasicNode => TiogaNodeOps.NewBasicNode[bs.class],
ENDCASE => ERROR;
Inherit[old, new];
DoInsertNode[root, old, new, where, event] };
InsertTextNode:
PUBLIC
PROC
[root: RefBranchNode, old: Ref, class: TiogaNode.ItemClassID ← TiogaNode.defaultTextClassID,
where: Place ← after, inherit: BOOL ← FALSE, event: Event ← NIL]
RETURNS [new: RefTextNode] = BEGIN
IF old=NIL THEN RETURN [NIL];
new ← TiogaNodeOps.NewTextNode[class];
IF inherit THEN Inherit[old, new];
DoInsertNode[root, old, new, where, event];
END;
InsertBranchNode:
PUBLIC
PROC [
root: RefBranchNode, old: Ref, where: Place ← after, inherit: BOOL ← FALSE, event: Event ← NIL]
RETURNS [new: TiogaNode.RefBranchNode] = BEGIN
IF old=NIL THEN RETURN [NIL];
new ← TiogaNodeOps.NewBranchNode[];
IF inherit THEN Inherit[old, new];
DoInsertNode[root, old, new, where, event];
END;
InsertBoxNode:
PUBLIC
PROC [
root: RefBranchNode, old: Ref, class: TiogaNode.ItemClassID,
where: Place ← after, inherit: BOOL ← FALSE, event: Event ← NIL]
RETURNS [new: TiogaNode.RefBoxNode] = BEGIN
IF old=NIL THEN RETURN [NIL];
new ← TiogaNodeOps.NewBoxNode[class];
IF inherit THEN Inherit[old, new];
DoInsertNode[root, old, new, where, event];
END;
InsertListNode:
PUBLIC
PROC [
root: RefBranchNode, old: Ref, class: TiogaNode.ItemClassID,
where: Place ← after, inherit: BOOL ← FALSE, event: Event ← NIL]
RETURNS [new: TiogaNode.RefListNode] = BEGIN
IF old=NIL THEN RETURN [NIL];
new ← TiogaNodeOps.NewListNode[class];
IF inherit THEN Inherit[old, new];
DoInsertNode[root, old, new, where, event];
END;
InsertBasicNode:
PUBLIC
PROC [
root: RefBranchNode, old: Ref, class: TiogaNode.BasicClassID,
where: Place ← after, inherit: BOOL ← FALSE, event: Event ← NIL]
RETURNS [new: TiogaNode.RefBasicNode] = BEGIN
IF old=NIL THEN RETURN [NIL];
new ← TiogaNodeOps.NewBasicNode[class];
IF inherit THEN Inherit[old, new];
DoInsertNode[root, old, new, where, event];
END;
Inherit:
PUBLIC
PROC [old, new: Ref, allprops:
BOOL ←
FALSE] = {
CopyProp:
PROC [name:
ATOM, value:
REF]
RETURNS [
BOOL] = {
newvalue: REF;
IF ~allprops
THEN
SELECT name
FROM
$Prefix, $Postfix, $StyleDef => NULL; -- these control formatting
ENDCASE => RETURN [FALSE]; -- don't copy anything else
IF (newvalue ← NodeProps.CopyInfo[name: name, value: value, from: old, to: new]) #
NIL
THEN NodeProps.PutProp[new, name, newvalue];
RETURN [FALSE] };
new.format ← old.format;
new.comment ← old.comment;
IF old.hasPropList
AND (allprops
OR old.hasprefix
OR old.haspostfix
OR old.hasstyledef)
THEN
[] ← NodeProps.MapProps[old, CopyProp, FALSE, FALSE] };
DoInsertNode:
PROC [root: RefBranchNode, old, new: Ref, where: Place, event: Event] = {
notify: REF InsertingNode Change;
oldBr, newBr: RefBranchNode;
Link:
PROC [node, sib: Ref] =
INLINE {
sib.next ← node.next; sib.last ← node.last; node.last ← FALSE; node.next ← sib };
NotifyBefore:
PROC =
INLINE {
new.new ← TRUE;
notify ← NEW[InsertingNode Change ← [InsertingNode[root, new, old, where]]];
Notify[notify, before] };
IF new = NIL OR old = NIL THEN RETURN;
IF where = before
THEN {
-- convert to other kind of insert
prev: Ref;
IF TiogaNodeOps.IsBranch[old] # TiogaNodeOps.IsBranch[new] THEN ERROR CannotDoEdit;
IF (prev ← TiogaTreeOps.Previous[old]) # NIL THEN { where ← sibling; old ← prev }
ELSE { where ← child; old ← TiogaTreeOps.Parent[old] }};
SELECT where
FROM
sibling => {
IF TiogaNodeOps.IsBranch[old] # TiogaNodeOps.IsBranch[new] THEN ERROR CannotDoEdit;
NotifyBefore[]; Link[old, new] };
after => {
oldBr ← TiogaNodeOps.NarrowToBranchNode[old];
newBr ← TiogaNodeOps.NarrowToBranchNode[new];
IF (oldBr=NIL) # (newBr=NIL) THEN ERROR CannotDoEdit;
NotifyBefore[]; Link[old, new];
IF oldBr #
NIL
AND oldBr.child #
NIL
THEN {
-- adopt oldBr's children
newBr.child ← oldBr.child;
TiogaTreeOps.LastSibling[newBr.child].next ← newBr;
oldBr.child ← NIL }};
child =>
WITH old
SELECT
FROM
br: RefBranchNode => {
NotifyBefore[];
newBr ← TiogaNodeOps.NarrowToBranchNode[new];
IF newBr #
NIL
THEN {
-- insert new branch as child of old branch
IF br.child # NIL THEN { new.next ← br.child; new.last ← FALSE }
ELSE { new.next ← br; new.last ← TRUE };
br.child ← newBr }
ELSE {
-- insert new as contents of old
IF br.contents # NIL THEN { new.next ← br.contents; new.last ← FALSE }
ELSE { new.next ← br; new.last ← TRUE };
br.contents ← TiogaNodeOps.NarrowToItemNode[new] }};
bx: TiogaNode.RefBoxNode => {
NotifyBefore[];
IF bx.contents # NIL THEN { new.next ← bx.contents; new.last ← FALSE }
ELSE { new.next ← bx; new.last ← TRUE };
bx.contents ← new };
ls: TiogaNode.RefListNode => {
NotifyBefore[];
IF ls.contents # NIL THEN { new.next ← ls.contents; new.last ← FALSE }
ELSE { new.next ← ls; new.last ← TRUE }};
ENDCASE => ERROR CannotDoEdit;
ENDCASE => ERROR;
Notify[notify, after];
UndoEvent.Note[event, UndoInsertNode, notify] };
UndoInsertNode:
PROC [undoRef:
REF, currentEvent: Event] =
TRUSTED {
saved: REF Change ← NARROW[undoRef];
WITH x:saved SELECT FROM
InsertingNode => { [] ← EditGroup.DeleteGroup[x.root, x.new, x.new, FALSE, currentEvent] };
ENDCASE => ERROR };
***** split & merge
JoinStatements:
PUBLIC
PROC [root, statement: RefBranchNode, event: Event ←
NIL]
RETURNS [loc: TreeLoc] = {
moves contents of statement to end of previous one and then deletes statement
pred: RefBranchNode ← TiogaTreeOps.Backward[statement].back;
dest, source: Ref;
IF pred = NIL OR TiogaTreeOps.Parent[pred] = NIL THEN ERROR CannotDoEdit;
dest ← TiogaTreeOps.Contents[pred];
IF (source ← TiogaTreeOps.Contents[statement])=
NIL
THEN
IF dest=NIL THEN loc ← [pred, NodeItself]
ELSE {
dest ← TiogaTreeOps.LastSibling[dest];
loc ← [dest,
IF ~TiogaNodeOps.IsText[dest]
THEN NodeItself
ELSE TiogaNodeOps.Size[TiogaNodeOps.NarrowToTextNode[dest]]] }
ELSE
-- move source contents to end of pred contents
IF dest=
NIL
THEN {
-- pred doesn't have contents yet
loc ← [source, IF TiogaNodeOps.IsText[source] THEN 0 ELSE NodeItself];
EditGroup.MoveGroup[
destRoot: root, sourceRoot: root, dest: pred, contents: TRUE,
sourceStart: source, sourceEnd: TiogaTreeOps.LastSibling[source], event: event] }
ELSE {
-- move to end of contents of pred
destText, sourceText: RefTextNode;
dest ← TiogaTreeOps.LastSibling[dest];
EditGroup.MoveGroup[
destRoot: root, sourceRoot: root, dest: dest, contents: FALSE,
sourceStart: source, sourceEnd: TiogaTreeOps.LastSibling[source], event: event];
IF (destText ← TiogaNodeOps.NarrowToTextNode[dest]) #
NIL
AND
(sourceText ← TiogaNodeOps.NarrowToTextNode[source]) # NIL THEN {
loc.node ← dest;
loc.where ← TextEdit.CopyText[root, root, destText, MaxLen, sourceText, 0, MaxLen, event].resultStart;
[] ← EditGroup.DeleteGroup[root, sourceText, sourceText, FALSE, event] }
ELSE loc ← [source, NodeItself] };
[] ← EditGroup.DeleteGroup[root, statement, statement, FALSE, event] };
BreakTextNode:
PUBLIC
PROC [root: RefBranchNode, loc: TreeLoc, event: Event ←
NIL]
RETURNS [new: Ref] = {
old: Ref ← loc.node;
oldTxt, newTxt: RefTextNode;
IF (oldTxt ← TiogaNodeOps.NarrowToTextNode[old]) = NIL THEN RETURN [NIL];
new ← Insert[root, old, after, event];
IF loc.where = NodeItself THEN RETURN;
newTxt ← TiogaNodeOps.NarrowToTextNode[new];
[] ← TextEdit.MoveText[destRoot: root, sourceRoot: root, dest: newTxt, destLoc: 0,
source: oldTxt, start: loc.where, event: event] };
BreakParent:
PUBLIC
PROC [root: RefBranchNode, node: Ref, before:
BOOL ←
TRUE, event: Event ←
NIL]
RETURNS [parent: Ref] = {
Inserts copy of parent as next sibling of parent.
If before is true, moves children starting with node to be contents of new.
Otherwise, moves children starting with next sibling of node.
Returns the parent of node after the break.
move, new: Ref;
IF node=NIL THEN RETURN [NIL];
IF (parent ← TiogaTreeOps.Parent[node])=NIL THEN ERROR CannotDoEdit;
IF TiogaNodeOps.IsBranch[node] AND TiogaNodeOps.IsBranch[parent] THEN ERROR CannotDoEdit;
new ← Insert[root, parent, after, event];
IF before THEN { move ← node; parent ← new }
ELSE move ← TiogaTreeOps.Next[node];
IF move#
NIL
THEN EditGroup.MoveGroup[
destRoot: root, sourceRoot: root, dest: new, contents: TRUE,
sourceStart: move, sourceEnd: TiogaTreeOps.LastSibling[move], event: event] };
BreakStatement:
PUBLIC
PROC [root: RefBranchNode, node: Ref, before:
BOOL ←
TRUE, event: Event ←
NIL]
RETURNS [RefBranchNode] = {
loc points somewhere in the contents of a statement. This works its way up breaking nodes until contents from node on have been moved to a new statement. If before is true, node moves to the new statement; otherwise, it stays in the old one.
Returns the statement which contains node after doing the break.
IF node=NIL THEN RETURN [NIL];
UNTIL TiogaNodeOps.IsBranch[node] DO node ← BreakParent[root, node, before, event]; ENDLOOP;
RETURN [TiogaNodeOps.NarrowToBranchNode[node]] };