Q&A of IntelliJ Plugin Development
IntelliJ IDEA is a nice IDE supporting various programming languages and helps us to write codes, debug, refactor, test, and so on. Although its default features are good enough, we can add new ones by developing plugins.
This post summarizes my exprience to develop a plugin in the Q&A format. Jetbrains provides comprehensive official documents (Plugin Development Guidelines and SDK DevGuide), so here I would like to focus on the more particular situations such as ‘How to create function like …’.
The sample code used in the post is here.
What is the first step to develop new plugins?
- Prepare a IntelliJ plugin project
- Follow the instructions here
- We can use any programming language appearing in the [Additional Libraries and Frameworks] in the [New Project] wizard.
The structure of a created project should be like:
your-plugin
+- .idea
| +- ...
|
+- resources
| +- META-INF
| +- plugin.xml // plugin settings file
+- src // plugin source directory
|
+- your-plugin.iml
How to create new menu items?
- Require the two steps
- Add
<actions>
inplugin.xml
to specify where you want to put new items - Create a class extending
AnAction
which performs what you want
- Add
- Follow the instructions here
How to create new intentions?
- What is intention?
- Editor’s suggestion of quickfix, refactoring and etc. (the detail is here)
- Available by pressing
<Alt> + <Enter>
- Require the two steps
- Add
<intentionAction>
inplugin.xml
to register your intention - Create a class extending
IntentionAction
which performs what you want
- Add
The below is the sample code of adding a new intention, HelloIntentionAction
which just println ‘hello’ when executed on the local variable.
plugin.xml
:
Add className
of the new intention into <extentions>
.
<idea-plugin>
...
<extensions defaultExtensionNs="com.intellij">
<!-- Add your extensions here -->
<intentionAction>
<className>com.tiqwab.intellij.HelloIntentionAction</className>
</intentionAction>
</extensions>
...
</idea-plugin>
HelloIntentionAction.scala
:
Prepare HelloIntentionAction
class.
package com.tiqwab.intellij
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.{PsiFile, PsiLocalVariable}
class HelloIntentionAction extends IntentionAction {
// Intention name shown in the popup
override def getText: String = "Hello"
// ???
override def getFamilyName: String = "Hello"
// ???
override def startInWriteAction(): Boolean = true
// Define when this intention is available
override def isAvailable(project: Project,
editor: Editor,
psiFile: PsiFile): Boolean = {
// Get PsiElement at the current position
// What is PsiElement: https://www.jetbrains.org/intellij/sdk/docs/basics/architectural_overview/psi_elements.html
val caretModel = editor.getCaretModel
val offset = caretModel.getOffset
val psiElement = Option(psiFile.findElementAt(offset))
// Check if the psiElement is local variable
psiElement.exists(_.getParent.isInstanceOf[PsiLocalVariable])
}
// Define what to do when the intention is executed
override def invoke(project: Project,
editor: Editor,
psiFile: PsiFile): Unit = println("Hello")
}
In the IDE, intentions are managed and handled like:
IntentionManagerImpl.myActions
seems to contains all available intentions.ShowIntentionActionHandler.availableFor
seems to check the intention should be listed in the current condition (callIntentionAction#isAvailable
)
How to create new popup menu items?
- What is popup menu?
- Right click menu in the editor
- You’ll see [Copy Reference], [Paste], and etc.
- Require the two steps
- Add
<action>
inplugin.xml
to register your popup item - Create a class extending
AnAction
which performs what you want
- Add
- Almost same procedure as described in Creating an Action, but there are some differences.
The below is the sample code of adding a new popup menu action, PopupHelloAction
which just println ‘hello’. This action appears in the popup menu only when the current cursor is on local variables.
plugin.xml
:
<idea-plugin>
...
<actions>
<!-- Popup menu settings -->
<action id="MyAction.PopupHello" class="com.tiqwab.intellij.PopupHelloAction" text="HelloPopup" description="Hello Popup Action">
<!-- Specify where you want to put item -->
<add-to-group group-id="EditorPopupMenu" />
</action>
</actions>
</idea-plugin>
PopupHelloAction.scala
:
package com.tiqwab.intellij
import com.intellij.openapi.actionSystem.{
AnAction,
AnActionEvent,
CommonDataKeys,
}
import com.intellij.openapi.editor.Editor
import com.intellij.psi.{PsiFile, PsiLocalVariable}
/**
* Sample of popup menu actions
*/
class PopupHelloAction extends AnAction {
// Enable and disable action
override def update(e: AnActionEvent): Unit = {
val dataContext = e.getDataContext
val isOnLocalVariableOpt = for {
project <- Option(e.getProject)
editor <- Option(e.getData[Editor](CommonDataKeys.EDITOR))
psiFile <- Option(e.getData[PsiFile](CommonDataKeys.PSI_FILE))
caretModel = editor.getCaretModel
offset = caretModel.getOffset
psiElement <- Option(psiFile.findElementAt(offset))
} yield {
psiElement.getParent.isInstanceOf[PsiLocalVariable]
}
isOnLocalVariableOpt match {
case None =>
e.getPresentation.setEnabledAndVisible(false)
case Some(false) =>
e.getPresentation.setEnabledAndVisible(false)
case Some(true) =>
e.getPresentation.setEnabledAndVisible(true)
}
}
// Perform what to do with the action
override def actionPerformed(anActionEvent: AnActionEvent): Unit =
println("hello from popup")
}
How to run and debug plugins?
- Just Run or Debug project in the usual way
- Follow the instruction here
Is it possible to use existing Actions?
- Yes, according to this answer
The below successfully calls RenameElementAction
from the custom action.
package com.tiqwab.intellij
import com.intellij.openapi.actionSystem.{AnAction,AnActionEvent,CommonDataKeys}
import com.intellij.refactoring.actions.RenameElementAction
class TellElementAction extends AnAction {
override def actionPerformed(e: AnActionEvent): Unit = {
val project = e.getProject
val element = e.getData(CommonDataKeys.PSI_ELEMENT)
new RenameElementAction().actionPerformed(e)
}
}
How to build project?
- Just click [Build] -> [Prepare Plugin Module …] in the main menu
- jar or zip file is created at the project root
- Follow the instruction here
Is it possible to install plugins from local archives?
- Yes, you can install plugins packaged as jar or zip following the steps:
- Click [File] -> [Settings]
- Click [Install plugin from disk…] in Plugins menu
- Specify the path of your archive
- Document says plugins are automatiically installed if put in the appropriate directory, but the IDE does not recognize it in my case
How to publish new plugins?
- Follow the instruction here
Is it possible to manage dependencies to other plugins?
- Add
<depends>
inplugin.xml
- Configure project settings to add the dependencies
- Configure run/debug settings to run IntelliJ IDEA with the dependent plugins
- Plugin Dependencies
- Developing IDEA plugin with dependency on Scala plugin