1
$\begingroup$

We know that there is an efficient way to delete all output from the EvaluationNotebook[]:

FrontEndTokenExecute["DeleteGeneratedCells"]

How is it possible to do the same for pre-existing output only under the EvaluationCell[] in the situation when CellAutoOverwrite -> False and GeneratedCell -> False is set for all output by default:

SetOptions[EvaluationNotebook[],
 StyleDefinitions -> 
  Notebook[{Cell[StyleData[StyleDefinitions -> "Default.nb"]], 
    Cell[StyleData[All], CellAutoOverwrite -> False, GeneratedCell -> False]}]]

Specifically, I would like to do this from CellProlog by setting something like

SetOptions[EvaluationNotebook[],
 CellProlog :> FrontEndTokenExecute["DeleteGeneratedCells"]]

but it should delete only output associated with EvaluationCell[], as it happens with the default settings. What can I use instead of FrontEndTokenExecute["DeleteGeneratedCells"] for this purpose?


I have tried temporarily reverting to the default stylesheet, then evoking PrintTemporary[] (what should cause auto-deletion of pre-existing output). But from CellProlog it doesn't work unfortunately:

SetOptions[EvaluationNotebook[], CellProlog :> (
  SetOptions[EvaluationNotebook[], StyleDefinitions -> "Default.nb"]; 
  PrintTemporary[]; 
  SetOptions[EvaluationNotebook[],
      StyleDefinitions -> 
       Notebook[{Cell[StyleData[StyleDefinitions -> "Default.nb"]], 
         Cell[StyleData[All], GeneratedCell -> False, CellAutoOverwrite -> False]}]])]
$\endgroup$
  • $\begingroup$ maybe something like: {CellProlog :> FrontEndExecute[ FrontEndToken[EvaluationNotebook[], "SelectNextLine"]]; If[Experimental`CellStyleNames[NotebookSelection[]] == "Output", CurrentValue[NotebookSelection[], CellAutoOverwrite] = True]; CellEpilog :> SelectionMove[EvaluationNotebook[], After, Cell]}? $\endgroup$ – kglr Oct 19 at 13:14
  • 1
    $\begingroup$ @kglr I wasn't able to make your approach working, unfortunately. But thanks for Experimental`CellStyleNames: I was able to develop something what can be thought as a start - see my answer. $\endgroup$ – Alexey Popkov Oct 19 at 14:44
1
$\begingroup$

Currently I have come to a much more complicated solution than I wished, which completely depends on the automatic grouping behavior (which I temporarily switch on):

SetOptions[EvaluationNotebook[], {CellProlog :> 
   AbortProtect[
    Module[{nb = EvaluationNotebook[], evalCell = EvaluationCell[], cells, pos, grouping, 
      groupingRules},
     If[CurrentValue[NextCell[], CellGroupingRules] == "OutputGrouping", 
       FrontEndExecute@FrontEnd`NotebookSuspendScreenUpdates[nb];
       grouping = CurrentValue[nb, CellGrouping];
       groupingRules = CurrentValue[evalCell, CellGroupingRules];
       CurrentValue[nb, CellGrouping] = Automatic;
       CurrentValue[evalCell, CellGroupingRules] = "InputGrouping";
       SelectionMove[evalCell, All, CellGroup, AutoScroll -> False];
       If[Length[cells = SelectedCells[]] > 1,
        pos = Position[cells, evalCell];
        If[pos =!= {} && pos[[1, 1]] < Length[cells], 
         NotebookDelete[cells[[pos[[1, 1]] + 1 ;;]]]]
        ];
       CurrentValue[evalCell, CellGroupingRules] = groupingRules;
       CurrentValue[nb, CellGrouping] = grouping;
       FrontEndExecute@FrontEnd`NotebookResumeScreenUpdates[nb];];]]}]

Note that I set CellGrouping to the default Automatic for the EvaluationNotebook[], and CellGroupingRules to the default "InputGrouping" for EvaluationCell[] in order to have it auto-grouped with next output cells (for the cases when automatic grouping is switched off), then I revert the original values of these options back.

Of course such implementation means that will be deleted only cells, which by default are auto-grouped with input cell: manually grouped cells won't be deleted even if they have style "Output" – that is because manual grouping changes the groping behavior by adding the option CellGroupingRules->{"GroupTogetherGrouping", 10000.}. It seems not reasonable to delete manually grouped cells because among them may present non-output cells, for example "Input" cells and so on. This differs from the standard behavior where all pre-existing output will be deleted on the base of the presence of both CellAutoOverwrite -> True and GeneratedCell -> True options.

Still looking for a better way to do it.


P.S. The whole approach has an issue: by the time the contents of the cell starts executing, the output will already be deleted, and therefore, for example, NextCell[] will return a different value than by default.

$\endgroup$
0
$\begingroup$

Here is another solution which should reproduce the default behavior exactly. It works by selecting under EvaluationCell[] a continuous sequence of cells each having both CellAutoOverwrite -> True and GeneratedCell -> True options (the system considers such cells as pre-existing output which should be replaced by new output). Then it deletes them.

This solution also utilizes an interesting observation that even if we manually set options CellAutoOverwrite -> True and GeneratedCell -> True for a cell with style "Input", the latter won't be overwritten by any output generated by previous input cell. Moreover, upon usual editing of the contents of this cell, these options will be removed. In this implementation this observation is used for limiting the set of cells which will be checked for these options: they can be located only between EvaluationCell[] and NextCell[CellStyle -> "Input"] (if the latter exists).

The StyleDefinitions given in the question are set temporarily for the time of evaluation of the contents of the cell, and then are reset to the defaults by CellEpilog. It is necessary because if they are changed in the CellProlog, the change has no effect during evaluation of the code of CellProlog, unfortunately.

SetOptions[EvaluationNotebook[], {CellProlog :> AbortProtect[
    Module[{nb = EvaluationNotebook[], evalCell = EvaluationCell[], cells, pos, 
      cellsBelow, nextInput, len}, 
     If[And[CurrentValue[#, GeneratedCell], CurrentValue[#, CellAutoOverwrite]] &@
       NextCell[],
      cells = Cells[nb]; pos = Position[cells, evalCell];
      If[Head[nextInput = NextCell[CellStyle -> "Input"]] === CellObject,
       cellsBelow = cells[[pos[[1, 1]] + 1 ;; Position[cells, nextInput][[1, 1]] - 1]],
       cellsBelow = cells[[pos[[1, 1]] + 1 ;;]]];
      len = 
       Total@Split[
          Boole@Thread[
            And[CurrentValue[cellsBelow, GeneratedCell], 
             CurrentValue[cellsBelow, CellAutoOverwrite]]]][[1]];
      NotebookDelete[cellsBelow[[1 ;; len]]]]; 
     SetOptions[nb, 
      StyleDefinitions -> 
       Notebook[{Cell[StyleData[StyleDefinitions -> "Default.nb"]], 
         Cell[StyleData[All], CellAutoOverwrite -> False, GeneratedCell -> False]}]]]], 
  CellEpilog :> SetOptions[EvaluationNotebook[], StyleDefinitions -> "Default.nb"]}]

The disadvantage is that it is relatively slow, especially for large Notebooks.


P.S. The whole approach has an issue: by the time the contents of the cell starts executing, the output will already be deleted, and therefore, for example, NextCell[] will return a different value than by default.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.