## 創建 plugin 專案 * 左側選單選取IDE Plugin ![image](https://hackmd.io/_uploads/ryoe__lia.png) ## 各檔案說明 * [**resource/META-INF/plugin.xml**](https://juejin.cn/post/6930813959775715336) -> plugin的設定檔 * id -> 這個plugin的唯一識別值(不能和其他的重複) * name -> plugin名稱(在搜索時會出現的名稱) * version -> 版本號 * vender -> 開發者主頁&email * depends -> 依賴項 * ==actions== -> 控制點選功能以後對應到的java class * id -> 唯一值 * class -> 對應到的java(點選後要執行的java class) * text -> 顯示的名稱 * description -> 描述 * group-id -> plugin的功能鍵要顯示在哪裡 * anchor -> 功能鍵位置 * keyboard-shortcut -> 快捷鍵 ``` xml <action id="tw.sc.demo2.Hello" class="tw.sc.demo2.Hello" text="Hello" description="show Hello"> <add-to-group group-id="HelpMenu" anchor="first"/> <keyboard-shortcut keymap="$default" first-keystroke="meta alt ENTER"/> </action> ``` ps. https://blog.csdn.net/justry_deng/article/details/121874359 此網址為基礎建置教學,實測後照做可以正常執行,==內含常用group-id== * **main/java/自定義** * class 需要extends AnAction,並Override actionPerformed * actionPerformed為plugin功能鍵點選後的直行進入點 * 以下程式碼為簡易的CreateGetController ```java public class CreateGetController extends AnAction { @Override public void actionPerformed(@NotNull AnActionEvent e) { Project project = e.getProject(); if (project != null) { // get editor Editor editor = e.getRequiredData(CommonDataKeys.EDITOR); if (editor != null) { // insert code WriteCommandAction.runWriteCommandAction(project, () -> { int offset = editor.getCaretModel().getOffset(); String codeToInsert = generateControllerCode("get"); editor.getDocument().insertString(offset, codeToInsert); }); } } } private String generateControllerCode(String type) { String controllerCode = ""; switch(type){ case "get": default: controllerCode = "@GetMapping(value = \"/\", produces = \"application/json\")\n" + "public BaseModel Controller() {\n" + " return new BaseModel();\n" + "}"; break; case "post": controllerCode = "@PostMapping(value = \"/\", produces = \"application/json\")\n" + "public BaseModel Controller() {\n" + " return new BaseModel();\n" + "}"; break; } return controllerCode; } } ``` ## swing * swing創建,創建後會有兩個檔案(java & form) ![image](https://hackmd.io/_uploads/B1_tCuliT.png) * form 檔用於拉介面,java檔跟介面相關的執行檔 * form拉的介面==要在對應的java中宣告==,且form中的field name要和宣告的變數名稱一樣 :point_down: 拉一個JText ![image](https://hackmd.io/_uploads/rJFBkKgoa.png) :point_down: 左側的field name(form檔) ==要和宣告一樣== ![image](https://hackmd.io/_uploads/Hk_HJFxoa.png) :point_down: 宣告(java檔) ==要和field name一樣== ![image](https://hackmd.io/_uploads/r1urkKgs6.png) * **java** * 要extends DialogWrapper,並Override createCenterPanel ``` java public class CreateControllerClassDialog extends DialogWrapper { @Override protected @Nullable JComponent createCenterPanel() { } } ``` ## 實作範例 * 自動寫入getController :point_down: plugin.xml ``` xml <group id="tw.sc.demo2.SCProd" text="_SCProd" description="SCProd"> <add-to-group group-id="EditorPopupMenu" anchor="last"/> <action id="tw.sc.demo2.SCProd.CreateGetController" class="tw.sc.demo2.CreateGetController" text="CreateGetController" description="show Hello"/> <add-to-group group-id="EditorPopupMenu" anchor="last"/> <action id="tw.sc.demo2.Hello" class="tw.sc.demo2.Hello" text="Hello" description="show Hello"> <add-to-group group-id="HelpMenu" anchor="first"/> </action> </group> ``` ![image](https://hackmd.io/_uploads/SkBAZFeo6.png) :point_down: java ```java public class CreateGetController extends AnAction { @Override public void actionPerformed(@NotNull AnActionEvent e) { Project project = e.getProject(); if (project != null) { // get editor Editor editor = e.getRequiredData(CommonDataKeys.EDITOR); if (editor != null) { // insert code WriteCommandAction.runWriteCommandAction(project, () -> { int offset = editor.getCaretModel().getOffset(); String codeToInsert = generateControllerCode("get"); editor.getDocument().insertString(offset, codeToInsert); }); } } } private String generateControllerCode(String type) { String controllerCode = ""; switch(type){ case "get": default: controllerCode = "@GetMapping(value = \"/\", produces = \"application/json\")\n" + "public BaseModel Controller() {\n" + " return new BaseModel();\n" + "}"; break; case "post": controllerCode = "@PostMapping(value = \"/\", produces = \"application/json\")\n" + "public BaseModel Controller() {\n" + " return new BaseModel();\n" + "}"; break; } return controllerCode; } } ``` * 自動創建java file :point_down: plugin.xml ```xml <action id="CreatePsiJavaFile" class="tw.sc.demo2.action.CreateController" text="Create Controller File"> <!-- 在 New 操作组的下面 --> <add-to-group group-id="ProjectViewPopupMenu" anchor="after" relative-to-action="WeighingNewGroup"/> <!--快捷鍵--> <!-- <keyboard-shortcut keymap="$default" first-keystroke="meta alt ENTER"/>--> </action> ``` :point_down: java ```java public class CreateController extends AnAction { @Override public void actionPerformed(@NotNull AnActionEvent e) { PsiElement psiElement =e.getData(CommonDataKeys.PSI_ELEMENT); PsiDirectory psiDirectory; if (psiElement instanceof PsiDirectory) { psiDirectory = (PsiDirectory) psiElement; } else { psiDirectory = psiElement.getContainingFile().getContainingDirectory(); } new CreateControllerClassDialog(psiDirectory).show(); } } ``` :point_down: swing的java ==目前僅能新建一個java檔,但程式碼邏輯內包含新建class、constructor等,但尚未成功== ```java public class CreateControllerClassDialog extends DialogWrapper { private final boolean createState; private Project myProject; private PsiDirectory myPsiDirectory; private JPanel mainPanel; private JLabel classNameLabel; private JTextField className; public CreateControllerClassDialog(@Nonnull PsiDirectory directory) { super(true); createState = true; setTitle("create.java.file");// 對話框標題 myPsiDirectory = directory; myProject = myPsiDirectory.getProject(); init(); } @Override protected @Nullable JComponent createCenterPanel() { mainPanel = new JPanel(new BorderLayout()); // 初始化 classNameLabel = new JLabel("Class Name: "); className = new JTextField(); // 把組件加到mainPanel mainPanel.add(classNameLabel, BorderLayout.WEST); mainPanel.add(className, BorderLayout.CENTER); // // 如果是 Class 展示添加 @Data 注解的??? // types.addItemListener(l -> dataPane.setVisible(l.getItem().equals(ClassType.Class))); return mainPanel; } public String getClassName() { return className.getText(); } @Override protected void doOKAction() { if (createState) { createJavaFile(); } else { // editJavaFile(); } // 關閉視窗 super.doOKAction(); } private void createJavaFile() { String classNameText = className.getText(); // use WriteCommandAction to do not-read(create、edit、delete) WriteCommandAction.runWriteCommandAction(myProject, "create.java.file", "Psi", () -> { try { PsiFile javaFile = myPsiDirectory.createFile(classNameText + ".java"); // 添加 PsiClass 到 PsiFile PsiClass psiClass = JavaDirectoryService.getInstance().createClass(myPsiDirectory, classNameText); // 在 PsiClass 中加入code addCodeToPsiClass(psiClass); javaFile.add(psiClass); // 添加 PsiFile 到 PsiDirectory myPsiDirectory.add(javaFile); } catch (Exception exception) { exception.printStackTrace(); } }); } private void addCodeToPsiClass(PsiClass psiClass) { String classCode = "public class MyClass {\n" + " // 添加方法\n" + " public void myMethod() {\n" + " // Your code here\n" + " }\n" + "\n" + " // 添加constructor\n" + " public MyClass() {\n" + " // Your code here\n" + " }\n" + "}\n"; // 使用 PsiElementFactory 建 PsiClass PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); PsiClass newClass = elementFactory.createClassFromText(classCode, null); // 取文件的大括號的位置 PsiElement lBrace = psiClass.getLBrace(); PsiElement rBrace = psiClass.getRBrace(); // 新建的添加到文件的大括號中 if (lBrace != null && rBrace != null) { psiClass.addBefore(newClass, rBrace); } } public enum ClassType { Class, Interface, Enum } } ``` :point_down: swing的form ![image](https://hackmd.io/_uploads/BJm8NteoT.png) ## 參考資料 * https://zhuanlan.zhihu.com/p/400059601?utm_id=0 -> 內含github,實測過後可使用 * https://blog.csdn.net/justry_deng/article/details/121874359 -> 初步教學 * https://www.cnblogs.com/Jcloud/p/17510682.html -> 後半段是較為進階的教學