6
$\begingroup$

Is there a way to store metadata in a cell in such a way that it can be accessed with Dynamic?

Think of e.g. how ExternalLanguage cells work. We can select whether they should use Python or NodeJS and this state is permanently stored in the CellEvaluationLanguage cell option.

enter image description here

The cell expression would be something like

Cell["", "ExternalLanguage",
 CellEvaluationLanguage->"NodeJS"]

It is unclear to me if CellEvaluationLanguage needs to be a built-in option for this to work. I tried something similar with an arbitrary option name and it did not work. For example, CurrentValue[EvaluationCell[], FooBar] = 123 will not set the FooBar option on the cell.

Next, I tried to use TaggingRules.

We can do

CurrentValue[EvaluationCell[], {TaggingRules, "FooBar"}] = 123

then examine the input cell's cell expression. It will have the FooBar tagging rule set. But it will also have inherited all tagging rules from the front end. On my machine I see this:

enter image description here

Is there a way that avoids these problems and still managed to store arbitrary hidden metadata in the cell?

What I am aiming for is implementing a similar selector to what we have for ExternalLanguage cells. Here's a proof of concept with TaggingRules that still has the problem I described above. Evaluate the following to add a selector to the input cell:

CurrentValue[EvaluationCell[], 
  CellFrameLabels] = {{None, 
   Cell[BoxData[
     PopupMenuBox[
      Dynamic[CurrentValue[
        ParentCell[EvaluationCell[]], {TaggingRules, 
         "MyRule"}]], {6 -> "6", 24 -> "24"}]]]}, {None, None}}

enter image description here

$\endgroup$
5
$\begingroup$

You can give "Input" cells a default TaggingRules option of TaggingRules -> {}. Then, using CurrentValue will not include the notebook tagging rules. For example:

SetOptions[
    EvaluationNotebook[],
    StyleDefinitions -> Notebook[
        {
        Cell[StyleData[StyleDefinitions->"Default.nb"]],
        Cell[StyleData["Input"],TaggingRules->{}]
        },
        StyleDefinitions->"PrivateStylesheetFormatting.nb"
    ]
]

Then,

CurrentValue[EvaluationNotebook[], TaggingRules] = {"parent" -> "default"};
CurrentValue[EvaluationNotebook[], TaggingRules]

{"parent" -> "default"}

Let's try using CurrentValue to modify a cell:

CurrentValue[EvaluationCell[], {TaggingRules, "key"}] = "value";
CurrentValue[EvaluationCell[], TaggingRules]

{"key" -> "value"}

The notebook tagging rule is not included.

$\endgroup$
  • $\begingroup$ Looks good. So you think TaggingRules is the way to go? This won't be an Input style cell anyway, so setting default TaggingRules for the style is completely fine. $\endgroup$ – Szabolcs Apr 12 at 21:38
2
$\begingroup$

This works for your explicit case:

CurrentValue[EvaluationCell[], CellFrameLabels] = {
   {
    None,
    Cell[
     BoxData[
      PopupMenuBox[
       Dynamic[
        CurrentValue[
         ParentCell[EvaluationCell[]],
         {TaggingRules, "MyRule"}, 
         FrontEnd`SetOptions[
          ParentCell[EvaluationCell[]],
          TaggingRules -> {"MyRule" -> None}
          ]
         ]
        ],
       {6 -> "6", 24 -> "24"}
       ]
      ]
     ]},
   {None, None}
   };
Options[EvaluationCell[], TaggingRules]

SetOptions didn't like operating on the ParentCell so I had to force it to pull that from the kernel, but it should still perform alright I think.

Basic Idea

Here's a kinda solution. I'm gonna assume when the CurrentValue isn't defined you use a default value. If that's the case you can do this:

CurrentValue[
 EvaluationCell[],
 {TaggingRules, "key"},
 FEPrivate`FrontEndExecute@
  FrontEnd`SetOptions[FrontEnd`EvaluationCell[], 
   TaggingRules -> {"key" -> "default"}]
 ]

That forces the TaggingRules to be directly set rather than updated. Here's a proof of concept. First set up some state that can be inherited:

SetOptions[EvaluationNotebook[], 
  TaggingRules -> {"parentKey" -> "default"}];

Now usually we'd get inheritance:

CurrentValue[
 EvaluationCell[],
 {TaggingRules, "key"},
 "default"
 ]
Options[EvaluationCell[], TaggingRules]

"default"

{TaggingRules -> {"parentKey" -> "default", "key" -> "default"}}

With this trick though we don't:

CurrentValue[
 EvaluationCell[],
 {TaggingRules, "key"},
 FEPrivate`FrontEndExecute@
  FrontEnd`SetOptions[FrontEnd`EvaluationCell[], 
   TaggingRules -> {"key" -> "default"}]
 ]
Options[EvaluationCell[], TaggingRules]

"default"

{TaggingRules -> {"key" -> "default"}}

Is it elegant? No. But it works if that's all you care about.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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