CDCellCommands.mesa   (part of ChipNDale)
Copyright © 1983, 1986 by Xerox Corporation.  All rights reserved.
by Christian Jacobi,  July 11, 1983 3:42 pm
last edited by Christian Jacobi,  March 27, 1986 8:06:04 pm PST
Last Edited by: Jacobi June 6, 1986 12:17:54 pm PDT
 
DIRECTORY
Ascii,
CD,
CDBasics,
CDCells,
CDCommandOps,
CDDirectory,
CDDirectoryOps,
CDInstances,
CDMarks,
CDMenus,
CDOps,
CDSequencer,
IO,
Real,
Rope,
RopeList,
TerminalIO;
 
CDCellCommands: 
CEDAR 
PROGRAM
IMPORTS Ascii, CD, CDOps, CDCells, CDCommandOps, CDDirectory, CDDirectoryOps, CDInstances, CDMarks, CDMenus, CDSequencer, IO, Real, Rope, RopeList, TerminalIO = 
 
BEGIN
orientForTest: CD.Orientation ← 0;
obCSystemForTest: CDCells.CoordSystem ← interrestCoords;
DrawCellComm: 
PROC [comm: CDSequencer.Command] =
BEGIN
name: Rope.ROPE; cellOb: CD.Object; 
TerminalIO.WriteRope["Include cell; "];
DO
name ← TerminalIO.RequestRope["type name\n"];
cellOb ← CDDirectory.Fetch[comm.design, name].object;
IF cellOb#NIL 
THEN {
inst: 
CD.Instance = CDCells.IncludeOb[design: comm.design, 
ob: cellOb, 
position: comm.pos, 
obCSystem: obCSystemForTest, 
orientation: orientForTest
].newInst;
 
CDOps.RedrawInstance[comm.design, inst, FALSE];
TerminalIO.WriteRopes[name, " inserted\n"];
RETURN
};
 
TerminalIO.WriteRopes[name, " not found\n"];
IF NOT TerminalIO.Confirm[choice: "another try ?" ] THEN RETURN;
ENDLOOP
 
END;
 
RemoveObComm: 
PROC [comm: CDSequencer.Command] =
BEGIN
name, msg: Rope.ROPE←NIL; done: BOOL; ob: CD.Object;
TerminalIO.WriteRope["remove object from directory; "];
name ← TerminalIO.RequestRope["type name\n"];
ob ← CDDirectory.Fetch[comm.design, name].object;
IF ob=
NIL 
THEN {
TerminalIO.WriteRopes[name, " not found\n"]; 
RETURN
};
 
[done, msg] ← CDDirectoryOps.RemoveIfUnused[comm.design, ob];
TerminalIO.WriteRope[msg];
IF ~done THEN TerminalIO.WriteRope[" not "]; 
TerminalIO.WriteRope["done\n"];
END;
 
DisplayCellNames: 
PROC [comm: CDSequencer.Command] =
BEGIN
EachEntry: CDDirectory.EachEntryAction 
--[name: Rope.ROPE, ob: CD.Object] RETURNS [quit: BOOL] -- =
BEGIN quit ← FALSE;
count ← count+1;
IF comm.key=$RestricedDisplayCellNames 
THEN {
IF Rope.Length[name]<=0 THEN RETURN
ELSE {
ch: CHAR = Rope.Fetch[name];
IF ~Ascii.Letter[ch] AND ~Ascii.Digit[ch] THEN RETURN
}
 
};
 
displayed ← displayed+1;
WITH ob.specificRef 
SELECT 
FROM
cp: CD.CellPtr => list ← CONS[cp.name, list]; 
ENDCASE => list ← CONS[Rope.Cat[name, " [", CDOps.ObjectInfo[ob], "]"], list];
 
END;
 
list: LIST OF Rope.ROPE ← NIL; count: INT ← 0; displayed: INT ← 0;
TerminalIO.WriteRope["Display object names\n"];
[] ← CDDirectory.Enumerate[comm.design, EachEntry];
list ← RopeList.Sort[list, RopeList.Compare];
FOR l: 
LIST 
OF Rope.
ROPE ← list, l.rest 
WHILE l#
NIL 
DO
TerminalIO.WriteRopes["  ", l.first, "\n"];
ENDLOOP;
 
