赞
踩
确认启用Plugin DevKit插件,该插件是IDEA自带的插件
创建项目
创建具体的插件模块, 如果该项目只开发一个插件则不用创建模块。
设置插件的sdk
在Run Configuration菜单下配置启动配置, 配置jre。 点击run按钮,会启动一个ieda实例,并且启用当前开发的插件。
可以发布到自定义仓库或者发布到idea公共仓库
每个插件都使用独立的ClassLoader, 所以每个插件可以使用不同版本的依赖,不会相互影响。如果插件的classLoader没有发现某个类,则默认由IDEA的ckassLoader加载。但是可以在plugin.xml中的元素下声明依赖其它插件,那么就会使用其它插件的classLoader加载未找到的类。
action官方文档
Action是实现插件功能的类, 一个Action类需要继承AnAction并且实现actionPerformed方法。当用户点击菜单或者工具栏按钮, 按快捷键,或者通过Help | Find Action点击时, IntelliJ Platform系统会回调对应Action的actionPerformed方法。
Action会被分组, 一个组可以包含actions也可以包含子组,一个action组就是一个菜单或者工具栏,子组就是子菜单。
通过plugin.xml注册action。
<actions> <!-- - "id" (required) - specifies a unique identifier for the action - "class" (required) - specifies the FQN of the class implementing the action - "text" (required) - specifies the default long-version text to be displayed for the action (tooltip for toolbar button or text for menu item) - "use-shortcut-of" (optional) - specifies the ID of the action whose keyboard shortcut this action will use - "description" (optional) - specifies the text which is displayed in the status bar when the action is focused - "icon" (optional) - specifies the icon which is displayed on the toolbar button or next to the menu item --> <action id="VssIntegration.GarbageCollection" class="com.example.impl.CollectGarbage" text="Garbage Collector: Collect _Garbage" description="Run garbage collector" icon="icons/garbage.png"> <!-- The <override-text> element defines an alternate version of the text for the menu action. Attributes: - "text" (required) - defines the text to be displayed for the action - "place" (required) - declares where the alternate text should be used. In this example, any time the action is displayed in the IDE main menu (and submenus), the override-text version should be used. 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"/> <!-- The <add-to-group> node specifies that the action should be added to an existing group. An action can be added to several groups. Attributes: - "group-id" (required) - specifies the ID of the group to which the action is added. The group must be an implementation of the DefaultActionGroup class. - "anchor" (required) - specifies the position of the action in the relative to other actions. Allowed values: "first", "last", "before", and "after". - "relative-to-action" (mandatory if "anchor" is "before" or "after") - specifies the action before or after which the current action is inserted. --> <add-to-group group-id="ToolsMenu" relative-to-action="GenerateJavadoc" anchor="after"/> <!-- The <keyboard-shortcut> node specifies the keyboard shortcut for the action. An action can have several keyboard shortcuts. Attributes: - "first-keystroke" (required) - specifies the first keystroke of the action. The keystrokes are specified according to the regular Swing rules. - "second-keystroke" (optional) - specifies the second keystroke of the action. - "keymap" (required) - specifies the keymap for which the action is active. IDs of the standard keymaps are defined as constants in the com.intellij.openapi.keymap.KeymapManager class. - "remove" (optional) - shortcut should be removed from the specified action. See the second <keyboard-shortcut> example element below. - "replace-all" (optional) - removes all keyboard and mouse shortcuts from the specified action before adding the specified shortcut. See the third <keyboard-shortcut> example element below. --> <!-- 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"/> <!-- The <mouse-shortcut> node specifies the mouse shortcut for the action. An action can have several mouse shortcuts. Attributes: - "keystroke" (required) - specifies the clicks and modifiers for the action. It is defined as a sequence of words separated by spaces: * mouse buttons: "button1", "button2", "button3" * modifier keys: "shift", "control", "meta", "alt", "altGraph" * button double-click: "doubleClick" - "keymap" (required) - specifies the keymap for which the action is active. IDs of the standard keymaps are defined as constants in the com.intellij.openapi.keymap.KeymapManager class. The <mouse-shortcut> element can also specify "remove" and "replace-all" attributes. See <keyboard-shortcut> description above for details. --> <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"/> <!-- The <group> element defines an action group. The <action>, <group> and <separator> elements defined within it are automatically included in the group. Attributes: - "id" (required) - specifies a unique identifier for the group. - "class" (optional) - specifies the FQN of the class implementing the group. If not specified, com.intellij.openapi.actionSystem.DefaultActionGroup is used. - "text" (optional) - specifies the text of the group (text for the menu item showing the submenu). - "description" (optional) specifies the text which is displayed in the status bar when the group has focus. - "icon" (optional) - specifies the icon which is displayed on the toolbar button or next to the menu group. - "popup" (optional) - specifies how the group is presented in the menu. * "true" - group actions are placed in a submenu * "false" - actions are displayed as a section of the same menu delimited by separators. - "compact" (optional) - specifies whether an action within that group is visible when disabled. Setting compact="true" specifies an action in the group isn't visible unless the action is enabled. --> <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/> <group id="TestActionSubGroup"/> <!-- 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>
扩展是插件最常用的一种扩展IDEA功能的方式, 只是这种方式没有直接把Action加到菜单或者工具栏那么直接。扩展功能是通过IDEA自带的或者其它插件提供的一些扩展点实现的。
声明扩展要在plugin.xml中添加标签。
<!-- defaultExtensionNs属性只有两种值: 1. com.intellij 使用 IntelliJ Platform核心扩展点 2. {ID of a plugin} 使用其它插件的扩展点,必须要配置其它插件的依赖 子标签的名称必须和扩展点的名称相同 扩展点有两种类型 3. 扩展点使用interface 属性声明, 则设置扩展点标签的implementation属性, 属性值设置实现了interface对应接口的实现类的全限定名 4. 扩展点使用beanClass属性声明,则可以设置beanClass对应的扩展点类中@Attribute注解标注的属性。 可以使用view | quick document 查看扩展点帮助 --> <extensions defaultExtensionNs="com.intellij"> <appStarter implementation="com.example.MyAppStarter"/> <projectTemplatesFactory implementation="com.example.MyProjectTemplatesFactory"/> </extensions> <!-- Declare extensions to access extension points in a custom plugin "another.plugin". The "myExtensionPoint" extension point has been declared using "beanClass" and exposes custom properties "key" and "implementationClass". --> <extensions defaultExtensionNs="another.plugin"> <myExtensionPoint key="keyValue" implementationClass="com.example.MyExtensionPointImpl"/> </extensions>
Service是插件的一个组件, 是为了把公共的逻辑放到一起,Service的实例是单例的。
有三种类型的Service, 应用级别的,项目级别的,模块级别的。
声明Service有两种方式
类上加@Service注解,service不需要被重写的时候可以使用这种方式
在plugin.xml中声明,通过applicationService,projectService扩展点声明
<extensions defaultExtensionNs="com.intellij">
<!-- Declare the application-level service -->
<applicationService
serviceInterface="mypackage.MyApplicationService"
serviceImplementation="mypackage.MyApplicationServiceImpl"/>
<!-- Declare the project-level service -->
<projectService
serviceInterface="mypackage.MyProjectService"
serviceImplementation="mypackage.MyProjectServiceImpl"/>
</extensions>
获取Service
MyApplicationService applicationService = ApplicationManager.getApplication()
.getService(MyApplicationService.class);
MyProjectService projectService = project.getService(MyProjectService.class);
实现类可以封装静态方法,方便获取
MyApplicationService applicationService = MyApplicationService.getInstance();
MyProjectService projectService = MyProjectService.getInstance(project);
和其它Service交互
@Service
public final class ProjectService {
private final Project myProject;
public ProjectService(Project project) {
myProject = project;
}
public void someServiceMethod(String parameter) {
AnotherService anotherService = myProject.getService(AnotherService.class);
String result = anotherService.anotherServiceMethod(parameter, false);
// do some more stuff
}
}
声明扩展点
有两种类型的扩展点
<idea-plugin>
<id>my.plugin</id>
<extensionPoints>
<extensionPoint
name="myExtensionPoint1"
beanClass="com.example.MyBeanClass"/>
<extensionPoint
name="myExtensionPoint2"
interface="com.example.MyInterface"/>
</extensionPoints>
</idea-plugin>
扩展点类
public class MyBeanClass extends AbstractExtensionPointBean { @Attribute("key") public String key; @Attribute("implementationClass") public String implementationClass; public String getKey() { return key; } public String getClass() { return implementationClass; } }
其它插件使用该扩展点
<idea-plugin> <id>another.plugin</id> <!-- Declare dependency on plugin defining extension point: --> <depends>my.plugin</depends> <!-- Use "my.plugin" namespace: --> <extensions defaultExtensionNs="my.plugin"> <myExtensionPoint1 key="someKey" implementationClass="another.some.implementation.class"/> <myExtensionPoint2 implementation="another.MyInterfaceImpl"/> </extension> </idea-plugin>
声明扩展点的类使用扩展点
public class MyExtensionUsingService {
private static final ExtensionPointName<MyBeanClass> EP_NAME =
ExtensionPointName.create("my.plugin.myExtensionPoint1");
public void useExtensions() {
for (MyBeanClass extension : EP_NAME.getExtensionList()) {
String key = extension.getKey();
String clazz = extension.getClass();
// ...
}
}
}
这个示例配置文件除了Action的配置,其余配置全部都配置了。
<!-- An optional "url" attribute specifies the link to the plugin homepage. It is displayed on the plugin page in the Marketplace. --> <idea-plugin url="https://example.com/my-plugin-site"> <!-- Unique identifier of the plugin. It should be a fully qualified name including namespace to not collide with existing plugins. It cannot be changed between the plugin versions. If not specified, <name> will be used (not recommended). --> <id>com.example.myplugin</id> <!-- Public plugin name. It should use Title Cases. Guidelines: https://plugins.jetbrains.com/docs/marketplace/plugin-overview-page.html#plugin-name --> <name>My Framework Support</name> <!-- Plugin version. Plugins uploaded to the Marketplace must follow the semantic versioning: https://plugins.jetbrains.com/docs/marketplace/semver.html. It is displayed in the "Plugins" settings dialog and in the Marketplace plugin page. --> <version>1.0.0</version> <!-- Vendor name or Organization ID (if you have one created). Attributes: - "url" (optional) - specifies the link to the vendor's homepage - "email" (optional) - specifies the vendor's email address Displayed on the Plugins Page. --> <vendor url="https://plugins.jetbrains.com/my-company" email="contact@example.com">My Company</vendor> <!-- IMPORTANT: This tag should not be used in free plugins. If you decide to make your plugin paid, you will need to define the parameters in the <product-descriptor> tag. You can also enable free functionality in a paid plugin. Learn more in a guide to selling plugin: https://plugins.jetbrains.com/build-and-market --> <product-descriptor code="PMYPLUGIN" release-date="20210901" release-version="20211" optional="true"/> <!-- Minimum and maximum IDE build versions compatible with the plugin. --> <idea-version since-build="193" until-build="193.*"/> <!-- Plugin description displayed on the Marketplace plugin page and in the IDE Plugin Manager. Simple HTML elements (text formatting, paragraphs, lists, etc.) can be added inside of <![CDATA[ ]]> tag. Guidelines: https://plugins.jetbrains.com/docs/marketplace/plugin-overview-page.html#plugin-description --> <description> <![CDATA[ Provides support for <a href="https://example.com/my-framework">My Framework</a>. <p>Includes support for: <ul> <li>code completion</li> <li>references</li> <li>refactoring</li> </ul> </p> ]]> </description> <!-- Short summary of new features and bugfixes in the latest plugin version. Displayed on the Marketplace plugin page and in the IDE Plugin Manager. Simple HTML elements can be included between <![CDATA[ ]]> tags. --> <change-notes>Initial release of the plugin.</change-notes> <!-- Product and plugin compatibility requirements. Read more: https://plugins.jetbrains.com/docs/intellij/plugin-compatibility.html --> <depends>com.intellij.modules.platform</depends> <depends>com.example.third-party-plugin</depends> <!-- Optional dependency on another plugin. If the plugin with the "com.example.my-second-plugin" ID is installed, the contents of "mysecondplugin.xml" (the format of this file conforms to the format of plugin.xml) will be loaded. --> <depends optional="true" config-file="mysecondplugin.xml">com.example.my-second-plugin</depends> <!-- Resource bundle (/messages/MyPluginBundle.properties) to be used with "key" attributes in extension points and implicit keys like "action.[ActionID].text|description". --> <resource-bundle>messages.MyPluginBundle</resource-bundle> <!-- Extension points defined by the plugin. Extension points are registered by a plugin so that other plugins can provide this plugin with certain data. Read more: https://plugins.jetbrains.com/docs/intellij/plugin-extension-points.html --> <extensionPoints> <extensionPoint name="testExtensionPoint" beanClass="com.example.impl.MyExtensionBean"/> <applicationService serviceImplementation="com.example.impl.MyApplicationService"/> <projectService serviceImplementation="com.example.impl.MyProjectService"/> </extensionPoints> <!-- Application-level listeners. For more information, see: https://plugins.jetbrains.com/docs/intellij/plugin-listeners.html#defining-application-level-listeners --> <applicationListeners> <listener class="com.example.impl.MyListener" topic="com.intellij.openapi.vfs.newvfs.BulkFileListener"/> </applicationListeners> <!-- Project-level listeners. For more information, see: https://plugins.jetbrains.com/docs/intellij/plugin-listeners.html#defining-project-level-listeners --> <projectListeners> <listener class="com.example.impl.MyToolwindowListener" topic="com.intellij.openapi.wm.ex.ToolWindowManagerListener"/> </projectListeners> <!-- Actions. For more information, see: https://plugins.jetbrains.com/docs/intellij/basic-action-system.html --> <actions> <action id="VssIntegration.GarbageCollection" class="com.example.impl.CollectGarbage" text="Collect _Garbage" description="Run garbage collector"> <keyboard-shortcut first-keystroke="control alt G" second-keystroke="C" keymap="$default"/> </action> </actions> <!-- Custom extensions declaration. For more information, see: https://plugins.jetbrains.com/docs/intellij/plugin-extensions.html#declaring-extensions --> <extensions defaultExtensionNs="VssIntegration"> <myExtensionPoint implementation="com.example.impl.MyExtensionImpl"/> </extensions> <!-- DEPRECATED: Do not use in new plugins! Plugin's application components. See https://plugins.jetbrains.com/docs/intellij/plugin-components.html for migration steps. --> <application-components> <component> <!-- Component's interface class --> <interface-class>com.example.Component1Interface</interface-class> <!-- Component's implementation class --> <implementation-class>com.example.impl.Component1Impl</implementation-class> </component> </application-components> <!-- DEPRECATED: Do not use in new plugins! Plugin's project components. See https://plugins.jetbrains.com/docs/intellij/plugin-components.html for migration steps. --> <project-components> <component> <!-- Interface and implementation classes are the same --> <implementation-class>com.example.Component2</implementation-class> <!-- If the "workspace" option is set "true", the component saves its state to the .iws file instead of the .ipr file. Note that the <option> element is used only if the component implements the JDOMExternalizable interface. Otherwise, the use of the <option> element takes no effect. --> <option name="workspace" value="true"/> <!-- If the "loadForDefaultProject" tag is present, the project component is instantiated also for the default project. --> <loadForDefaultProject/> </component> </project-components> <!-- DEPRECATED: Do not use in new plugins! Plugin's module components. See https://plugins.jetbrains.com/docs/intellij/plugin-components.html for migration steps. --> <module-components> <component> <implementation-class>com.example.Component3</implementation-class> </component> </module-components> </idea-plugin>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。