ExtendScript Debugger Extension for VS CodeA VS Code Extension that enables debugging ExtendScript scripts and extensions in Adobe’s ExtendScript-enabled applications.
Supported features
¹ Changes to the Caught Exceptions setting while a script is running or stopped at a breakpoint will only apply to scopes created after the setting is changed. Unsupported Features
Getting StartedInstallationInstall the extension through the usual means. The extension requires VS Code v1.62 or newer. Migration from V1 VersionsThe ExtendScript Debugger V2 is a complete rewrite of the V1 version. The internals received a complete overhaul that substantially increased stability, performance, flexibility, and improved compatibility with native VS Code features. As a result of this overhaul, the launch configuration properties have changed. The following is a table of properties that have been renamed:
The Additionally, the manner in which the extension operates has changed dramatically. It is highly recommended that you read the following section as it provides an overview of how to use this extension with three common use cases. Using the DebuggerThis extension was designed to support a wide variety of use cases. Three common use cases are outlined below to provide guidance on how certain features may be used. Running a ScriptThe extension supports running (evaluating) a script in a host application without an active debug session. This functionality may be triggered via the Debugging a ScriptThe most direct way to debug a script in the extension is to start a debug session configured with a Debugging Event CallbacksDebugging ExtendScript triggered via a callback (e.g. with ScriptUI or CEP) requires that the debugger be connected when that script is run. A To debug ExtendScript triggered by callbacks, start a debug session configured with an Additional notes:
Debugger ConfigurationThe ExtendScript Debugger is capable of debugging with and without a standard launch configuration. Zero ConfigurationIf you have not yet defined a When you select "ExtendScript", you will be asked to select a Debugging Mode. Once you have made your choice, simply select your target host application and, if applicable, the target engine and the debug session will start. Launch ConfigurationSetting up a launch configuration allows you to simplify and customize the process of starting a debug session. To start, please follow the standard steps to initialize a launch configuration. When you add a new ExtendScript configuration to your
With the configuration above, you can select the "Attach To ExtendScript Engine" option in VS Code's Debug and Run view and initiate a debug session. Because no host application is specified, the extension will look up installed applications and show a list from which you may select a target. If your selected application is running and supports multiple engines, the extension will then ask which engine should be debugged. Once your selections are made, the debug session will begin. See the "Advanced Configuration" section below for an explanation of available configuration options. Attach and Launch Mode SupportVS Code supports two debug session request types:
The main difference between Recommended Configuration NamesVS Code currently uses a “play” button for both Compound Launch ConfigurationsThe ExtendScript Debugger extension supports Compound Launch Configurations. Scenarios where this may be of interest include:
Please keep in mind that the Advanced ConfigurationThe following configuration options are accepted by both
The following configuration options are accepted by
Notes:
DebuggingStarting an ExtendScript
Any breakpoint, error, or exception encountered while an ExtendScript debug session is active will cause VS Code to show the debug state and enable interacting with the host application. The above does not apply to Remote DebuggingThe ExtendScript Debugger extension does not currently support Remote Debugging. Identifying Application SpecifiersEvery Adobe application has a unique application specifier. This extension most commonly refers to them with the name VS Code CommandsThe ExtendScript Debugger extension adds the following Commands to VS Code:
These commands may be triggered from the Command Palette or by custom key bindings. The key bindings approach provides access to several configuration options for the Evaluate Script in HostThe ExtendScript Debugger extension provides an When triggered, the command will show a list of installed host applications from which to select a target. If the host application has multiple ExtendScript engines running, a second list showing these options will appear. After the application and engine have been selected, the contents of the currently active editor will be sent to the host application for evaluation. Notes:
Custom Key Binding ArgumentsThe most flexible way to trigger the The command string is
Example of a configured key binding:
When triggered, the command above would cause the contents of the currently active editor to be sent to the "MyCoordinator" engine in InDesign and, if a debug session was active, pause on the first executable line of the script. Notes:
Evaluate Script in Attached HostThe
The command string is Halt Script in HostThe The command string is Clear Error HighlightsTriggering the The command string is Export to JSXBinYou can export your The command string is VS Code Status Bar ButtonsThe ExtendScript Debugger extension adds two new buttons to the Status Bar that appear/disappear based on context. Eval in Adobe... ButtonThis button appears when a document either:
is focused. Clicking this button triggers the When an Halt in Adobe... ButtonThis button appears when a script evaluation is triggered from within VS Code. If only a single evaluation process is actively running, then the button will read Halt in Adobe [name of application] (engine)... and clicking it will immediately halt that evaluation process. If more than one evaluation process is active, then the button will read Halt in Adobe... and clicking it will open a list showing all active evaluation processes. Selecting a process from this list will cause that process to halt. Batch Export to JSXBinBy using the
InDesign Server (or When Host Applications Go Rogue)During installation InDesign Server registers itself incorrectly for communication with other applications (including debuggers). The result is that the debugger is able to access certain information about the application but it fails to make any connections to running instances. To correct for this, the ExtendScript Debugger contains several configuration options and settings to enable the extension's features to correctly interface with InDesign Server instances. The ExtendScript Debugger extension supports per-configuration properties and "global" settings to work around the issue. The
|
Property | Type | Description | Default Value |
---|---|---|---|
appSpecRegExp |
string | A JavaScript regular expression value that is used to test against “Host Application Specifier” values for applicability. This applies to any custom hostAppSpecifier used in either debug configurations or custom key binding arguments. Proper declaration of the regular expression will allow custom application instances to resolve as expected. |
"" |
registeredSpecifier |
string | The specifier that the host application registers for itself during installation. | "" |
commsSpecifier |
string | The specifier by which the "default" application instance will communicate. | "" |
Taken together, these properties constitute two “sets” of information:
- Specifying the
appSpecRegExp
andregisteredSpecifier
values will effectively add theregisteredSpecifier
property to any debug configuration or key binding argument whereappSpecRegExp
matches thehostAppSpecifier
. - Specifying the
commsSpecifier
andregisteredSpecifier
values will enable the baseEvaluate Script in Host...
command and Eval in Adobe... button to work with the default instance of the specified application.
Example:
"extendscript.advanced.applicationSpecifierOverrides": [
{
"appSpecRegExp": "indesignserver[_a-z0-9]*-17",
"registeredSpecifier": "indesignserver-17.0",
"commsSpecifier": "indesignserver-17.064"
}
]
The appSpecRegExp
in the example above will successfully match against a hostAppSpecifier
with value "indesignserver_myconfig-17.064" and will instruct any configuration in which it was found to use the registeredSpecifier
value of "indesignserver-17.0". Additionally, if the Evaluate Script in Host...
command is run without custom arguments, then the extension will match the registeredSpecifier
value of "indesignserver-17.0" against the specifier it automatically uses, find that they are the same, and then use the commsSpecifier
value of "indesignserver-17.064" for communication. If a "default" InDesign Server 2022 instance is running, then the script evaluation process will proceed as expected.
Notes:
- This feature can be used to point the Eval in Adobe... button and base
Evaluate Script in Host...
command to a specific instance. This is only recommended if you always use the same application instance (e.g. InDesign Server port and configuration settings). In such cases, simply specify the full instance specifier for thecommsSpecifier
property.
Common Extensibility Platform (CEP)
CEP extensions run scripts in one of two separate contexts:
- An ExtendScript engine. This engine is provided by the host application and supports the host application's DOM.
- A JavaScript engine. This engine is provided by CEF (which is part of the CEP runtime) and supports the HTML DOM used for the extension's UI.
Of these two contexts (and where supported by the host application), the ExtendScript Debugger extension can be used to debug scripts run in the ExtendScript engine context (#1 above).
NOTE: The JavaScript engine context (#2 above) can be debugged using VS Code's built-in JavaScript debugger (see here for instructions to enable debugging this context). Once configured properly, both contexts can be debugged simultaneously using a Compound Launch Configuration.
Unfortunately, no two host applications implement the ExtendScript engine context in the same way. Some are easy to debug, some require special configuration to work with, and some (e.g. Photoshop) simply do not support debugging CEP ExtendScript engines.
This section describes how to use the ExtendScript Debugger extension to debug CEP ExtendScript contexts where such functionality is supported by the host application.
General CEP Debugging Notes
This section outlines certain topics relevant to debugging CEP ExtendScript contexts.
Loading Scripts
There are three different ways to ask a Host Application to evaluate ExtendScript scripts in CEP:
- The CSXS Manifest's
<ScriptPath>
Element. - The
//@include
Preprocessor Directive. - The
$.evalFile()
Function.
Loading a script with option #1 treats the file as an unnamed script. As suggested here:
An unnamed script is assigned a unique name generated from a number.
NOTE: Some host applications don't even assign a number for scripts loaded in this manner. The script's name evaluates to the empty string.
Such scripts are effectively anonymous scripts and complicate the debugging experience. Unfortunately, when a breakpoint or exception is encountered in such a script, the ExtendScript Debugger extension has no way to connect that message to a file in the project. In such circumstances, a new unsaved file will be shown with the break state.
Scripts loaded with either option #2 or #3 as listed above do not suffer from this issue. In these circumstances, host applications provide the ExtendScript Debugger extension with the information required to connect breakpoints or exceptions to the correct source file in the project and the debugger will operate as expected.
Please see the following sections for examples on how to load CEP ExtendScript scripts in ways that support an improved debugging experience.
Treating the <ScriptPath>
Script as a Loader
In this scenario, you might create a file called "loader.jsx" and specify the file in your CSXS Manifest's <ScriptPath>
. This file itself would have the same problem outlined above. However, the purpose of this script is simply to load the scripts that actually contain your business logic.
Note that the <ScriptPath>
script is not automatically invoked by the host application by default. One event that causes the evaluation of this script is when CSInterface.evalScript()
is called for the first time. There may be other events that also trigger the specified script to evaluate.
Important Note: Photoshop (amongst others?) does not support loading scripts in this manner. Attempts to process other files from the one specified within the
<ScriptPath>
element will fail. This appears to be documented here. Photoshop also does not support debugging CEP ExtendScript.
There are two ways to use this approach:
- Preprocessor directives. Scripts loaded using the
//@include
preprocessor directive maintain all of the information necessary to communicate with the debugger. Example://@include "helloworld.jsx" //@include "someotherscript.jsx"
- Using the
$.evalFile()
function. Scripts loaded using the$.evalFile()
function maintain all of the information necessary to communicate with the debugger. Example:$.evalFile($.includePath + "/helloworld.jsx"); $.evalFile($.includePath + "/someotherscript.jsx");
Loading ExtendScript from the JavaScript Context
In this scenario, you trigger the $.evalFile()
function from the browser context via CEP's CSInterface.evalScript()
function. For this option, you might add the following logic to a <script>
block in your extension's HTML somewhere:
const csInterface = new CSInterface();
// Use the extension path reported by the CSInterface.
const path = csInterface.getSystemPath(SystemPath.EXTENSION);
csInterface.evalScript(`$.evalFile("${path}/host/helloworld.jsx")`);
csInterface.evalScript(`$.evalFile("${path}/host/someotherscript.jsx")`);
Or, alternatively (for non-Photoshop [and possibly others?] applications):
const csInterface = new CSInterface();
// Use the include path set for the CEP's ExtendScript context.
csInterface.evalScript(`$.evalFile($.includePath + "/host/helloworld.jsx")`);
csInterface.evalScript(`$.evalFile($.includePath + "/host/someotherscript.jsx")`);
Important Note: Photoshop (amongst others?) does not support the second alternative. The value of
$.includePath
resolves to the empty string.
Reloading CEP Extensions and ExtendScript
Restarting a CEP extension will also cause it to reevaluate the ExtendScript. Another way to reevaluate the ExtendScript is to use the ExtendScript Debugger extension's various methods of running a script. Note that this may cause oddities as the ExtendScript engine itself isn't reset - you're just overwriting the existing variable and function definitions. This can cause surprising issues if you're not careful.
Manually Enabling Debugging
Some host applications run their CEP ExtendScript engine in a manner that constantly resets the "debug level" of the engine to "No Debugging". When this happens, an attached debug session may appear to ignore breakpoints and exceptions. Fortunately, it is possible to work around this issue by manually setting the debug level of the ExtendScript engine with the $.level
property. Setting this property to either 1
or 2
will reenable the debugging features of the engine.
There are two approaches to manually adjusting the debug level so that you can debug your CEP callback scripts. Depending upon your workflow, one of these may be more flexible for you than the other:
- Set
$.level
inside the ExtendScript callback function. With this approach, you simply set the value at the top of the function you wish to debug. See:function DoSomething() { $.level = 1; // Breakpoints will work here. }
- Set the
$.level
when calling the ExtendScript callback function. ExtendScript functions triggered from CEP browser contexts use theCSInterface.evalScript()
API. We can set the$.level
value from within this interface as follows:csInterface.evalScript(`$.level = 1; DoSomething();`);
Host Application Specific Notes
This section provides host application-specific details about CEP ExtendScript engines and their quirks (where possible). The list of host applications is non-exhaustive.
Notes about the "Basic Details" in the sections below:
- The "Name of
<ScriptPath>
Script" detail will be either "[None]" or "[Numerical]". These are both anonymous but have distinct implications on how the files appear when encountered by the debugger. - The "
<ScriptPath>
Script Can Include Files" detail refers to whether or not the script can be used as a loader script.
After Effects
Basic Details:
- Name of
<ScriptPath>
Script: [Numerical] - Name of Engine:
main
<ScriptPath>
Script Can Include Files: Yes
Quirks:
- After Effects requires that you manually set
$.level = 1
in order to handle debug breakpoints in callback sections. - Adjusting breakpoints in VS Code's interface while a debug session is attached will also cause the next breakpoint encountered to be triggered. This is temporary however: subsequent calls to the same function with the existing breakpoint will not be triggered.
- This is due the fact that adjusting breakpoints effectively sets
$.level = 1
for the next script evaluation.
- This is due the fact that adjusting breakpoints effectively sets
Audition
Basic Details:
- Name of
<ScriptPath>
Script: [None] - Name of Engine: The value of the
Id
attribute of theExtension
CSXS manifest element. <ScriptPath>
Script Can Include Files: Yes
Quirks:
- Specifying a custom engine with the
Engine="EngineName"
attribute of the<ScriptPath>
CSXS manifest element will cause the CEP extension's ExtendScript context to fail to start altogether. - CEP Extensions in Audition are automatically assigned custom debuggable engines with a name that matches the Extension ID specified in the CSXS manifest (e.g.
com.test.extension
).- Attaching a debug session to such an engine enables all debugging capabilities.
- These engines will shut down when the CEP extension is closed. When this happens, an attached debug session will automatically end.
Illustrator
Basic Details:
- Name of
<ScriptPath>
Script: [Numerical] - Name of Engine: Depends on time of initialization and whether or not the extension was the first to initialize an engine.
- Welcome Screen and First to Init:
transient
- After Welcome Screen or Not First to Init: [None]
- Welcome Screen and First to Init:
<ScriptPath>
Script Can Include Files: Yes
Quirks:
- Illustrator runs CEP ExtendScript in one of two different engine contexts. Which engine context the script is run in depends upon startup timing. Specifically:
- If the CEP extension is started before a file is opened and the "Welcome to Illustrator" window is still open, then the extension's ExtendScript will run in an engine named
transient
. This engine does not exist until a CEP extension is run that also triggers ExtendScript evaluation (e.g. viaCSInterface.evalScript()
). Once the engine exists, it is possible to connect a debug session with the ExtendScript Debugger extension. Restarting the extension will not change its association with thetransient
engine.- This only applies to the first CEP extension started. Any subsequent extension started will work as though it was started after a file is opened. As such, only a single CEP extension's ExtendScript will be debuggable during any single run of Illustrator.
- If the CEP extension is started after a file is opened and the standard editing interface is visible, then the extension's ExtendScript will run in an engine named
""
(the empty string). This is effectively a private, nameless engine and cannot be debugged.
- If the CEP extension is started before a file is opened and the "Welcome to Illustrator" window is still open, then the extension's ExtendScript will run in an engine named
- Illustrator requires that you manually set
$.level = 1
in order to handle debug breakpoints in callback sections.
InDesign
Basic Details:
- Name of
<ScriptPath>
Script: [None] - Name of Engine: Depends upon whether the
Engine
attribute of the<ScriptPath>
CSXS manifest element is defined.- Defined: The value specified in the
Engine
attribute. - Not Defined:
{EXTENSION_ID}_Engine_Id
, where{EXTENSION_ID}
is the value of theId
attribute of theExtension
CSXS manifest element.
- Defined: The value specified in the
<ScriptPath>
Script Can Include Files: Yes
Quirks:
- Debugging CEP with InDesign requires that you connect the debugger to the engine before you start your extension. This requires that you create a custom
attach
mode launch configuration that targets the engine that the extension will use. You would then attach to InDesign before starting up the CEP extension. If you accidentally start your CEP extension before starting the debug session, you must restart InDesign. A configuration for the engine specified above might look like:{ "type": "extendscript-debug", "request": "attach", "name": "Attach to My CEP Engine", "hostAppSpecifier": "indesign-17.064", // By default (where the Extension ID specified in the CSXS Manifest is "com.test.extension"): "engineName": "com.test.extension_Engine_Id", // Or if the manifest contains <ScriptPath Engine="My CEP Engine">: // "engineName": "My CEP Engine", }
Photoshop
Basic Details:
- Name of
<ScriptPath>
Script: [Numerical] - Name of Engine: [None]
<ScriptPath>
Script Can Include Files: No
Quirks:
- Photoshop's CEP's ExtendScript context cannot be directly debugged. This is due to the fact that Photoshop runs CEP ExtendScript in private, nameless engines.
- Due to this limitation, it is best to debug ExtendScript that will be used in CEP contexts directly in the
main
ExtendScript engine as you would other scripts (e.g. by using the extension's various ways to run a script).
- Due to this limitation, it is best to debug ExtendScript that will be used in CEP contexts directly in the
- Related CEP notes:
- Photoshop does not support including files from within the script specified in the CSXS manifest's
<ScriptPath>
. - The
$.includePath
property is not supported (it resolves to the empty string).
- Photoshop does not support including files from within the script specified in the CSXS manifest's
Premiere Pro
Basic Details:
- Name of
<ScriptPath>
Script: [None] - Name of Engine:
main
orNewWorld
(depends upon version of Premiere Pro) <ScriptPath>
Script Can Include Files: Yes
Quirks:
Premiere Pro does not currently have any application-specific quirks. Simply connecting a debugger should be enough for all contexts to be debuggable out of the box.
General Notes
- If the ExtendScript Toolkit (ESTK) connects to a host application, then the ExtendScript Debugger extension will no longer be able to function correctly as a debugger. Restarting the host application is enough to fix this issue.
- A single host application can only be debugged by a single VS Code window. If two or more VS Code windows attempt to maintain debug sessions with a single host application at the same time, only the last one to connect will work.
- A single VS Code window can manage multiple debug sessions with multiple host application/engine combinations at the same time.
- Once a VS Code Window connects to a host application, it will begin acting as the de facto debugger for all future debugging purposes (until another VS Code window connects). For host applications that support multiple engines, this may mean that an engine with no active debug session triggers a breakpoint and notifies the ExtendScript Debugger extension about the break. In these cases, the extension will attempt to notify you and offer you the ability to attach a debug session.
- Changes to the "Caught Exceptions" breakpoint while a script is evaluating (e.g. stopped at a breakpoint) will only apply to newly created scopes (stack frames).
- When an
Evaluate Script in Host...
command is run without an active debug session and fails with an error status, the extension will highlight the line of source code reported with the error. You may clear these highlights in one of the following manners:- Focus another source file such that the source file with a highlight becomes a background tab in VS Code.
- Close and reopen the source file.
- Start another script evaluation.
- Start a debug session.
- If the "Show Result Messages" setting is enabled, dismiss the relevant error message (if hidden, click the notification bell in the right side of the status bar).
- Run the
Clear Error Highlights...
command.
- The ExtendScript Debugger extension ignores the
#target
and#targetengine
preprocessor directives. The extension will always use either the configuredhostAppSpecifier
andengineName
settings or, if not otherwise specified, those dynamically chosen in the relevant UI. - When disconnecting from a Debug Session:
- The host engine is instructed to unregister all VS Code breakpoints and continue evaluation.
- Any script-based breakpoints (e.g.
debugger
or$.bp()
) subsequently encountered by the host engine will cause the host engine to pause and await communication from a debugger. When this occurs, the extension will attempt to notify you and offer you the ability to attach a debug session to investigate the breakpoint details. If you dismiss or otherwise miss this notification, you may either halt the evaluation process or manually connect anattach
mode debug session.
Resources
Forums
Known Issues
- The Extension fails to work on Apple devices using Apple Silicon (e.g. M1 processors). Internally, the extension interfaces with a special library that handles communication with host applications. This library is currently Intel-only. To successfully run the extension on Apple devices running Apple Silicon, VS Code itself must be run with Rosetta. Please see Apple's documentation for information on how to configure a universal build of VS Code to run using Rosetta. Alternatively, you can download the Intel-specific build of VS Code and run it directly.
- The Extension fails to work on Windows on ARM devices. Use of the ExtendScript Debugger on Windows on ARM devices is not supported at this time.
- Bring Target to Front does not work for certain host applications. Certain host applications on certain operating systems may ignore the extension's request to come forward. A possible workaround is to add
BridgeTalk.bringToFront("host-app-specifier")
to the top of the script you wish to evaluate. - The debugger fails to connect to InDesign Server. The ExtendScript Debugger extension fails to recognize that InDesign Server is running. This is due to a BridgeTalk registration issue in InDesign Server itself. See the InDesign Server (or When Host Applications Go Rogue) section for information on how to work around this issue.
- The
this
object does not appear in the Variables view. All ExtendScript engines contain a bug that causes the implicitthis
variable to display incorrect contents when viewed from all but the top stack frame in a given call stack (only the implicitthis
for the top stack frame is ever resolved). For consistency, the implicitthis
variable is not listed. If you need to view the contents of the implicitthis
in any context, you may do so by addingvar _this = this;
to your script. The_this
variable will appear in the Variables view and allow you to inspect the contents of the implicitthis
as expected.- This issue also affects the Debug Console. Entering
this
into the Debug Console will only ever refer to the implicitthis
resolved in the context of the top stack frame.
- This issue also affects the Debug Console. Entering
- Unencoded binary values may break the underlying debugger protocol. All host applications have a known bug where attempts to send binary-encoded data to the debugger will fail. This typically results in missing Debug Console output or an empty Variables view. Scenarios where you may encounter this issue include when attempting to view the results of a binary file
read()
operation or when writing binary values directly in ExtendScript. The following script, for instance, will trigger this issue:
To work around this issue and "see" the contents of the problematic variable, you may encode it usingvar x = "\0"; // String representation of "NULL" $.writeln("x is: " + x); // Write the value of `x` to the Debug Console: does nothing $.bp(); // Ask the debugger to break: the Variables view will show an error
encodeURI()
,toSource()
, or by using abtoa()
polyfill. For example:
Please note that this issue is present in all ExtendScript debuggers, including the original ESTK.var x = encodeURI("\0"); // Encoded string representation of "NULL" $.writeln("x is: " + x); // Write the value of `x` to the Debug Console: prints "x is: %00" $.bp(); // Ask the debugger to break: the Variables view works as expected
FAQ
- Can debug sessions or the
Evaluate Script in Host...
command be configured to launch the host application?The ExtendScript Debugger extension does not currently support launching host applications.
- How do I halt evaluation of a script that wasn't started from VS Code?
There are currently two options:
- Connect an
attach
mode debug session to the host engine within which the script is evaluating. Once connected use the "Stop" debug action to simultaneously end the debug session and halt the script. The "Disconnect" button can be converted into a "Stop" button by holding theAlt
/option
key. - Attempt to evaluate a script (e.g. with a command or by starting a
launch
mode debug session) in the host engine within which the script is evaluating. The active evaluation will be detected and you will be offered the option to halt the active evaluation process and retry evaluating the script you specified.
- Connect an
Terms & Conditions
Your use of this application is governed by the Adobe General Terms of Use.
© 2022 Adobe. All rights reserved. Adobe Privacy Policy.