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. 获取修改value

    val() 方法,获取和修改有value属性的元素,有value属性的元素有input.botton.select等.相当于JavaScript中的value. <!DOCTYPE html&g ...

  2. ERP出库审核业务(四十四)

    结束表单流程的代码: protected void btnSubmit_Click(object sender, EventArgs e) { if(this.txtreceiveDate.Text! ...

  3. hdu 1005 根据递推公式构造矩阵 ( 矩阵快速幂)

    f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7. Sample Input1 1 3 //a b n1 2 100 0 0 ...

  4. thinkphp搭建后台品字形框架页面

    页面分为三个部分 head,left,right共同组成了index 在indexController中 function Index(){ $this->display(); } //展现后腰 ...

  5. python全栈开发day31-操作系统介绍,异步、同步、阻塞、非阻塞,进程

    一.网络编程内容回顾 1.arp协议 #交换机 #广播.单播 2.ip协议 3.tcp和udp协议 tcp:可靠的,面向连接的,字节流传输,长连接 三次握手:一方发送请求,另一方确认请求同时发送请求, ...

  6. Codeforces Round #441(Div.2) F - High Cry

    F - High Cry 题目大意:给你n个数,让你找区间里面所有数或 起来大于区间里面最大数的区间个数. 思路:反向思维,找出不符合的区间然后用总数减去.我们找出每个数掌控的最左端 和最右端,一个数 ...

  7. BZOJ1968 [Ahoi2005]COMMON 约数研究 数论

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1968 题意概括 求 ΣF(i)   (1<=i<=n)N<=1000000 F( ...

  8. C++和java的区别和联系

    今晚,数院的一个兄弟借我Java课本,顺便问了一句“Java和C++到底有啥区别啊”.一下子有点问蒙了,“啊额.....运行平台不同....”  "一个在高层,一个在底层...." ...

  9. Redis持久化(persistence)

    Redis 持久化 Redis 提供了多种不同级别的持久化方式: RDB 持久化可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot). AOF 持久化记录服务器 ...

  10. QT学习之菜单栏与工具栏

    QT学习之菜单栏与工具栏 目录 简单菜单栏 多级菜单栏 上下菜单栏 工具栏 简单菜单栏 程序示例 from PyQt5.QtWidgets import QApplication, QMainWind ...