Function Repository Resource:

SaveReadableNotebook

Source Notebook

Save a notebook to a file that is formatted to maximize readability when viewing changes in version control systems

Contributed by: Richard Hennigan (Wolfram Research)

ResourceFunction["SaveReadableNotebook"][notebook,"file"]

saves notebook to "file" as a Notebook expression formatted for readability.

Details and Options

In ResourceFunction["SaveReadableNotebook"][notebook,], the value for notebook can be any of the following:
Notebook[]a notebook expression
NotebookObject[]a currently open notebook
"path"a pathname of a saved notebook
ResourceFunction["SaveReadableNotebook"] accepts the same options as ReadableForm with the the following additions:
"ExcludedCellOptions"{CellChangeTimes,ExpressionUUID}cell options that should be discarded from the saved notebook
"ExcludedNotebookOptions"{WindowSize,WindowMargins}notebook options that should be discarded

Examples

Basic Examples (3) 

Save a NotebookObject to a human-readable file:

In[1]:=
nb = CreateDocument[{
   TextCell["Test notebook", "Title"],
   TextCell["This is a test", "Text"],
   ExpressionCell[Defer[1 + 1], "Input"],
   ExpressionCell[2, "Output"]
   }]
Out[1]=
In[2]:=
ResourceFunction["SaveReadableNotebook"][nb, FileNameJoin[{$TemporaryDirectory, "readable.nb"}]]
Out[2]=
In[3]:=
FilePrint[%]

Save a Notebook expression:

In[4]:=
ResourceFunction["SaveReadableNotebook"][
 Notebook[{Cell["Hello world", "Text"]}],
 FileNameJoin[{$TemporaryDirectory, "readable.nb"}]
 ]
Out[4]=
In[5]:=
FilePrint[%]

Save a copy of a notebook file that already exists:

In[6]:=
ResourceFunction["SaveReadableNotebook"][
 FindFile["ExampleData/document.nb"],
 FileNameJoin[{$TemporaryDirectory, "readable.nb"}]
 ]
Out[6]=
In[7]:=
FilePrint[%, 20]

Options (6) 

ExcludedCellOptions (3) 

By default, some cell options are automatically stripped:

In[8]:=
ResourceFunction["SaveReadableNotebook"][
  Notebook[{Cell["Hello world", "Text", ExpressionUUID -> CreateUUID[]]}],
  FileNameJoin[{$TemporaryDirectory, "readable.nb"}]
  ] // FilePrint

Preserve all cell options:

In[9]:=
ResourceFunction["SaveReadableNotebook"][
  Notebook[{Cell["Hello world", "Text", ExpressionUUID -> CreateUUID[]]}],
  FileNameJoin[{$TemporaryDirectory, "readable.nb"}],
  "ExcludedCellOptions" -> {}
  ] // FilePrint

Ignore specific options:

In[10]:=
ResourceFunction["SaveReadableNotebook"][
  Notebook[{Cell["Hello world", "Text", FontColor -> Red, FontSize -> 14]}],
  FileNameJoin[{$TemporaryDirectory, "readable.nb"}],
  "ExcludedCellOptions" -> {FontColor}
  ] // FilePrint

ExcludedNotebookOptions (3) 

By default, some notebook options are automatically stripped:

In[11]:=
ResourceFunction["SaveReadableNotebook"][
  Notebook[{Cell["Hello world", "Text"]}, WindowSize -> {1000, 1000}],
  FileNameJoin[{$TemporaryDirectory, "readable.nb"}]
  ] // FilePrint

Preserve all notebook options:

In[12]:=
ResourceFunction["SaveReadableNotebook"][
  Notebook[{Cell["Hello world", "Text"]}, WindowSize -> {1000, 1000}],
  FileNameJoin[{$TemporaryDirectory, "readable.nb"}],
  "ExcludedNotebookOptions" -> {}
  ] // FilePrint

Ignore specific options:

In[13]:=
ResourceFunction["SaveReadableNotebook"][
  Notebook[{Cell["Hello world", "Text"]}, Background -> Red],
  FileNameJoin[{$TemporaryDirectory, "readable.nb"}],
  "ExcludedNotebookOptions" -> {Background}
  ] // FilePrint

Applications (5) 

SaveReadableNotebook can be used to create notebook files that are well suited for version control systems that look at changes to files on a line-by-line basis.

Here’s a test notebook:

In[14]:=
nb = NotebookPut@Notebook[{
     Cell["Test notebook", "Title"],
     Cell["This is a test.", "Text"],
     Cell[BoxData[RowBox[{"1", "+", "1"}]], "Input"],
     Cell[BoxData["2"], "Output"]
     }];
NotebookSave[nb, FileNameJoin[{$TemporaryDirectory, "original.nb"}]];

Now make changes to the notebook, then save to a new file:

In[15]:=
NotebookSave[nb, FileNameJoin[{$TemporaryDirectory, "changed.nb"}]];

It can be difficult to visualize what actually changed:

In[16]:=
fileDiff[file1_, file2_, max_ : Infinity] :=
  Column@Take[
    Flatten@Replace[
      SequenceAlignment[Import[file1, "Lines"], Import[file2, "Lines"]],
      {{a___String}, {b___String}} :>
       Grid[{
         {Item[StringRiffle[{a}, "\n"], Background -> LightRed]},
         {Item[StringRiffle[{b}, "\n"], Background -> LightGreen]}
         }],
      {1}
      ],
    UpTo[max]
    ];
In[17]:=
fileDiff[
 FileNameJoin[{$TemporaryDirectory, "original.nb"}],
 FileNameJoin[{$TemporaryDirectory, "changed.nb"}]
 ]
Out[17]=

Create a formatted version of each notebook and view changes for those files instead:

In[18]:=
ResourceFunction["SaveReadableNotebook"][
  FileNameJoin[{$TemporaryDirectory, "original.nb"}],
  FileNameJoin[{$TemporaryDirectory, "original_readable.nb"}]
  ];
ResourceFunction["SaveReadableNotebook"][
  FileNameJoin[{$TemporaryDirectory, "changed.nb"}],
  FileNameJoin[{$TemporaryDirectory, "changed_readable.nb"}]
  ];
fileDiff[
 FileNameJoin[{$TemporaryDirectory, "original_readable.nb"}],
 FileNameJoin[{$TemporaryDirectory, "changed_readable.nb"}]
 ]
Out[20]=

The formatted notebook files still open normally:

In[21]:=
NotebookOpen[
 FileNameJoin[{$TemporaryDirectory, "changed_readable.nb"}]]
Out[21]=

Requirements

Wolfram Language 11.3 (March 2018) or above

Version History

  • 1.1.1 – 17 June 2022
  • 1.1.0 – 06 May 2022
  • 1.0.0 – 03 December 2018

Related Resources

License Information