TerminalIO.WriteF[" %g objects counted  ", IO.int[count]];
IF count#displayed THEN TerminalIO.WriteF[" %g displayed", IO.int[displayed]];
TerminalIO.WriteLn[]
END;
 
CreateCellAndName: 
PROC [comm: CDSequencer.Command] =
BEGIN
TerminalIO.WriteRope["Create cell  "]; 
IF ~CDCells.CreateCellSelected[comm.design].done 
THEN 
TerminalIO.WriteRope[" not done\n"];
 
END;
 
CreateCellDefaultName: 
PROC [comm: CDSequencer.Command] =
BEGIN
TerminalIO.WriteRope["Create cell without name\n"]; 
IF ~CDCells.CreateCellSelected[comm.design, "-no name-"].done 
THEN 
TerminalIO.WriteRope["  not done\n"];
 
END;
 
PushIntoCellS: 
PROC [comm: CDSequencer.Command] =
BEGIN
VExpand: 
PROC [me: 
CD.Object, design: 
CD.Design] 
RETURNS [ob: 
CD.Object] = {
ob ← CDDirectory.ExpandComplete[me, design, design];
IF ob=NIL THEN TerminalIO.WriteRope["expand failed\n"]
ELSE TerminalIO.WriteRope["object expanded\n"];
};
 
inst: CD.Instance ← CDCommandOps.TheInstance[comm: comm, text: "Push into cell "]; 
IF inst#
NIL 
THEN {
WHILE ~CDCells.IsCell[inst.ob] 
DO
TerminalIO.WriteRopes[CDOps.ObjectInfo[inst.ob], " is not cell;"]; 
IF ~ inst.ob.class.inDirectory THEN CDSequencer.Quit[" not done"];
SELECT TerminalIO.RequestSelection[label: "convert to cell?", 
choice: LIST["all instances", "this instance"],
text: " convert to cell?\n",
default: 1] FROM
1 => {
--all instances
ob: CD.Object ← VExpand[inst.ob, comm.design]; IF ob=NIL THEN RETURN;
CDSequencer.MarkChanged[comm.design];
CDDirectory.ReplaceObject[design: comm.design, old: inst.ob, new: ob]
};
 
2 => {
--this instance
ob: CD.Object ← VExpand[inst.ob, comm.design]; IF ob=NIL THEN RETURN;
CDSequencer.MarkChanged[comm.design];
inst.ob ← ob;
};
 
ENDCASE => CDSequencer.Quit["no expansion; not done"];
 
ENDLOOP;
 
IF CDCells.PushInCellInstance[comm.design, inst] THEN TerminalIO.WriteRope["done\n"] 
ELSE TerminalIO.WriteRope["not done\n"];
};
 
END;
 
ExpandComm: 
PROC [comm: CDSequencer.Command] =
BEGIN
others: CD.InstanceList ← NIL; cnt: INT ← 0; someOb: CD.Object ← NIL;
ExpandInclude: 
PROC [inst: 
CD.Instance, ob: 
CD.Object] = {
--replace the instance by an instance of the expanded object ob 
--and include the instance into "others" 
cp: CD.CellPtr ← NARROW[ob.specificRef];
include: CD.InstanceList ← CDInstances.ComposedList[cp.contents, inst.location, inst.ob.size, inst.orientation];
FOR il: 
CD.InstanceList ← include, il.rest 
WHILE il#
NIL 
DO
il.first.selected ← TRUE;
others ← CONS[il.first, others];
ENDLOOP;
 
someOb ← inst.ob;
cnt ← cnt+1;
CDOps.DelayedRedraw[comm.design, CDInstances.InstRectO[inst]];
};
 
Dont: 
PROC [inst: 
CD.Instance, msg: Rope.
ROPE] = {
others ← CONS[inst, others];
inst.selected ← FALSE;
CDOps.DelayedRedraw[comm.design, CDInstances.InstRectO[inst]];
TerminalIO.WriteRopes[CDOps.ObjectInfo[inst.ob], " "];
TerminalIO.WriteRopes[msg, "; deselected\n"];
};
 
