14 KiB
Run Configurations
Implementing run configurations management support.
Product Help: Run/Debug Configuration
A run configuration is a specific type of run profile. Run configurations can be managed from the UI and persisted between IDE restarts. They allow users to specify execution options like a working directory, environment variables, program arguments, and other parameters required to run a process. Run configurations can be started from the Run toolbar, the editor, and executed programmatically from actions or other components.
Architecture Overview
The following diagram shows the key run configurations classes:
Run Configuration API (except SettingsEditor
class, which is a class shared by many IntelliJ Platform APIs) is a part of the Execution API.
ConfigurationType
The entry point of a run configuration implementation is ConfigurationType
.
It is responsible for the run configuration type and instances presentation and contains configuration factories.
A single configuration type can have multiple configuration factories, e.g., the Docker configuration type can create run configurations for:
- Dockerfile
- Docker Image
- Docker-compose
To see the list of configuration types available in the IDE, go to Run | Edit Configurations and click the Add button (+ icon).
ConfigurationType
implementations are registered in the com.intellij.configurationType
extension point (EP).
Standard base classes for configuration type implementations are:
SimpleConfigurationType
- used for configuration types that have a single configuration factory. Actually, this configuration type is also a configuration factory, and there is no need for setting up a factory.ConfigurationTypeBase
- used for configuration types that have multiple configuration factories. Factories should be added in the constructor by calling theaddFactory()
method.
ConfigurationFactory
ConfigurationFactory
classes are responsible for creating run configuration instances.
The only method required to be implemented is createTemplateConfiguration()
, which is called once for each project to create the run configuration template.
The actual run configurations are created in the createConfiguration()
method by cloning the template.
Configuration factory presentation is inherited from the containing configuration type. If customization is needed, override the presentation methods in the factory class.
RunConfiguration
RunConfiguration
extends RunProfile
and represents a named profile that can be run by the Execution API.
When implementing a run configuration class, consider using one of the standard base classes:
RunConfigurationBase
- a general-purpose base class that contains the most basic implementation of a run configuration.LocatableConfigurationBase
- a base class for configurations that can be created from context.ModuleBasedConfiguration
- a base class for a configuration that is associated with a specific module (e.g., Java run configurations use the selected module to determine the run classpath).
SettingsEditor
A run configuration may allow editing its general settings and settings specific to a program runner.
If it is required, a RunConfiguration
implementation should return a SettingsEditor
instance from:
getConfigurationEditor()
for editing run configuration settingsgetRunnerSettingsEditor()
for editing settings for a specific program runner
A SettingsEditor
implementation must provide the following methods:
getComponent()
- creates a UI component for displaying settings controlsapplyEditorTo()
- copies the current editor UI state into the target settings objectresetEditorFrom()
- resets the current editor UI state to the initial settings state
In the case of run configuration settings, the settings object is RunConfiguration
itself.
Settings specific to a program runner must implement ConfigurationPerRunnerSettings
.
If a settings editor is complex, consider splitting it into multiple editors.
These editors should be added to the SettingsEditorGroup
object, which is a SettingsEditor
's implementation itself and must be returned from getConfigurationEditor()
or getRunnerSettingsEditor()
.
Each editor added to the group is displayed in a separate tab.
See ApplicationConfiguration.getConfigurationEditor()
as a reference.
If the settings editor requires validation, implement CheckableRunConfigurationEditor
.
Persistence
Run configuration settings are persistent.
They are stored in the file system and loaded back after the IDE restart.
Persisting and loading settings are performed by writeExternal()
and readExternal()
methods of RunConfiguration
class correspondingly.
The actually stored configurations are represented by instances of the RunnerAndConfigurationSettings
class, which combines a run configuration with runner-specific settings and stores general run configuration flags and properties.
Creating a Run Configuration Programmatically
If a plugin requires creating run configurations programmatically, .e.g, from a custom action, perform the following steps:
RunManager.createConfiguration()
- creates an instance ofRunnerAndConfigurationSettings
.RunManager.addConfiguration()
- makes the created configuration persistent by adding it to either the list of shared configurations stored in a project or to the list of local configurations stored in the workspace file.
Creating a Run Configuration from Context
Run configurations can be created and run from context, e.g., by right-clicking an application main method, a test class/method, etc., directly in the editor or the project view.
This is achieved by implementing LazyRunConfigurationProducer
and registering it in com.intellij.runConfigurationProducer
EP.
The extension requires implementing the following methods:
getConfigurationFactory()
- returns the factory creating run configurations of the type specified in the extension class implementation.setupConfigurationFromContext()
- receives a blank configuration of the specified type and aConfigurationContext
containing information about a source code location (accessible by callinggetLocation()
orgetPsiLocation()
). The implementation needs to check whether the location is applicable to the configuration type (e.g. if it's in a file of the supported language). If it is, put the correct context-specific settings into the run configuration and return true. Return false otherwise.isConfigurationFromContext()
- checks if a configuration was created from the specified context. This method allows reusing an existing run configuration, which applies to the current context, instead of creating a new one and possibly ignoring the user's customizations in the existing one.
To support the automatic naming of configurations created from context, the configuration should extend LocatableConfigurationBase
.
It supports generating a name for a configuration from its settings and tracking whether the user changed the name.
Running Configurations from the Gutter
If a run configuration is closely related to a PSI element (e.g., runnable method, test, etc.), it is possible to allow running configurations by clicking the editor gutter icon.
It is achieved by implementing RunLineMarkerContributor
, which provides information like the icon, tooltip content, and available actions for a given PSI element.
The standard method for providing the information is getInfo()
.
If computing the information is slow, implement getSlowInfo()
, which is used by the editor highlighting mechanism to gather information in batch, and apply all the information at once to avoid icons blinking.
To provide the standard executor actions like Run, Debug, etc., use ExecutorAction.getActions()
.
Starting a Run Configuration Programmatically
The easiest way to run an existing run configuration is using ProgramRunnerUtil.executeConfiguration(RunnerAndConfigurationSettings, Executor)
.
RunnerAndConfigurationSettings
can be retrieved with, e.g., RunManager.getConfigurationSettings(ConfigurationType)
.
The executor can be retrieved with a static method if a required executor exposes one or with ExecutorRegistry.getExecutorById()
.
Refactoring Support
Some run configurations contain references to classes, files, or directories in their settings, and these settings usually need to be updated when the corresponding element is renamed or moved.
To support that, a run configuration needs to implement the RefactoringListenerProvider
interface.
The RefactoringListenerProvider.getRefactoringElementListener()
's implementation should check whether the refactored element is referred from the run configuration.
If it is, return a RefactoringElementListener
that updates the run configuration according to the new name and location of the element.
Modifying Existing Run Configurations
Plugins can modify existing run configurations before they are run, e.g., by adding additional process parameters.
However, there is no single platform-wide extension point, and different IDEs provide different configuration base classes and extension points, allowing for their modifications.
To see what is possible in your case, check the RunConfigurationExtensionBase
inheritors.
Examples:
RunConfigurationExtension
implementations registered incom.intellij.runConfigurationExtension
EP allow for modifying Java run configurations extendingRunConfigurationBase
.PythonRunConfigurationExtension
implementations registered inPythonid.runConfigurationExtension
EP allow for modifying configuration extendingAbstractPythonRunConfiguration
etc.
Referencing Environment Variables in Run Configurations
Run configurations can define user environment variables specific to a given run configuration and include system environment variables.
Sometimes, it is convenient to reference existing variables in newly created variables, e.g., if a user creates an EXTENDED_PATH
variable and builds it from a custom entry and the system PATH
variable, they should reference it in the value by surrounding it with the $
character: /additional/entry:$PATH$
.
To substitute variable references with the actual references, it is required to call EnvironmentUtil.inlineParentOccurrences()
(available since 2023.2).
Before Run Tasks
Sometimes, it is necessary to perform specific tasks before a configuration is actually run, e.g., build the project, run a build tool preparation task, launch a web browser, etc. Plugins can provide custom tasks that can be added by users to a created run configuration.
To provide a custom task, implement BeforeRunTaskProvider
and register it in com.intellij.stepsBeforeRunProvider
EP.
The provider implementation is responsible for creating a task instance for a given run configuration and executing the task.