IntelliJ Platform Plugin SDK Help

Actions

The actions system allows plugins to add their items to IntelliJ Platform-based IDE menus and toolbars. For example, one of the action classes is responsible for the File | Open File... menu item and the Open... toolbar button.

Actions in the IntelliJ Platform require a code implementation and must be registered. The action implementation determines the contexts in which an action is available and its functionality when selected in the UI. Registration determines where an action appears in the IDE UI. Once implemented and registered, an action receives callbacks from the IntelliJ Platform in response to user gestures.

The Creating Actions tutorial describes the process of adding a custom action to a plugin. The Grouping Actions tutorial demonstrates three types of groups that can contain actions.

Action Implementation

An action is a class derived from the abstract class AnAction (see also Useful Action Base Classes below). The IntelliJ Platform calls methods of actions when a user interacts with a menu item or toolbar button.

Principal Implementation Overrides

Every IntelliJ Platform action should override AnAction.update() and must override AnAction.actionPerformed().

AnAction.update()

An action's method AnAction.update() is called by the IntelliJ Platform framework to update an action state. The state (enabled, visible) of an action determines whether the action is available in the UI. An object of the AnActionEvent type is passed to this method and contains information about the current context for the action.

Actions are made available by changing the state in the Presentation object associated with the event context. As explained in Overriding the AnAction.update() Method, it is vital update() methods execute quickly and return execution to platform.

AnAction.getActionUpdateThread()

AnAction.getActionUpdateThread() returns an ActionUpdateThread, which specifies if the update() method is called on a background thread (BGT) or the event-dispatching thread (EDT). The preferred method is to run the update on the BGT, which has the advantage of guaranteeing application-wide read access to PSI, the virtual file system (VFS), or project models. Actions that run the update session on the BGT should not access the Swing component hierarchy directly. Conversely, actions that specify to run their update on EDT must not access PSI, VFS, or project data but have access to Swing components and other UI models.

All accessible data is provided by the DataContext as explained in Determining the Action Context. When switching from BGT to EDT is necessary, actions can use AnActionEvent.getUpdateSession() to access the UpdateSession and then call UpdateSession.compute() to run a function on EDT.

Inspection Plugin DevKit | Code | ActionUpdateThread is missing highlights missing implementation of AnAction.getActionUpdateThread().

AnAction.actionPerformed()

An action's method AnAction.actionPerformed() is called by the IntelliJ Platform if available and selected by the user. This method does the heavy lifting for the action: it contains the code executed when the action gets invoked. The actionPerformed() method also receives AnActionEvent as a parameter, which is used to access any context data like projects, files, selection, and similar. See Overriding the AnAction.actionPerformed() Method for more information.

Miscellaneous

There are other methods to override in the AnAction class, such as changing the default Presentation object for the action. There is also a use case for overriding action constructors when registering them with dynamic action groups, demonstrated in the Grouping Actions tutorial.

Overriding the AnAction.update() Method

The method AnAction.update() is periodically called by the IntelliJ Platform in response to user gestures. The update() method gives an action to evaluate the current context and enable or disable its functionality. Implementors must ensure that changing presentation and availability status handles all variants and state transitions; otherwise, the given Action will get "stuck".

Determining the Action Context

The AnActionEvent object passed to update() carries information about the current context for the action. Context information is available from the methods of AnActionEvent, providing information such as the Presentation and whether the action is triggered by a Toolbar. Additional context information is available using the method AnActionEvent.getData(). Keys defined, for example, in CommonDataKeys are passed to the getData() method to retrieve objects such as Project, Editor, PsiFile, and other information. Accessing this information is relatively light-weight and is suited for AnAction.update().

Enabling and Setting Visibility for an Action

Based on information about the action context, the AnAction.update() method can enable, disable, or hide an action. An action's enabled/disabled state and visibility are set using methods of the Presentation object, which is accessed using AnActionEvent.getPresentation().

The default Presentation object is a set of descriptive information about a menu or toolbar action. Every context for an action – it might appear in multiple menus, toolbars, or Navigation search locations – has a unique presentation. Attributes such as an action's text, description, and icons and visibility and enable/disable state, are stored in the presentation. The attributes in a presentation get initialized from the action registration. However, some can be changed at runtime using the methods of the Presentation object associated with an action.

The enabled/disabled state of an action is set using Presentation.setEnabled(). The visibility state of an action is set using Presentation.setVisible(). If an action is enabled, the AnAction.actionPerformed() can be called if a user selects an action in the IDE. A menu action shows in the UI location specified in its registration. A toolbar action displays its enabled (or selected) icon, depending on the user interaction.

