当前位置 博文首页 > 盛夏温暖流年:IDEA插件开发之基础篇

    盛夏温暖流年:IDEA插件开发之基础篇

    作者:[db:作者] 时间:2021-07-13 19:01

    一.插件功能

    IntelliJ IDEA 是一款流行的JAVA 开发 IDE,对于提高编程效率有非常大的帮助。但是,还是会有一些特殊的需求它并不能满足,此时我们就需要通过开发插件来实现了。

    主要的插件功能包含以下四种类型:

    • 自定义语言支持:如果有 IDEA 暂时不支持的语言,可以自己写一个插件来支持,例如 Go 语言原来的支持就是通过插件做的,官方有自定义语言插件支持的教程;

    • 框架支持:例如Struts 2 的框架支持;

    • 工具集成:可以给 IDEA 的自带功能进行增强,例如对 Git 的操作增加 CodeReview 的功能;

    • 用户界面:自定义插件来改变用户界面,比如 BackgroundImage;

    二.插件开发常用场景

    1.常用对象

    JAVA相关应用里面的常用对象:

    PsiFile: 应用中的文件,如.Java的文件或者是.xml的文件等;

    PsiDirectory: 应用中的目录;

    PsiJavaFile: Java源文件,如Demo.java;

    PsiClass: 某个类,一个文件中可能会有多个类;

    PsiMethod: 类中的某个方法;

    PsiField: 类中的某个属性;

    PsiAnnotation: 注解;

    2.常用操作

    Action 是 IDEA 插件开发中比较基本的概念,插件利用 Action 来往菜单栏和工具栏添加新的菜单或按钮,它继承了 com.intellij.openapi.actionSystem.AnAction,当对应的菜单栏或者工具按钮被点击,则Action被调用,最为关键的就是 actionPerformed 方法。它的定义如下:

    public void actionPerformed(@NotNull AnActionEvent anActionEvent) {}
    

    定义好之后就可以在方法里面编写我们想要实现的插件功能了,常用的操作如下:

    (1). 获取当前项目:

    Project project = anActionEvent.getProject();
    

    (2). 获取当前的编辑器对象:

    Editor editor = anActionEvent.getData(CommonDataKeys.EDITOR);
    

    (3). 获取当前编辑的文件:

    PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
    // 如果是Java文件,可以转换成PsiJavaFile
    PsiJavaFile javaFile = (PsiJavaFile)psiFile;
    

    (4). 获取JavaFile中的Class:

    // 一个文件中可能会定义有多个Class,因此返回的是一个数组
    PsiClass[] classes = javaFile.getClasses();
    

    (5). PsiClass的常用方法:

    1.获取所有属性:getFields、getAllFields
    
    2.查找属性:findFieldByName(),其中第二个参数是是否查找父类的属性;
    
    3.获取所有方法:getMethods/getAllMethods
    
    4.查找方法:findMethodsByName
    
    

    (6).在Class中创建Field:

    PsiElementFactory elementFactory = PsiElementFactory.SERVICE.getInstance(project);
    PsiField cField = elementFactory.createFieldFromText(annotationStringBuilder.toString() + "private String test;", null);
    aClass.add(cField);
    

    (7).在Class中创建Method:

    PsiMethod method = elementFactory.createMethodFromText("public void test(){}", null);
    aClass.add(method); 
    

    (8).判断Class或者Field是否包含有某个注解及获取注解属性值:

    PsiAnnotation psiAnnotation = field.getAnnotation("javax.persistence.Column");
    PsiAnnotationMemberValue memberValue = psiAnnotation.findAttributeValue("columnDefinition");
    if (null != memberValue) {
        String str = memberValue.getText();
    }
    

    (9).Import类:引入类操作是在File中进行的,在Class类上是无法导入的,如果已经获取到了javaFile对象,可以这样导入,否则需要先获取到Class所在的File后再进行导入:

    javaFile.importClass(aClass);
    

    (10).根据class获取所在文件:

    PsiJavaFile psiJavaFile = (PsiJavaFile) aClass.getContainingFile()

    (11).获取类所在包:

    // 先获取到文件后再获取文件所在包
    String daoPackage = ((PsiJavaFile) aClass.getContainingFile()).getPackageName();
    

    (12).创建文件(包含文件中的类):

    javaFile = (PsiJavaFile) PsiFileFactory.getInstance(project).createFileFromText("Test.java", JavaFileType.INSTANCE, "public class Test {}");
    

    (13).获取当前文件所在包:

    PsiDirectory containerDirectory = javaFile.getContainingDirectory();
    

    (14).创建子包(子目录):

    parentDirectory.createSubdirectory("test");  
    

    (15).将文件添加到包中去

    psiDirectory.add(javaFile);  
    

    (16).获取Resource目录:

    ModuleRootManager rootManager = ModuleRootManager.getInstance(module);
    List<VirtualFile> sourceRoots = rootManager.getSourceRoots(JavaModuleSourceRootTypes.RESOURCES);
    VirtualFile resourceDirectory = sourceRoots.get(0);
    

    (17).创建xml文件并加入到某个目录:

    // content对应于XML文件内容
    psiFile = PsiFileFactory.getInstance(project).createFileFromText(fileName, XMLLanguage.INSTANCE,content);
    psiDirectory.add(psiFile);
    

    (18).IDEA不允许在主线程进行实时的文件写入,需要通过一个异步任务进行:

    WriteCommandAction.runWriteCommandAction(project, () -> FileUtil.createFile());
    

    IDEA插件开发的具体实现可参考:

    IDEA插件开发之实践篇

    cs