IntelliJ IDEA is currently the best JAVA development IDE, its own functions have been very powerful, but everyone’s needs are not the same, some needs IDEA itself can not meet, so we need to develop plug-ins to solve. To improve the efficiency of development, we can use the plug-in function provided by IDEA to meet our needs. What if I don’t have the features I need? It’s simple, we build one!

What can plug-ins do?

IDEA plug-ins can do almost anything because they encapsulate the capabilities of the IDE itself. The main plug-in functions include the following four types:

  • Custom language support: If there is a language that IDEA does not support temporarily, you can write a plug-in to support it. For example, the original support for Go language was done through the plug-in, and later made a separate Goland. There are official tutorials supported by custom language plug-ins.
  • Framework support: Such as Struts 2 framework support
  • Tool integration: You can enhance the built-in functions of IDEA, such as adding the function of CodeReview to Git operations. Refer to the Gerrit
  • User interface: Custom plugins change the user interface. Reference the BackgroundImage

In order to reduce the duplication of code writing, I wrote a code generation plug-in IDEA code generation plug-in CodeMaker, which supports custom code generation templates.

Hello world plug-in

As usual, we’ll start with Hello World.

Create a new GradLe plugin project

Some tutorials recommend starting with the default plugin project with IDEA, but I prefer to use Gradle to manage the entire plugin project. It is very convenient to manage dependencies later, otherwise you have to manage them manually.

Click New Project and select Gradle

Next fill in the project properties

To configure Gradle, use the default configuration

After creating a project, IDEA will automatically start parsing the project dependencies, because it needs to download a SDK dependency package of several hundred megabytes, so it will take a long time, and it will be faster to open science online.

After Gradle dependencies are resolved, the project structure is shown below, where plugin.xml is the configuration of the plug-in and build.gradle is the configuration of the project dependencies (analogous to POM.xml).

Here is the plugin.xml generated by default

<idea-plugin> <! <id>com.xiaokai.test.demo</id> <! <name>Demo</name> <! -- Developer info --> <vendor email="[email protected]" url="http://www.yourcompany.com">YourCompany</vendor> <! --> <description><! [CDATA[ Enter short descriptionforyour plugin here.<br> <em>most HTML tags may be used</em> ]]></description> <! -- please see http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/plugin_compatibility.html on how to target different products --> <! -- uncomment toenable plugin inall products <depends>com.intellij.modules.lang</depends> --> <! -- Dependent on other plug-in capabilities --> < Extensions defaultExtensionNs="com.intellij"> <! -- Add your extensions here --> </extensions> <! -- Plugin actions --> <actions> <! -- Add your actions here --> </actions> </idea-plugin>Copy the code

Create an Action

Action is the handler for the event response in IDEA, and its actionPerformed is like the onClick method in JS. As you can see, plug-in development is essentially no different from Web or Android development because it’s event-driven programming.

We can use the Action generator provided by IDEA directly

Clicking OK generates the class file in SRC:

package com.xiaokai.test;

import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;

public class HelloWorldAction extends AnAction {

    @Override
    public void actionPerformed(AnActionEvent e) {
        // TODO: insert action logic here
    }
}

Copy the code

At the same time, the action information is registered with plugin.xml

<! -- Plugin actions --> <actions> <! -- Add your actions here --> <action id="demo.hello.world" class="com.xiaokai.test.HelloWorldAction" text="HelloWorld"
                description="Say Hello World">
            <add-to-group group-id="GenerateGroup" anchor="last"/>
        </action>
    </actions>
Copy the code

Pop-up dialog box

After creating the Action, we will start to write the logic inside it. Since we are teaching Hello World, let’s try the simplest pop-up dialog.

@override public void actionPerformed(AnActionEvent e) {// Obtain the current Project context e.getData(PlatformDataKeys.PROJECT); PsiFile PsiFile = LLDB etData(commonDatakeys.psi_file); String classPath = psifile.getVirtualFile ().getPath(); String title ="Hello World!"; / / display dialog Messages. ShowMessageDialog (project classPath, the title, the Messages. GetInformationIcon ()); }Copy the code

After the code is written, open the Gradle screen and click runIde to launch an IDEA with the plugin installed. You can then test it. You can also right-click Debug mode to enable breakpoints.

The running effect is as follows:

Advanced tutorials

If you want to learn more about the principles and design philosophy, you can see the official documentation of the IntelliJ Platform SDK. But to be honest, the documentation is pretty poor, basically a brief introduction of concepts and principles without in-depth analysis. So if you want to dig deeper, you’re on your own. The most reliable way to learn is to look at other people’s plug-ins. For example, if you want to know how to implement automatic code generation, you can look for plug-ins that support this feature and see how their source code is written.

When I was writing CodeMaker, I did it by eating the source code myself. Here’s a quick look at some of the apis I’ve used, which are mostly undocumented and passed on in code.

What is the element selected by the cursor

PsiElement = anActionEvent. GetData (langDatakeys.psi_element); PsiElement = anActionEvent. // If the cursor does not select a class, a dialog box is displayed to remind youif(psiElement == null || ! (psiElement instanceof PsiClass)) { Messages.showMessageDialog(project,"Please focus on a class"."Generate Failed", null);
            return;
        }
Copy the code

Gets all class objects for the current class file

A class file might have inner classes, so reading them returns a list

    public static List<PsiClass> getClasses(PsiElement element) {
        List<PsiClass> elements = Lists.newArrayList();
        List<PsiClass> classElements = PsiTreeUtil.getChildrenOfTypeAsList(element, PsiClass.class);
        elements.addAll(classElements);
        for(PsiClass classElement: classElements) {// get the internal classElements. AddAll (getClasses(classElement)); }return elements;
    }
Copy the code

Formatting code

    public static void reformatJavaFile(PsiElement theElement) {
        CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(theElement.getProject());
        try {
            codeStyleManager.reformat(theElement);
        } catch (Exception e) {
            LOGGER.error("reformat code failed", e); }}Copy the code

Use a sticking board

        CopyPasteManager.getInstance()
            .setContents(new SimpleTransferable(table.toString(), DataFlavor.allHtmlFlavor));
Copy the code

More and more

For more tips, see my project CodeMaker, as well as other open source plug-ins.