5

I would like to accomplish the following: upon evaluation of an input cell, it should self-destruct (i.e. delete itself). I tried to hack something together with SelectionMove and NotebookDelete, but didn't quite get what I wanted.

Here are potential use cases:

  • the command might be a shorthand for a series of other commands that will be generated dynamically and inserted into the notebook

  • the command might only be used for side effects (e.g. to set a notebook option or to open a new notebook); leaving the command in the notebook after evaluation serves no purpose and creates clutter

Edit: As per Mr. Wizard, the answer is SelectionMove[EvaluationNotebook[], Previous, Cell]; NotebookDelete[];. I don't know why it wasn't working for me before. Here is some code that uses this idiom.

writeAndEval[nb_, boxExpr_] := (NotebookWrite[nb, 
    CellGroupData[{Cell[BoxData[boxExpr], "Input"]}]];
   SelectionMove[nb, Previous, Cell];
   SelectionMove[nb, Next, Cell];
   SelectionEvaluate[nb]);

addTwoAndTwo[] := Module[{boxExpr},
  boxExpr = RowBox[{"2", "+", "2"}];
  SelectionMove[EvaluationNotebook[], Previous, Cell];
  NotebookDelete[];
  writeAndEval[EvaluationNotebook[], boxExpr];
  ]

Now, running addTwoAndTwo[] deletes the original input and makes it look as if you've evaluated "2+2". Of course, you can do all sorts of things instead and not necessarily print to the notebook.

Edit 2: Sasha's abstraction is quite elegant. If you are curious about "real-world" usage of this, check out the code I posted in the "what's in your toolbag" question: What is in your Mathematica tool bag?

Community
  • 1
  • 1
Leo Alekseyev
  • 12,893
  • 5
  • 44
  • 44
  • Leo, the application I envisioned was that of transparent use, where a user would evaluate a cell on their on machine, and have it replaced with the output. For example, where you want a graphic (but don't want the bytes for a graphic), you put the code for the graphic instead, and change the `CellEvaluationFunction` as shown. Then, the user would evaluate all cells, producing the final document that you intended him to read, without excess Input cells cluttering it up. – Mr.Wizard May 07 '11 at 02:13

2 Answers2

9

To affect all Input cells, evaluate this is the notebook:

SetOptions[EvaluationNotebook[], CellEvaluationFunction -> 
  ( (
    SelectionMove[EvaluationNotebook[], All, EvaluationCell]; NotebookDelete[];
    ToExpression@#
  )&)
]

If you only want to affect one cell, then select the cell and use the Options Inspector to set CellEvaluationFunction as above.

Mr.Wizard
  • 24,179
  • 5
  • 44
  • 125
8

Or, building on Mr. Wizard's solution, you can create a function SelfDestruct, which will delete the input cell, if you intend to only do this occasionally:

SetAttributes[SelfDestruct, HoldAllComplete];
SelfDestruct[e_] := (If[$FrontEnd =!= $Failed,
   SelectionMove[EvaluationNotebook[], All, EvaluationCell]; 
   NotebookDelete[]]; e)

Then evaluating 2+3//SelfDestruct outputs 5 and deletes the input cell. This usage scenario seems more appealing to me.

Community
  • 1
  • 1
Sasha
  • 5,935
  • 1
  • 25
  • 33
  • Ah, this is precisely what I wanted. This allowed me to clean up lots of nasty code... gotta give you the check mark :) – Leo Alekseyev May 06 '11 at 22:07