Sometimes it is a nice thing to extend an editor to have it do some new stuff, like being able to revert an open file to its state on disk. In this post I’m going to quickly demonstrate how to start and finish a plugin to extend theIntelliJ IDEA editor from Jetbrains. These instructions will work if you have the Ultimate or Community edition, and you can make the plugin available for all IntelliJ based editors including WebStorm, PyCharm, RubyMine and PHPStorm.

Whether you can finish these instructions under 30 minutes depends on your internet connection speed, because you have to do a git clone of the IntelliJ Community Edition source code, and that’s a lot of stuff to download.

At my current employer Floobits we are working on an IntelliJ plugin, and through that process I have learned most of this.

System requirements

OS: I have developed plugins for IntelliJ on both Mac OS X and Windows and the steps are the same.

Java: JDK 6 works, JDK 7 might not. I compile with a Java 1.6 JDK.

HD space: Lots of space for multiple copies of IntelliJ IDEA and its source code.

Getting the environment set up.

Resource: Official Jetbrain instructions

Step 1: Download and install Community Edition of IntelliJ IDEA

The first step, is to download and install the Community version of IntelliJ IDEA if you don’t already have it. Even if you have the Ultimate version of IntelliJ IDEA, you will need the Community version. This is because the Ultimate version is closed source and when you’re debugging it is nice to be able to see the source and definitions for IntelliJ resources. Note I still use the Ultimate version of IntelliJ IDEA (version 13) to develop the plugin. I debug and test the plugin using the Community version.

Remember the path to where the Community Edition was installed to, you’ll need this in a moment.

Step 2: Do a shallow git clone of the IntelliJ IDEA Community Edition source code

git clone --depth 1 https://github.com/JetBrains/intellij-community.git

This step will take the longest because it takes forever to do a git clone of the IntelliJ source code. Thus do a shallow git clone using –depth 1 in the command. This is really simple on a Mac or any *nix based system, just use git clone –depth 1. On Windows I used Atlassian’s SourceTree which allows you to specify the depth in the GUI. A depth of 1 reduces the download because the history is truncated to a depth of 1. If you do not do this step, downloading the source code will take you days.

Step 3: Create a project and set up your project structure.

Create a project

Fire up the version of IntelliJ that you want to use to write code. This can be either of the Ultimate or Community versions. Create a new project. Name it whatever you want to call your plugin. I’m going to call mine DiskRead.

Set up the SDK

If you already have a Java JDK skip this paragraph. If you don’t have one already, you’ll have to get a Java JDK. Somewhere or other on the Jetbrains site it recommends Java 1.6, but Oracle will warn you that it is out of date. I have had problems using the JDK 7 when interacting with Intellij jar files compiled with 1.6. Once you have downloaded a Java JDK, you’ll need to create an SDK for this in IntelliJ IDEA even though we will not use it directly. In the project structure dialog that appears after you create a new project, create a new SDK for the version of Java you downloaded similar to the step below, only you’ll be giving it the path to where you installed the Java JDK.

Setup a Plugin SDK by clicking the “new” button next to the Project SDK:

Note that the SDK setup project structure dialog looks a little different on Windows.

It will prompt you to locate the Comunity Edition that you installed. You are not to give it the path to the source you downloaded, this step requires the path to the Community Edition of IntelliJ that you installed in the first step. On a Mac the path for this is:

/Applications/IntelliJ IDEA 13 CE.app

On Windows the path was:

C:\\Program Files (x86)\JetBrains\IntelliJ IDEA Community Edition 13.0.1

Click finish if you are happy with where it will create the project, but you are not yet done setting things up.

You should now see a project window for the project you just created. Go to File->Project Structure from the menu. On a mac you can just hit ⌘+; on Windows it’s Cntrl+Alt+Shift+S. On the left side, click on “SDKs” and check out the classpath tab:

Next click on the sourcepath tab:

Here you’ll add the path to the shallow git clone for the IntelliJ Community edition source you checked out. Click the plus button at the bottom. Find the path in the dialog that appears. Click OK, then you should see a bunch of classes were added. Click apply and ok.

We are still not done settings everything up. Next you’ll want to set up a build and debug configuration. From the top menu go to Run -> Edit configurations:

Give the build configuration a name, it’s not important what it is. I also recommend checking “Show idea.log” because it gives you a nice tab in the debug window to show you info and warning statements.

Congratulations, you are now all done setting up!

Developing the plugin

Resources

IntelliJ IDEA Plugin Development Guide

Plugin Development FAQ

IntelliJ IDEA Architectural Overview

Making it work.

So now that the environment is all set up, in order to get my file to reflect the state on disk I need to create an action. First thing is to use the GUI to create a new action:

