前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Idea插件开发

Idea插件开发

作者头像
码客说
发布2024-08-04 09:31:09
1350
发布2024-08-04 09:31:09
举报
文章被收录于专栏:码客

前言

https://www.w3cschool.cn/intellij_idea_doc/

JDK要求必须11以上,我这里使用的是17。

下载JDK17

https://www.oracle.com/cn/java/technologies/downloads/#jdk17-windows

安装后确认下版本

代码语言:javascript
复制
java --version

环境变量中的JAVA_HOME也要设置为JDK17的路径。

创建项目

创建项目

项目打开后点击plugin.xml配置插件的基本信息

如下

代码语言:javascript
复制
<idea-plugin>
    <id>cn.psvmc.VueComp</id>
    <name>VueComp</name>
    <vendor email="183518918@qq.com" url="https://www.psvmc.cn">码客说</vendor>
    <description><![CDATA[
    方便生成Vue页面模板.<br>
    <em>支持TS+Less+组合式API</em>
    <em>模板、脚本和样式分离</em>
  ]]></description>
    <depends>com.intellij.modules.platform</depends>
    <extensions defaultExtensionNs="com.intellij">
    </extensions>
    <actions>
        <action id="cn.psvmc.vuecomp.CreateVueCompAction"
                class="cn.psvmc.vuecomp.CreateVueCompAction"
                text="创建Vue组件/页面">
            <add-to-group group-id="NewGroup" anchor="first"/>
            <!-- 可通过 ctrl + H 快捷键触发 -->
            <keyboard-shortcut keymap="$default" first-keystroke="ctrl H"/>
        </action>
    </actions>
</idea-plugin>

报错

Could not resolve org.jetbrains.intellij.plugins:gradle-intellij-plugin:1.8.0

环境变量中的JAVA_HOME也要设置为JDK17的路径。

示例

简单提示

这里我们只是简单的在右下角弹出通知显示项目根目录

CreateVueCompAction.java

代码语言:javascript
复制
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;

public class CreateVueCompAction extends AnAction {

    @Override
    public void actionPerformed(AnActionEvent e) {
        Notifications.Bus.notify(new Notification("Print", "", e.getProject().getBasePath(), NotificationType.INFORMATION), e.getProject());
    }
}

当然也可以弹窗显示

代码语言:javascript
复制
Messages.showMessageDialog(e.getProject().getBasePath(), "Project BasePath", Messages.getInformationIcon());

在plugin.xml的根节点下添加

代码语言:javascript
复制
<actions>
    <action id="cn.psvmc.vuecomp.CreateVueCompAction"
            class="cn.psvmc.vuecomp.CreateVueCompAction"
            text="创建Vue组件/页面">
        <add-to-group group-id="NewGroup" anchor="first"/>
        <!-- 可通过 ctrl + H 快捷键触发 -->
        <keyboard-shortcut keymap="$default" first-keystroke="ctrl H"/>
    </action>
</actions>

也可以在代码文件夹上点击鼠标右键,选择 New => Plugin DevKit => Action

如果没有的话,那么可能需要在先在IDEA中装个 Plugin DevKit插件。

获取选中的文件夹

代码语言:javascript
复制
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;

import java.util.ArrayList;
import java.util.List;

public class CreateVueCompAction extends AnAction {
    @Override
    public void actionPerformed(AnActionEvent e) {
        Project project = e.getProject();
        if (project == null) {
            Messages.showMessageDialog("No project found", "Error", Messages.getErrorIcon());
            return;
        }

        VirtualFile[] files = e.getData(com.intellij.openapi.actionSystem.CommonDataKeys.VIRTUAL_FILE_ARRAY);
        if (files == null || files.length == 0) {
            Messages.showMessageDialog("No file selected", "Error", Messages.getErrorIcon());
            return;
        }

        List<String> folderPathList = new ArrayList<>();
        for (VirtualFile file : files) {
            if (file.isDirectory()) {
                folderPathList.add(file.getPath());
            }
        }
        String  folderPaths= String.join("\n", folderPathList);
        Messages.showMessageDialog(folderPaths, "选择的文件夹", Messages.getInformationIcon());
    }
}

文件创建及写入

代码语言:javascript
复制
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;

import java.io.IOException;

