IntelliJ plugin development with Optimizely’s plugin

Tom Zurkan
5 min readJun 15, 2020

Turn On, Plug in, drop App

That was the name of my hack project at Optimizely. It was an IntelliJ plugin for all versions of IntelliJ with code complete for Go, Java, Kotlin, and Python. The plugin has now been released publicly. It was a great experience. I liked the IntelliJ ecosystem. You can literally create an IDE for a language that doesn’t exist. It essentially does all your basic lexical tokenizing for you.

After my experience, I wanted to write about it. I am very excited about Optimizely’s plugin and I think it will make using Optimizely seamless. In the first article of this series I wrote about how to use the Optimizely plugin. In this second article, I want to talk a little bit about the internals and developing IntelliJ plugins.

The first thing I’m going to say is that this article is light. You have access to the source code and that should speak volumes. Second, when I started this project, I didn’t see too many articles on IntelliJ plugin development. Now, there seems to be tons. So, I don’t want to repeat what other people already wrote. However, I did think that some documentation was hard to find, so I pointed out where you can find those.

Let’s look at creating a plugin from the perspective of the Optimizely plugin. The plugin is written in Java but could have been written in Kotlin. I like using gradle. It is more adaptable than using the IntelliJ IDE to manage your project. So, take an existing project from the IntelliJ samples and clone it.

Heck, clone the whole repo. It has tons of good examples. They are buried in the How To Guide so I wanted to link directly to them here. Better yet, clone the Optimizely Plugin. It has tons of nice examples as well. I found most of the coding and setup pretty intuitive once I got going. The How to Guide from Jetbrains was also helpful.

The other thing that is completely invaluable for auto complete is the PSI Viewer. The PSI stands for Program Structure Interface which as the name implies gives you the structure of your whole program from file to file. The PSI viewer is available when you debug your plugin by running ./gradlew runIde. You will end up poking around the viewer for a while in order to find the right element that you want to auto-complete on.

PSIViewer

So, let’s go through the Optimizely plugin a little deeper. First, I created actions. The actions are your menu.

It was easy to set those up along with an application level service that the actions used.

And figure out how to insert text:

You can see that I just use an insert at the caret in the editor and that works out fine. Another thing to notice is that I use a dynamic menu group for “Jump To”.

The dynamic menu is only available if you have set your SDK key with option-o s.

Keyboard shortcuts are important here. They allow you to continue to develop without having to reach for the mouse.

The key bindings allow the user to use keyboard shortcuts to invoke these menu items. They are defined in the plugin.xml. You can see an example in the action mentioned above.

Speaking of plugin.xml, you will also notice that I used optional dependencies to include the auto-complete for each language depending on what was available per IDE.

The gradle build became a challenge as I wanted to use one plugin for all the IDEs.

As you can see, I had to settle on a 2019 build. As a matter of fact, the latest version of Android is still built on a 2019 version. If you decide to create a plugin, you will get pretty familiar with the IDE builds and matching the appropriate language plugin build. I hope this saves you some time.

I used Java Swing for the debug dialog and that is the UI for all IntelliJ based IDEs. The dialog wrapper for the debug dialog was a lot of fun. I didn’t know Java Swing very well before this. I thought it was pretty easy to pick up and organize. It kind of had a ReactJS feel to it. It was easy enough to create a menu action that invokes the dialog.

Notice how the views take models and how the lambdas allow access to other ui elements. It’s pretty nice. The BoxLayout seemed to work best.

For the auto complete which is language specific, the PSI Viewer again was invaluable. There was a lot of trial and error in finding the right element to listen for in the CompletionContributor. I finally ended up creating a gradle based debug configuration to debug from the IDE. That was also very useful. Simply create a gradle run environment with intellij-plugin as the project and runIde as the task:

That concludes our high level walkthrough of the IntelliJ plugin. I hope it gives you confidence in using it as well as any ideas for developing new plugins.

Please checkout the open source Optimizely plugin. It will definitely help you get started if you want to write your own. I know that most of the work was poking around in all the documentation to find something. For instance, how to insert into the editor. That said, I also think that the plugin itself will be useful for those who develop on any IntelliJ based product. Happy Coding!

--

--

Tom Zurkan

Engineer working on full stack. His interests lie in modern languages and how best to develop elegant crash proof code.