# Summary

I have two blocks of code, reproduced at the bottom of this post, each of which provides significant utility. The first, which automatically formats outputs as 'input = output', consists of a \$PrePrint and a \$Post statement. The second, which allows easy inline combination of math and text, consists of a \$PreRead and a \$PrePrint. I’d like to implement both simultaneously, but can’t because only one \$PrePrint statement can be active in given session. I’d thus like to merge these into a single block of code, which contains just one \$PrePrint statement, enabling me to obtain their combined functionality, and thus easily produce outputs that combine input, output and text.

# Details

The first piece of code (code block 1, below), written by Simon Rochester (Would like input and output printed on same line, w/o needing extra syntax), directs MMA to print input and output on a single line, in TraditionalForm, without the need for any added syntax. For example:

int = Integrate[x^2, x]
int/x
%/x


$\text{int}=\int x^2 \, dx=\frac{x^3}{3}$

$\frac{\text{int}}{x}=\frac{x^2}{3}$

$\frac{\%}{x}=\frac{x}{3}$

g[x_] := Sin[x]
g[Pi]


$g(x\_):=\sin(x)$

$g(\pi)=0$

a = 2


$a=2$

The second piece of code (code block 2, below), originally written by Mr. Wizard (Notebook formatting - easier descriptions for equations and results?), and which I extended with significant assistance from MB1965 (How to generalize this combined PreRead + PrePrint code?), enables me to output math and text on a single line, with minimal added syntax — I can put text before, after, or both before and after the math; I can also output text alone:

"Text before."; Integrate[x^2, x]
Integrate[x^2, x]; "Text after"
"Text before."; Integrate[x^2, x]; "Text after."
"Text only.";


$\color{blue}{\textit {Text before.}}\>\frac{x^3}{3}$

$\frac{x^3}{3} \>\>\color{blue}{\textit {Text after.}}$

$\color{blue}{\textit {Text before.}}\>\frac{x^3}{3}\>\>\color{blue}{\textit {Text after.}}$

$\color{blue}{\textit {Text only.}}$

Note that the semicolon is only needed as a separator (not a terminator), except in the "text only" case.

# Objective

I’d like to implement both code blocks simultaneously, enabling me to obtain their combined functionality, e.g.:

"Letting"; int=Integrate[x^2,x]
"We find that"; int/x; ", as expected."


$\color{blue}{\textit {Letting}}\>\text{int}=\int x^2 \, dx=\frac{x^3}{3}$

$\color{blue}{\textit {We find that}}\>\frac{int}{x} = \frac{x^2}{3}\> \color{blue}{\textit {, as expected.}}$

# Motivation

The rationale for this is to enable me to create, with minimal extra work, notebooks that are easily readable by non-MMA users. Thus, once the above objective is met, I can then use R. M.’s code-hiding palette (Is there a way to hide or toggle the visibility of code?) to remove all the input, leaving me with just the output alone.

# Issues

The one issue I’ve noticed is that, while code block 1 will output both input and output even if there is normally no printed output, e.g.:

g[x_]:=Sin[x]


$g(\text{x$\_$}):=\sin (x)$

….code block 2 doesn’t output anything when there is no printed math output:

"Text before."; g[x_]:=Sin[x]


[No ouput]

MB1965 suggested this is because “whenever it [\$PreRead] encounters a Null return it doesn't bother to even check$PrePrint and simply returns nothing”. MB1965 further noted that, if an extra ""; "" is added after the math (where the second pair of quotes can contain text, if text after the math is desired), MMA will then print all the quoted text:

"Text before."; g[x_] := Sin[x]; ""; ""
g[x_] := Sin[x]; ""; "Text after"
"Text before"; g[x_] := Sin[x]; ""; "Text after"


$\color{blue}{\textit {Text before.}}$

$\color{blue}{\textit {Text after.}}$

$\color{blue}{\textit {Text before.}}\>\>\>\color{blue}{\textit {Text after.}}$

