3
$\begingroup$

I know, you can get rid of no longer used private styles by opening Format>Edit Stylesheet, mark the styles no longer needed and then delete them by Edit>Clear. This was already dealt at Delete a style type from stylesheet

How can I programmatically do that for some other notebook?

$\endgroup$

3 Answers 3

1
$\begingroup$

Another option is to edit the stylesheet notebook itself. First we programmatically extract this (any better ways to do this would be appreciated):

notebookObjectStylesheet[nb_NotebookObject, 
   Optional[Automatic, Automatic]] :=
  notebookObjectStylesheet[nb,
   MatchQ[
    CurrentValue[nb, StyleDefinitions], _String | _FrontEnd`FileName]
   ];
notebookObjectStylesheet[nb_NotebookObject, 
   savedSheet : True | False] :=

  notebookObjectStylesheet[nb, savedSheet] =
   With[{
     sdefs =
      Replace[
       CurrentValue[nb, StyleDefinitions], {
        s : _String | _FrontEnd`FileName :>
         FrontEndExecute@
          FrontEnd`FindFileOnPath[
           If[! StringQ[s], ToFileName@s, s],
           "StyleSheetPath"
           ]
        }]},
    SelectFirst[FrontEndExecute@FrontEnd`ObjectChildren[$FrontEnd],
     If[StringQ@sdefs,
       Quiet@NotebookFileName[#] === sdefs,
       NotebookGet[#] === sdefs
       ] &
     ]
    ];

Then we can use it like so:

default = notebookObjectStylesheet[EvaluationNotebook[]]

NotebookObject[FrontEndObject[LinkObject["k98bv_shm", 3, 1]], 4]

That's the default stylesheet notebook.

Now we can write some editing helper functions:

getCellsForStyle[nb_, styleNames_] :=
  Select[Cells[nb],
   MatchQ[
     Cell[StyleData[Sequence @@ Flatten@{styleNames}], ___]
     ]@*NotebookRead
   ];
applyCellStyleEdits[cells_] :=

  With[{groups = GroupBy[cells, ParentNotebook]},
   KeyValueMap[
     CheckAll[
       With[{nb = #, cs = #2},
        FrontEndExecute@
         FrontEnd`NotebookSuspendScreenUpdates[nb];
        Map[
         Function[
          SelectionMove[#, All, Cell,
           AutoScroll -> False
           ];
          FrontEndTokenExecute[nb, "ToggleShowExpression"]~Do~2;
          ],
         cells
         ];
        FrontEndExecute@
         FrontEnd`NotebookResumeScreenUpdates[nb]
        ],
       FrontEndExecute@
        FrontEnd`NotebookResumeScreenUpdates[nb]
       ] &,
     groups
     ];
   ];
editCellsForStyle[nb_, styleNames_, edits_?OptionQ] :=

 With[{cs = getCellsForStyle[nb, styleNames]},
  SetOptions[#, edits] & /@ cs;
  applyCellStyleEdits[cs]
  ]

And use it like so:

editCellsForStyle[default, "Input",
 FontColor -> Purple
 ]

purple example

And we reset it like so:

editCellsForStyle[default, "Input",
 FontColor -> Inherited
 ]

One nice thing about this, though, is the changes are temporary. We'd have to call NotebookSave on the edited style sheet to get them to be saved permanently.

For instance, I can do something ridiculous like this:

editCellsForStyle[default, "Input",
 FontSize -> 5
 ]

tiny text

But when I quit the front end and restart:

FrontEndTokenExecute@"FrontEndQuitNonInteractive"

Everything is back to normal:

back-to-normal

Moreover, if we want to then delete some collection of styles, it's as simple as this:

deleteCellsForStyle[nb_, styleNames_, edits_?OptionQ] :=

 NotebookDelete@getCellsForStyle[nb, styleNames]
$\endgroup$
0
$\begingroup$

Do it like this: (but this does not wipe two options, see usage):

    WipeOtherNotebooksStylesheet::usage =
    "WipeOtherNotebooksStylesheet[fn]:\n
Wipes the privete stylesheet of the target notebook designated by fn. If the target notebook would be open when the function is activated, one would risk to loose unstored edits during closing. To prevent this, the target notebook is stored when the function finishes.\nIt returns the options after this action.\nCell[StyleData[All," .
        Printout "]..] and Cell[StyleData[All]] can not be wiped this way.";

WipeOtherNotebooksStylesheet[fn_] :=
Module[{nbk      (* notebook handle *)
       ,nsel     (* everything but the defined styles *)
       ,opt      (* target nb's options *)
       ,sd       (* style definitions *)
       }
      ,nbk = NotebookOpen[fn];
       If[nbk == $Failed
         ,Print["WipeOtherNotebooksStylesheet: Wrong Filename: ", fn]; 
             Throw["Wrong filename!"]  (* ===THROW===> *)
            ];
          sd = StyleDefinitions /. Options[nbk];
          If[Head[sd] == Notebook, sd = sd[[1]]];
          nsel = Select[sd
                       ,! MatchQ[#
                                ,Cell[StyleData[x_String /;
                                                StringMatchQ[x
                                                            ,"*"
                                                            ]
                                                ,___
                                                ]
                                     ,___
                                     ]
                                ]&
                       ];  (* Select[nsel
                                    ,!MatchQ[Cell[StyleData["All",___]]]
                                    ]  would return {}
                           *)
       SetOptions[nbk, StyleDefinitions -> nsel];
       opt = Options[nbk];
       NotebookSave[nbk]; (* the nb might have been open before *)
       NotebookClose[nbk];(* this would close it without asking *)
       opt
      ];                  (* WipeOtherNotebooksStylesheet *)
$\endgroup$
3
  • $\begingroup$ Would be nice to have Catch if we have Throw. $\endgroup$
    – Kuba
    Jan 23, 2017 at 19:23
  • $\begingroup$ It was meant to be used like this: Catch[WipeOtherNotebooksStylesheet["nonexisting"]]. If it is called in some nested structure which fails if fed with a wrong filename, Catch would be used one or more levels up. However, you have to acknowledge that "nonexisting" is an non existing file if that happens. - How would you prefer to do error handling in this situation, Kuba? $\endgroup$ Jan 25, 2017 at 16:59
  • $\begingroup$ You can also wipe styles from a notebook's private stylesheet so you don't have to have a saved file. And this allows for easy temporary changes to things like the default style sheet. $\endgroup$
    – b3m2a1
    Aug 22, 2017 at 1:27
0
$\begingroup$

I've finally worked all of my stylesheet code into a package. You load it like so:

Get["http://raw.githubusercontent.com/b3m2a1/mathematica-tools/master/StylesheetEdit.wl"]

Then the relevant function is StyleSheetDelete which you can use like:

StyleSheetNew["ExternalLanguage"]

StyleSheetCells["ExternalLanguage"]

(* {CellObject[165249]} *)

StyleSheetDelete["ExternalLanguage"]

StyleSheetCells["ExternalLanguage"]

(* {} *)
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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