Skip to content

Instantly share code, notes, and snippets.

@lshifr
Last active December 18, 2015 15:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lshifr/5808568 to your computer and use it in GitHub Desktop.
Save lshifr/5808568 to your computer and use it in GitHub Desktop.
Code formatter palette for mathematica.stackexchange.com
Module[{quitOnFail},
quitOnFail[$Failed]:= Return[$Failed,Module];
quitOnFail[arg_]:=arg;
quitOnFail[
Quiet@Import["https://raw.github.com/lshifr/ProjectInstaller/master/BootstrapInstall.m"]
];
quitOnFail[Quiet@Needs["ProjectInstaller`"]];
Map[ProjectInstaller`ProjectUninstall,{"CodeFormatter","SEFormatter"}];
quitOnFail[
Quiet@ProjectInstaller`ProjectInstall[
URL["https://github.com/lshifr/CodeFormatter/archive/master.zip"]
]
];
quitOnFail[
Quiet@ProjectInstaller`ProjectInstall[
URL["https://gist.github.com/lshifr/5808568/download"]
]
];
quitOnFail[Quiet@Needs["SEFormatter`"]]
]
{
"author" ->
{
"name" -> "Leonid Shifrin",
"email" -> "lshifr@gmail.com",
"url" -> "http://www.mathprogramming-intro.org"
},
"name" -> "SEFormatter",
"version" -> "1.0",
"mathematica_version" -> "8.0+",
"dependencies" -> {{"CodeFormatter"}},
"description"-> "Code-formatting palette for Mathematica SE",
"url" -> "https://gist.github.com/gists/5808568/download",
"license" -> "MIT"
}
(* Mathematica Package *)
(* :Title: SEFormatter *)
(* :Author: Leonid B. Shifrin *)
(* :Summary: Code formatting palette for mathematica.stackexchange.com
(but can be useful also for other formatting purposes) *)
(* :Context: SEFormatter` *)
(* :Package version: 1.0 *)
(* :Copyright: Copyright 2013, Leonid B.Shifrin.
The package is released under MIT Open Source license
*)
(* :History: Version 1.0 June 2013 *)
(* :Keywords: code, format, pretty-print *)
(* :Mathematica version: 8.0 *)
BeginPackage["SEFormatter`", { "CodeFormatter`"}]
(* Exported symbols added here with SymbolName::usage *)
LineWidth::usage = "An option for SEFormatterPalette";
TabWidth::usage = "An option for SEFormatterPalette";
CodeBackground::usage = "An option for SEFormatterPalette";
LineWidthValues::usage = "An option for SEFormatterPalette";
TabWidthValues::usage = "An option for SEFormatterPalette";
OffsetValues::usage = "An option for SEFormatterPalette";
FontSizeValues::usage = "An option for SEFormatterPalette";
SEFormatterPalette::usage =
"SEFormatterPalette[opts] creates a palette window for SE code formatting";
Begin["`Private`"] (* Begin Private Context *)
ClearAll[throwError];
throwError[args_List]:=
(
Message[formattingPalette::frmtfailMessageName];
Throw[$Failed,error[formattingPalette,args]]
);
ClearAll[catchError];
SetAttributes[catchError,HoldAll];
catchError[code_,f_]:=
Catch[code,_error,f];
Clear[extractBoxedCode];
extractBoxedCode[boxes_]:=
(
If[
#1==={}
,
{}
,
(*else*)
ToExpression[
First[#1]/.
{
BoxData[r_RowBox]:>r,
BoxData[{r__}]:>
Replace[
DeleteCases[
RowBox[{r}],
s_String/;StringMatchQ[s,Whitespace],
{2}
],
RowBox[{rr_,";"}]:>Sequence[rr,";"],
{2}
]
},
StandardForm,
MakeBoxes
]
]&
)[
Cases[boxes,Cell[b_BoxData,___]:>b,{0,\[Infinity]}]
]
ClearAll[makeSEFormatButton];
SetAttributes[makeSEFormatButton, HoldAll];
makeSEFormatButton[result_Symbol, lineWidth_, tabWidth_, overallTab_, errorVar_Symbol] :=
Button["Format",
Function[
code,
catchError[code,
Function[{value, tag},
errorVar = (tag /. error[_, args_] :> args);
value
]
],
HoldAll
]@
Module[{read,boxedCode, formatted},
read = NotebookRead[SelectedNotebook[]];
boxedCode = extractBoxedCode[read];
If[boxedCode === {},
throwError[{"failed_to_extract_code_from_boxes"}]
];
formatted =
Catch[
CodeFormatter`SEFormat[boxedCode, lineWidth, tabWidth, overallTab],
_
];
If[MatchQ[formatted, {$Failed, __}], throwError[Rest[formatted]]];
errorVar = Null;
result = formatted
]];
ClearAll[SEFormatterPalette];
Options[SEFormatterPalette] = {
FieldSize -> {80, {2, Infinity}},
LineWidth -> 80,
TabWidth -> 4,
Offset -> 4,
ImageSize -> {900, 600},
FontSize -> 18,
CodeBackground -> Lighter[Yellow, 0.95],
LineWidthValues -> Range[70, 100, 5],
TabWidthValues -> {2, 3, 4, 5, 6},
OffsetValues -> {0, 2, 4, 8, 10},
FontSizeValues -> Range[8, 25]
};
SEFormatterPalette[opts : OptionsPattern[{SEFormatterPalette,Notebook}]] :=
With[{framed = Framed[#, FrameStyle -> Gray, Background -> LightGreen] &,
lwidth = OptionValue[LineWidth],
offset = OptionValue[Offset],
tab = OptionValue[TabWidth],
isize = OptionValue[ImageSize],
fieldsize = OptionValue[FieldSize],
fsize = OptionValue[FontSize],
codebackgr = OptionValue[CodeBackground],
lineWidthVals = OptionValue[LineWidthValues],
tabVals = OptionValue[TabWidthValues],
offsetVals = OptionValue[OffsetValues],
fsizeVals = OptionValue[FontSizeValues]
},
DynamicModule[{string, boxed = Null, error = Null, errorDetails = Null, errControl, errorReporting = "Compact"},
string := StringJoin@Cases[boxed, _String, Infinity];
error := errorDetails =!= Null;
errControl :=
Control[{{errorReporting, "Compact","Error reporting"}, {"Compact", "Verbose"}}];
CreatePalette[
{
Dynamic@
If[error,
Column[{
Style["Formatting error encountered", Red],
If[errorReporting === "Verbose",
Row[{"Error details: ", Style[errorDetails, Pink]}],
(* else *)
""
]
}],
(* else *)
""
]
,
Row[{
makeSEFormatButton[boxed, lwidth, tab, offset, errorDetails],
Button["Copy", CopyToClipboard[string]]
}]
,
Manipulate[
boxed = SEFormat[boxed, lineWidth, tabWidth, overallTab];
Pane[
Style[
InputField[Dynamic[string], String,FieldSize -> fieldsize,Background -> codebackgr],
"Program",
FontSize -> fontSize,
FontWeight -> Bold
],
Scrollbars -> True,
ImageSize -> isize
]
,
Row[{
framed@Control[{{lineWidth, lwidth,"Line width"}, lineWidthVals}],
framed@Control[{{tabWidth, tab,"Tab width"}, tabVals}],
framed@Control[{{overallTab, offset,"Offset"}, offsetVals}],
framed@Control[{{fontSize, fsize,"Font Size"}, fsizeVals}],
framed@errControl
}, " "]
,
ControlPlacement -> Top
]
},
WindowTitle -> "SE Code Formatter",
Sequence @@ FilterRules[FilterRules[{opts},Options[Notebook]],Except[FontSize|ImageSize]]
]
]
]
(* Working around an annoying bug I wasn't able to fix yet, which shows up only upon the first run *)
NotebookClose[SEFormatterPalette[Visible -> False]];
End[] (* End Private Context *)
EndPackage[]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment