4
$\begingroup$

Let's import a notebook:

nb = ImportString["Notebook[{},TrackCellChangeTimes->False]", "NB"]
(* Notebook[{}, TrackCellChangeTimes -> False] *)

All is well so far. Now let's re-export it:

ExportString[nb, "NB"]

Now the output contains

$CellContext`TrackCellChangeTimes -> False

instead of

TrackCellChangeTimes -> False

This happens with every valid notebook or cell option that doesn't already have a corresponding symbol in the System` context, and thus Import creates it in Global` instead.

Why does this happen? What's a reasonable workaround?

Notes:

  • I need the notebooks exported with full cache information, so I cannot export them as a plain expression.

  • NotebookSave suffers from the same problem.

  • The problem goes away if I use "TrackCellChangeTimes" (a string) instead of TrackCellChangeTimes.

    However, cycling such a notebook expression through NotebookPut and NotebookGet "removes" the quotes and converts the string to a symbol again. Thus I do not know how to get strings for such options when importing a notebook.

  • I am using Import/Export to post-process notebooks created by the documentation tools and fix things. The unwanted $CellContext causes subtle breakage that I did not even notice until now.

$\endgroup$
  • 1
    $\begingroup$ Should I delete my answer and make it a duplicate? Programming scripts to create and modify stylesheets $\endgroup$ – Kuba Nov 30 '16 at 19:32
  • 1
    $\begingroup$ @Kuba Please don't delete, the duplicate is too long. This answer is clear an simple. Let's keep it as is. $\endgroup$ – Szabolcs Nov 30 '16 at 19:48
3
$\begingroup$

TL;DR;

You can redirect unknown symbols to System` which will be stripped later:

Block[{$Context = "System`"},
 nb = ImportString["Notebook[{},TrackCellChangeTimes->False]", "NB"]
]

Digging in boxes' (cell expressions)* typesetting

*in opposite to expressions typesetting e.g.: Global`symbol -> RowBox[{"symbol"}]

That is acutally quite important part of typsetting. So when will the context be stripped? When will $CellContext` appear? Here is a small test:

sample = {
 {#, #, #2, "System`"},
 {#, #2, #2, "System`"},
 {#, "System`", #2},
 {#, #2, #2},
 {#, #2, #2, "System`", #}
 } & @@@ {{"JLink`", "Global`"}, {"Global`", "JLink`"}, 
    {"System`", "JLink`"}, {"FrontEnd`", "Global`"}
 } //  Flatten[#, 1] &;

 result = Block[{$Context = #2, $ContextPath = {##3}}, Reap[
       Module[{str},
        str = 
         ExportString[
          Notebook[{}, Symbol[# <> "TrackCellChangeTimes"] -> False], 
          "NB"];
        str = StringToStream[str];
        Sow[{#, #2, {##3}, Find[str, "TrackCellChangeTimes"]}];
        Close[str];
        ]][[-1, 1, 1]]
     ] & @@@   sample;

result // SortBy[Last] //  TableForm[#, TableAlignments -> Right, 
   TableHeadings -> {None, Style[#, Bold, 15] & /@ {"symbol's context", "$Context",  "$ContextPath", "exported string"}}] &

enter image description here

So the rules seem to be as follows:

Which[

  • Symbol's context is System`?

    Leave only the symbol name.

  • Symbol's context is the same as current $Context?

    Use $CellContext`symbolName

  • Is symbol's context Global`,FrontEnd` or any FrontEnd related?

    Leave only the symbol name.

  • True

    Use symbol's full name.

]

$\endgroup$
  • $\begingroup$ It was of course WholeGroupCellOpener for me too. $\endgroup$ – Szabolcs Nov 30 '16 at 19:41
  • 1
    $\begingroup$ @Szabolcs I've conducted a little investigation, have to go now. Tell me if I've missed something. $\endgroup$ – Kuba Nov 30 '16 at 20:39

Not the answer you're looking for? Browse other questions tagged or ask your own question.