<> <> DIRECTORY EditSpan, EditSpanSupport, EditGroup, EditNotify, NodeProps, Rope, UndoEvent, TextEdit, TreeSlice, TiogaLooks, TiogaNode, TiogaNodeOps, TiogaTreeOps; EditNodeImpl: CEDAR PROGRAM IMPORTS NodeProps, TextEdit, EditGroup, TiogaNodeOps, TiogaTreeOps, UndoEvent, EditSpan, EditNotify EXPORTS EditSpan SHARES TiogaNode = BEGIN OPEN EditSpan, EditSpanSupport, TreeSlice, EditNotify; Slice: TYPE = TreeSlice.Slice; nullSpan: TreeSpan = TiogaTreeOps.nullSpan; nullBranchSpan: BranchSpan = TiogaTreeOps.nullBranchSpan; <<***** New nodes>> Insert: PUBLIC PROC [root: RefBranchNode, old: Ref, where: Place _ after, event: Event _ NIL] RETURNS [new: Ref] = TRUSTED { <> 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, 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] = { newitm, olditm: TiogaNode.RefItemNode; newbs, oldbs: TiogaNode.RefBasicNode; 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.props # NIL 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] = { <> 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] = { <> <> <> <> 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] = { <> <> IF node=NIL THEN RETURN [NIL]; UNTIL TiogaNodeOps.IsBranch[node] DO node _ BreakParent[root, node, before, event]; ENDLOOP; RETURN [TiogaNodeOps.NarrowToBranchNode[node]] }; END....