home *** CD-ROM | disk | FTP | other *** search
/ Enter 2006 February / enter-2006-02.iso / files / Illustrator_CS2_ue_TryOut.exe / bridge / Adobe Bridge 1.0.msi / Data1.cab / _0debugger.jsx next >
Encoding:
Text File  |  2005-03-24  |  27.8 KB  |  1,011 lines

  1. /**************************************************************************
  2. *
  3. *  @@@BUILDINFO@@@ 10debugger.jsx 1.0.0.51 20-Feb-2005
  4. *  Copyright 2005 Adobe Systems Incorporated
  5. *  All Rights Reserved.
  6. *
  7. * NOTICE:  All information contained herein is, and remains the property of
  8. * Adobe Systems Incorporated  and its suppliers,  if any.  The intellectual 
  9. * and technical concepts contained herein are proprietary to  Adobe Systems 
  10. * Incorporated  and its suppliers  and may be  covered by U.S.  and Foreign 
  11. * Patents,patents in process,and are protected by trade secret or copyright 
  12. * law.  Dissemination of this  information or reproduction of this material
  13. * is strictly  forbidden  unless prior written permission is  obtained from 
  14. * Adobe Systems Incorporated.
  15. **************************************************************************/
  16.  
  17. // The current debugger contains the debugger that has either been selected
  18. // by the user, or by a request connect command from a target application.
  19.  
  20. var currentDebugger = null;
  21.  
  22. // The own debugger is the fallback when a connect request fails.
  23.  
  24. var ownDebugger = null;
  25.  
  26. /* 
  27. The Debugger object is the core object that talks to the debugging
  28. backend. There is one Debugger object per active connection.
  29. */
  30.  
  31. function Debugger (target, engine)
  32. {
  33.     this.target        = target;        // the target name
  34.     this.engine     = engine;        // the engine name
  35.     this.current    = false;        // true if this is the current debugger for the given target
  36.     this.dynamic    = false;        // true if the engine is created on the fly
  37.     this.waiting    = false;        // true if the engine state is "waiting"
  38.     this.error        = null;            // on runtime errors, the error message
  39.     this.document    = null;            // the doc being debugged
  40.     this.frame        = -1;            // the stack frame we are looking at during debugging
  41.     this.line        = -1;            // the current line
  42.     this.documents    = {};            // active documents collection; properties are script IDs
  43.     this.profileLevel = 0;            // the profiling level
  44.     this.state        = Debugger.INACTIVE;
  45.     this.oldStack    = false;        // for targets with versions <= 3.6.36
  46.  
  47.     Debugger.all.push (this);
  48. }
  49.  
  50. // The documents object holds information about the documents currently being debugged.
  51. // Each property (which is the document's scriptID) contains an object with the following
  52. // properties:
  53. // document:    the Document object
  54. // profData:    the Document object's ProfilerData object
  55. // savedText:   the original text of the document
  56. // The latter property contains the original document text in case the app returned a different
  57. // text for the currently executed script (it may e.g. contain included files).
  58.  
  59. //////////////////////////////////////////////////////////////////////
  60. // Static properties and methods
  61.  
  62. // Debugger status values
  63.  
  64. Debugger.RUNNING            = localize ("$$$/ESToolkit/Toolbar/Engine/State/Running=running");
  65. Debugger.STOPPED            = localize ("$$$/ESToolkit/Toolbar/Engine/State/Stopped=stopped");
  66. Debugger.WAITING            = localize ("$$$/ESToolkit/Toolbar/Engine/State/Waiting=waiting");
  67. Debugger.INACTIVE            = "";
  68.  
  69. // Line flags for editor lines
  70.  
  71. Debugger.BP_DISABLED        = 0x80;        // this line has a BP
  72. Debugger.BP_ENABLED            = 0xC0;        // the BP is enabled
  73. Debugger.BP_COND_DISABLED    = 0xA0;        // this line has a conditional BP
  74. Debugger.BP_COND_ENABLED    = 0xE0;        // the conditional BP is enabled
  75. Debugger.BP_ENABLED_MASK    = 0x40;        // the breakpoint is enabled
  76. Debugger.BP_COND_MASK        = 0x20;        // set for a conditional breakpoint
  77. Debugger.BP_MASK            = 0xE0;        // BP mask
  78. Debugger.VISITED            = 0x08;        // line has been visited
  79. Debugger.COLOR_MASK            = 0x07;        // background color mask
  80. Debugger.CURRENT_COLOR        = 0xFFFF00;    // yellow background
  81. Debugger.ERROR_COLOR        = 0xFF7F7F;    // red background
  82. Debugger.STACK_COLOR        = 0x7FFF7F;    // green background
  83.  
  84. // The list of all debuggers.
  85.  
  86. Debugger.all = [];
  87.  
  88. // The list of all connected applications. This is an object whose
  89. // properties are the BridgeTalk names of all connected apps with
  90. // the value set to true.
  91.  
  92. Debugger.connected = {};
  93.  
  94. // Create my own debugger, but do not connect yet. During startup,
  95. // there may be a connect request from another app which takes precedence.
  96.  
  97. Debugger.createOwn = function()
  98. {
  99.     ownDebugger = new Debugger (BridgeTalk.appSpecifier, "main");
  100.     window.setupEngines (BridgeTalk.appSpecifier);
  101. }
  102.  
  103. // Connect to a target app. This call attempts to launch the target,
  104. // identifies the app as the debugger, collects the list of engines,
  105. // creates the necessary debugger instances, and activates the debugger
  106. // on the first engine returned. The supplied name is the BridgeTalk name.
  107. // If doc and dbgLevel are supplied, the connect request was due to an 
  108. // autoconnect from within Debugger.start(). We need to fire a Start commend
  109. // with these two arguments if present.
  110.  
  111. Debugger.connect = function (target, doc, dbgLevel)
  112. {
  113.     if (!currentDebugger || currentDebugger.target != target)
  114.     {
  115.         BridgeTalk.checkTarget (target);
  116.         var bt = BridgeTalk.create (target, "Connect");
  117.         bt.doc = doc;
  118.         bt.dbgLevel = dbgLevel;
  119.         bt.onOwnResult = function (bt)
  120.         {
  121.             var engines = Debugger.setupConnection (bt);
  122.             // strip the debugger suffix if present
  123.             var target = this.target.replace ("#estk", "");
  124.             if (target != BridgeTalk.appSpecifier)
  125.                 app.toFront();
  126.             if (currentDebugger.target == target && this.doc)
  127.             {
  128.                 if (engines == 1)
  129.                     currentDebugger.start (doc, dbgLevel);
  130.                 else
  131.                 {
  132.                     var displayName = BridgeTalk.getTargetDisplayName (target);
  133.                     messageBox ("$$$/ESToolkit/Alerts/PleaseSwitch=Please select target %1!", displayName);
  134.                     window.engines.active = true;
  135.                 }
  136.             }
  137.         }
  138.         bt.safeSend();
  139.     }
  140. }
  141.  
  142. // Execute a remote connection request.
  143.  
  144. Debugger.remoteConnect = function (bt)
  145. {
  146.     Debugger.setupConnection (bt, true);
  147. }
  148.  
  149. // Disconnect all active debuggers from a target; called when the target goes down.
  150.  
  151. Debugger.disconnect = function (target, quiet)
  152. {
  153.     BridgeTalk.setConnected (target, false);
  154.  
  155.     for (var i = 0; i < Debugger.all.length; i++)
  156.     {
  157.         var dbg = Debugger.all [i];
  158.         if (dbg.target == target)
  159.         {
  160.             if (dbg.status == Debugger.RUNNING)
  161.             {
  162.                 // for the first active debugger on a target, display the error message
  163.                 if (!quiet)
  164.                 {
  165.                     errorBox ("$$$/ESToolkit/Alerts/TargetDead=%1 does not respond anymore!^nThe debugging session will be aborted.",
  166.                               BridgeTalk.getTargetDisplayName (target));
  167.                     quiet = true;
  168.                 }
  169.                 dbg.setStoppedState();
  170.             }
  171.         }
  172.     }
  173.     if (currentDebugger.target == target)
  174.         Debugger.connect (BridgeTalk.appSpecifier);
  175. }
  176.  
  177. // Get all debuggers for a given target.
  178.  
  179. Debugger.getAll = function (target)
  180. {
  181.     var debuggers = [];
  182.     for (var i = 0; i < Debugger.all.length; i++)
  183.     {
  184.         var dbg = Debugger.all [i];
  185.         if (dbg.target == target)
  186.             debuggers.push (dbg);
  187.     }
  188.     return debuggers;
  189. }
  190.  
  191. // Get the current debugger for a given target.
  192.  
  193. Debugger.getCurrent = function (target)
  194. {
  195.     for (var i = 0; i < Debugger.all.length; i++)
  196.     {
  197.         var dbg = Debugger.all [i];
  198.         if (dbg.target == target && dbg.current)
  199.             return dbg;
  200.     }
  201.     return null;
  202. }
  203.  
  204. // Setup a debugger connection by reading the body of the given BT message.
  205. // This message is either a received ConnectRequest message, or the reply
  206. // of a Connect message. This will also activate this debugger. Returns the 
  207. // number of engines discovered.
  208.  
  209. Debugger.setupConnection = function (bt, remote)
  210. {
  211.     var reply  = bt.splitBody();
  212.     var target = bt.sender.replace ("#estk", "");
  213.     var selEngine = bt.headers.Engine;
  214.     var selDebugger = null;
  215.     var engines = 0;
  216.  
  217.     BridgeTalk.setConnected (target, true, bt.headers ["Sender-ID"]);
  218.  
  219.     for (var i = 0; i < reply.length; i++)
  220.     {
  221.         if (reply [i].length == 0)
  222.             // list of supported commands
  223.             break;
  224.         var engine = reply [i][0];
  225.         var status = reply [i][1];
  226.         if (!selEngine)
  227.             selEngine = engine;
  228.         // if we are connected by a remote request, the debugger is always active!
  229.         // create the debugger if not yet present
  230.         var dbg = Debugger.find (target, engine);
  231.         if (!dbg)
  232.             dbg = new Debugger (target, engine);
  233.         // BUG FIX - if an app reports "running" pre x43, set to empty
  234.         if (bt.headers.Version < "3.6.43" && status == "running")
  235.             status = "";
  236.  
  237.         if (dbg.state != Debugger.STOPPED)
  238.           switch (status)
  239.         {
  240.             case "running":    if (dbg.state != Debugger.STOPPED) 
  241.                                 dbg.state = Debugger.RUNNING; break;
  242.             case "active":  dbg.waiting = true;
  243.                             dbg.state = Debugger.WAITING; break;
  244.             default:        dbg.state = Debugger.INACTIVE;
  245.         }
  246.         dbg.dynamic = (status == "dynamic");
  247.         if (engine == selEngine)
  248.             selDebugger = dbg;
  249.         engines++;
  250.     }
  251.     // add the engines
  252.     window.setupEngines (target);
  253.     if (selDebugger)
  254.     {
  255.         if (remote)
  256.         {
  257.             documents.clearProfData();
  258.             selDebugger.profileLevel = 0;
  259.             selDebugger.error        = null;
  260.             selDebugger.documents    = {};
  261.         }
  262.         selDebugger.activate();
  263.     }
  264.     return engines;
  265. }
  266.  
  267. // Find a debugger by target name and engine name
  268.  
  269. Debugger.find = function (target, engine)
  270. {
  271.     // strip the debugger suffix if present
  272.     target = target.replace ("#estk", "");
  273.     for (var i = 0; i < Debugger.all.length; i++)
  274.     {
  275.         var dbg = Debugger.all [i];
  276.         if (dbg.target == target && dbg.engine == engine)
  277.             return dbg;
  278.     }
  279.     return null;
  280. }
  281.  
  282. // Check for any open debug session. If found, ask the user
  283. // if it is OK to stop debugging, and, if so, terminate debugging.
  284.  
  285. Debugger.queryExit = function()
  286. {
  287.     for (var i = 0; i < Debugger.all.length; i++)
  288.     {
  289.         var dbg = Debugger.all [i];
  290.         if (dbg.isActive())
  291.         {
  292.             if (!app.shutdown && !queryBox ("$$$/ESToolkit/Alerts/StopDebugging=Stop debugging?"))
  293.                 return false;
  294.             else
  295.                 break;
  296.         }
  297.     }
  298.     for (i = 0; i < Debugger.all.length; i++)
  299.     {
  300.         var dbg = Debugger.all [i];
  301.         if (dbg.isActive())
  302.             dbg.stop();
  303.     }
  304.     return true;
  305. }
  306.  
  307. //////////////////////////////////////////////////////////////////////
  308. // Methods
  309.  
  310. // Mark this debugger as being active (i.e. its engine is running)
  311.  
  312. Debugger.prototype.activate = function()
  313. {
  314.     if (this != currentDebugger)
  315.     {
  316.         if (currentDebugger)
  317.         {
  318.             currentDebugger.clearProfData();
  319.             // the current debugger for the current target switches
  320.             if (currentDebugger.target == this.target)
  321.                 currentDebugger.current = false;
  322.         }
  323.         currentDebugger = this;
  324.         this.current = true;
  325.         this.getScripts();
  326.         this.getVariables (true);
  327.         this.restoreProfData();
  328.         if (this.document)
  329.             this.setDocument (this.document);
  330.         else
  331.             Document.setCurrentLine (null);
  332.     }
  333.     debugMenu.reflectState();
  334.     window.selectAppAndEngine (this.target, this.engine);
  335.     window.setEngineState (this);
  336.     window.running = this.isActive();
  337. }
  338.  
  339. // Is this debugger active?
  340.  
  341. Debugger.prototype.isActive = function()
  342. {
  343.     return (this.state == Debugger.RUNNING || this.state == Debugger.STOPPED);
  344. }
  345.  
  346. // eval the contents of a document in the target engine
  347.  
  348. Debugger.prototype.start = function (doc, dbgLevel)
  349. {
  350.     // should not happen
  351.     if (this.isActive())
  352.         return;
  353.  
  354.     // first, check the syntax
  355.     var result = doc.checkSyntax (app.includePath);
  356.     if (result != true)
  357.     {
  358.         window.statusLine = result;
  359.         app.beep();
  360.         return;
  361.     }
  362.     
  363.     // Does the doc contain a #target directive?
  364.     var target = app.scanForTarget (doc.text);
  365.     if (target)
  366.     {
  367.         var displayName = BridgeTalk.getTargetDisplayName (target);
  368.         if (!displayName)
  369.         {
  370.             errorBox ("$$$/ESToolkit/Alerts/CannotConnect=Cannot connect to target %1!", target);
  371.             return;
  372.         }
  373.         else if (!currentDebugger || currentDebugger.target != target)
  374.         {
  375.             // Wrong debugger: if there is only one target engine, auto-switch to that target
  376.             var targetDebugger = null;
  377.             for (var i = 0; i < Debugger.all.length; i++)
  378.             {
  379.                 var dbg = Debugger.all [i];
  380.                 if (dbg.target == target)
  381.                 {
  382.                     if (targetDebugger)
  383.                     {
  384.                         // more than one target: we cannot switch
  385.                         targetDebugger = null;
  386.                         break;
  387.                     }
  388.                     targetDebugger = dbg;
  389.                 }
  390.             }
  391.             if (targetDebugger)
  392.             {
  393.                 if (targetDebugger.connected)
  394.                 {
  395.                     targetDebugger.activate();
  396.                     currentDebugger.start (doc, dbgLevel);
  397.                 }
  398.                 else
  399.                     // this also starts the script
  400.                     Debugger.connect (target, doc, dbgLevel);
  401.             }
  402.             else
  403.                 Debugger.connect (target, doc, dbgLevel);
  404.             return;
  405.         }
  406.     }
  407.     if (dbgLevel == undefined)
  408.         dbgLevel = 0;
  409.  
  410.     this.profileLevel = prefs.profileLevel;
  411.     if (this.profileLevel)
  412.         documents.clearProfData();
  413.  
  414.     this.setState (Debugger.RUNNING);
  415.     this.error = null;
  416.     this.clearDocuments();
  417.     
  418.     window.statusLine = "";
  419.  
  420.     // send all known breakpoints in case there are pre-loaded scripts
  421. //    documents.sendBP();
  422.  
  423.     var bt = BridgeTalk.create (this.target, "Eval");
  424.     bt.headers.Engine = this.engine;
  425.     bt.headers.DebugLevel = dbgLevel;
  426.     bt.headers.ScriptID = doc.scriptID;
  427.     bt.headers.Profiling = this.profileLevel;
  428.     if (prefs.dontBreakOnErrors)
  429.         bt.headers.DebugFlags = 1024;
  430.     // add the debugger for onResult
  431.     bt.dbg = this;
  432.     bt.onOwnResult = function (bt)
  433.     {
  434.         this.dbg.stop (true);
  435.         // the reply is datatype,result
  436.         var reply = bt.splitBody();
  437.         print (reply [0][1]);
  438.     }
  439.     bt.onOwnError = function (bt)
  440.     {
  441.         this.dbg.stop (true);
  442.         // display the error message
  443.         // if there is no line number and script name info, use an alert
  444.         // but not if the error is "Execution Halted"
  445.         if (!bt.headers.ScriptID && !bt.headers.Line && bt.headers ["Error-Code"] != -34)
  446.             errorBox (bt.body);
  447.     }
  448.     // send the text if the doc is modified or out of sync with the disk image
  449.     if (doc.modified || doc.outOfSync)
  450.         bt.body = doc.text;
  451.         
  452.     // set up all breakpoints for this document
  453.     doc.attachBP (bt);
  454.     bt.safeSend();
  455.     
  456.     // show that this debugger is active
  457.     this.activate();
  458. }
  459.  
  460. // Stop debugging. Get the final profiling data, the final variables, 
  461. // and clear the stack trace display.
  462.  
  463. Debugger.prototype.stop = function (dontHalt)
  464. {
  465.     // halt the engine
  466.     if (this.isActive())
  467.     {
  468.         if (!dontHalt)
  469.             this.execute ("Halt");
  470.     }
  471.     if (this.profileLevel)
  472.         this.getProfData (true);
  473.     this.setStoppedState();
  474.  
  475.     // no stack display
  476.     window.stack.clear();
  477.     this.getVariables (true);
  478. }
  479.  
  480. // Set the state of the debugger with reflection into the UI.
  481.  
  482. Debugger.prototype.setState = function (state)
  483. {
  484.     // cannot set a state of Inactive if the engine is in Waiting state
  485.     if (this.waiting && state == Debugger.INACTIVE)
  486.         state = Debugger.WAITING;
  487.     this.state = state;
  488.     if (this == currentDebugger)
  489.     {
  490.         window.setEngineState (this);
  491.         debugMenu.reflectState();
  492.     }
  493. }
  494.  
  495. // Put this debugger into a stopped state without sending any messages.
  496.  
  497. Debugger.prototype.setStoppedState = function()
  498. {
  499.     if (currentDebugger == this)
  500.         window.running = false;
  501.     this.setState (Debugger.INACTIVE);
  502.     this.error    = null;
  503.     this.clearDocuments();
  504.     Document.setCurrentLine (null);
  505. }
  506.  
  507. // Get a list of editable scripts from the target and populate the Scripts pane
  508.  
  509. Debugger.prototype.getScripts = function()
  510. {
  511.     window.scripts.getScripts();
  512. }
  513.  
  514. // Do a eval of the supplied text without any breakpoints etc.
  515.  
  516. Debugger.prototype.eval = function (text, noReply)
  517. {
  518.     // this BridgeTalk instance does not carry any script ID
  519.     var bt = BridgeTalk.create (this.target, "Eval");
  520.     bt.headers.Profiling = this.profileLevel;
  521.     bt.headers.Engine = this.engine;
  522.     bt.body = text;
  523.     bt.dbg = this;
  524.     bt.noReply = noReply;
  525.     bt.onResult = function (bt)
  526.     {
  527.         // the reply is datatype,result
  528.         if (!this.noReply)
  529.         {
  530.             var reply = bt.splitBody();
  531.             print (localize ("$$$/ESToolkit/Panes/Console/Result=Result:"), ' ', reply [0][1]);
  532.         }
  533.         this.dbg.getVariables();
  534.         this.destroy();
  535.     }
  536.     bt.onOwnError = function (bt)
  537.     {
  538.         // the reply is the message
  539.         print (localize ("$$$/ESToolkit/Panes/Console/Error=Error:"), ' ', bt.body);
  540.         app.beep();
  541.     }
  542.     bt.safeSend();
  543. }
  544.  
  545. // Get the variables of the current scope.
  546.  
  547. Debugger.prototype.getVariables = function (all)
  548. {
  549.     // get only for engines that are either not dynamic, or that are active
  550.     if (!this.dynamic || this.state != Debugger.INACTIVE)
  551.         window.variables.getVariables (this.target, this.engine, (this.state == Debugger.STOPPED) ? "" : "$.global", all);
  552.     else
  553.         window.variables.clear();
  554. }
  555.  
  556. // Get the profiling data of this execution.
  557.  
  558. Debugger.prototype.getProfData = function (erase)
  559. {
  560.     if (!this.profileLevel)
  561.         return;
  562.     var bt = BridgeTalk.create (this.target, "ProfilerData");
  563.     bt.headers.Engine = this.engine;
  564.     if (erase)
  565.         bt.headers.Clear = "1";
  566.     bt.dbg = this;
  567.     bt.onOwnResult = function (bt)
  568.     {
  569.         if (this.dbg.profileLevel)
  570.         {
  571.             var docObj = null;
  572.             var prevScriptID = null;
  573.  
  574.             var reply = bt.splitBody();
  575.             for (var i = 0; i < reply.length; i++)
  576.             {
  577.                 // line, time, hits, function, module
  578.                 var line = +reply [i][0];
  579.                 var time = +reply [i][1];
  580.                 var hits = +reply [i][2];
  581.                 // var func =  reply [i][3];
  582.                 var scriptID = reply [i][4];
  583.                 // this is only transmitted on change
  584.                 if (scriptID)
  585.                 {
  586.                     // get that doc
  587.                     if (!docObj || prevScriptID != scriptID)
  588.                     {
  589.                         docObj = this.dbg.documents [scriptID];
  590.                         if (!docObj)
  591.                         {
  592.                             doc = documents.find (scriptID);
  593.                             if (!doc)
  594.                                 continue;    // doc seems to be closed already
  595.                             docObj = this.dbg.documents [scriptID] = { document:doc, line:-1 };
  596.                         }
  597.                         // set the profiler data for the previous doc
  598.                         if (prevScriptID)
  599.                             this.dbg.restoreProfData (prevScriptID);
  600.                         prevScriptID = scriptID;
  601.                     }
  602.                 }
  603.                 if (docObj)
  604.                 {
  605.                     if (!docObj.profData)
  606.                         docObj.profData = new ProfilerData;
  607.                     docObj.profData.add (line, hits, time);
  608.                 }
  609.             }
  610.             // show for the last doc
  611.             if (prevScriptID)
  612.                 this.dbg.restoreProfData (prevScriptID);
  613.         }
  614.     }
  615.     bt.safeSend();
  616. }
  617.  
  618. // Clear the profiling data for this debugger during deactivation.
  619. // If the script ID is given, just restore the data for the given document.
  620.  
  621. Debugger.prototype.clearProfData = function (scriptID)
  622. {
  623.     if (this.profileLevel)
  624.     {
  625.         if (scriptID)
  626.         {
  627.             // for a specific document
  628.             var docObj = this.documents [scriptID];
  629.             if (docObj)
  630.                 docObj.document.clearProfData();
  631.         }
  632.         else
  633.         {
  634.             for (var scriptID in this.documents)
  635.                 this.clearProfData (scriptID);
  636.         }
  637.     }
  638. }
  639.  
  640. // Restore the code profiler data for this debugger during activation.
  641. // If the script ID is given, just restore data for the given document.
  642.  
  643. Debugger.prototype.restoreProfData = function (scriptID)
  644. {
  645.     if (this.profileLevel)
  646.     {
  647.         if (scriptID)
  648.         {
  649.             // for a specific document
  650.             var docObj = this.documents [scriptID];
  651.             if (docObj)
  652.                 docObj.document.profileData = docObj.profData;
  653.         }
  654.         else
  655.         {
  656.             for (var scriptID in this.documents)
  657.                 this.restoreProfData (scriptID);
  658.         }
  659.     }
  660. }
  661.  
  662. // Get the help tip text for the given text.
  663.  
  664. Debugger.prototype.getHelpTip = function (doc, line, text)
  665. {
  666.     // Can only do help tips if not running
  667.     if (this.dynamic || (this.state != Debugger.RUNNING))
  668.     {
  669.         doc.helpTip = "";
  670.         return;
  671.     }
  672.  
  673.     if (this.error && line == this.line)
  674.         // display the error
  675.         doc.helpTip = this.error;
  676.     else if (text.length && Document.checkSyntax (text) == true)
  677.     {
  678.         // we create a simple Eval command and ignore any errors
  679.         var bt = BridgeTalk.create (this.target, "Eval");
  680.         bt.headers.Engine = this.engine;
  681.         // we want the target to walk the stack until we have a result
  682.         bt.headers.WalkStack = 1;
  683.         // no script ID - we supply the script on the fly
  684.         bt.doc  = doc;
  685.         bt.text = text;
  686.         bt.dbg  = this;
  687.         // the result handler creates something like 'type name = value'
  688.         // and sets the help tip
  689.         bt.onOwnResult = function (bt) 
  690.         {
  691.             // the doc attached to the BridgeTalk instance
  692.             var doc = this.doc;
  693.             if (doc)
  694.             {
  695.                 // the reply of eval is datatype,result
  696.                 var reply = bt.splitBody();
  697.                 var dataType = reply [0][0];
  698.                 var result   = reply [0][1];
  699.                 if (dataType == "Function")
  700.                     text = dataType + ' ' + this.text;
  701.                 else if (dataType != "undefined")
  702.                 {
  703.                     if (dataType == "string")
  704.                     {
  705.                         result = '"' + app.escape (result) + '"';
  706.                         // Truncate a string after 20 characters
  707.                         if (result.length > 20)
  708.                             result = result.substr (0, 20) + '"...';
  709.                     }
  710.                     text = dataType + ' ' + this.text + ' = ' + result;
  711.                 }
  712.                 else if (this.text == "undefined")
  713.                     text = "";
  714.                 doc.helpTip = text;
  715.             }
  716.         }
  717.         // the error handler displays the error
  718.         bt.onOwnError = function (bt)
  719.         {
  720.             // the doc attached to the BridgeTalk instance
  721.             if (this.doc)
  722.                 this.doc.helpTip = bt.body;
  723.         }
  724.         bt.body = text;
  725.         bt.safeSend();
  726.     }
  727.     else
  728.         doc.helpTip = "";
  729. }
  730.  
  731. // Continue the execution after a breakpoint.
  732. // If the debugger is inactive, start a session.
  733.  
  734. Debugger.prototype.doContinue = function (doc, dbgLevel)
  735. {
  736.     if (dbgLevel == undefined)
  737.         dbgLevel = 1;
  738.  
  739.     window.statusLine = "";
  740.  
  741.     if (this.state == Debugger.RUNNING)
  742.         return;
  743.  
  744.     if (this.state == Debugger.STOPPED)
  745.     {
  746.         // clear the current line
  747.         Document.setCurrentLine (null);
  748.         this.execute ("Continue");
  749.     }
  750.     else
  751.     {
  752.         // execute the given document
  753.         // first, check the syntax
  754.         var result = doc.checkSyntax (app.includePath);
  755.         if (result == true)
  756.             // if OK, send over to the target
  757.             this.start (doc, dbgLevel);
  758.         else
  759.         {
  760.             // otherwise, display the error and beep
  761.             window.statusLine = result;
  762.             app.beep();
  763.         }
  764.     }
  765. }
  766.  
  767. // Start/continue debugging by issuing the given command if the debugger is active.
  768.  
  769. Debugger.prototype.execute = function (cmd)
  770. {
  771.     if (cmd == "Continue" && this.state != Debugger.STOPPED)
  772.         return;
  773.         
  774.     var bt = BridgeTalk.create (this.target, cmd);
  775.     bt.headers.Engine = this.engine;
  776.     bt.headers.Profiling = this.profileLevel;
  777.     bt.headers.IgnoreErrors = 0;
  778.     if (prefs.dontBreakOnErrors)
  779.         bt.headers.DebugFlags = 1024;
  780.     bt.dbg = this;
  781.     if (this.document)    // the doc may not be there if there was a load error
  782.         bt.headers.ScriptID = this.document.scriptID;
  783.  
  784.     // ask whether to clear any runtime error first
  785.     if (cmd != "Halt")
  786.     {
  787.         if (this.error && queryBox ("$$$/ESToolkit/Alerts/ClearErrors=Clear runtime error?"))
  788.             bt.headers.IgnoreErrors = 1;
  789.         if (this.document)
  790.             // re-attach existing breakpoints
  791.             this.document.attachBP (bt);
  792.     }
  793.     this.setState (Debugger.RUNNING);
  794.     this.error = null;
  795.     bt.safeSend();
  796.     // Indicate the execution by switching the document to front
  797.     if (this.document)
  798.         document = this.document;
  799. }
  800.  
  801. // Load a script from the target.
  802.  
  803. Debugger.prototype.loadScript = function (scriptID)
  804. {
  805.     window.scripts.loadScript (this.target, this.engine, ScriptID, 
  806.                             BridgeTalk.getTargetDisplayName (this.target), this);
  807. }
  808.  
  809. // Scroll the current document to the current line
  810.  
  811. Debugger.prototype.showNextStatement = function()
  812. {
  813.     if (this.state == Debugger.STOPPED)
  814.         window.stack.switchToBottom();
  815. }
  816.  
  817. // In halt mode, switch to the given stack frame
  818.  
  819. Debugger.prototype.switchFrame = function (frame)
  820. {
  821.     var bt = BridgeTalk.create (this.target, "SwitchFrame");
  822.     bt.headers.Engine = this.engine;
  823.     if (this.oldStack)
  824.         frame = window.stack.output.items.length - frame;
  825.     bt.body = frame;
  826.     bt.safeSend();
  827. }
  828.  
  829. // Process a received message
  830.  
  831. Debugger.prototype.processMsg = function (bt)
  832. {
  833.     switch (bt.headers.Command)
  834.     {
  835.         case "Print":        // print msg to console
  836.             window.console.write (bt.body);
  837.             break;
  838.         case "Breakpoints":    // list of moved or removed breakpoints
  839.             var doc = documents.find (bt.headers.ScriptID);
  840.             if (doc)
  841.                 doc.updateBP (bt);
  842.             break;
  843.         case "Error":    // runtime error
  844.             this.error = bt.headers.ErrorMessage.replace (/\n/g, " ");
  845.             print (this.error);
  846.             // if the debugger is active, this is a halt at a throw
  847.             if (this.state == Debugger.RUNNING && bt.headers.ErrorCode == 54)
  848.                 this.error = localize ("$$$/ESToolkit/Messages/ExceptionThrown=JavaScript exception thrown");
  849.             window.statusLine = this.error;
  850.             // fall thru
  851.         case "Break":    // breakpoint hit
  852.         case "Frame":    // stack frame changed
  853.             app.toFront();
  854.             this.setState (Debugger.STOPPED);
  855.             window.running = true;
  856.             this.line = parseInt (bt.headers.CurrentLine) - parseInt (bt.headers.FirstLine);
  857.             this.frame = parseInt (bt.headers.Frame);
  858.             var frames = parseInt (bt.headers.Frames);
  859.             var source = null;
  860.  
  861.             if (bt.headers.Command != "Frame")
  862.             {
  863.                 // the body contains the stack trace, a newline, and the source
  864.                 var srcStart = bt.body.indexOf ("\n\n");
  865.                 var stackTrace = bt.body;
  866.                 if (srcStart >= 0)
  867.                 {
  868.                     stackTrace = bt.body.substr (0, srcStart + 1);
  869.                     source = bt.body.substr (srcStart + 2);
  870.                 }
  871.                 window.stack.update (stackTrace);
  872.             }
  873.             // set up the document
  874.             var doc = this.document;
  875.             if (!doc || doc.scriptID != bt.headers.ScriptID)
  876.             {
  877.                 doc = documents.find (bt.headers.ScriptID);
  878.                 if (doc)
  879.                 {
  880.                     // we have the doc on display; make sure it displays the right thing
  881.                     if (source && doc.text != source)
  882.                     {
  883.                         doc.savedText = doc.text;
  884.                         doc.text      = source;
  885.                         window.breakpoints.update();
  886.                     }
  887.                 }
  888.                 else
  889.                 {
  890.                     // no doc yet - it came from the target
  891.                     if (source)        // supplied by break
  892.                     {
  893.                         doc = Document.create (this.title, source, bt.headers.ScriptID);
  894.                     }
  895.                     else
  896.                     {
  897.                         // no source supplied (pre-x41): set off an async get script request
  898.                         window.scripts.loadScript (bt.headers.ScriptID);
  899.                         // may be there already...
  900.                         doc = documents.find (bt.headers.ScriptID);
  901.                     }
  902.                 }
  903.             }
  904.             if (doc)
  905.                 this.setDocument (doc);
  906.             // Get local variables
  907.             this.getVariables (true);
  908.             // and get the profiler data
  909.             if (this.profileLevel)
  910.                 this.getProfData (false);
  911.             // execute a delayed toFront to avoid a deadlock
  912.             app.scheduleTask ("app.toFront()", 1, false);
  913.             break;
  914.  
  915.         case "Exit":
  916.             this.stop (true);
  917.             break;
  918.     }
  919. }
  920.  
  921. // Set the current document and highlighting.
  922.  
  923. Debugger.prototype.setDocument = function (doc)
  924. {
  925.     var color = Debugger.STACK_COLOR;
  926.     var errorMsg = "";
  927.     if (this.frame == 0)
  928.     {
  929.         color = Debugger.CURRENT_COLOR;
  930.         if (this.error)
  931.         {
  932.             color = Debugger.ERROR_COLOR;
  933.             errorMsg = this.error;
  934.             app.beep();
  935.         }
  936.     }
  937.     window.statusLine = errorMsg;
  938.  
  939.     Document.setCurrentLine (doc, this.line, color);
  940.     // scroll to that line
  941.     doc.setSelection (doc.lineToOffset (this.line), 0, true);
  942.     // Add the doc to my documents list if not present
  943.     var docObj = this.documents [doc.scriptID];
  944.     if (!docObj)
  945.         this.documents [doc.scriptID] = docObj = { document:doc, profData:null };
  946.     // bring the document to front
  947.     if (this.document != doc)
  948.         this.document = doc;
  949.     if (doc)
  950.         document = doc;
  951. }
  952.  
  953. // Remove a document from the debugger because it is about to being closed.
  954.  
  955. Debugger.prototype.closeDocument = function (doc)
  956. {
  957.     delete this.documents [doc.scriptID];
  958.     if (this.document == doc)
  959.         this.document = null;
  960. }
  961.  
  962. // Check if the given document is actively being debugged.
  963.  
  964. Debugger.prototype.isDocumentActive = function (doc)
  965. {
  966.     return (this.isActive()
  967.         &&  this.documents [doc.scriptID]
  968.         && (this.documents [doc.scriptID].document == doc));
  969. }
  970.  
  971. // Erase all documents.
  972.  
  973. Debugger.prototype.clearDocuments = function()
  974. {
  975.     this.document    =
  976.     this.lines        = null;
  977.     // restore any saved text
  978.     for (var scriptID in this.documents)
  979.     {
  980.         var doc = this.documents [scriptID].document;
  981.         if (doc)
  982.         {
  983.             // THIS IS A TEMP FIX: check the current text for containing
  984.             // an included file. Only then it is necessary to reload the doc
  985.             // after a debug session.
  986.             var text = doc.text;
  987.             doc.containsInclude = (text.indexOf ("// +++++ #include ") >= 0
  988.                                 && text.indexOf ("// ----- #include ") > 0);
  989.             if (doc.savedText)
  990.             {
  991.                 // the doc was here before any break/error occured
  992.                 // restore the saved text if different
  993.                 if (text != doc.savedText)
  994.                 {
  995.                     doc.text = doc.savedText;
  996.                     window.breakpoints.update();
  997.                 }
  998.                 delete doc.savedText;
  999.             }
  1000.             else
  1001.             {
  1002.                 // the doc arrived via a break/error
  1003.                 if (doc.containsInclude)
  1004.                     // need to grab the original document
  1005.                     window.scripts.loadScript (doc.scriptID);
  1006.             }
  1007.         }
  1008.     }
  1009.     this.documents    = {};
  1010. }
  1011.