2

This post is a continuation of an earlier Question, How to programmatically change CellStyle of all Cells from "Input" to "Code"? but with a different problem. The solution that works best was selected from the given link and set to a function ChangeCellStyle. It works fine when calling it with default values but when reversing the CellStyle so as to undo the changes it does nothing and I cannot figure out why.

Below are two helpers and the stage (top parent function). If you include backup it works fine so please ignore it. However I am not all that confident replace is bug free.

(* helpers *)
ClearAll[backup, replace]

backup[seq_ : "", app_ : "GCS_BACKUP", src_ : NotebookFileName[], tar_ : True] := Module[{ sub = Evaluate["." <> FileExtension[src]], new, dst }, new = app <> Evaluate[ToString[seq]] <> sub; dst = StringReplace[src, sub -> new]; CopyFile[src, dst, OverwriteTarget -> tar]];

replace[objs_, from_, to_] := NotebookWrite[#, Block[{expr = NotebookRead[#]}, Join[expr[[1 ;; 1]], Replace[Rest[expr], from -> to, {1}]]]] & /@ objs;

(* stage *) ClearAll[ChangeCellStyle]

Options[ChangeCellStyle] = {"From" -> "Input", "To" -> "Code", Method -> Automatic, "MIMEType" -> Automatic, OverwriteTarget -> True}; ChangeCellStyle[cells_ : Automatic, bak_ : True, opts : OptionsPattern[]] := Module[{ bk = If[TrueQ[bak], backup[], None], objs = Which[ MemberQ[cells, _CellObject], cells, True, Evaluate[Cells[CellStyle -> OptionValue["From"]]] ] }, Echo[bk, Row[{"backup", Style[" [Rule]", Orange, Bold]}]]; replace[objs, OptionValue["From"], OptionValue["To"]] ];

Both "forward" calling styles work.

nb = EvaluationNotebook[];

(* forward 1 *) ChangeCellStyle[];

(* forward 2 *) cells = Cells[nb, CellStyle -> OptionValue["Input"]]; ChangeCellStyle[cells, From -> "Input", To -> "Code"];

This is what I wish to fix. Attempting to reverse the style changes fails.

(* backwards 1 (undo) *)
cells = Cells[nb, 
  CellStyle -> OptionValue["Code"]]; ChangeCellStyle[cells, 
 From -> "Code", To -> "Input"] 
Jules Manson
  • 2,457
  • 11
  • 19

2 Answers2

5

The issue is that the From-> "Code" option is assigned to the bak_ parameter, rather than being interpreted as an option. You can wrap the parameter in Shortest, or restrict it e.g. to True|False:

ChangeCellStyle[Shortest[cells_ : Automatic], Shortest[bak_ : True], opts : OptionsPattern[]] :=
  Module[...]

ChangeCellStyle[cells_List : Automatic, bak: True|False : True, opts : OptionsPattern[]] := Module[...]

Both give the desired behavior. Note that I have also applied a similar strategy to cells_, to prevent it from "eating up" options if it's not specified.

Lukas Lang
  • 33,963
  • 1
  • 51
  • 97
  • nice catch on the subtle nuances that newer coders like me would miss and i did. lol. if you dont mind me asking how much experience do you have with MMA and what kind of problems do you tackle (mech eng, aero eng, quantum mechanics, electric circuits, etc)? i am always fascinated by other technical fields. anyway thank you so much., :) – Jules Manson Jan 13 '23 at 00:14
  • the 2nd didnt work. did you intend to write it like this ChangeCellStyle[cells_List : Automatic, bak : _True | False : True, opts : OptionsPattern[]]? – Jules Manson Jan 15 '23 at 09:40
  • 1
    @JulesManson There was a closing ] that shouldn't have been there, should be fixed now (note that it really should be bak: True|False : True without the _ - the syntax is name:pattern:default, where the pattern is True|False, i.e. exactly True or False) – Lukas Lang Jan 15 '23 at 10:42
  • thanks for the syntax correction and tip. :-)

    ChangeCellStyle[cells_List : Automatic, bak : True | False : True, opts : OptionsPattern[]]

    – Jules Manson Feb 26 '23 at 05:47
2

I cannot seem to run your code. In any case, your issue may be related to an issue I was having in solving the same problem. I tried creating a function to change the cell style programmatically. It seemed to work but would not work in reverse. The problem in my case is that my code was appending the new cell style, rather than replacing it. It turns out that cells can have more than one cell style, which is strange. I'm not sure how the style is resolved when this happens. You can check your underlying code to see if you are having the same issue. I would see something like "Input" appended after "Code".

In any case, I picked up the following solution in StackExchange somewhere. It works for me, although there may be issues with it that I'm not aware of.

DynamicModule[{xh, yh},
 Row[{
   InputField[Dynamic@xh, String, FieldSize -> 10], "->",
   InputField[Dynamic@yh, String, FieldSize -> 10],
   Button["Go", 
    NotebookPut[
     NotebookGet[SelectedNotebook[]] /. 
      Cell[x_, xh, y___] -> Cell[x, yh, y], InputNotebook[]]]}]]
B flat
  • 5,523
  • 2
  • 14
  • 36