selected: CD.InstanceList ← NIL;
TerminalIO.WriteRope["expand\n"];
[selected, others] ← CDInstances.SplitSelected[CDOps.InstList[comm.design]];
FOR il: 
CD.InstanceList ← selected, il.rest 
WHILE il#
NIL 
DO
IF ~il.first.ob.class.inDirectory THEN Dont[il.first, "atomic, can not be expanded"]
ELSE {
ob: CD.Object ← il.first.ob;
WHILE ob#
NIL 
AND ~CDCells.IsCell[ob] 
DO
ob ← CDDirectory.ExpandComplete[ob, comm.design, comm.design];
IF ob=il.first.ob THEN ob ← NIL; --to exit loop
IF ob#
NIL 
AND CDCells.IsCell[ob] 
THEN {
TerminalIO.WriteRopes[CDOps.ObjectInfo[il.first.ob], " converted to cell\n"];
[] ← CDDirectoryOps.RemoveIfUnused[comm.design, ob];
}
 
ENDLOOP;
 
IF ob#NIL  AND CDCells.IsCell[ob] THEN ExpandInclude[il.first, ob] 
ELSE Dont[il.first, "can not be converted to cell to expand"]
}
 
ENDLOOP;
 
IF cnt>0 THEN CDOps.SetInstList[comm.design, others];
IF cnt=1 AND someOb#NIL THEN TerminalIO.WriteRopes[CDOps.ObjectInfo[someOb], " expanded"]
ELSE TerminalIO.WriteF1["%g objects expanded\n", IO.int[cnt]];
END;
 
PopFromCellMenu: 
PROC [comm: CDSequencer.Command] =
BEGIN
TerminalIO.WriteRope["pop\n"];
IF ~CDCells.PopFromCell[comm.design, interactive] 
THEN 
TerminalIO.WriteRope["  not done\n"];
 
END;
 
PopFromCellFlush: 
PROC [comm: CDSequencer.Command] =
BEGIN
TerminalIO.WriteRope["pop and flush\n"];
IF ~CDCells.PopFromCell[comm.design, flush] 
THEN 
TerminalIO.WriteRope["  not done\n"];
 
END;
 
PopFromCellReplace: 
PROC [comm: CDSequencer.Command] =
BEGIN
TerminalIO.WriteRope["pop and replace\n"];
IF ~CDCells.PopFromCell[comm.design, replace] 
THEN 
TerminalIO.WriteRope["  not done\n"];
 
END;
 
PopFromCellNew: 
PROC [comm: CDSequencer.Command] =
BEGIN
TerminalIO.WriteRope["pop and new\n"];
IF ~CDCells.PopFromCell[comm.design, newcell] 
THEN 
TerminalIO.WriteRope["  not done\n"];
 
END;
 
CleanUpDirectoryComm: 
PROC [comm: CDSequencer.Command] =
BEGIN
autoOnly: BOOL ← comm.key#$DeleteUnUsedObjects;
TerminalIO.WriteRope["Prune directory\n"]; 
CDDirectoryOps.PruneDirectory[design: comm.design, autoOnly: autoOnly, askFirst: TRUE];
END;
 
DrawWithBorder: 
PROC [comm: CDSequencer.Command] =
BEGIN
TerminalIO.WriteRope["Draw cell(s) with border\n"]; 
FOR l: 
CD.InstanceList ← CDOps.InstList[comm.design], l.rest 
WHILE l#
NIL 
DO
IF l.first.selected 
THEN {
CDCells.SetBorder[l.first.ob, TRUE];
CDOps.RedrawInstance[comm.design, l.first, FALSE];
}
 
ENDLOOP;
 
END;
 
DrawWithoutBorder: 
PROC [comm: CDSequencer.Command] =
BEGIN
TerminalIO.WriteRope["Draw cell(s) without border\n"]; 
FOR l: 
CD.InstanceList ← CDOps.InstList[comm.design], l.rest 
WHILE l#
NIL 
DO
IF l.first.selected 
THEN {
CDCells.SetBorder[l.first.ob, FALSE];
CDOps.RedrawInstance[comm.design, l.first];
}
 
ENDLOOP;
 
END;
 