So I right click on src in the project sidebar and click “new” and then click “Action.” This will lead to a dialog to create a new Action. You give it a name, an id, a class name, a helpful description and then assign it to a group which will tell IntelliJ where to put this action. Actions don’t have to be a part of groups, and you can even make buttons that go into the project UI, but in this case I just want it to be in the “toolbar” menu like so:

You can also assign keyboard shortcuts, as I did.

Once you’re all done there click OK and two things should have happened:

  1. Your plugin.xml should be updated to reflect your new action. You can see this XML file by selecting it from within the META-INF directory in your project sidebar. You should see your action in the actions section.

  2. A new class called ReadCurrentFile was created.

For me the new class looks like this:

import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
/**
* User: bjorn
* Date: 1/29/14
* Time: 12:28 PM
*/
public class ReadCurrentFile extends AnAction {
public void actionPerformed(AnActionEvent e) {
// TODO: insert action logic here
}
}

I do some little magic coding and write the code to get my plugin to do what I want:

import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.sun.org.apache.bcel.internal.generic.NEW; import java.io.*;
import java.util.regex.Pattern; /**
* User: bjorn
* Date: 1/29/14
* Time: 12:28 PM
*/
public class ReadCurrentFile extends AnAction {
public void actionPerformed(AnActionEvent e) {
final Project project = e.getProject();
if (project == null) {
return;
}
Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor();
if (editor == null) {
return;
}
final Document document = editor.getDocument();
if (document == null) {
return;
}
VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(document);
if (virtualFile == null) {
return;
}
final String contents;
try {
BufferedReader br = new BufferedReader(new FileReader(virtualFile.getPath()));
String currentLine;
StringBuilder stringBuilder = new StringBuilder();
while ((currentLine = br.readLine()) != null) {
stringBuilder.append(currentLine);
stringBuilder.append("\n");
}
contents = stringBuilder.toString();
} catch (IOException e1) {
return;
}
final Runnable readRunner = new Runnable() {
@Override
public void run() {
document.setText(contents);
}
};
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
CommandProcessor.getInstance().executeCommand(project, new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(readRunner);
}
}, "DiskRead", null);
}
});
}
}

This basically does one thing: When the action is run (like by selecting it from the tools menu), it reads the current file from disk and updates it. It does this by getting the current active editor from the project, then getting the document from it, using that to get the VirtualFile and then using a plain old Java File to read the contents from disk. Reading from the VirtualFile would accomplish nothing, as that is the cached content that I’m trying to replace from disk.

The runnables and invoke later nested classes you see there are required by IntelliJ. It’s very verbose, but basically you can’t write a file in the main thread, it needs to be done in a runWriteAction which requires an invokeLater. If you want to read from VirtualFiles and documents you’d need to run that in a similar runReadAction. IntelliJ will scream at you at runtime if you forget to do this.

The last thing I do is update the document with setText. Internally IntelliJ documents represent new lines with the unixy “\n” line ending in all cases. Attempting to use a carriage return will result in an assertion error. So thus I append all new lines to the StringBuffer as “\n” instead of what they originally were and any carriage returns will be replaced with new lines. When IntelliJ writes files to disk, it will use the type of new line characters you have selected in your preferences, but internally it is always “\n”.

Testing it

Finally, I click Run->Debug and IntelliJ will spawn a second IntelliJ instance which will have my plugin installed. I open up a dummy project, write some text into a file without saving it (note I have all automated saves disabled in my settings), and then go to the Tools menu to select my action. I see it runs, and removed all the text I added into the file.

Deploying

Now that I’m all done I want to tell the world about it and install it myself. For that, go back to your regular IntelliJ and go to Build ->Prepare Plugin Module “DiskRead” For Deployment

This may create either a zip file or a jar file. You can install this new file right into your IntelliJ by opening up settings and going to plugin and clicking the “Install from Disk” or you can go ahead and get your plugin up on the officialJetbrains plugin repository.

Final note

If you want your plugin to work in PyCharm or RubyMine or any of the other IntelliJ based editors you need to uncomment a line in your plugin.xml.

Change this:

  <!-- uncomment to enable plugin in all products
<depends>com.intellij.modules.lang</depends>
-->

To this:

  <depends>com.intellij.modules.lang</depends>

I put the source code in a GitHub repo:

https://github.com/btipling/DiskRead/

Any errors or comments, please send to @bjorntipling

