There are many IntelliJ plugins out there. Still, existing SDK documentation does not cover every development step. Here I describe how a basic IntelliJ plugin with menu and import/export functionality can be developed.
Sometimes, after working on some project for a long enough period, you end up with a particular window layout that is convenient for you, e.g., console on the right side, source code on the left, debug window at the top.
However, if you open the same project on a different machine, the layout you’ve so delicately configured will be lost. Same situation will happen if you want to reuse a layout from some other project.
Preserve Layout Plugin allows you to export the layout of any IntelliJ project and then import it back. Export is done using the XML format.
About this blog post
I wrote this post to address the issues I encountered during development of such plugin. As of current date (Oct 20, 2017), IntelliJ SDK documentation is way far from being complete. Below is my collection of findings regarding missing pieces.
For initial setup, if you never developed a JetBrains’ plugin, I highly recommend to go through the Getting Started section of IntelliJ Platform SDK.
You will notice that some sections are missing and greyed out. However, just by following these initial setup steps you will get just enough to create your own plugin. It is important to mention that in order to debug a plugin you will need the source code of IntelliJ Community Edition checked out and attached to the project.
If you are familiar with plugin development for IntelliJ, it is safe to skip this section.
To play around a little bit, let’s create a very simple plugin with one action. Just to test the things and confirm that setup is working.
First thing you might look in to is the
plugin.xml file that contains the
basic configuration of your plugin.
After filling in the standard information fields like
we can jump straight to the
Here we can statically position and initialize our actions.
plugin.xml is sufficient enough for most needs. However, when doing complex
stuff, we can initialize actions dynamically in Java.
Let’s position our action in the Project View popup menu, the one that appears when you right-click the project name in IDEA.
You can see that we created a unique
id for this action. A class for the
should also be specified. A name and description will be
<add-to-group ...> tag is the one responsible for tying our action to the
specific menu in IDEA.
Obviously, we will need a class responsible for this action. Let’s make it
super simple: it will print project’s name to the console. You can
notice that we inherit from
AnAction class and override the
After we run this code, IDEA will spawn a new instance of itself with our plugin installed by default. After we right click on the project (you will need a project to be created or open) and invoke context menu, we will see that LayoutExporter action appeared in this menu. Clicking this action will print a project name to the console output.
Of course, we can assign actions to a different menu. For example, in
preserve-layout-plugin actions are added to the
Window layout in IDEA
Stepping into the actual logic, we might ask ourselves where is the layout of current project stored in IntelliJ IDEA? Turns out it can be stored in two ways:
directory based project: in
file based project: in
.iwsfile in a project directory
JetBrains is planning to deprecate the file based format. But we still have to support both options.
Getting current window layout:
To obtain current layout state we obtain an instance of the
Having the manager, we can now ask it for a current layout. An instance of
DesktopLayout will be returned. Then we cas use
DesktopLayout to return
org.jdom.Element representation of itself.
Next step is to save this XML/DOM Element somewhere.
File Saver dialog & Saving/writing a file
File Saving dialog:
Somehow, file saving dialog in IntelliJ is invoked in a different way,
comparing to File Chooser. It is also not mentioned yet in documentation.
However, you can come across a
FileSaverDescriptor class, which when
instantiated and passed to
FileChooserFactory as a parameter will produce a correct dialog window.
Writing to a File in IntelliJ:
Actual data writing is simple, but not obvious. It is required to execute
“write” operations outside of the main thread. To address this,
a very convenient
Besides that, best approach to write a file to a disk is through
VirtualFile abstraction layer.
Let’s take a look at a composed example of logic required to save an XML to a file in IntelliJ.
File Chooser dialog & importing layout
The best way to select a file in IntelliJ is to use the
and the overloaded function
chooseFile that accepts a callback parameter to
be called after the file is selected. When using this approach IntelliJ is
able to invoke native file chooser dialog window on every platform.
Now we need a callback function
As you can notice,
importLayoutFileToProject makes 2 calls to the helping methods.
One to parse the imported XML file, and the other to apply the parsed
layout to IDE. Let’s implement them as well.
Having all that we can now import and export window layout’s of any project. However, it would be nice to notify a user about results of the export/import process.
Basic notifications are very easy to fire in IntelliJ:
Here we can change the icon to emphasize the
Make plugin runnable in every JetBrains IDE
Last thing but not the least important. To support every JetBrains IDE it is
required to specify the
<depends> tag in
<plugin>. More details about
plugin compatibility are available at SDK docs.
This plugin has been developed thanks to Alexander Zolotov from JetBrains team. He provided tons of invaluable tips and advices during the development of this plugin.