原创

自动化编程技术------IDEA插件开发

前言

之前的文章自动化编程---JSR269中,我们实现了使用Processor自动生成代码,但是不能在debug时使用自动生成的代码,要解决这个问题就需要依托IDEA的插件功能了,在这篇文章中,我就来跟大家一起探索一下IDEA插件的开发过程,并实现一个小demo,废话少说,我们现在直接开始。

名词解释

为了更好理解,以下内容将以spring中的概念作类比。

  • Action:可以理解为spring中的controller,当用户点击插件中的按钮或触发某个事件时,就会调用Action中的方法。所有的Action都需要继承com.intellij.openapi.actionSystem.AnAction抽象类并实现actionPerformed方法。

  • Service:可以理解为spring中普通的类(不是spring中的service),service分为应用级和工程级

  • plugin.xml:插件的配置文件,类比spring中的配置文件,这里配置了插件信息、作者信息等,当然他最重要的作用是,所有的Action都需要这这个配置文件中进行配置。

    今日目标

  • 创建一个IDEA插件工程
  • 在IDEA菜单中展示插件
  • 点击插件按钮,展示我的信息

创建项目

为了方便我们开发调试,最好还是下载一个IDEA社区版,稍后要将其作为sdk使用,当然你也可以用专业版左右运行的SDK,只是专业版不开源,有bug不好调试。

创建一个新项目,选择IntelliJ platform plugin,SDKs选择我们之前下载好的社区版IDEA的路径,然后提示我们选择JDK,就选择我们本地的jdk即可。

基本配置

项目创建完成之后,在resources.META-INF文件夹下有一个plugin.xml文件,其中我们可以配置我们插件的基本信息,包括作者的信息和组件、事件等的注册信息。

<idea-plugin>
  <id>yzstu</id>  <!-- 当前插件的唯一id号 -->
  <name>A demo</name> <!-- 插件的名称 -->
  <version>1.0</version>  <!-- 插件的版本号 -->
  <vendor email="dikeywang@163.com" url="https://blog.yzstu.cn">yzstu</vendor>  <!-- 开发者信息 -->

  <description>This is a idea plugin just for test and learning</description> <!-- 插件的描述 -->

  <change-notes>This is a idea plugin just for test and learning</change-notes> <!-- 插件的更新信息 -->

  <!-- please see https://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/build_number_ranges.html for description -->
  <idea-version since-build="173.0"/> <!-- 表示当前插所支持的idea版本 -->

  <!-- please see https://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/plugin_compatibility.html
       on how to target different products -->
  <depends>com.intellij.modules.platform</depends>

  <extensions defaultExtensionNs="com.intellij">
    <!-- Add your extensions here -->
  </extensions>

  <!-- 新增的Action类需要在这里注册 -->
  <actions>
    <!-- Add your actions here -->
  </actions>

</idea-plugin>

实现第一个功能

创建service

先提前说一下,我们这里讲的应用级别的service和项目级别的service是没有实际意义的,只是为了说明有这两种service和他们在创建过程中的差异来进行创建的。

应用级别service

这里我创建了BaseService、HiService两个接口,其实可以不用创建,创建他们是为了变现我们在开发过程中的继承架构。

BaseService

package cn.yzstu.demo.service;

/**
 * @author Baldwin
 */
public interface BaseService {
}

HiService

package cn.yzstu.demo.service;

/**
 * @author Baldwin
 */
public interface HiService extends BaseService {
    String sayHi();
}

HiServiceImpl

package cn.yzstu.demo.service;

/**
 * @author Baldwin
 */
public class HiServiceImpl implements HiService {
    @Override
    public String sayHi() {
        return "Hello!!!";
    }
}

项目级别service

这个service就没有任何的继承关系,我们在做demo的时候像这样直接创建service就行

package cn.yzstu.demo.service;

/**
 * @author Baldwin
 */
public class AuthorInfo {
    public String getAuthorInfo() {
        return "Baldwin create me -_-!";
    }
}

注册service

看完上面创建service后,你可能会感觉到疑惑,他们两个从代码上来看,是没有本质的区别的,那为什么一个是应用级别的而另一个是项目级别的呢?其实决定一个service是什么级别的,是service的注册方式。

  <extensions defaultExtensionNs="com.intellij">
    <!-- 应用级的service注册 -->
    <applicationService serviceImplementation="cn.yzstu.demo.service.HiServiceImpl" id="hiService"/>

    <!-- 项目级的service注册 -->
    <projectService serviceImplementation="cn.yzstu.demo.service.AuthorInfo" id="authorInfo"/>
  </extensions>

应用级别的service是在applicationService节点下注册,而项目级别的是在projectService节点下注册的,其实还有一种service是模块级别的,在moduleService节点下进行注册,我们今天没有关于moduleService的内容。

创建action

package cn.yzstu.demo.action;

import cn.yzstu.demo.service.AuthorInfo;
import cn.yzstu.demo.service.HiServiceImpl;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.ui.Messages;
import org.jetbrains.annotations.NotNull;

/**
 * @author Baldwin
 */
public class Demo extends AnAction {

    @Override
    public void actionPerformed(@NotNull AnActionEvent anActionEvent) {
        // 获取应用级别的service,所有的idea client共用这一个service
        HiServiceImpl hiServiceImpl = ServiceManager.getService(HiServiceImpl.class);
        // 获取项目级别的service,当前打开的客户端所拥有的service
        AuthorInfo projectService = ServiceManager.getService(anActionEvent.getProject(), AuthorInfo.class);
        Messages.showMessageDialog(hiServiceImpl.sayHi() + projectService.getAuthorInfo(), "提示", Messages.getInformationIcon());
    }
}

注册Action

现在直接启动插件,我们刚才创建的Action是不会生效的,就像是在spring中的bean,不注册到BeanFactory中也是不生效的,我们在插件开发中需要把所有的Action注册到plugin.xml中才能行。

  <actions>
    <action class="cn.yzstu.demo.action.Demo" id="demo" text="ShowAuthor" description="test demo" >
      <add-to-group group-id="HelpMenu" anchor="first"/>
    </action>
  </actions>

我们注册一个Action时涉及到了几个设置项:

  • class:Action全类名
  • id:Action的全局唯一id
  • text:在菜单中的名称
  • group-id:选择在某一个菜单中展示,我们这里设置的是HelpMenu,也就是会在Help下进行展示。可选的参数有很多,假如你开启代码联想功能,可以直接在提示栏中进行选择
  • anchor:在菜单中的位置,我们这里选择的是第一个。代码联想功能下选择

运行插件

就像我们运行springboot项目一样。直接点击debug按钮,假如你是从头开始看这篇文章,并按照流程设置好SDK的话,项目运行之后会在沙盒模式下启动一个IDEA客户端,并且我们的当前开发的插件会自动安装到IDEA客户端上,我们点击菜单栏中的help按钮,就可以看到我们的插件入口了

我们点击ShowAuthor按钮就会出现我们是想的展示作者信息的弹窗

总结

过程中可能会出现问题的环节是SDK的设置,总结一下就是你需要配置jdk和插件运行的SDK,这里的SDK指的就是一个IDEA的安装包路径,我们建议使用社区版作为SDk,最好是把IDEA源码下载下来作为SDK,这暗影对后期的debug有很大帮助。

在编码方面其实没有很多难度,毕竟现在只是初步探索

正文到此结束