How to make an IntelliJ IDEA plugin in less than 30 minutes的更多相关文章

  1. Intellij MyBatisPlus Plugin插件破解

    1. 下载原始的MyBatisPlus Plugin插件. 2. 下载替换包,请根据实际版本下载: https://github.com/myoss/profile/tree/master/idea/ ...

  2. 从零开始编写IntelliJ IDEA插件

    写Java代码的时候,经常会涉及到重复性的操作,这个时候就会想要是有这样一个插件就好了,如果是大家都会遇到的场景,IDE或许已经提供了,再不然也有可能有人编写了相关的插件.要是这个操作是你们的编码环境 ...

  3. IntelliJ IDEA手工安python装插件方法

    IntelliJ IDEA手工安装插件方法 以IntelliJ IDEA 11.0.1安装python为例: (1)下载python插件地址:http://plugins.intellij.net/p ...

  4. 在IntelliJ IDEA14中安装go语言插件

    go语言的集成开发环境仍不成熟,试用了liteide,感觉很不适应,弹出菜单对程序员的干扰太大.所以就试大牌的IntelliJ IDEA,这工具本来是JAVA开发阵营的,不过它已经变为一个非常强大的支 ...

  5. 安装IntelliJ IDEA JetGroovy(转)

    JetGroovy是一个免费而且开源的专用于支持Groovy和Grails的IntelliJ IDEA插件.这个插件是由JetBrains公司自己开发的,对于Groovy语言和Web框架都提供了无以伦 ...

  6. intellij idea该插件开发摘要

    最近在做一个intellij idea插件,功能是读取表和数据库信息字段和预先定义的模板来生成代码文件(实体,service,springmvc该controller,freemark文件等). 找了 ...

  7. intellij idea 插件开发--快速定位到mybatis mapper文件中的sql

    intellij idea 提供了openApi,通过openApi我们可以自己开发插件,提高工作效率.这边直接贴个链接,可以搭个入门的demo:http://www.jianshu.com/p/24 ...

  8. IntelliJ IDEA Configuring projects

    https://www.jetbrains.com/help/idea/configuring-projects.html Configuring projects A project in Inte ...

  9. Intellij IDEA 插件开发秘籍

    来这里找志同道合的小伙伴! 这里总结一下 Intellij IDEA 插件开发的知识,供大家参考,本篇文章包含以下内容: 开发环境搭建 Component 介绍 Extension Point And ...

随机推荐

  1. python+selenium三:鼠标事件与键盘事件

    1.鼠标事件:# 每个模拟事件后需加.perform() 才会执行# context_click() 右击# double_click() 双击# drag_and_drop(source, targ ...

  2. python 全栈开发,Day43(python全栈11期月考题)

    python全栈11期月考题 1.常用字符串格式化有哪些?并说明他们的区别 2.请手写一个单例模式(面试题) 3.利用 python 打印前一天的本地时间,格式为‘2018-01-30’(面试题) 4 ...

  3. Linux下安装JDK7和TomCat7

    [BEGIN] 2016/9/9 14:20:49[root@rzhd jdk]# ll总用量 149916-rw-r--r-- 1 root root 153512879 9月 9 14:20 jd ...

  4. Mistwald POJ

    一开始看不出来是快速幂矩阵的题目 先要把整个地图离散化为1,2,3,4,.... 连成一个有向图 邻接矩阵的平方意为:假如a->b  且b->c     那么一次平方后   a->c ...

  5. 6-14 Abbott的复仇 uva816

    我的第一题bfs 将方向固定  NESW  然后左转和右转就是+3和+1!!! 还有就是  建立一个数组 储存父节点  这样就可以往回打印出路径   打印的截至条件是 d[][][]==0时  说明到 ...

  6. java语言打印上三角和下三角,进一步得到九九乘法表

    关于下面两种图形的打印问题 ***** 与 * ****  ** *** *** ** **** *  ***** 一:程序 1.先打印下三角 2.结果 3.后打印上三角 4.结果 二:知识点 1.f ...

  7. Python - __name__ == '__main__'

    if __name__ == '__main__': app.run() __name__系统变量指示模块应如何被加载,他的值为"__main__"时表示当前模块是被直接执行. _ ...

  8. 树莓派(Raspbian系统)中使用pyinstaller封装Python代码为可执行程序

    一.前言 将做好的Python软件运行在树莓派上时,不想公开源码,就需要对文件进行封装(或称打包),本文主要介绍使用pyinstaller封装Python代码为可执行程序. Python是一个脚本语言 ...

  9. Linux/Window 正斜杠 反斜杠

    文件目录结构: Linux 是用正斜杠 目录名区分大小写 Window 是用反斜杠 目录名不区分大小写

  10. Object类浅析

    Object类的方法有: hashCode(): 返回该对象的哈希码值 hashCode 的常规协定是: 在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回 ...