IntelliJ Plugin Development Cookbook

This post is intended to help people writing IntelliJ plugins, with a focus on plugins for Java projects. Although the IntelliJ docs are pretty good, this post collects together lots of small “how to” instructions that I’ve found useful when writing a custom plugin.

Introduction

IntelliJ Plugin Development docs: https://www.jetbrains.org/intellij/sdk/docs/welcome.html https://www.jetbrains.org/intellij/sdk/docs/basics/getting_started.html

It is really important to understand the different ways you can interact with files:

  1. As VirtualFiles, which confusingly, are the files on the filesystem.
  2. As structured, understood files, called PSI files. e.g. a Java file is a PSI file
  3. As files open in the Editor.
  4. XML files
IntelliJ file docs:
https://www.jetbrains.org/intellij/sdk/docs/basics/architectural_overview/virtual_file.html https://www.jetbrains.org/intellij/sdk/docs/basics/architectural_overview/documents.html
https://www.jetbrains.org/intellij/sdk/docs/reference_guide/editors.html

Structured files like Java or XML are called PSI:
https://www.jetbrains.org/intellij/sdk/docs/basics/architectural_overview/psi.html
https://www.jetbrains.org/intellij/sdk/docs/basics/psi_cookbook.html

How to add an action to a menu

In your plugin.xml:
 
<actions>
    <action id="com.ice.refactor.RemoveFacadeUsageAction" class="com.ice.refactor.RemoveFacadeUsageAction" text="Remove Facade Usage"
            description="Remove facade usage">
        <add-to-group group-id="RefactoringMenu4" anchor="last"/>
    </action>
However by far the easiest way to do this is to use the custom inspection / quick fix – if you have an action not yet added to the plugin config, right click on the class name and IntelliJ will open a dialog box to help you add the config. Really cool!

How to add settings to your plugin

See this useful post: Adding plugin settings

Essentially:

  • Create a Configuration class
  • Create a Form class that it will bind to
  • Use the Visual Editor to design the form
  • Use the PropertiesComponent.getInstance() to save simple properties like booleans and strings

Find the PSI element under the carat

  
final Editor editor = event.getData(CommonDataKeys.EDITOR);
int findElementFlags = TargetElementUtil.REFERENCED_ELEMENT_ACCEPTED + TargetElementUtil.ELEMENT_NAME_ACCEPTED + TargetElementUtil.LOOKUP_ITEM_ACCEPTED;
TargetElementUtil targetElementUtil = new TargetElementUtil();
PsiElement psiElement = targetElementUtil.findTargetElement(editor, findElementFlags, offset);

Getting the text under the carat

  
final Editor editor = event.getData(CommonDataKeys.EDITOR);
int offset = editor.getCaretModel().getOffset();
Document document = editor.getDocument();
String textUnderCarat = document.getText(TextRange.from(offset - 10, offset + 30));

Getting the VirtualFile from the Document in the editor

 
VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(document);

See: Virtual file

Find classes implementing an interface

 
PsiClass interfaceClass = (PsiClass)psiElement;
PsiElement psiImplClass = DefinitionsScopedSearch.search(interfaceClass).findFirst();
PsiClass facadeImplementationClass = (PsiClass)psiImplClass;

Find usages of a method

Collection usages = ReferencesSearch.search(myMethod).findAll();

Find children of a PSI element

PsiTreeUtil.findChildOfType

Add an annotation to a Java class

 
javaPsiFacade = JavaPsiFacade.getInstance(event.getProject());
PsiElementFactory elementFactory = javaPsiFacade.getElementFactory();
PsiAnnotation inputAnnotation = elementFactory.createAnnotationFromText(annotationText, psiClass);
// Note that we pass in the desired annotation, but another java object is actually created and added to the target. 
// This is what we must pass back to our caller. 
PsiAnnotation actualAnnotation = (PsiAnnotation)targetLocation.addAfter(inputAnnotation, targetLocation);

Show a message / error dialog

Messages.showMessageDialog(project, “Element under carat is not a Java class name”, “Refactoring Plugin”, Messages.getErrorIcon());

Permit message dialogs in tests

TestDialogManager.setTestDialog(TestDialog.OK);

Write messages to the event log

Notifications.Bus.notify(newNotification(“your-plugin-group”,”YourActionName”,message,NotificationType.INFORMATION));

Load an XML file

Simply load as a PsiFile and then cast to XmlFile.
This entry was posted in IntelliJ, Java, Uncategorized and tagged , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

HTML tags are not allowed.

517,762 Spambots Blocked by Simple Comments