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. php中foreach()跳出循环或者终止循环的实现方法

    $arr = array('a','b','c','d','e'); $html = ''; foreach($arr as $key => $value){ if($value=='b'){ ...

  2. poj2279 线性dp

    #include<iostream> #include<cstdio> #include<cstring> #define ll long long using n ...

  3. Android strings.xml中定义字符串显示空格

    <string name="str">字 符 串</string> 其中   就表示空格.如果直接在里面键入空格,无论多少空格都只会显示一个. 用的XML转 ...

  4. Ajax和JSON完成二级菜单联动的功能

    首先需要找好JSON的包哦: 链接:http://pan.baidu.com/s/1jH6gN46 密码:lbh1 1:首先创建一个前台页面,比如secondMenu.jsp,源码如下所示: < ...

  5. [转] SSO单点登录原理和流程分析

    WEB的登录那些事#### 说道账户登录和注册,其实我们每天都在亲身感受着,像微博.知乎还有简书等等.我们总是需要定期的去重新登录一下,对于这种认证机制,我们都能说出来两个名词,Cookie.Sess ...

  6. mvn2gradle

    mvn项目根目录下,运行 gradle init --type pom 备注: 1)确保build.gradle, settings.gradle不存在 2)gradle 3.1测试通过 3)修改bu ...

  7. HDU5818 Joint Stacks 左偏树,可并堆

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - HDU5818 题意概括 有两个栈,有3种操作. 第一种是往其中一个栈加入一个数: 第二种是取出其中一个栈的顶 ...

  8. BZOJ5120 [2017国家集训队测试]无限之环 费用流

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ5120 题意概括 原题挺简略的. 题解 本题好难. 听了任轩笛大佬<国家队神犇>的讲课才 ...

  9. Flutter常用组件(Widget)解析-Container

    一个组件它往往包含了一些常见的painting, positioning和sizing这样的小部件. Container相当于我们常用的div,在Flutter中用的非常多,现在来看看Containe ...

  10. android studio 代码模板

    作者:韩梦飞沙 Author:han_meng_fei_sha 邮箱:313134555@qq.com E-mail: 313134555 @qq.com android studio 代码模板 an ...