public class CreateVueCompAction extends AnAction {
    @Override
    public void actionPerformed(AnActionEvent e) {
        ApplicationManager.getApplication().runWriteAction(() -> {
            Project project = e.getProject();
            if (project == null) {
                return;
            }
            VirtualFile[] files = e.getData(com.intellij.openapi.actionSystem.CommonDataKeys.VIRTUAL_FILE_ARRAY);
            if (files == null || files.length == 0) {
                Messages.showMessageDialog("未选择文件夹!", "错误", Messages.getErrorIcon());
                return;
            }
            for (VirtualFile file : files) {
                if (file.isDirectory()) {
                    try {
                        String fileName = "main.txt";
                        VirtualFile newFile = file.findChild(fileName);
                        if (newFile == null) {
                            newFile = file.createChildData(this, fileName);
                            String content = "Hello, World!";
                            VirtualFile finalNewFile = newFile;
                            WriteAction.run(() -> {
                                finalNewFile.setBinaryContent(content.getBytes());
                            });
                        }
                    } catch (IOException ignored) {
                    }
                }
            }
            VirtualFileManager.getInstance().refreshWithoutFileWatcher(true);
        });
    }
}

生成Vue文件

代码语言:javascript
复制
import cn.psvmc.vuecomp.utils.ZFreeMarkerUtils;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class CreateVueCompAction extends AnAction {
    @Override
    public void actionPerformed(AnActionEvent e) {
        ApplicationManager.getApplication().runWriteAction(() -> {
            Project project = e.getProject();
            if (project == null) {
                return;
            }
            VirtualFile[] files = e.getData(com.intellij.openapi.actionSystem.CommonDataKeys.VIRTUAL_FILE_ARRAY);
            if (files == null || files.length == 0) {
                Messages.showMessageDialog("未选择文件夹!", "错误", Messages.getErrorIcon());
                return;
            }
            for (VirtualFile file : files) {
                if (file.isDirectory()) {
                    String fileName = file.getName();
                    Map<String, Object> dataModel = new HashMap<>();
                    dataModel.put("fileName", fileName);
                    List<Map<String, String>> templateList = new ArrayList<>();
                    Map<String, String> templateMap = new HashMap<>();
                    templateMap.put("templateName", "ts_vue.ftl");
                    templateMap.put("fileNameAll", fileName + ".vue");
                    templateList.add(templateMap);

                    Map<String, String> styleMap = new HashMap<>();
                    styleMap.put("templateName", "style.ftl");
                    styleMap.put("fileNameAll", fileName + ".less");
                    templateList.add(styleMap);

                    for (Map<String, String> item : templateList) {
                        try {
                            String fileNameAll = item.get("fileNameAll");
                            String templateName = item.get("templateName");
                            VirtualFile newFile = file.findChild(fileNameAll);
                            if (newFile == null) {
                                newFile = file.createChildData(this, fileNameAll);
                                String content = ZFreeMarkerUtils.getStrByFtl(templateName, dataModel);
                                VirtualFile finalNewFile = newFile;
                                WriteAction.run(() -> {
                                    finalNewFile.setBinaryContent(content.getBytes());
                                });
                            } else {
                                Notification notice = new Notification("Print", "", "文件已存在", NotificationType.INFORMATION);
                                Notifications.Bus.notify(notice, e.getProject());
                            }
                        } catch (IOException ignored) {
                        }
                    }
                }
            }
            VirtualFileManager.getInstance().refreshWithoutFileWatcher(true);
        });
    }
}

对应的模板文件

ts_vue.ftl

代码语言:javascript
复制
<template>
    <div class="${fileName}">
        {{ loginName }}
    </div>
</template>

<script lang="ts" setup>
    import {ref} from "vue";
    const loginName = ref(null)
</script>

<style src="./${fileName}.less" lang="less" scoped>
</style>

style.ftl

代码语言:javascript
复制
.${fileName} {
}

使用的时候,先创建我们的组件文件夹,比如MainView,右键点击创建Vue组件/页面,就会在这个文件夹中创建跟文件夹同名的两个文件。

打包

Gradle中通过Tasks/build/build来打包我们的插件。

构建好后我们可以在build/distributions目录下面找到我们的zip包,拿到后直接在idea上面进行离线安装即可。

注意

网上有说用intellij/buildPlugin打包,这是不对的,这样打的是Jar包,我们代码中引用的模板文件不会打进去,就不能正常使用。

注意事项

构建配置

build.gradle.kts

