Plug-ins are the only possible way for third-parties to extend IDEA functionality. Every plug-in uses API exposed by IDEA or other plug-ins to implement its functionality. This document is focused on plug-in system architecture and plug-in lifecycle. It doesn’t specify any of the other APIs which may be used by plug-ins.
There are 3 ways how to organize plug-in content:
1. Plug-in consists of one .jar file placed in IDEA_HOME/plugins/. The archive should contain configuration file (META-INF/plugin.xml) and classes which implement the plug-in functionality. Configuration file specifies plug-in name, description, version, vendor, IDEA version plug-in is supposed to be used with, plug-in components, actions and action groups, action user interface placement.
IDEA_HOME
Plugins Sample.jar/ com/foo/..... ... ... META-INF plugin.xml
2. Plug-in files are located in a folder:
IDEA_HOME
Plugins Sample lib libfoo.jar libbar.jar classes com/foo/..... ... ... META-INF plugin.xml
The 'classes' folder and all jars located in the 'lib' folder are automatically added to the classpath.
3. Plug-in files are located in a jar-file which is placed to the lib folder:
IDEA_HOME
Plugins Sample lib libfoo.jar libbar.jar Sample.jar/ com/foo/..... ... ... META-INF plugin.xml
All the jars from 'lib' folder are automatically added to the classpath.
Components are the fundamental concept of plug-ins integration. There are 2 kinds of components: application-level and project-level. Application-level components are created and initialised on IDEA start-up. Project-level components are created for each Project instance present in IDEA (please note that components might be created for even unopened projects). Application-level component can be acquired from Application instance with getComponent(Class) method. Project-level component can be acquired from Project instance with getComponent(Class) method.
Every component should have interface and implementation classes specified in the configuration file. The interface class will be used for retrieving the component from other components and the implementation class will be used for component instantiation. Note that two components of the same level (Application or Project) cannot have the same interface class. Interface and implementation classes can be the same.
Each component has the unique name which is used for its externalization and other internal needs. The name of component is returned by its getComponentName() method.
It's recommended to name components in plugin_name.component_name form.
Application-level component's implementation class should implement the ApplicationComponent interface. It should have constructor with no parameters which will be used for its instantiation.
Project-level component's implementation class should implement the ProjectComponent interface. It should have constructor with a single parameter of Project type or with no parameters. If a component needs Project instance it should provide constructor of the first form and store its parameter into a field for later use.
Every components state will be automatically saved & loaded if component
implements JDOMExternalizable interface.
Application-level component's state is saved in the xml file with plug-ins
name in IDEA_HOME/config/plugins folder.
Project-level component saves its state to the project (.ipr) file. If workspace
option in the plugin.xml is set to true component will save its configuration
to the workspace (.iws) file instead of project (.ipr) file.
Note that component should always be ready to save its state.
Defaults (components' predefined settings) should be placed in the component_name.xml file. Put this file in the plug-in's classpath in the folder corresponding to the default package. readExternal() method will be called on the <component> root tag. If component has defaults readExternal method is called twice: the first time for defaults and the second time for saved configuration.
Note that you should not request any other components in the constructor of your component, otherwise you'll get an assertion. If you need access to other components when initializing your component you can access them in the initComponent method.
Each plug-in can contribute a number of actions to the IDEA user interface. Normally all actions are specified in the configuration file. The configuration file also specifies action placement in UI. Plug-in vendor can place actions into the main menu, pop-up menus or the toolbar. See actions.html for the detailed description.
Here is a sample plugin.xml:
<idea-plugin>
<!--
Plug-in name -->
<name>VssIntegration</name>
<!--
Description -->
<description>Vss
integration plug-in</description>
<!--
Plug-in version -->
<version>1.0</version>
<!--
Plug-in's vendor -->
<vendor>Foo
Inc.</vendor>
<!--
Minimum and maximum IDEA version plug-in is supposed to work with -->
<idea-version
min=”3.0”
max=”3.1”/>
<!--
Plug-in's application components -->
<application-components>
<component>
<!--
Component's interface class -->
<interface-class>com.foo.Component1Interface</interface-class>
<!--
Component's implementation class -->
<implementation-class>com.foo.impl.Component1Impl</implementation-class>
</component>
</application-components>
<!--
Plug-in's project components -->
<project-components>
<component>
<!--
Interface and implementation classes are the same -->
<interface-class>com.foo.Component2</interface-class>
<!--
Save state to the .iws instead of .ipr -->
<option
name="workspace"
value="true"
/>
</component>
</project-components>
<!--
Actions -->
<actions>
<action
id="VssIntegration.GarbageCollection"
class="com.foo.impl.CoolectGarbage"
text="Collect
_Garbage" description="Run
garbage collector">
<keyboard-shortcut
first-keystroke="control
alt G" second-keystroke="C"
keymap="$default"/>
</action>
</actions>
</idea-plugin>