When an action is disabled, AnAction.actionPerformed() will not be called. Toolbar actions display their respective icons for the disabled state. The visibility of a disabled action in a menu depends on whether the host menu (for example, "ToolsMenu") containing the action has the compact attribute set. See Grouping Actions for more information about the compact attribute and menu actions' visibility.

An example of enabling a menu action based on whether a project is open is demonstrated in PopupDialogAction.update().

Overriding the AnAction.actionPerformed() Method

When the user selects an enabled action, be it from a menu or toolbar, the action's AnAction.actionPerformed() method is called. This method contains the code executed to perform the action, and it is here that the real work gets done.

By using the AnActionEvent methods and CommonDataKeys, objects such as the Project, Editor, PsiFile, and other information is available. For example, the actionPerformed() method can modify, remove, or add PSI elements to a file open in the editor.

The code that executes in the AnAction.actionPerformed() method should execute efficiently, but it does not have to meet the same stringent requirements as the update() method.

An example of inspecting PSI elements is demonstrated in the action_basics SDK code sample in PopupDialogAction.actionPerformed().

Action IDs

Every action and action group has a unique identifier. Basing the identifier for a custom action on the fully qualified name of the implementation is the best practice, assuming the package incorporates the <id> of the plugin. Including the plugin identifier in the action identifier should prevent it from clashing with other plugins' actions. An action must have a unique identifier for each place. It is used in the IDE UI, even though the FQN of the implementation is the same. Definitions of identifiers for the standard IntelliJ Platform actions are in IdeActions.

Grouping Actions

Groups organize actions into logical UI structures, which in turn can contain other groups. A group of actions can form a toolbar or a menu. Subgroups of a group can form submenus of a menu.

Actions can be included in multiple groups and thus appear in different places within the UI. An action must have a unique identifier for each place it appears in the UI. See the Action Declaration Reference section for information about how to specify locations.

Presentation

A new Presentation gets created for every place where the action appears. Therefore, the same action can have a different text or icon when it appears in different places of the user interface. Different presentations for the action are created by copying the Presentation returned by the AnAction.getTemplatePresentation() method.

The compact Attribute

A group's compact attribute specifies whether an action within that group is visible when disabled. See Registering Actions in plugin.xml for an explanation of how the compact attribute is set for a group. If the compact attribute is true for a menu group, an action in the menu only appears if its state is both enabled and visible. In contrast, if the compact attribute is false, an action in the menu appears if its state is disabled but visible. Some menus like Tools have the compact attribute set, so there isn't a way to show an action on the Tools menu if it is not enabled.

Host Menu compact Setting

Action Enabled

Visibility Enabled

Menu Item Visible?

Menu Item Appears Gray?

T

F

T

F

N/A

T

T

T

T

F

F

F

T

T

T

F

T

T

T

F

All other combinations of compact, visibility, and enablement produce N/A for gray appearance because the menu item isn't visible.

See the Grouping Actions tutorial for examples of creating action groups.

Registering Actions

There are two main ways to register an action: either by registering it in the plugin.xml file or through code.

Registering Actions in plugin.xml

Registering actions in plugin.xml is demonstrated in the following reference examples, which document all elements and attributes used in the <actions> section and describe each element's meaning.

Action Declaration Reference

The places where actions can appear are defined by constants in ActionPlaces. Group IDs for the IntelliJ Platform are defined in PlatformActions.xml.

This and additional information can also be found by using the Code Completion, Quick Definition, and Quick Documentation features.

<actions> <action id="VssIntegration.GarbageCollection" class="com.example.impl.CollectGarbage" text="Garbage Collector: Collect _Garbage" description="Run garbage collector" icon="icons/garbage.png"> <!-- The second <override-text> element uses the alternate attribute "use-text-of-place" to define a location (EditorPopup) to use the same text as is used in MainMenu. It is a way to specify the use of an alternate menu text in multiple discrete menu groups. --> <override-text place="MainMenu" text="Collect _Garbage"/> <override-text place="EditorPopup" use-text-of-place="MainMenu"/> <!-- Provide alternative names for searching action by name --> <synonym text="GC"/> <add-to-group group-id="ToolsMenu" relative-to-action="GenerateJavadoc" anchor="after"/> <!-- Add the first and second keystrokes to all keymaps... --> <keyboard-shortcut keymap="$default" first-keystroke="control alt G" second-keystroke="C"/> <!-- ...except the "Mac OS X" keymap and its children. --> <keyboard-shortcut keymap="Mac OS X" first-keystroke="control alt G" second-keystroke="C" remove="true"/> <!-- The "Mac OS X 10.5+" keymap and its children will have only this keyboard shortcut for this action. --> <keyboard-shortcut keymap="Mac OS X 10.5+" first-keystroke="control alt G" second-keystroke="C" replace-all="true"/> <mouse-shortcut keymap="$default" keystroke="control button3 doubleClick"/> </action> <!-- This action declares neither a text nor a description attribute. If it has a resource bundle declared, the text and descriptions will be retrieved based on the action-id incorporated in the key for a translated string. --> <action id="sdk.action.PopupDialogAction" class="sdk.action.PopupDialogAction" icon="SdkIcons.Sdk_default_icon"/> <group class="com.example.impl.MyActionGroup" id="TestActionGroup" text="Test Group" description="Group with test actions" icon="icons/testGroup.png" popup="true" compact="true"> <action id="VssIntegration.TestAction" class="com.example.impl.TestAction" text="My Test Action" description="My test action"/> <!-- The <separator> element defines a separator between actions. It can also have an <add-to-group> child element. --> <separator/> <!-- A group that is excluded from "Help | Find Action..." and "Navigate | Search Everywhere" --> <group id="TestActionSubGroup" searchable="false"/> <!-- The <reference> element allows adding an existing action to the group. The mandatory "ref" attribute specifies the ID of the action to add. --> <reference ref="EditorCopy"/> <add-to-group group-id="MainMenu" relative-to-action="HelpMenu" anchor="before"/> </group> </actions>