代码语言:javascript
复制
plugins {
    id("java")
    id("org.jetbrains.intellij") version "1.8.0"
}

group = "cn.psvmc"
version = "1.0-SNAPSHOT"

repositories {
    maven("https://maven.aliyun.com/repository/central")
    maven("https://maven.aliyun.com/repository/public")
    maven ("https://maven.aliyun.com/repository/gradle-plugin")
    maven ("https://maven.aliyun.com/repository/apache-snapshots")
    mavenCentral()
    gradlePluginPortal()
    mavenCentral()
}

// Configure Gradle IntelliJ Plugin
// Read more: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html
intellij {
    version.set("2021.3.3")
    type.set("IC") // Target IDE Platform

    plugins.set(listOf(/* Plugin Dependencies */))
}

tasks {
    // Set the JVM compatibility versions
    withType<JavaCompile> {
        options.encoding = "UTF-8"
        sourceCompatibility = "11"
        targetCompatibility = "11"
    }

    patchPluginXml {
        sinceBuild.set("213")
        untilBuild.set("223.*")
    }
}

注意相比于自动生成项目的配置,这里更改了如下几点:

镜像库

代码语言:javascript
复制
repositories {
    maven("https://maven.aliyun.com/repository/central")
    maven("https://maven.aliyun.com/repository/public")
    maven ("https://maven.aliyun.com/repository/gradle-plugin")
    maven ("https://maven.aliyun.com/repository/apache-snapshots")
    mavenCentral()
    gradlePluginPortal()
    mavenCentral()
}

编码

要设置编码,否则中文会乱码。

代码语言:javascript
复制
withType<JavaCompile> {
    options.encoding = "UTF-8"
    sourceCompatibility = "11"
    targetCompatibility = "11"
}

项目本身也设置为UTF-8

插件版本设置

intellij中的version.set("2021.3.3")和patchPluginXml中的sinceBuild.set("213")要匹配。

这是我们插件支持的最低IDEA版本

运行的时候会自动下载该版本的IDEA来运行我们的插件。

这个版本可以在IDEA的 Help => About 查看

Java版本设置

还有这个版本要和对应IDEA依赖的Java版本一致,可以和我们插件项目依赖的Java版本不一致,我就是用的JDK17,而这里配置的11,可以正常编译运行。

代码语言:javascript
复制
withType<JavaCompile> {
    sourceCompatibility = "11"
    targetCompatibility = "11"
}

更换gradle版本

默认的7.5我在构建的时候报错,所以就更换为7.6版本了。

gradle-wrapper.properties

代码语言:javascript
复制
#Wed Mar 20 15:45:42 HKT 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-7.6-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

镜像地址

https://mirrors.cloud.tencent.com/gradle/

构建报错

Caused by: java.lang.NullPointerException: getHeaderField(“Location”) must not be null

这个错误不影响。

FreeMarker使用

build.gradle.kts中添加

代码语言:javascript
复制
dependencies {
    implementation("org.freemarker:freemarker:2.3.31")
}

resources/templates/template.ftl

代码语言:javascript
复制
# This is an example template
Hello, ${name}!

工具类

代码语言:javascript
复制
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

import java.io.*;
import java.util.HashMap;
import java.util.Map;
public class ZFreeMarkerUtils {
    public static String getStrByFtl(String templateName,Map<String, Object> dataModel) {
        try {
            // 配置 Freemarker
            Configuration cfg = new Configuration(Configuration.VERSION_2_3_31);
            cfg.setClassForTemplateLoading(ZFreeMarkerUtils.class, "/templates");
            Template template = cfg.getTemplate(templateName);
            try (StringWriter out = new StringWriter()) {
                template.process(dataModel, out);
                String result = out.toString();
                System.out.println(result);
                return result;
            } catch (TemplateException e) {
               return "";
            }

        } catch (IOException ex) {
            return "";
        }
    }

    public static void test(){
        // 创建数据模型
        Map<String, Object> dataModel = new HashMap<>();
        dataModel.put("name", "World");
        getStrByFtl("template.ftl",dataModel);
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-08-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 创建项目
  • 示例
    • 简单提示
      • 获取选中的文件夹
        • 文件创建及写入
          • 生成Vue文件
          • 打包
          • 注意事项
            • 构建配置
              • 镜像库
              • 编码
              • 插件版本设置
              • Java版本设置
            • 更换gradle版本
              • 构建报错
              • FreeMarker使用
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档