Last active
December 18, 2015 15:59
-
-
Save lshifr/5808568 to your computer and use it in GitHub Desktop.
Code formatter palette for mathematica.stackexchange.com
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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`"]] | |
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"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" | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(* 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