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]]]

In&Out Example


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]

Out

f[5];

This approach can be extended to also cover CompoundExpressions 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];]