Localizing Actions and Groups

Action and group localization use resource bundles containing property files named $NAME$Bundle.properties, each file consisting of key=value pairs. The action_basics plugin demonstrates using a resource bundle to localize the group and action entries added to the Editor Popup Menu.

When localizing actions and groups, the text and description attributes are not declared in plugin.xml. Instead, those attribute values vary depending on the locale and get declared in a resource bundle.

The name and location of the resource bundle must be declared in the plugin.xml file. In the case of action_basics, only a default localization resource bundle (/resources/messages/BasicActionsBundle.properties) is provided:

<resource-bundle>messages.BasicActionsBundle</resource-bundle>

2020.1
If necessary, a dedicated resource bundle to use for actions and groups can be defined on <actions>:

<actions resource-bundle="messages.MyActionsBundle"> <!-- action/group defined here will use keys from MyActionsBundle.properties --> </actions>

See Extending DefaultActionGroup for a tutorial of localizing Actions and Groups.

For Actions, the key in property files incorporates the action ID in this specific structure:

  • action.<action-id>.text=Translated Action Text

  • action.<action-id>.description=Translated Action Description

2020.1
If <override-text> is used for an action ID, the key includes the place attribute:

  • action.<action-id>.<place>.text=Place-dependent Translated Action Text

For Groups, the key in the property files incorporates the group ID in this specific structure:

  • group.<group-id>.text=Translated Group Text

  • group.<group-id>.description=Translated Group Description

2020.3
If <override-text> is used for a group ID, the key includes the place attribute:

  • group.<group-id>.<place>.text=Place-dependent Translated Group Text

Registering Actions from Code

Two steps are required to register an action from code:

  • First, an instance of the class derived from AnAction must be passed to the registerAction() method of ActionManager, to associate the action with an ID.

  • Second, the action needs to be added to one or more groups. To get an instance of an action group by ID, it is necessary to call ActionManager.getAction() and cast the returned value to DefaultActionGroup.

Building a Toolbar/Popup Menu from Actions

If a plugin needs to include a toolbar or popup menu built from a group of actions in its user interface, that is achieved through ActionPopupMenu and ActionToolbar. These objects can be created through calls to the ActionManager.createActionPopupMenu() and createActionToolbar() methods. To get a Swing component from such an object, call the respective getComponent() method.

If an action toolbar is attached to a specific component (for example, a panel in a tool window), call ActionToolbar.setTargetComponent() and pass the related component's instance as a parameter. Setting the target ensures that the toolbar buttons' state depends on the state of the related component, not on the current focus location within the IDE frame.

See Toolbar in UI Guidelines for an overview.

Useful Action Base Classes

Toggle/Selection

Use ToggleAction or DumbAwareToggleAction for actions with the "selected"/"pressed" state (for example, menu item with checkbox, toolbar action button). See also ToggleOptionAction.

Popup Menus

In popup menus, ToggleAction no longer closes the popup by default. Use Presentation.setKeepPopupOnPerform() with KeepPopupOnPerform.IfRequested in the action constructor or its update() method.

Back/Forward Navigation

Use BackAction and ForwardAction to provide a navigation trail taken from History provided by History.KEY.

Runtime Placeholder Action

For actions registered at runtime (for example, in a tool window toolbar), add an <action> entry with EmptyAction to "reserve" Action ID, so they become visible in Settings | Keymap.

Executing Actions Programmatically

Sometimes, it is required to execute actions programmatically, for example, executing an action implementing logic needed in another place, and the implementation is out of our control. Executing actions can be achieved with ActionUtils.invokeAction().

Last modified: 10 December 2024