It would be great if I could get a fix for this corner case in the merged code.

# Code block 1

$PrePrint = (TraditionalForm@HoldForm[In[line] = #] /. line ->$Line /. DownValues[In] /.
{HoldPattern[a_ = a_] :> a,
HoldPattern[a_ = HoldForm[a_]] :> a,
HoldPattern[(c : (a_ = b_)) = b_] :> c,
HoldPattern[(a_ = b_) = c_] :> HoldForm[a = b = c]
}
) &;

$Post = (Replace[#, Null -> HoldForm[In[line]] /. line ->$Line /. DownValues[In]]) &;


# Code block 2

$note1 = Null;$note2 = Null;
$note3 = Null;$PreRead =
Replace[#, {RowBox[{note1_String?(StringMatchQ[#, "\"*\""] &), ";",
body__, ";",
note2_String?(StringMatchQ[#, "\"*\""] &)}] :> ($note1 = Style[ToExpression@note1, FontFamily -> "Times", Italic, FontSize -> 15, Blue];$note2 =
Style[ToExpression@note2, FontFamily -> "Times", Italic, FontSize -> 15, Blue];
RowBox[{body}]),
RowBox[{body__, ";",
note_String?(StringMatchQ[#, "\"*\""] &)}] :> ($note2 = Style[ToExpression@note, FontFamily -> "Times", Italic, FontSize -> 15, Blue];$note1 = Null;
RowBox[{body}]),
RowBox[{note_String?(StringMatchQ[#, "\"*\""] &), ";",
body__}] :> ($note1 = Style[ToExpression@note, FontFamily -> "Times", Italic, FontSize -> 15, Blue];$note2 = Null;
RowBox[{body}]),
RowBox[{note_String?(StringMatchQ[#, "\"*\""] &),
";"}] :> ($note3 = Style[ToExpression@note, FontFamily -> "Times", Italic, FontSize -> 15, Blue];$note2 = Null; $note1 = Null; RowBox[{note}]), e_ :> ($note1 = Null; $note2 = Null; e)}] &;$PrePrint = Which[($note1 == Null &&$note2 == Null && $note3 =!= Null), # &[$note3, $note3 = Null], ($note1 =!= Null && $note2 =!= Null &&$note3 == Null), # &[
Row[{$note1, Spacer[5], Pane@#, Spacer[5],$note2}], $note1 = Null,$note2 = Null],
($note1 =!= Null &&$note2 =!= Null && $note3 == Null), # &[ Row[{$note1, Spacer[5], Pane@#, Spacer[5], $note2}],$note1 =
Null, $note2 = Null], ($note1 =!= Null && $note2 === Null &&$note3 == Null), # &[
Row[{$note1, Spacer[5], Pane@#}],$note1 = Null],
($note1 === Null &&$note2 =!= Null && $note3 == Null), # &[ Row[{Pane@#, Spacer[5],$note2}], $note2 = Null], True, #] &;  ## 1 Answer I took the liberty of partitioning your code into functions for each formatting step. For part 2, you simply need to edit the $PreRead so that it never actually sees Null. Here's a function that does that:

boxExpr[body_] :=
RowBox@{"Replace", "[", "\"thisIsJustATag\"", ";", body, ",",
"Null", "->", "\"\"", "]"};


The "thisIsJustATag" there will make more sense in a moment.

Then I pulled out the note extraction task and used boxExpr everywhere there was RowBox[{body}]. Note that I'm using the styleNote function I defined in my suggestion at the bottom. To deal with issue (2) mentioned in the comments we also apply boxExpr in the no-note case.

extractNotes[boxes_] :=
Replace[boxes, {RowBox[{note1_String?(StringMatchQ[#, "\"*\""] &),
";", body__, ";",
note2_String?(StringMatchQ[#, "\"*\""] &)}] :> ($note1 = styleNote[note1, "Before"];$note2 =
styleNote[note2, "After"];
boxExpr@body),
RowBox[{body__, ";",
note_String?(StringMatchQ[#, "\"*\""] &)}] :> ($note2 = styleNote[note, "After"];$note1 = Null;
boxExpr@body),
RowBox[{note_String?(StringMatchQ[#, "\"*\""] &), ";",
body__}] :> ($note1 = styleNote[note, "After"];$note2 = Null;
boxExpr@body),
RowBox[{note_String?(StringMatchQ[#, "\"*\""] &),
";"}] :> ($note3 = styleNote[note, "Neither"];$note2 = Null; $note1 = Null; note), e_ :> ($note1 = Null; $note2 = Null; boxExpr@e)}];  Next I tackled joining the two parts. Easiest to do via a two step process. First we apply the Part 1 code you supplied plus a tweak to remove the Replace expression we added in boxExpr (this is where the tag is important): applyFormatting[out_] := With[{line =$Line},
HoldForm[In[line] = $placeHolder] /. DownValues[In] /. {$placeHolder -> out,
HoldPattern[
Replace[CompoundExpression["thisIsJustATag", expr_],
Null -> ""]] :> expr
}
/. {
HoldPattern[a_ = ""] :> a,
HoldPattern[a_ = a_] :> a,
HoldPattern[a_ = HoldForm[a_]] :> a,
HoldPattern[(c : (a_ = b_)) = b_] :> c,
HoldPattern[(a_ = b_) = c_] :> HoldForm[a = b = c]
}
];


And then I pulled out the note formatting function and cleaned that up a little (using Switch is easier than Which here I think):

addNotes[formatted_] :=
TraditionalForm@Switch[{$note1,$note2, $note3}, {Null, Null, Except@Null}, With[{r =$note3}, $note3 = Null; r], {Except@Null, Except@Null, _}, With[{r1 =$note1, r2 = $note2},$note1 = $note2 = Null; Row[{r1, formatted, r2}, Spacer[5]] ], {Except@Null, _, _}, With[{r =$note1}, $note1 = Null; Row[{r, formatted}, Spacer[5]] ], {_, Except@Null, _}, With[{r =$note2}, $note2 = Null; Row[{formatted, r}, Spacer[5]] ], _, formatted ];  And then all we need is this: $PreRead = extractNotes;
$PrePrint = addNotes@*applyFormatting;  to get the desired result. ### Suggestion To make your life easier I'd suggest adding a store of text styles like: $outputStyles =
<|
"Default" -> {
Blue,
15,
Italic,
FontFamily -> "Times"
},
"Before" -> {
Blue,
15,
Italic,
FontFamily -> "Times"
},
"After" -> {
Blue,
15,
Italic,
FontFamily -> "Times"
}
|>;


and a styling function like:

styleNote[note_, style_] :=
Style[ToExpression@note,
Sequence @@ Lookup[$outputStyles, style,$outputStyles["Default"]]];


And then you can replace all of your note styling calls with a simple styleNote calls which will allow you to change how you do the styling without changing your $PreRead at all. For example you can change the color for your after note text like this: $outputStyles["After"] = $outputStyles["After"] /. Blue -> Red  No need to edit the $PreRead function at all this way.

### All together

For those who don't want to copy all the pieces in, this is all the formatting code as I have it:

$note1 = Null;$note2 = Null;
$note3 = Null;$outputStyles =
<|
"Default" -> {
Blue,
15,
Italic,
FontFamily -> "Times"
},
"Before" -> {
Blue,
15,
Italic,
FontFamily -> "Times"
},
"After" -> {
Blue,
15,
Italic,
FontFamily -> "Times"
}
|>;

boxExpr[body_] :=

RowBox@{"Replace", "[", "\"thisIsJustATag\"", ";", body, ",",
"Null", "->", "\"\"", "]"};
styleNote[note_, style_] :=

Style[ToExpression@note,
Sequence @@ Lookup[$outputStyles, style,$outputStyles["Default"]]];

extractNotes[boxes_] :=
Replace[boxes, {RowBox[{note1_String?(StringMatchQ[#, "\"*\""] &),
";", body__, ";",
note2_String?(StringMatchQ[#, "\"*\""] &)}] :> ($note1 = styleNote[note1, "Before"];$note2 =
styleNote[note2, "After"];
boxExpr@body),
RowBox[{body__, ";",
note_String?(StringMatchQ[#, "\"*\""] &)}] :> ($note2 = styleNote[note, "After"];$note1 = Null;
boxExpr@body),
RowBox[{note_String?(StringMatchQ[#, "\"*\""] &), ";",
body__}] :> ($note1 = styleNote[note, "After"];$note2 = Null;
boxExpr@body),
RowBox[{note_String?(StringMatchQ[#, "\"*\""] &),
";"}] :> ($note3 = styleNote[note, "Neither"];$note2 = Null; $note1 = Null; note), e_ :> ($note1 = Null; $note2 = Null; boxExpr@e)}]; applyFormatting[out_] := With[{line =$Line},
HoldForm[In[line] = $placeHolder] /. DownValues[In] /. {$placeHolder -> out,
HoldPattern[
Replace[CompoundExpression["thisIsJustATag", expr_],
Null -> ""]] :> expr
}
/. {
HoldPattern[a_ = ""] :> a,
HoldPattern[a_ = a_] :> a,
HoldPattern[a_ = HoldForm[a_]] :> a,
HoldPattern[(c : (a_ = b_)) = b_] :> c,
HoldPattern[(a_ = b_) = c_] :> HoldForm[a = b = c]
}
];
TraditionalForm@Switch[{$note1,$note2, $note3}, {Null, Null, Except@Null}, With[{r =$note3}, $note3 = Null; r], {Except@Null, Except@Null, _}, With[{r1 =$note1, r2 = $note2},$note1 = $note2 = Null; Row[{r1, formatted, r2}, Spacer[5]] ], {Except@Null, _, _}, With[{r =$note1}, $note1 = Null; Row[{r, formatted}, Spacer[5]] ], {_, Except@Null, _}, With[{r =$note2}, $note2 = Null; Row[{formatted, r}, Spacer[5]] ], _, formatted ];$PreRead = extractNotes;
$PrePrint = addNotes@*applyFormatting;  • Thanks for taking the time to go through this! I tried your "all together" code block on a variety of inputs. It worked on all of them, with four exceptions: (1) The output of "Text alone"; is unformatted. (2) g[x_] := Sin[x] gives no output. (3) "Text before."; g[x_] := Sin[x] and g[x_] := Sin[x]; "Text after." both give the text properly, but format the math with an extra set of parentheses and an extra equals sign: "(g(x_) := sin(x)) =" . (4) "Text before."; g[x_] := Sin[x]; "Text after." gives only "(g(x_) := sin(x)) =" (no text). – theorist Jan 3 '17 at 6:23 • ....in addition, the math no longer formats in TraditionalForm, even though you have TraditionalForm@HoldForm[In[line] =$placeHolder] in your code. I mention this principally as a curiosity, since I can easily correct it by setting Preferences->Evaluation->Output to TraditionalForm. – theorist Jan 3 '17 at 6:26
• I also just noticed a vertical offset between the text and the math that's been present since Mr. Wizard's orig. code. When there's both an = sign and a fraction in the output, the text is usu. vertically offset higher than the math (i.e., not in line with the = sign). E.g., in the output of "Text before."; a = 3/x , the text is higher, but in "Text before."; 3/x and "Text before."; test = {{f1, f2}, {g1, g2}} it's not. The exception is with sums, where the text is lower, e.g., "Text before."; sum = Sum[1/p^2, {p, 1, Infinity}]. Any idea what's causing this, and how to correct it? – theorist Jan 3 '17 at 6:33