SetSimplification: 
PROC [comm: CDSequencer.Command] =
BEGIN
inst: CD.Instance; multiple: BOOL;
TerminalIO.WriteRope["Set cell simplification #\n"]; 
[inst, multiple] ← CDOps.SelectedInstance[comm.design];
IF multiple THEN TerminalIO.WriteRope["   multiple selection; not done\n"] 
ELSE IF inst=NIL THEN TerminalIO.WriteRope["   no selection; not done\n"] 
ELSE {
TerminalIO.WriteRope[inst.ob.class.describe[inst.ob]];
IF 
ISTYPE[inst.ob.specificRef, 
CD.CellPtr] 
THEN {
cptr: CD.CellPtr ~ NARROW[inst.ob.specificRef];
h: CD.Number ← MAX[1, inst.ob.size.y];
TerminalIO.WriteF["   [currently: simplification if height < %g pixels", [integer[Real.Round[cptr.simplifyOn*h]]]];
cptr.simplifyOn ← MIN[MAX[TerminalIO.RequestInt[" pixels] type > "], 0], LAST[NAT]]/h;
CDOps.RedrawInstance[comm.design, inst];
TerminalIO.WriteRope["   done\n"];
}
 
ELSE TerminalIO.WriteRope[" not a cell; not done\n"]; 
}
 
END;
 
RenameComm: 
PROC [comm: CDSequencer.Command] =
BEGIN
RenameOnInst: 
PROC[design: 
CD.Design, inst: 
CD.Instance] =
BEGIN
done: BOOL ← FALSE;
IF inst=NIL THEN TerminalIO.WriteRope["   no object;\n"] 
ELSE {
TerminalIO.WriteRope[inst.ob.class.describe[inst.ob]];
IF ~inst.ob.class.inDirectory THEN TerminalIO.WriteRope[" object can not have name;\n"]
ELSE {
newName: Rope.ROPE ← TerminalIO.RequestRope[" new name > "];
IF Rope.IsEmpty[newName] THEN newName ← "-";
done ← CDDirectory.Rename[design, inst.ob, newName];
};
 
};
 
IF done THEN TerminalIO.WriteRope["done\n"] ELSE TerminalIO.WriteRope[" not done\n"]
END;
 
inst: CD.Instance = CDCommandOps.TheInstance[comm];
IF inst#NIL THEN RenameOnInst[comm.design, inst]
END;
 
ReplaceComm: 
PROC [comm: CDSequencer.Command] =
BEGIN
newName, oldName: Rope.ROPE; old, new: CD.Object; found: BOOL;
offset: CD.Position ← [0, 0];
lambda: CD.Number ← comm.design.technology.lambda;
TerminalIO.WriteRope["replace an entry allover in the design\n"];
oldName ← TerminalIO.RequestRope["  replace (name) > "];
[found, old] ← CDDirectory.Fetch[comm.design, oldName];
IF ~found THEN {TerminalIO.WriteRopes["  ", oldName, " not found\n"]; RETURN};
newName ← TerminalIO.RequestRope["  by (name) > "];
[found, new] ← CDDirectory.Fetch[comm.design, newName];
IF ~found THEN {TerminalIO.WriteRopes["  ", newName, " not found\n"]; RETURN};
TerminalIO.WriteRope["  do you want to specify an offset?\n"];
SELECT TerminalIO.RequestSelection[label: "offset", 
choice: LIST["lambda", "ints", "none"]] FROM
1 => {
offset.x ← TerminalIO.RequestInt["  x in lambda >"]*lambda;
offset.y ← TerminalIO.RequestInt["  y in lambda >"]*lambda;
};
 
2 => {
offset.x ← TerminalIO.RequestInt["  x in ints >"];
offset.y ← TerminalIO.RequestInt["  y in ints >"];
};
 
ENDCASE => offset ← [0, 0];
 
CDDirectory.ReplaceObject[design: comm.design, old: old, new: new, off: offset];
SELECT TerminalIO.RequestSelection[label: "cleanup ?", 
choice: LIST["remove replaced ob from dir", "remove replaced ob from dir and rename other", "no"]] FROM
1 => [] ← CDDirectoryOps.RemoveIfUnused[comm.design, old];
2 => CDDirectoryOps.RenameNRemove[comm.design, new, oldName];
ENDCASE => NULL;
 
TerminalIO.WriteRope["  end replace\n"];
END;
 
--**PushByName ************************
foundAndStop: SIGNAL = CODE;
HandleRec: 
TYPE = 
RECORD [
stopFlag: REF BOOL ← NIL,
iDidIt: BOOL ← FALSE,
gMark: CDMarks.MarkRange, 
cell: CD.Object ← NIL,
drawStack: CD.InstanceList ← NIL
];
 
