It would be convenient if there were a style sheet that automatically indented input cells, and automatically commented output cells, so that one could generate a stack exchange response in WL, and just copy the output. Is there such a style sheet?
2 Answers
I've come up with a stylesheet to do this, given below. Some of the issues that I needed to address were:
- Prevent cell labels from showing up.
- Indent both input and output cells so that they are code.
- Automatically comment the output.
- Produce output that works correctly with Copy. That is, no need to use Copy As | Plain Text.
- Allow one to copy multiple Code/Output/Text cells at once.
- Support InputForm and FullForm.
Since the input typically uses white space to control appearance, I modified the Code style instead of the Input style.
To prevent cell labels from showing up, I needed to set
ShowCellLabel->False
at the notebook level. However, I still want to see the labels in a notebook. I did this by settingShowCellLabel->True
for Code, Input and Output cell styes.To indent the input cells, I added a
CellEpilog
to the Code style, that looks for tabs, and inserts tabs if none are found. One could modify my code to look for spaces instead. To indent the output cells, I added aCellEvaluationFunction
to the Code style. TheCellEvaluationFunction
also turned the output into a comment. In both cases (CellEpilog
andCellEvaluationFunction
), one needs to use FullForm in some cases, e.g.,Pattern[a, Blank[]]
instead ofa_
:Using
RawBoxes @ ToString[.., InputForm]
produces an Output cell that yields "Copy As | Plain Text" output when using the Copy command. This means one can highlight multiple cells, and then use the Copy (Ctrl-C) command, instead of using the right-click context menu to do Copy As.Using
InputForm
orFullForm
wrappers gave me some problems withPageWidth
, so using the wrappers with long lines will need some post-processing help.Use Alt-8 (Cmd-8 on a mac) to begin a Code cell. I gave Code cells a light blue background to indicate that they are cells intended to be copied to Stack Exchange.
Improvement suggestions are welcome.
The stylesheet is given below:
Notebook[
{
Cell[StyleData[StyleDefinitions->"Default.nb"]],
Cell[StyleData["Notebook"],ShowCellLabel->False,MenuSortingValue->10000],
Cell[StyleData["Code"],
CellEpilog :> With[{cellObject=EvaluationCell[]},
NotebookWrite[cellObject,
With[{cell=NotebookRead[cellObject]},
Replace[cell,
{
Cell[BoxData[RowBox[{"\t",BlankSequence[]}]],BlankSequence[]]->cell,
Cell[BoxData[Pattern[a,Blank[]]],Pattern[b,BlankSequence[]]]:>Cell[BoxData[RowBox[{"\t",ReplaceAll[a,"\n"->Sequence["\n","\t"]]}]],b]
}
]
]
]
],
CellEvaluationFunction ->
(
Replace[ToExpression[#1],
{
Alternatives[Null,$Failed]->Null,
Alternatives[Pattern[e,Blank[InputForm]],Pattern[e,Blank[FullForm]]]:>RawBoxes[StringJoin["\t(* ",ToString[e]," *)"]],
Pattern[e,Blank[]]:>RawBoxes[StringReplace[StringJoin["\t(* ",ToString[e,InputForm,PageWidth->60]," *)"],"\\\n"->"\\\n\t"]]
}
]&
),
InitializationCell->False,
ShowCellLabel->True,
MenuSortingValue->10000,
Background->RGBColor[0.477119,0.957519,1]
],
Cell[StyleData["Input"],ShowCellLabel->True,MenuSortingValue->10000],
Cell[StyleData["Output"],ShowCellLabel->True,MenuSortingValue->10000]
},
Saveable->False,WindowSize->{808,689},WindowMargins->{{Automatic,143},{40,Automatic}},
ShowCellLabel->False,
FrontEndVersion->"11.0 for Mac OS X x86 (32-bit, 64-bit Kernel) (July 28, 2016)",
StyleDefinitions->"PrivateStylesheetFormatting.nb"
]
Here's another version that uses Blockquote to display output:
Notebook[
{
Cell[StyleData[StyleDefinitions->"Default.nb"]],
Cell[StyleData["Notebook"],ShowCellLabel->False,MenuSortingValue->10000],
Cell[StyleData["Code"],
CellEpilog:>With[{cellObject=EvaluationCell[]},
NotebookWrite[cellObject,
With[{cell=NotebookRead[cellObject]},
Replace[cell,
{
Cell[BoxData[RowBox[{"\t",BlankSequence[]}]],BlankSequence[]]->cell,
Cell[BoxData[Pattern[a,Blank[]]],Pattern[b,BlankSequence[]]]:>Cell[BoxData[RowBox[{"\t",ReplaceAll[a,Rule["\n",Sequence["\n","\t"]]]}]],b]
}
]
]
]
],
CellEvaluationFunction->
(
Replace[ToExpression[#1],
{
Alternatives[Null,$Failed]->Null,
Alternatives[Pattern[e,Blank[InputForm]],Pattern[e,Blank[FullForm]]]:>RawBoxes[StringJoin[">",ToString[e]]],
Pattern[e,Blank[]]:>RawBoxes[StringJoin[">",ToString[e,InputForm]]]
}
]&
),
InitializationCell->False,
ShowCellLabel->True,
MenuSortingValue->10000,
Background->RGBColor[0.477119,0.957519,1]
],
Cell[StyleData["Input"],ShowCellLabel->True,MenuSortingValue->10000],
Cell[StyleData["Output"],ShowCellLabel->True,MenuSortingValue->10000]
},
Saveable->False,WindowSize->{808,689},WindowMargins->{{Automatic,143},{40,Automatic}},
ShowCellLabel->False,
FrontEndVersion->"11.0 for Mac OS X x86 (32-bit, 64-bit Kernel) (July 28, 2016)",
StyleDefinitions->"PrivateStylesheetFormatting.nb"
]
-
11$\begingroup$ Very cool! Let me join others in saying it is a pleasure to have you on this site. $\endgroup$ Commented Dec 31, 2016 at 19:24
-
1$\begingroup$ [email protected] are these "others"? You seem to be the only person to have welcomed Carl to the site. (Sorry Carl, I guess I need to add a New Year's resolution to not pick on you... Neat idea, by the way) $\endgroup$ Commented Dec 31, 2016 at 20:12
-
1
-
2$\begingroup$ I entered an expression such as
Sqrt[\[Alpha]]
, then copied it and pasted it into Stackexchange .. which repeated it asSqrt[\[Alpha]]
... It would be cool if the stylesheet could automate the conversion of same to something like Sqrt[ $\alpha$] $\endgroup$– wolfiesCommented Jan 1, 2017 at 13:59 -
4$\begingroup$ @Mr.Wizard I always thought Leonid and Carl were sworn enemies from the DC Comics universe. $\endgroup$ Commented Jan 1, 2017 at 21:40
My initial versions mangled the downvalues of Out, used by %. Also, my initial versions defaulted to InputForm.
Edited to add support for compound/multiple expressions in an input, and to mark up messages.
Edited to fix bug when code cell is last cell of notebook
Edited to quiet messages during reformatting of cells
I've made some core changes to the style sheet.
Previously, I used calls like
Cells[CellLabel->"Out[55]//FullForm="]
to find all of the output cells associated with an input. This required that I determined the line numbers of a cell when it contained multiple lines. I also usedNextCell[EvaluatedCell[]]
in theCellProlog
to find the next cell before evaluation so that I could figure out what messages occurred for a given input.Now I use a more robust method. In the
CellProlog
, I give the evaluation cell the optionCellTags->"StackExchange"
andCellLabelAutoDelete->False
. This combination means that all the cells generated from the input have the optionCellTags->"StackExchange"
and include the originalCellLabel
. Hence, it is much easier to find the associated cells using theCellTags
option, and it is easy to restore the originalCellLabel
because the label hasn't been deleted. I also made a number of improvements to the formatting of output cells, to support forms likeTeXForm
, and to produce the normal plain text for output instead ofOutputForm
.Finally, I mentioned earlier that style sheets needed to use
FullForm
in some places. However, if you paste theNotebook[]; NotebookPut@@%;
expression I give for the style sheet, it turns out that the conversion fromStandardForm
toFullForm
needed for style sheets happens automatically. This means that I can rewrite my notebook expression so that it is a little bit easier to read, and I can include some comments.
An example of the use of the style sheets. Before evaluation, we have:
After evaluation (using the blockquote style sheet), we have:
And, the version pasted using "Copy" (where all 3 cells are selected) is seen below:
Row[{N[Pi,100], x^2, "c"}] //InputForm
Row[{3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844376249654`100., x^2, "c"}]
Row[{N[Pi,100], x^2, "c"}] //FullForm
Row[List[3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844376249654`100.,Power[x,2],"c"]]
Row[{N[Pi,100], x^2, "c"}]
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068x^2c
Using the new multi-input/message markdown support
Now, the following will work (here I use the code style sheet):
which looks like the following when pasted:
1/0
Row[{N[Pi,100],b^2,"c"}]//FullForm
Sin[x,y];
3+6
Power::infy: Infinite expression 1/0 encountered. >>
(* ComplexInfinity *)
(* Row[List[3.141592653589793238462643383279502884197169399375\
1058209749445923078164062862089986280348253421170679\
82148086513282306647093844376249654`100.,
Power[b, 2], "c"]] *)
Sin::argx: Sin called with 2 arguments; 1 argument is expected. >>
(* 9 *)
The style sheets are given below, first the code style sheet, followed by the blockquote style sheet. Install by copying and evaluating the code below, then selecting Install Stylesheet:
code style sheet
Notebook[
{
Cell[StyleData[StyleDefinitions->"Default.nb"]],
(* the Notebook style needs to have ShowCellLabel\[Rule]False so that copying the cells doesn't copy the label *)
Cell[StyleData["Notebook"], ShowCellLabel->False, MenuSortingValue->10000],
Cell[StyleData["Code"],
(* CellTags and CellLabelAutoDelete options mean the generated cells include information needed for
* postprocessing. The $Output PageWidth change is useful for creating strings with linebreaks *)
CellProlog:>(
SetOptions[EvaluationCell[], CellTags->"StackExchange", CellLabelAutoDelete->False];
width=Options[$Output, PageWidth];
SetOptions[$Output, PageWidth->60]
),
CellEpilog:>Quiet @ With[{
cellObject = EvaluationCell[],
out = Cells[CellTags->"StackExchange", CellStyle->"Output"],
message = Cells[CellTags->"StackExchange", CellStyle->"Message"]
},
SetOptions[$Output, width];
(* reformat input/code cell if needed, and remove CellTags/CellLabelAutoDelete added in CellProlog *)
Replace[NotebookRead[cellObject],
Cell[BoxData[a_], "Code", b__Rule] :>
NotebookWrite[cellObject,
Cell[BoxData @ If[MatchQ[a, RowBox[{"\t", __}]],
a,
RowBox[{"\t", If[ListQ[a], RowBox, Identity] @ ReplaceAll[a, "\n"->Sequence["\n","\t"]]}]
],
"Code", TextClipboardType -> "PlainText", FilterRules[{b}, CellLabel]
]
]
];
(* add CellLabelAutoDelete\[Rule]False to the output cells so that the original CellLabel can be reused *)
Map[SetOptions[#, CellLabelAutoDelete->False]&, out];
(* add > to the beginning of Message cells *)
Cases[message,
obj_ :> Replace[NotebookRead[obj],
Cell[BoxData[a_], s__String, b__] :>
NotebookWrite[obj, Cell[BoxData[RowBox[{">", a}]], s, DeleteCases[{b}, CellTags->_]]]
]
];
(* reformat output cells so that they appear as commented code *)
Cases[out,
obj_ :> Replace[NotebookRead[obj],
{
(* setting PageWidth\[Rule]60 in the Prolog means indenting adding indents is all that's needed *)
Cell[a_String, s__String, b__] :>
NotebookWrite[obj,
Cell[
StringJoin["\t(* ", StringReplace[a, "\n"->"\n\t"], " *)"],
s, TextClipboardType -> "PlainText", DeleteCases[{b}, CellTags|CellLabelAutoDelete->_]
]
],
(* ExportPacket produces a plaintext string, and ExportString adds linebreaks
* Some postprocessing of the ExportString output is needed
*)
c:Cell[_BoxData, s__String, b__] :>
NotebookWrite[obj,
Cell[
StringReplace[
ExportString[First@FrontEndExecute@ExportPacket[c, "PlainText"], "Package", PageWidth->60],
Shortest[__]~~"\n\""~~o___~~"\"\n"~~EndOfString :>
"\t(* "<>StringReplace[o, {"\\\\"->"\\", "\\\n"->"\\\n\t", "\\"~~x_ :> x}] <>" *)"
],
s, TextClipboardType -> "PlainText", DeleteCases[{b}, CellTags|CellLabelAutoDelete->_]
]
]
}
],
{1}
]
],
InitializationCell->False,
ShowCellLabel->True,Background->RGBColor[0.477119`,0.957519`,1]
],
Cell[StyleData["Input"],ShowCellLabel->True],
Cell[StyleData["Output"],ShowCellLabel->True]
},
Saveable->False,WindowSize->{808,689},WindowMargins->{{Automatic,143},{40,Automatic}},
FrontEndVersion->"10.3 for Mac OS X x86 (32-bit, 64-bit Kernel) (December 10, 2015)",
StyleDefinitions->"PrivateStylesheetFormatting.nb"
];
NotebookPut @ %;
block quote style sheet
Notebook[
{
Cell[StyleData[StyleDefinitions->"Default.nb"]],
(* the Notebook style needs to have ShowCellLabel\[Rule]False so that copying the cells doesn't copy the label *)
Cell[StyleData["Notebook"], ShowCellLabel->False, MenuSortingValue->10000],
Cell[StyleData["Code"],
(* CellTags and CellLabelAutoDelete options mean the generated cells include information needed for
* postprocessing. The $Output PageWidth change is useful for creating strings with linebreaks *)
CellProlog:>(
SetOptions[EvaluationCell[], CellTags->"StackExchange", CellLabelAutoDelete->False];
width=Options[$Output, PageWidth];
SetOptions[$Output, PageWidth->60]
),
CellEpilog:>Quiet @ With[{
cellObject = EvaluationCell[],
out = Cells[CellTags->"StackExchange", CellStyle->"Output"],
message = Cells[CellTags->"StackExchange", CellStyle->"Message"]
},
SetOptions[$Output, width];
(* reformat input/code cell if needed, and remove CellTags/CellLabelAutoDelete added in CellProlog *)
Replace[NotebookRead[cellObject],
Cell[BoxData[a_], "Code", b__Rule] :>
NotebookWrite[cellObject,
Cell[BoxData @ If[MatchQ[a, RowBox[{"\t", __}]],
a,
RowBox[{"\t", If[ListQ[a], RowBox, Identity] @ ReplaceAll[a, "\n"->Sequence["\n","\t"]]}]
],
"Code", TextClipboardType -> "PlainText", FilterRules[{b}, CellLabel]
]
]
];
(* add CellLabelAutoDelete\[Rule]False to the output cells so that the original CellLabel can be reused *)
Map[SetOptions[#, CellLabelAutoDelete->False]&, out];
(* add >- to the beginning of Message cells *)
Cases[message,
obj_ :> Replace[NotebookRead[obj],
Cell[BoxData[a_], s__String, b__] :>
NotebookWrite[obj, Cell[BoxData[RowBox[{">-", a}]], s, DeleteCases[{b}, CellTags->_]]]
]
];
(* add > to output cells to produce blockquote formatting *)
Replace[out,
obj_ :> Replace[NotebookRead[obj],
{
Cell[a_String, s__String, b__] :>
NotebookWrite[obj,
Cell[StringJoin[">", a],
"Output", TextClipboardType -> "PlainText", DeleteCases[{b}, CellTags|CellLabelAutoDelete -> _]
]
],
Cell[BoxData[a_], s__String, b__] :>
NotebookWrite[obj,
Cell[BoxData[RowBox[{">",a}]],
"Output", TextClipboardType -> "PlainText", DeleteCases[{b}, CellTags|CellLabelAutoDelete -> _]
]
]
}
],
{1}
]
],
InitializationCell->False,
ShowCellLabel->True,Background->RGBColor[0.477119`,0.957519`,1]
],
Cell[StyleData["Input"],ShowCellLabel->True],
Cell[StyleData["Output"],ShowCellLabel->True]
},
Saveable->False,WindowSize->{808,689},WindowMargins->{{Automatic,143},{40,Automatic}},
FrontEndVersion->"10.3 for Mac OS X x86 (32-bit, 64-bit Kernel) (December 10, 2015)",
StyleDefinitions->"PrivateStylesheetFormatting.nb"
];
NotebookPut @ %;
-
$\begingroup$ My last edit was motivated by the case where a user sets On["Packing"]. In that case, we get messages due to unpacking while reformatting the cells for import into stack exchange. There shouldn't be any messages while reformatting the cells, unless there is a bug in the reformatting code, so the Quiet prevents any such message from being generated. If there is a bug in the reformatting code, one can remove the Quiet for debugging purposes. $\endgroup$ Commented Jan 7, 2017 at 21:38
ServiceObject
to upload to SE on top of what I've alread built and go the other way too, even without much trouble. But I think such things largely exist. Halirutan has his SEUploader which, unless I'm wrong, pushes a notebook to SE as an answer. And Carl has a largely functional downloader. If Halirutan included Carl's downloader in his uploader palette I think that would cover all the cases except chat. $\endgroup$