Multiple output cells, suppressed by semicolon
New Implemantation:
f[x_] := Dynamic[
NotebookWrite[EvaluationCell[], Cell[BoxData[ToBoxes[#]], "Echo"] & /@ Range[x]];,
None, TrackedSymbols :> {}, Evaluator -> None]
Original Answer:
As Dynamic
objects are only evaluated when they are visible, one can use them to print cells only when there is no ;
at the end of the input. The following one removes the Out
cell containing a DynamicWrapper
as the Dynamic
object itself, after the cells are printed.
ClearAll@f
f[x_] := Module[{evalCellObject},
DynamicWrapper["",
evalCellObject = EvaluationCell[];
NotebookWrite[EvaluationNotebook[], Cell[BoxData[ToBoxes[#]], "Echo"] & /@ Range[x]];
NotebookDelete[evalCellObject]]]
The code below is currently broken but I'll leave it for reference. I'll attempt a full rewrite somewhat later. Thanks to gwr for testing my code and pointing out problems.
The first possibility that comes to mind is the use of $PreRead
and $PrePrint
to set a global variable, then use the value of this variable within your function to control Cell generation. A basic example building on andre's code:
$print = True;
$PrePrint = ($print = True; #) &;
$PreRead = Replace[#, row : RowBox[{__, ";"}] :> ($print = False; row)] &;
f[x_] :=
(If[$print, CellPrint @ ExpressionCell[#, "Output"] &] /@ {x + 1, x + 2};)
Now:
f[0] (* "prints" two cells *)
1 2
f[0]; (* prints nothings *)
This one checks if the input ended with ;
and prints Echo
cells if it didn't.
f[x_] := If[
Cases[NotebookRead[EvaluationCell[]],
BoxData[RowBox[{___, last_}]] :> last] == {";"},
Null,
CellPrint[ExpressionCell[#, "Echo"]] & /@ Range[x];
]
For example:
f[5]
f[5];
This approach can be extended to also cover CompoundExpression
s containing f
by checking if the function is followed by ;
, instead of checking if the input ended with ;
.
f[x_] := If[Cases[NotebookRead[EvaluationCell[]],
BoxData[RowBox[{___, RowBox[{"f", ___}], end_, ___}]] :> end] == {";"},
Null,
CellPrint[ExpressionCell[#, "Echo"]] & /@ Range[x];]