I recently found myself wanting a similar thing, that is, for the saved .wl to be formatted with the autoindentation and autospacing of the frontend's editor.
The frontend will apply autoindentation for Input
style cells in the Package stylesheet, so I first change the cell style from the default Code
to Input
(+initialization cell).
I found I can then capture the frontend's formatting by toggling the cell style to CodeText
and back to Input
. This inserts explicit spaces for autoindentation and autospacing in the cell, and upon saving the .wl file will be formatted similar to what you see on screen in the package editor.
Programmatically, this can be done with
SaveFormattedNotebook[nb_NotebookObject] := (
Scan[(
SelectionMove[#, All, Cell];
FrontEndTokenExecute[nb, "Style", "CodeText"];
FrontEndTokenExecute[nb, "Style", "Input"];
) &, Cells[nb, CellStyle -> {"Input"}]];
NotebookSave[nb])
However, this'll leave the in-editor package with a bunch of redundant spaces, which should be removed, being careful not to delete spaces in comment blocks (* *)
or strings ""
IsCommentRowBoxQ[RowBox[{box_, ___}]] := TrueQ[box == "(*"];
IsCommentRowBoxQ[___] := False
IsStringLiteralBoxQ[s_String] :=
TrueQ[StringLength[s] > 2 && First@Characters[s] === "\""];
IsStringLiteralBoxQ[___] := False
CellApplyAutoIndent[cell_Cell] :=
With[{indentingNewline = FromCharacterCode[FromDigits["F3A3", 16]]},
Map[# /. "\n" -> indentingNewline &, cell, {-1}]]
CellRemoveExpressionWhitespace[c_?IsCommentRowBoxQ] := c;
CellRemoveExpressionWhitespace[s_?IsStringLiteralBoxQ] := s;
CellRemoveExpressionWhitespace[RowBox[boxes_]] :=
RowBox[Map[CellRemoveExpressionWhitespace, boxes]];
CellRemoveExpressionWhitespace[s_String] :=
StringDelete[s, " "];
CellRemoveExpressionWhitespace[
Cell[BoxData[boxes__], cellStyle_String, cellOptions___]] :=
Cell[BoxData[Map[CellRemoveExpressionWhitespace, boxes]], cellStyle,
cellOptions];
CellRemoveExpressionWhitespace[x___] := x
FormatNotebook[nb_NotebookObject] :=
Scan[NotebookWrite[#,
CellRemoveExpressionWhitespace@
CellApplyAutoIndent@
NotebookRead[#]] &, Cells[nb, CellStyle -> {"Input"}]]
In addition to removing redundant whitespace, this also replaces \n line endings with \[IndentingNewLine]
. This is necessary when opening a previously saved .wl file in the editor, since this will have \n line endings which means there is no autoformatting applied.