MyDrawChild: 
CD.DrawProc =
BEGIN
IF inst.ob.class.inDirectory 
THEN {
h: REF HandleRec ← NARROW[pr.devicePrivate];
IF inst.ob=h.cell 
THEN {
h.drawStack ← CONS[inst, h.drawStack];
h.iDidIt ← TRUE;
SIGNAL foundAndStop
};
 
WITH inst.ob.specificRef 
SELECT 
FROM
cp: 
CD.CellPtr => {
IF inst.ob.marked#h.gMark 
THEN {
inst.ob.marked ← h.gMark;
h.drawStack ← CONS[inst, h.drawStack];
inst.ob.class.drawMe[inst: inst, pos: inst.location, orient: inst.orientation, pr: pr]; 
h.drawStack ← h.drawStack.rest;
};
 
};
 
ENDCASE => NULL;
 
}
 
END;
 
PushNamedComm: 
PROC [comm: CDSequencer.Command] = 
BEGIN
name: Rope.ROPE;
design: CD.Design ← comm.design;
h: 
REF HandleRec = 
NEW[HandleRec←[
stopFlag: NEW[BOOL],
gMark: 0
]];
 
myDrawRef: 
CD.DrawRef ← 
CD.CreateDrawRef[[
design: design,
interestClip: CDBasics.universe,
drawChild: MyDrawChild,
devicePrivate: h
]];
 
pushStack: CD.InstanceList ← NIL; --will be draw stack in reversed order
MyDrawWithMark: 
PROC [mark: CDMarks.MarkRange] =
BEGIN
h.gMark ← mark;
--draw only from pushed in cell point in hierarchy
design.actual.first.dummyCell.ob.class.drawMe[inst: design.actual.first.dummyCell, pos: [0, 0], orient: CD.original, pr: myDrawRef ! foundAndStop => CONTINUE];
END;
 
ReverseInstanceList: 
PROC [list: 
CD.InstanceList] 
RETURNS[val: 
CD.InstanceList] = {
val ← NIL;
UNTIL list = 
NIL 
DO
val ← CONS[list.first, val];
list ← list.rest;
ENDLOOP;
 
RETURN[val];
}; 
 
TerminalIO.WriteRope["Push into cell by name\n"]; 
--get name, find if cell really exists
WITH comm.data 
SELECT 
FROM
r: Rope.
ROPE => {
TerminalIO.WriteRopes["Push into cell", r, "\n"]; 
name ← r;
};
 
ENDCASE => {
TerminalIO.WriteRope["Push into cell by name\n"]; 
name ← TerminalIO.RequestRope["cell name >"];
};
 
 
h.cell ← CDDirectory.Fetch[design, name].object;
IF h.cell=
NIL 
THEN {
TerminalIO.WriteRopes["design does not have object ", name, "\n"];
RETURN
};
 
--if we are already pushed in, it would not harm the program, 
--but it is checked because it would confuse the designer
FOR pl: 
LIST 
OF 
CD.PushRec ← design.actual, pl.rest 
WHILE pl#
NIL 
DO
IF pl.first.mightReplace#
NIL 
AND pl.first.mightReplace.ob=h.cell 
THEN {
TerminalIO.WriteRope["design is already pushed in\n"];
RETURN
}
 
ENDLOOP;
 
 
--check if a path to the cell exists, and build the path 
CDMarks.DoWithMark[comm.design, MyDrawWithMark 
! CDMarks.MarkOccupied => GOTO markError
];
 
IF ~h.iDidIt 
THEN {
TerminalIO.WriteRope["not found in accessible position\n"];
RETURN
};
 
 
--there is a path
--make pushStack in push order; (reverse order as drawStack)
pushStack ← ReverseInstanceList[h.drawStack];
Don't trust that silly List module;
TRUSTED { pushStack ← LOOPHOLE[List.Reverse[LOOPHOLE[h.drawStack]]]};
 
 
--do the pushes
WHILE pushStack#
NIL 
DO
--select exclusively the application we want to push in
--pushing in makes a copy of the application list! check for the right object
inst: CD.Instance ← NIL;
CDSequencer.CheckAborted[design];
FOR il: 
CD.InstanceList ← CDOps.InstList[design], il.rest 
WHILE il#
NIL 
DO
IF il.first.ob=pushStack.first.ob 
THEN {
inst ← il.first;
EXIT
};
 
REPEAT 
FINISHED => {
TerminalIO.WriteRope["finding cell failed\n"];
RETURN
}
 
