How to make an IntelliJ IDEA plugin in less than 30 minutes
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
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:
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.
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的更多相关文章
- Intellij MyBatisPlus Plugin插件破解
1. 下载原始的MyBatisPlus Plugin插件. 2. 下载替换包,请根据实际版本下载: https://github.com/myoss/profile/tree/master/idea/ ...
- 从零开始编写IntelliJ IDEA插件
写Java代码的时候,经常会涉及到重复性的操作,这个时候就会想要是有这样一个插件就好了,如果是大家都会遇到的场景,IDE或许已经提供了,再不然也有可能有人编写了相关的插件.要是这个操作是你们的编码环境 ...
- IntelliJ IDEA手工安python装插件方法
IntelliJ IDEA手工安装插件方法 以IntelliJ IDEA 11.0.1安装python为例: (1)下载python插件地址:http://plugins.intellij.net/p ...
- 在IntelliJ IDEA14中安装go语言插件
go语言的集成开发环境仍不成熟,试用了liteide,感觉很不适应,弹出菜单对程序员的干扰太大.所以就试大牌的IntelliJ IDEA,这工具本来是JAVA开发阵营的,不过它已经变为一个非常强大的支 ...
- 安装IntelliJ IDEA JetGroovy(转)
JetGroovy是一个免费而且开源的专用于支持Groovy和Grails的IntelliJ IDEA插件.这个插件是由JetBrains公司自己开发的,对于Groovy语言和Web框架都提供了无以伦 ...
- intellij idea该插件开发摘要
最近在做一个intellij idea插件,功能是读取表和数据库信息字段和预先定义的模板来生成代码文件(实体,service,springmvc该controller,freemark文件等). 找了 ...
- intellij idea 插件开发--快速定位到mybatis mapper文件中的sql
intellij idea 提供了openApi,通过openApi我们可以自己开发插件,提高工作效率.这边直接贴个链接,可以搭个入门的demo:http://www.jianshu.com/p/24 ...
- IntelliJ IDEA Configuring projects
https://www.jetbrains.com/help/idea/configuring-projects.html Configuring projects A project in Inte ...
- Intellij IDEA 插件开发秘籍
来这里找志同道合的小伙伴! 这里总结一下 Intellij IDEA 插件开发的知识,供大家参考,本篇文章包含以下内容: 开发环境搭建 Component 介绍 Extension Point And ...
随机推荐
- hdu3530 双单调队列的维护
单调队列有部分堆的功能,但其只能维护给定区间中比v大的值或者比v小的值,且其一般存储元素的下标. 思路:两个单调队列维护最大值与最小值的下标,如果区间的最大值最小值之差大于给定范围,则选择队首靠左的删 ...
- locust的安装与使用
Contents Locust这一款开源性能测试工具.然而,当前在网络上针对Locust的教程极少,不管是中文还是英文,基本都是介绍安装方法和简单的测试案例演示,但对于较复杂测试场景的案例演示却基本没 ...
- Maven的下载,安装,配置,测试,初识以及Maven私服
:Maven目录分析 bin:含有mvn运行的脚本 boot:含有plexus-classworlds类加载器框架 conf:含有settings.xml配置文件 lib:含有Maven运行时所需要的 ...
- PHPexcel的用法
由于经常要统计学生的考试成绩,就研究了下PHPexcel这个插件 顺便说一下,读取方法只针对xls文件. 如果报错,可以先生存一个xls文件,把需要读取的xls内容复制进去. <?php //读 ...
- day8--socket网络编程进阶
socket:socket就是实现服务器和客户端数据的交换,服务器端接收并发送数据,客户端发送并接收数据,并且需要注意的是,在python3中,socket值接收字节.因为客户端在发送连接给服务器的时 ...
- zstu 4247-萌新的旅行
题目大意: zstu的萌新们准备去自助旅行,他们租了一辆吉普车,然后选择了n个城市作为游览地点.然后他们惊喜的发现他们选择的城市刚好绕城一个环. 也就是说如果给所有城市按照0,1,2,……,n-1编号 ...
- BZOJ1146 [CTSC2008]网络管理Network 树链剖分 主席树 树状数组
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1146 题意概括 在一棵树上,每一个点一个权值. 有两种操作: 1.单点修改 2.询问两点之间的树链 ...
- 046 hiveserver2以及beeline客户端的使用
一:开启服务 1.启动前端的hiveserver2 按住ctrl+c就可以结束这个服务. 2.怎么知道已经开启的服务 如果进程在后台,可以查出来,kill这些进程. 3.后端开启服务 二:beelin ...
- Spring日记_01 之 Maven搭建 - 阿里云镜像替换maven配置文件
# 项目环境搭建 ## 1. Eclipse + Maven 中央库太慢所以使用 阿里云镜像:maven.aliyun.com 1. 配置Aliyun Maven 仓库 导入配置文件 set ...
- Spring MVC 注解 @RequestParam解析
在Spring MVC 后台控制层获取参数的方式主要有两种,一种是requset.getParameter(“name”),另一种是用注解@Resquest.Param直接获取. 一.基本使用获取提交 ...