Skip navigation
Currently Being Moderated

doScript (UndoModes) breaks InDesign's Undo (CS4)

Jun 4, 2009 1:24 PM

I wrote a little script. To make sure that I can undo it all in one go, I used:

 

app.doScript(main, undefined, undefined, UndoModes.fastEntireScript,"My script");

 

Once the script completes, InDesign's regular undo is broken. It no longer undoes separate steps, but will only revert to the point before which the script has been run.

 

What can I add at the end of the script to return things to normal?

 

Thanks,

Ariel

 
Replies
  • Currently Being Moderated
    Jun 4, 2009 1:48 PM   in reply to [Ariel]

    If you use try/catch in your script, you should probably use 

    UndoModes.entireScript instead.

     

    The reason is kind of complicated...

     

    HTH,

    Harbs

     
    |
    Mark as:
  • Currently Being Moderated
    Sep 21, 2010 4:09 PM   in reply to Harbs.

    Harbs. wrote:

     

    If you use try/catch in your script, you should probably use 

    UndoModes.entireScript instead.

     

    The reason is kind of complicated...

     

    Hi Harbs,

     

    I would love to have more details on that complicated reason. Can you tell me more?

     

    [For performance purpose, one of my script needs the fastEntireScript mode, but I use a number of try...catch... So?]

     

    Thanks!

     

    Marc

     
    |
    Mark as:
  • Currently Being Moderated
    Sep 22, 2010 12:04 AM   in reply to Marc Autret

    Very simple:

     

    When you catch an error, InDesign rolls back to the last snapshot of the document state (to ensure the document is in a stable state).

     

    What FAST_ENTIRE_SCRIPT does is that it does not take snapshots of the document while the script is running, so the last snapshot is at the start of the script (or in some extreme cases the before you enter certain functions, but I have not figured out how that works).

     

    Therefore if you catch an error, the document state will roll back to the beginning of the script and continue from there. This undoes everything your script did until that point and very likely renders many of your variables invalid. This is not what you want 99% of the time...

     

    Harbs

     
    |
    Mark as:
  • Currently Being Moderated
    Sep 22, 2010 12:07 AM   in reply to Harbs.

    Hmm...

     

    First it was complicated and now it's simple...

     

    I guess it depends on your frame of reference...

     

    Harbs

     
    |
    Mark as:
  • Currently Being Moderated
    Sep 22, 2010 9:29 AM   in reply to Harbs.

    Thanks Harbs. It's not that simple on my frame of reference ;-)

     

    I understand that a try...catch block needs a kind of "restoration point" which involves ID snapshot. So if there is no intermediate snapshot —due to the fastEntireScript mode— we have a problem. But is it supposed here that the app.doScript() call is embedded within a try...catch?

     

    What I don't understand is the precondition of the "undo history bug" mentioned by Thomas Silkjær (http://indesigning.net/indesign-undo-history-ruined-by-doscript).

     

    In other words, is it secure to use app.doScript(myProcess, ScriptLanguage.javascript, undefined, UndoModes.fastEntireScript) as the main statement of my script and to make the try...catch error management within myProcess?

     

    Here is a test that doesn't seem to muddle the undo history up:

     

    var main = function()
    {
         var tf = app.activeDocument.textFrames[0];
         tf.contents = "foo bar";
         
         try{s.nonExistingProperty;}
         catch(_){}
    }

    app.doScript(
         main,
         ScriptLanguage.javascript,
         undefined,
         UndoModes.fastEntireScript
         );

     

    @+

    Marc

     
    |
    Mark as:
  • Currently Being Moderated
    Oct 2, 2010 5:41 PM   in reply to Marc Autret

    Hi Marc,

     

    Last week was a holiday for me...

     

    I have no idea what Thomas's bug is. Would you care to elaborate?

     

    Your script should end without the words "foo bar" in your text frame because it should revert to the beginning of your script. Are you seeing different results?

     

    Hmm. I just tested, and it does not revert the way I said...

     

    It's obviously not as simple as I thought. Maybe it depends on how intensive the script is?

     

    Harbs

     
    |
    Mark as:
  • Currently Being Moderated
    Oct 2, 2010 6:01 PM   in reply to Marc Autret

    I changed yourscript a bit, and it loses the changes:

     

    var main = function()
    {
         var tf = app.activeDocument.textFrames[0];
         tf.contents = "foo bar";
         var x;
         try{
         for(x in tf){
         var a=tf[x];
         }
         }catch(e){}
         
    }
     
    app.doScript(
         main,
         ScriptLanguage.javascript,
         undefined,
         UndoModes.fastEntireScript
         );
     
     
    

     

    There appears to be some threshold where the scripting engine decides that it can't take snapshots...

     

    I'd say that the safest path is to avoid FAST_ENTIRE_SCRIPT entirely when you use try-catch.

     

    Also, I have found that FAST_ENTIRE_SCRIPT is much pickier about what is valid code. I have had more than one instance where I had code which executed fine in regular mode, but failed when run in FAST_ENTIRE_SCRIPT...

     

    Harbs

     
    |
    Mark as:
  • Currently Being Moderated
    Oct 2, 2010 7:43 PM   in reply to Harbs.

    Hi Harbs,

     

    Thanks a lot for your help. I'm really really not familiar with that 'Undo Modes' maze and I'm pretty sure I missed the obvious. My problem is in fact a paradox. I have a complete script which provides two main features —depending on what the user choose in a dialog:

     

    (a) I need Feature_1 to be undoable, and the —safe— UndoModes.entireScript option is fine because it's not a huge process.

     

    (b) However, Feature_2 is a time consuming function which is considerably slowed by the entireScript undo mode. I found that switching my global app.doScript() statement to fastEntireScript undo mode dramatically speeds up the process —as you explained, InDesign doesn't need to take intermediate snapshots during the script progress.

     

    (c) But my script uses try-catch error management, including within Feature_2 code.

     

    So I don't see any solution. I was wondering whether it's possible to embed an app.doScript(... UndoModes.fastEntireScript) statement within a block which is itself executed by app.doScript(... UndoModes.entireScript)... Crazy idea?

     

    [Hope you had a good holiday.]

     

    @+

    Marc

     
    |
    Mark as:
  • Currently Being Moderated
    Oct 3, 2010 12:14 AM   in reply to Marc Autret

    AFAIK, there's no solution other than going through the code and bending over backwards to remove all try/catch statements in you script.

     

    I had a situation similar to yours, and I spent a week going through thousands of lines of code scattered over many, many functions in multiple files, removing any dependence on try/catch. It was a huge headache, and it took me about a week to do, but I did it...

     

    There's very few situations where try/catch is REALLY necessary. It's usually possible to do a ridiculous amount of checking instead...

     

    Harbs

     
    |
    Mark as:
  • Currently Being Moderated
    Oct 3, 2010 12:14 AM   in reply to Marc Autret

    Marc Autret wrote:

     

    [Hope you had a good holiday.]

    Thanks. Yeah, it was great!

     

    Harbs

     
    |
    Mark as:
  • Currently Being Moderated
    Oct 3, 2010 2:58 AM   in reply to Harbs.

    Welcome back Harbs

     

    --

    tomaxxi

     
    |
    Mark as:
  • Currently Being Moderated
    Oct 3, 2010 3:53 AM   in reply to Harbs.

    Harbs. wrote:

     

    AFAIK, there's no solution other than going through the code and bending over backwards to remove all try/catch statements in you script.

     

    (...)

     

    Yeah, I knew you'd end up suggesting this solution ;-)

     

    But I really can't remove all try/catch, because my script is based on several included libraries that themselves use try-catch!

     

    Bad news for me...

     

    @+

    Marc

     
    |
    Mark as:
  • Currently Being Moderated
    Oct 20, 2010 8:13 PM   in reply to Harbs.

    I did go through my script and removed all try/catches. Unfortunately, I ran into the undo bug. What happens is after running a script with fastEntireScript if you do things in InDesign that both have the same "undo name" it will undo both when you press Ctrl+Z.

     

    For example:

     

    1) Run script that has a app.doScript() and is set to fastEntireScript.

     

    2) Move a text frame

     

    3) Move another text frame

     

    4) Press Ctrl+Z, both steps 2&3 will become undone.

     

    I had to go back to using entireScript .

     
    |
    Mark as:
  • Currently Being Moderated
    Oct 21, 2010 9:51 AM   in reply to Fred Goldman

    At this point, I think that only an Adobe developer may explain the internal mechanism of those tricky undo modes and how to prevent the undo bug. It would be really beneficial for scripters!

     

    @+

    Marc

     
    |
    Mark as:
  • Currently Being Moderated
    Oct 21, 2010 12:11 PM   in reply to Marc Autret

    I wonder if the bug is there in CS5, too?

     
    |
    Mark as:
  • Currently Being Moderated
    Oct 21, 2010 1:45 PM   in reply to Marc Autret

    Marc Autret wrote:

     

    At this point, I think that only an Adobe developer may explain...

     

    I asked Jonathan Brown if he has more to add to this and this was his response:

     

    The undo modes feature involves a complicated interaction between the scripting architecture and the command processing architecture. In other words, it would take two Adobe developers to figure out what’s going on to a greater depth than has already been described.

     

    So basically, (for better or for worse) the only way we might find out more is by trial and error.

     

    If anyone can try to reproduce that undo bug with clear steps both in CS4 and CS5, you can either file the bug yourself, or I can do it through the Partner Portal. Chances are it has not been filed yet...

     

    Harbs

     
    |
    Mark as:
  • Currently Being Moderated
    Oct 21, 2010 5:55 PM   in reply to Harbs.

    I tried it in CS4 on my laptop running Vista x86 and on my desktop running Vista x64 and I consistently have found the same bug. Even if the script that is called by doScript() is simply an alert it will ruin the undos when set to fastEntireScript.

     

    However, in CS5 I have unable to produce it. Maybe it was fixed .

     
    |
    Mark as:
  • Currently Being Moderated
    Nov 17, 2010 5:28 AM   in reply to Fred Goldman

    Has anyone any idea how to fix the undo after the fastEntireScript broke it? I have some scripts which really need to use the fastEntireScript option for reasons of efficiency.

     

    I've tried running a second script using a different option to see if it would restore functionality, but no joy as yet.

     

    This is a real shame, as the option to 'suppress' Undo, or to at least put it all in one step, is something we've all wanted for a long time

     

    Mike

     
    |
    Mark as:
  • Currently Being Moderated
    Nov 17, 2010 6:06 AM   in reply to mikewedge

    Changing from fastEntireScript to entireScript doesn't help for you?

     
    |
    Mark as:
  • Currently Being Moderated
    Nov 17, 2010 6:39 AM   in reply to Fred Goldman

    Hi Fred

     

    Yes, that gets around the problem; I was just trying to use FastEntireScript to squeeze the performce as tight as I could. Reckon I'll just have to make do for now

     

    cheers

     

    Mike

     
    |
    Mark as:
  • Currently Being Moderated
    Feb 11, 2011 6:08 PM   in reply to mikewedge

    After further testing, it appears that the fastEntireScript undo mode always disturbs the InDesign history in CS4, regardless of error catching. I don't think that the try...catch block makes fastEntireScript unusable but that fastEntireScript itslef is faulty and makes try...catch unusable.

     

    Run this innocent script in ID CS4:

     

    var func1 = function(){/*noop*/};
    app.doScript(
         func1,
         ScriptLanguage.javascript,
         undefined,
         UndoModes.fastEntireScript
         );
    

     

    Once that's done InDesign sounds unable to restore the normal undo behavior until the next session. A simple test: create two text frames, move the first, move the 2nd, then call Edit / Undo. You see that several undo steps are made at once! And there is no way to get back to normal. The fastEntireScript undo mode causes a kind of offset error on the undo stack or something.

     

    Then I tried different strategies to prevent ID from falling into Undo Hysteria after a fast-entire-script execution. The only solution I found is to enclose the fast-entire-script block within an entire-script block (other modes won't work). Like this:

     

    var myLauncher = function()
         {
         alert('Undo mode:' + app.activeScriptUndoMode); // still in safe zone
     
         app.doScript(
              myFastFunc,
              undefined,
              undefined,
              UndoModes.fastEntireScript, // => dangerous zone
              "MyFastEntireScript");
     
         alert('Undo mode:' + app.activeScriptUndoMode); // safe zone restored
         };
     
    var myFastFunc = function()
         {
         alert('Undo mode:' + app.activeScriptUndoMode); // dangerous zone
         // do something --but please avoid try...catch here
         };
     
    app.doScript(
         myLauncher,
         ScriptLanguage.javascript,
         undefined,
         UndoModes.entireScript, // => safe zone
         "MyEntireScript");
    

     

    If I rely on my tests InDesign returns to normal when the script terminates, i.e. you can undo actions one by one.

     

    What I don't know is whether the fast-entire zone is actually 'fast'.

    Also, it probably remains a very bad idea to allow try...catch within the fast zone.

     

    @+

    Marc

     
    |
    Mark as:
  • Currently Being Moderated
    Aug 22, 2011 7:45 AM   in reply to Marc Autret
     
    |
    Mark as:
  • Currently Being Moderated
    Aug 22, 2011 12:13 PM   in reply to Marc Autret

    That was an excellent write up. And the was a great find with the workaround! Wrapping the fastEntireScript and an entireScript was ingenius.

     
    |
    Mark as:

More Like This

  • Retrieving data ...

Bookmarked By (0)

Answers + Points = Status

  • 10 points awarded for Correct Answers
  • 5 points awarded for Helpful Answers
  • 10,000+ points
  • 1,001-10,000 points
  • 501-1,000 points
  • 5-500 points