ENDLOOP;
 
 
IF ~CDCells.PushInCellInstance[design, inst] 
THEN {
TerminalIO.WriteRope["push failed\n"];
CDSequencer.ExecuteCommand[$ResetScaleTop, design, dontQueue, comm];
RETURN
};
 
pushStack ← pushStack.rest
ENDLOOP;
 
 
--we are successully pushed in
--position the viewer
CDSequencer.ExecuteCommand[$ResetScaleTop, design, dontQueue, comm];
TerminalIO.WriteRope["done\n"];
 
--help the garbage collector
h.drawStack ← NIL; myDrawRef.viewerPrivate ← NIL; myDrawRef ← NIL; pushStack ← NIL;
 
EXITS
markError => TerminalIO.WriteRope["**inconsistent use of mark\n"];
 
END;
 
CDSequencer.ImplementCommand[$PopMenu, PopFromCellMenu,, doQueue];
CDSequencer.ImplementCommand[$PopNew, PopFromCellNew,, doQueue];
CDSequencer.ImplementCommand[$PopFlush, PopFromCellFlush,, doQueue];
CDSequencer.ImplementCommand[$PopReplace, PopFromCellReplace,, doQueue];
CDSequencer.ImplementCommand[$PushS, PushIntoCellS,, doQueue];
CDSequencer.ImplementCommand[$ExpandS, ExpandComm];
CDSequencer.ImplementCommand[$CreateCellSAndName, CreateCellAndName];
CDSequencer.ImplementCommand[$CreateCellSUnNamed, CreateCellDefaultName];
CDSequencer.ImplementCommand[$DisplayCellNames, DisplayCellNames,, doQueue];
CDSequencer.ImplementCommand[$RestricedDisplayCellNames, DisplayCellNames,, doQueue];
CDSequencer.ImplementCommand[$DrawCell, DrawCellComm];
CDSequencer.ImplementCommand[$RemoveCell, RemoveObComm,, doQueue];
CDSequencer.ImplementCommand[$DeleteUnUsedObjects, CleanUpDirectoryComm,, doQueue];
CDSequencer.ImplementCommand[$DeleteUnUsedAutoObs, CleanUpDirectoryComm,, doQueue];
CDSequencer.ImplementCommand[$CellSimplification, SetSimplification,, doQueue];
CDSequencer.ImplementCommand[$RenameS, RenameComm,, doQueue];
CDSequencer.ImplementCommand[$Replace, ReplaceComm];
CDSequencer.ImplementCommand[$DrawWithoutBorder, DrawWithoutBorder];
CDSequencer.ImplementCommand[$DrawWithBorder, DrawWithBorder];
CDSequencer.ImplementCommand[$PushNamed, PushNamedComm];
CDMenus.CreateEntry[$CellMenu, "create", $CreateCellSAndName];
CDMenus.CreateEntry[$CellMenu, "expand", $ExpandS];
CDMenus.CreateEntry[$CellMenu, "push in", $PushS];
CDMenus.CreateEntry[$CellMenu, "pop out", $PopMenu];
CDMenus.CreateEntry[$CellMenu, "transform to", $TransformToCellS];
CDMenus.CreateEntry[$CellMenu, "border on sel.", $DrawWithBorder];
CDMenus.CreateEntry[$CellMenu, "border off sel.", $DrawWithoutBorder];
CDMenus.CreateEntry[$CellMenu, "push named", $PushNamed];
CDMenus.CreateEntry[$CellMenu, "  DIRECTORY", $DirectoryMenu];
CDMenus.CreateEntry[$DirectoryMenu, "list subset dir", $RestricedDisplayCellNames];
CDMenus.CreateEntry[$DirectoryMenu, "list complete dir", $DisplayCellNames];
CDMenus.CreateEntry[$DirectoryMenu, "prune subset dir", $DeleteUnUsedAutoObs];
CDMenus.CreateEntry[$DirectoryMenu, "prune complete dir", $DeleteUnUsedObjects];
CDMenus.CreateEntry[$DirectoryMenu, "remove ob from dir", $RemoveCell];
CDMenus.CreateEntry[$DirectoryMenu, "replace ob", $Replace];
CDMenus.CreateEntry[$DirectoryMenu, "list imports", $DisplayImports];
CDMenus.CreateEntry[$DirectoryMenu, "list importee's ob", $DisplayImportedEntries];
CDMenus.CreateEntry[$DirectoryMenu, "  CELLS", $CellMenu];
END.