├── .gitignore ├── README.md ├── gradle.properties ├── idea-study-01 ├── build.gradle ├── resources │ ├── META-INF │ │ ├── plugin.xml │ │ ├── pluginIcon.svg │ │ └── pluginIcon_dark.svg │ ├── icons │ │ ├── halo.png │ │ └── right │ │ │ ├── HaloBasic.png │ │ │ ├── controller.png │ │ │ └── mapper.png │ └── templates │ │ └── Controller.java.ftl └── src │ └── org │ └── xujin │ └── idea │ └── right │ ├── BasicActionOpenDialog.java │ ├── BasicComBoxRenderer.java │ ├── BasicCreateSelectInfoStep.form │ ├── BasicCreateSelectInfoStep.java │ ├── HaloConstant.java │ ├── NewBasicExeAction.java │ ├── model │ ├── NewRightContext.java │ ├── NewRightModel.java │ └── SelectedTypeModel.java │ └── utils │ ├── FreemarkerConfiguration.java │ ├── HaloIdeaUtils.java │ └── PisFileByFreeMarkerUtil.java ├── idea-study-02 ├── build.gradle ├── resources │ ├── META-INF │ │ ├── plugin.xml │ │ ├── pluginIcon.svg │ │ └── pluginIcon_dark.svg │ ├── icons │ │ ├── halo.png │ │ └── right │ │ │ ├── HaloBasic.png │ │ │ ├── controller.png │ │ │ └── mapper.png │ └── templates │ │ └── Controller.java.ftl └── src │ └── org │ └── xujin │ └── idea │ └── right │ ├── BasicActionOpenDialog.java │ ├── BasicComBoxRenderer.java │ ├── BasicCreateSelectInfoStep.form │ ├── BasicCreateSelectInfoStep.java │ ├── HaloConstant.java │ ├── NewBasicExeAction.java │ ├── linemarker │ ├── AppMgmtNavigationHandler.java │ ├── FunctionTooltip.java │ └── HaloLineMarker.java │ ├── model │ ├── NewRightContext.java │ ├── NewRightModel.java │ └── SelectedTypeModel.java │ └── utils │ ├── FreemarkerConfiguration.java │ ├── HaloIdeaUtils.java │ └── PisFileByFreeMarkerUtil.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .idea 3 | *.zip 4 | out 5 | .DS_Store 6 | .gradle/ 7 | build/ 8 | gradle/ 9 | gradlew 10 | gradlew.bat 11 | /idea-sandbox 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # idea-study 2 | idea插件开发学习 3 | 4 | ## 相关资料 5 | 6 | ### SDK文档 7 | 8 | http://www.jetbrains.org/intellij/sdk/docs/welcome.html 9 | 10 | 1. Adding New Steps to Project Wizard 11 | 12 | * http://www.jetbrains.org/intellij/sdk/docs/tutorials/project_wizard.html 13 | 14 | * http://www.jetbrains.org/intellij/sdk/docs/tutorials/project_wizard/adding_new_steps.html 15 | 16 | 2.line_marker_provider 17 | 18 | * https://www.jetbrains.org/intellij/sdk/docs/tutorials/custom_language_support/line_marker_provider.html 19 | 20 | 21 | 3. Building plugins with Gradle 22 | 23 | 24 | * http://www.jetbrains.org/intellij/sdk/docs/tutorials/build_system.html 25 | 26 | * http://www.jetbrains.org/intellij/sdk/docs/tutorials/build_system/prerequisites.html 27 | 28 | ## 分享内容 29 | 30 | 1. 插件结构(Plugin Structure) 31 | 32 | 2. 自定义ComBox的图标-参考资料:https://www.logicbig.com/tutorials/java-swing/combo-box-icons.html 33 | 34 | 3. 两种开发IDEA插件开发方式: 35 | 36 | https://blog.csdn.net/ExcellentYuXiao/article/details/80273109 37 | 38 | 39 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | pluginVersion=1.0.0-SNAPSHOT 2 | ideaVersion=2019.1.3 -------------------------------------------------------------------------------- /idea-study-01/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | maven { url 'http://dl.bintray.com/jetbrains/intellij-plugin-service' } 4 | } 5 | 6 | } 7 | 8 | plugins { 9 | id 'java' 10 | id 'org.jetbrains.intellij' version '0.4.9' 11 | } 12 | 13 | repositories { 14 | mavenLocal() 15 | mavenCentral() 16 | } 17 | 18 | dependencies { 19 | // compile group: 'commons-io', name: 'commons-io', version: '2.5' 20 | //compile group: 'com.alibaba', name: 'fastjson', version: '1.2.58' 21 | compile group: 'org.freemarker', name: 'freemarker', version: '2.3.28' 22 | //compile group: 'mysql', name: 'mysql-connector-java', version: '5.1.24' 23 | 24 | } 25 | 26 | apply plugin: 'java' 27 | 28 | sourceCompatibility = JavaVersion.VERSION_1_8 29 | targetCompatibility = JavaVersion.VERSION_1_8 30 | 31 | tasks.withType(JavaCompile) { 32 | options.encoding = "UTF-8" 33 | } 34 | 35 | sourceSets { 36 | main { 37 | java.srcDirs 'src' 38 | resources.srcDirs 'resources' 39 | } 40 | test { 41 | java.srcDirs 'test' 42 | resources.srcDirs 'test-resources' 43 | } 44 | } 45 | 46 | intellij { 47 | version ideaVersion //调试插件IDEA的版本 48 | pluginName 'HaloTools' 49 | updateSinceUntilBuild false 50 | sandboxDirectory = "${rootProject.projectDir}/idea-sandbox/idea-${ideaVersion}" 51 | plugins 'maven' 52 | } 53 | 54 | group 'org.xujin.idea' 55 | version pluginVersion 56 | 57 | -------------------------------------------------------------------------------- /idea-study-01/resources/META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.xujin.idea.plugin 4 | HaloTools 5 | 1.0 6 | xujin.org 7 | 8 | 9 | <p>Enhances your productivity when developing applications based on Halo Framework.</p> 10 | 11 | 12 | com.intellij.modules.lang 13 | com.intellij.modules.platform 14 | com.intellij.modules.java 15 | org.jetbrains.idea.maven 16 | 17 | 18 | 19 | 20 | 22 | 23 | 24 | 25 | 26 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /idea-study-01/resources/META-INF/pluginIcon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /idea-study-01/resources/META-INF/pluginIcon_dark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /idea-study-01/resources/icons/halo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareKing/idea-study/e7b085f4c75e49ada5d90360578832cbf11bd3f3/idea-study-01/resources/icons/halo.png -------------------------------------------------------------------------------- /idea-study-01/resources/icons/right/HaloBasic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareKing/idea-study/e7b085f4c75e49ada5d90360578832cbf11bd3f3/idea-study-01/resources/icons/right/HaloBasic.png -------------------------------------------------------------------------------- /idea-study-01/resources/icons/right/controller.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareKing/idea-study/e7b085f4c75e49ada5d90360578832cbf11bd3f3/idea-study-01/resources/icons/right/controller.png -------------------------------------------------------------------------------- /idea-study-01/resources/icons/right/mapper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareKing/idea-study/e7b085f4c75e49ada5d90360578832cbf11bd3f3/idea-study-01/resources/icons/right/mapper.png -------------------------------------------------------------------------------- /idea-study-01/resources/templates/Controller.java.ftl: -------------------------------------------------------------------------------- 1 | package ${selectedPackage}; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.web.bind.annotation.*; 5 | 6 | @RestController 7 | @RequestMapping("/") 8 | public class ${className} { 9 | 10 | 11 | } 12 | -------------------------------------------------------------------------------- /idea-study-01/src/org/xujin/idea/right/BasicActionOpenDialog.java: -------------------------------------------------------------------------------- 1 | package org.xujin.idea.right; 2 | 3 | import com.intellij.ide.util.projectWizard.ModuleWizardStep; 4 | import com.intellij.ide.wizard.AbstractWizard; 5 | import com.intellij.openapi.module.Module; 6 | import com.intellij.openapi.options.ConfigurationException; 7 | import com.intellij.openapi.project.Project; 8 | import com.intellij.openapi.ui.Messages; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | /** 12 | * Halo Basic组创建 13 | * @author xujin 14 | */ 15 | public class BasicActionOpenDialog extends AbstractWizard { 16 | 17 | private Project myProject; 18 | private Module myModule; 19 | 20 | public BasicActionOpenDialog(Project project, Module module) { 21 | super("Create Halo Basic Class", project); 22 | myProject = project; 23 | myModule = module; 24 | ModuleWizardStep[] wizardSteps = createWizardSteps(); 25 | for (ModuleWizardStep wizardStep : wizardSteps) { 26 | addStep(wizardStep); 27 | } 28 | init(); 29 | } 30 | 31 | public ModuleWizardStep[] createWizardSteps() { 32 | return new ModuleWizardStep[]{ 33 | new BasicCreateSelectInfoStep(myProject,myModule) 34 | }; 35 | } 36 | 37 | /** 38 | * 点击Ok,之后去生成对应的扩展点 39 | */ 40 | @Override 41 | protected void doOKAction() { 42 | ModuleWizardStep step = getCurrentStepObject(); 43 | try { 44 | if (step.validate()) { 45 | super.doOKAction(); 46 | } 47 | } catch (ConfigurationException e) { 48 | Messages.showErrorDialog(step.getComponent(), e.getMessage(), e.getTitle()); 49 | } 50 | } 51 | 52 | @Nullable 53 | @Override 54 | protected String getHelpID() { 55 | return BasicActionOpenDialog.class.getName(); 56 | } 57 | 58 | 59 | } 60 | 61 | -------------------------------------------------------------------------------- /idea-study-01/src/org/xujin/idea/right/BasicComBoxRenderer.java: -------------------------------------------------------------------------------- 1 | package org.xujin.idea.right; 2 | 3 | 4 | import org.xujin.idea.right.model.SelectedTypeModel; 5 | 6 | import javax.swing.*; 7 | import java.awt.*; 8 | import java.util.ArrayList; 9 | import java.util.HashMap; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | /** 14 | * 下拉列表渲染 15 | */ 16 | public class BasicComBoxRenderer extends DefaultListCellRenderer { 17 | private Map iconMap = new HashMap<>(); 18 | private Color background = new Color(0, 100, 255, 15); 19 | private Color defaultBackground = (Color) UIManager.get("List.background"); 20 | 21 | public BasicComBoxRenderer() { 22 | iconMap.put(HaloConstant.COMBOX_CONTROLLER,new ImageIcon(getClass().getResource("/icons/right/controller.png"))); 23 | iconMap.put(HaloConstant.COMBOX_MAPPER,new ImageIcon(getClass().getResource("/icons/right/mapper.png"))); 24 | 25 | } 26 | 27 | public static List getSelectedList(){ 28 | List list=new ArrayList(); 29 | SelectedTypeModel blank=new SelectedTypeModel(); 30 | blank.setName(""); 31 | blank.setValue(HaloConstant.COMBOX_BLANK); 32 | list.add(blank); 33 | 34 | SelectedTypeModel controller=new SelectedTypeModel(); 35 | controller.setName("Controller"); 36 | controller.setValue(HaloConstant.COMBOX_CONTROLLER); 37 | list.add(controller); 38 | 39 | SelectedTypeModel mapper=new SelectedTypeModel(); 40 | mapper.setName("Mapper"); 41 | mapper.setValue(HaloConstant.COMBOX_MAPPER); 42 | list.add(mapper); 43 | 44 | 45 | 46 | return list; 47 | } 48 | 49 | @Override 50 | public Component getListCellRendererComponent(JList list, Object value, int index, 51 | boolean isSelected, boolean cellHasFocus) { 52 | super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); 53 | SelectedTypeModel emp = (SelectedTypeModel) value; 54 | this.setText(emp.getName()); 55 | this.setIcon(iconMap.get(emp.getValue())); 56 | if (!isSelected) { 57 | this.setBackground(index % 2 == 0 ? background : defaultBackground); 58 | } 59 | return this; 60 | } 61 | } -------------------------------------------------------------------------------- /idea-study-01/src/org/xujin/idea/right/BasicCreateSelectInfoStep.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 |
101 | -------------------------------------------------------------------------------- /idea-study-01/src/org/xujin/idea/right/BasicCreateSelectInfoStep.java: -------------------------------------------------------------------------------- 1 | package org.xujin.idea.right; 2 | 3 | import com.intellij.ide.util.projectWizard.ModuleWizardStep; 4 | import com.intellij.openapi.module.Module; 5 | import com.intellij.openapi.options.ConfigurationException; 6 | import com.intellij.openapi.project.Project; 7 | import org.xujin.idea.right.model.NewRightContext; 8 | import org.xujin.idea.right.model.SelectedTypeModel; 9 | 10 | import javax.swing.*; 11 | import java.awt.event.ItemEvent; 12 | import java.awt.event.ItemListener; 13 | import java.util.List; 14 | 15 | /** 16 | * @author xujin 17 | */ 18 | public class BasicCreateSelectInfoStep extends ModuleWizardStep { 19 | 20 | private JPanel myMainPanel; 21 | 22 | private JPanel myPackagePanel; 23 | 24 | /** 25 | * 类名 26 | */ 27 | private JTextField className; 28 | 29 | /** 30 | * 下拉列表框 31 | */ 32 | private JComboBox kind; 33 | 34 | 35 | 36 | 37 | private Project myProject; 38 | private Module myModule; 39 | 40 | 41 | 42 | 43 | /** 44 | * 创建Mapper选择数据对象相关 45 | */ 46 | private JLabel dataObjectTip; 47 | private JTextField dataObjectValue; 48 | private JButton dataObjectChooseButton; 49 | 50 | /** 51 | * @param project 52 | * @param module 53 | */ 54 | public BasicCreateSelectInfoStep(Project project, Module module) { 55 | myProject = project; 56 | myModule = module; 57 | initComBox(); 58 | dataObjectTip.setVisible(false); 59 | dataObjectValue.setVisible(false); 60 | dataObjectChooseButton.setVisible(false); 61 | 62 | kind.addItemListener(new ItemListener() { 63 | @Override 64 | public void itemStateChanged(ItemEvent e) { 65 | SelectedTypeModel selectedTypeModel = (SelectedTypeModel) e.getItem(); 66 | switch (selectedTypeModel.getValue()) { 67 | case HaloConstant.COMBOX_CONTROLLER: 68 | NewRightContext.setClassType(HaloConstant.COMBOX_CONTROLLER); 69 | break; 70 | default: 71 | NewRightContext.setClassType(null); 72 | } 73 | 74 | } 75 | }); 76 | } 77 | 78 | 79 | 80 | private void initComBox() { 81 | 82 | List list = BasicComBoxRenderer.getSelectedList(); 83 | for (SelectedTypeModel seleType : list) { 84 | kind.addItem(seleType); 85 | } 86 | kind.setRenderer(new BasicComBoxRenderer()); 87 | //Trinity trinity=new Trinity<>("Class", IconUtil.HALO , JavaTemplateUtil.INTERNAL_CLASS_TEMPLATE_NAME); 88 | //comboBox1.addItem(trinity); 89 | 90 | 91 | } 92 | 93 | @Override 94 | public JComponent getComponent() { 95 | return myMainPanel; 96 | } 97 | 98 | @Override 99 | public boolean validate() throws ConfigurationException { 100 | if (className.getText().isEmpty()) { 101 | throw new ConfigurationException("Class name cannot be empty", "Create Class Tips"); 102 | } 103 | NewRightContext.setClassName(className.getText()); 104 | return super.validate(); 105 | } 106 | 107 | 108 | @Override 109 | public void updateDataModel() { 110 | 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /idea-study-01/src/org/xujin/idea/right/HaloConstant.java: -------------------------------------------------------------------------------- 1 | package org.xujin.idea.right; 2 | 3 | /** 4 | * Halo Constant 5 | * @author xujin 6 | */ 7 | public interface HaloConstant { 8 | 9 | String COMBOX_BLANK="0"; 10 | 11 | /** 12 | * 创建Controller 13 | */ 14 | String COMBOX_CONTROLLER="1"; 15 | 16 | 17 | /** 18 | * 创建Mapper 19 | */ 20 | String COMBOX_MAPPER="2"; 21 | 22 | 23 | } 24 | -------------------------------------------------------------------------------- /idea-study-01/src/org/xujin/idea/right/NewBasicExeAction.java: -------------------------------------------------------------------------------- 1 | package org.xujin.idea.right; 2 | 3 | import com.intellij.openapi.actionSystem.AnAction; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.actionSystem.DataKeys; 6 | import com.intellij.openapi.application.Result; 7 | import com.intellij.openapi.command.WriteCommandAction; 8 | import com.intellij.openapi.module.Module; 9 | import com.intellij.openapi.module.ModuleUtil; 10 | import com.intellij.openapi.project.DumbAwareRunnable; 11 | import com.intellij.openapi.project.DumbService; 12 | import com.intellij.openapi.project.Project; 13 | import com.intellij.openapi.roots.ModuleRootManager; 14 | import com.intellij.openapi.vfs.VirtualFile; 15 | import org.apache.commons.lang3.StringUtils; 16 | import org.jetbrains.annotations.NotNull; 17 | import org.jetbrains.idea.maven.project.MavenProjectsManager; 18 | import org.xujin.idea.right.model.NewRightContext; 19 | import org.xujin.idea.right.model.NewRightModel; 20 | import org.xujin.idea.right.utils.HaloIdeaUtils; 21 | import org.xujin.idea.right.utils.PisFileByFreeMarkerUtil; 22 | 23 | 24 | /** 25 | * 右键创建Basic Action 26 | * @author xujin 27 | */ 28 | public class NewBasicExeAction extends AnAction { 29 | 30 | @Override 31 | public void actionPerformed(AnActionEvent e) { 32 | 33 | Project project = e.getProject(); 34 | /** 35 | * 从Action中得到一个虚拟文件 36 | */ 37 | VirtualFile virtualFile = e.getData(DataKeys.VIRTUAL_FILE); 38 | if (!virtualFile.isDirectory()) { 39 | virtualFile = virtualFile.getParent(); 40 | } 41 | Module module = ModuleUtil.findModuleForFile(virtualFile, project); 42 | 43 | String moduleRootPath = ModuleRootManager.getInstance(module).getContentRoots()[0].getPath(); 44 | String actionDir = virtualFile.getPath(); 45 | String str = StringUtils.substringAfter(actionDir, moduleRootPath + "/src/main/java/"); 46 | //获取右键后的路径 47 | String basePackage = StringUtils.replace(str, "/", "."); 48 | NewRightContext.clearAllSet(); 49 | NewRightContext.setSelectedPackage(basePackage); 50 | BasicActionOpenDialog dialog = new BasicActionOpenDialog(project, module); 51 | if (!dialog.showAndGet()) { 52 | return; 53 | } 54 | 55 | DumbService.getInstance(project).runWhenSmart((DumbAwareRunnable) () -> new WriteCommandAction(project) { 56 | @Override 57 | protected void run(@NotNull Result result) { 58 | switch (NewRightContext.getClassType()) { 59 | case HaloConstant.COMBOX_CONTROLLER: 60 | createByFtl(project, moduleRootPath,"Controller.java.ftl"); 61 | break; 62 | } 63 | MavenProjectsManager manager = MavenProjectsManager.getInstance(project); 64 | //解决依赖 65 | manager.forceUpdateAllProjectsOrFindAllAvailablePomFiles(); 66 | //优化生成的所有Java类 67 | HaloIdeaUtils.doOptimize(project); 68 | 69 | } 70 | }.execute()); 71 | 72 | } 73 | 74 | 75 | /** 76 | * 通过ftl创建 Controller 77 | * @param project 78 | * @param moduleRootPath 79 | */ 80 | private void createByFtl(Project project, String moduleRootPath, String ftlName) { 81 | NewRightModel newRightModel= NewRightContext.copyToNewRightModel(); 82 | try { 83 | PisFileByFreeMarkerUtil.createFile(project, newRightModel, moduleRootPath,ftlName); 84 | NewRightContext.clearAllSet(); 85 | } catch (Exception ex) { 86 | ex.printStackTrace(); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /idea-study-01/src/org/xujin/idea/right/model/NewRightContext.java: -------------------------------------------------------------------------------- 1 | package org.xujin.idea.right.model; 2 | 3 | public class NewRightContext { 4 | 5 | /** 6 | * 类名 7 | */ 8 | private static String className; 9 | 10 | /** 11 | * 所选择的类的类型 12 | */ 13 | private static String classType; 14 | 15 | /** 16 | * 创建java类所在的包 17 | */ 18 | private static String selectedPackage; 19 | 20 | 21 | public static String getClassType() { 22 | return classType; 23 | } 24 | 25 | public static void setClassType(String classType) { 26 | NewRightContext.classType = classType; 27 | } 28 | 29 | public static String getClassName() { 30 | return className; 31 | } 32 | 33 | public static void setClassName(String className) { 34 | NewRightContext.className = className; 35 | } 36 | 37 | public static String getSelectedPackage() { 38 | return selectedPackage; 39 | } 40 | 41 | public static void setSelectedPackage(String selectedPackage) { 42 | NewRightContext.selectedPackage = selectedPackage; 43 | } 44 | 45 | public static void clearAllSet() { 46 | classType = null; 47 | className = null; 48 | selectedPackage = null; 49 | } 50 | 51 | public static NewRightModel copyToNewRightModel() { 52 | NewRightModel newRightModel = new NewRightModel(); 53 | newRightModel.setClassName(className); 54 | newRightModel.setSelectedPackage(selectedPackage); 55 | return newRightModel; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /idea-study-01/src/org/xujin/idea/right/model/NewRightModel.java: -------------------------------------------------------------------------------- 1 | package org.xujin.idea.right.model; 2 | 3 | public class NewRightModel { 4 | 5 | /** 6 | * 类名 7 | */ 8 | private String className; 9 | 10 | /** 11 | * 所选择的类的类型 12 | */ 13 | private String classType; 14 | 15 | /** 16 | * 创建java类所在的包 17 | */ 18 | private String selectedPackage; 19 | 20 | public String getClassName() { 21 | return className; 22 | } 23 | 24 | public void setClassName(String className) { 25 | this.className = className; 26 | } 27 | 28 | public String getClassType() { 29 | return classType; 30 | } 31 | 32 | public void setClassType(String classType) { 33 | this.classType = classType; 34 | } 35 | 36 | public String getSelectedPackage() { 37 | return selectedPackage; 38 | } 39 | 40 | public void setSelectedPackage(String selectedPackage) { 41 | this.selectedPackage = selectedPackage; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /idea-study-01/src/org/xujin/idea/right/model/SelectedTypeModel.java: -------------------------------------------------------------------------------- 1 | package org.xujin.idea.right.model; 2 | 3 | /** 4 | * 下拉列表选中模型 5 | * @author xujin 6 | */ 7 | public class SelectedTypeModel { 8 | 9 | /** 10 | * 下拉列表显示的名称 11 | */ 12 | private String name; 13 | 14 | /** 15 | * 下拉列表的value 16 | */ 17 | private String value; 18 | 19 | public String getName() { 20 | return name; 21 | } 22 | 23 | public void setName(String name) { 24 | this.name = name; 25 | } 26 | 27 | public String getValue() { 28 | return value; 29 | } 30 | 31 | public void setValue(String value) { 32 | this.value = value; 33 | } 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /idea-study-01/src/org/xujin/idea/right/utils/FreemarkerConfiguration.java: -------------------------------------------------------------------------------- 1 | package org.xujin.idea.right.utils; 2 | 3 | import freemarker.template.Configuration; 4 | 5 | public class FreemarkerConfiguration extends Configuration { 6 | private String basePackagePath; 7 | 8 | public FreemarkerConfiguration() { 9 | this(""); 10 | } 11 | 12 | public FreemarkerConfiguration(String basePackagePath) { 13 | super(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); 14 | setClassForTemplateLoading(getClass(), basePackagePath); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /idea-study-01/src/org/xujin/idea/right/utils/HaloIdeaUtils.java: -------------------------------------------------------------------------------- 1 | package org.xujin.idea.right.utils; 2 | 3 | import com.intellij.openapi.application.ApplicationManager; 4 | import com.intellij.openapi.application.ModalityState; 5 | import com.intellij.openapi.application.Result; 6 | import com.intellij.openapi.command.WriteCommandAction; 7 | import com.intellij.openapi.project.DumbAwareRunnable; 8 | import com.intellij.openapi.project.DumbService; 9 | import com.intellij.openapi.project.Project; 10 | import com.intellij.openapi.startup.StartupManager; 11 | import com.intellij.openapi.vfs.VirtualFile; 12 | import com.intellij.psi.PsiJavaFile; 13 | import com.intellij.psi.PsiManager; 14 | import com.intellij.psi.codeStyle.CodeStyleManager; 15 | import com.intellij.psi.codeStyle.JavaCodeStyleManager; 16 | import com.intellij.util.DisposeAwareRunnable; 17 | import org.jetbrains.annotations.NotNull; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | /** 23 | * @author xujin 24 | */ 25 | public class HaloIdeaUtils { 26 | public static final String DEFAULT_CHARSET = "UTF-8"; 27 | 28 | public static void invokeAndWait(Project p, Runnable r) { 29 | invokeAndWait(p, ModalityState.defaultModalityState(), r); 30 | } 31 | 32 | public static void invokeAndWait(Project p, ModalityState state, Runnable r) { 33 | if (isNoBackgroundMode()) { 34 | r.run(); 35 | } else { 36 | ApplicationManager.getApplication().invokeAndWait(DisposeAwareRunnable.create(r, p), state); 37 | } 38 | } 39 | 40 | public static void invokeLater(Project p, Runnable r) { 41 | invokeLater(p, ModalityState.defaultModalityState(), r); 42 | } 43 | 44 | public static void invokeLater(Project p, ModalityState state, Runnable r) { 45 | if (isNoBackgroundMode()) { 46 | r.run(); 47 | } else { 48 | ApplicationManager.getApplication().invokeLater(DisposeAwareRunnable.create(r, p), state); 49 | } 50 | 51 | } 52 | 53 | public static void runWhenInitialized(final Project project, final Runnable r) { 54 | if (project.isDisposed()) { 55 | return; 56 | } 57 | if (isNoBackgroundMode()) { 58 | r.run(); 59 | return; 60 | } 61 | if (!project.isInitialized()) { 62 | StartupManager.getInstance(project).registerPostStartupActivity(DisposeAwareRunnable.create(r, project)); 63 | return; 64 | } 65 | runDumbAware(project, r); 66 | } 67 | 68 | public static boolean isNoBackgroundMode() { 69 | return (ApplicationManager.getApplication().isUnitTestMode() 70 | || ApplicationManager.getApplication().isHeadlessEnvironment()); 71 | } 72 | 73 | public static void runDumbAware(final Project project, final Runnable r) { 74 | if (DumbService.isDumbAware(r)) { 75 | r.run(); 76 | } else { 77 | DumbService.getInstance(project).runWhenSmart(DisposeAwareRunnable.create(r, project)); 78 | } 79 | } 80 | 81 | private static List virtualFiles = new ArrayList<>(); 82 | 83 | public static void addWaitOptimizeFile(VirtualFile virtualFile) { 84 | virtualFiles.add(virtualFile); 85 | } 86 | 87 | public static void doOptimize(Project project) { 88 | DumbService.getInstance(project).runWhenSmart((DumbAwareRunnable) () -> new WriteCommandAction(project) { 89 | @Override 90 | protected void run(@NotNull Result result) { 91 | for (VirtualFile virtualFile : virtualFiles) { 92 | try { 93 | PsiJavaFile javaFile = (PsiJavaFile) PsiManager.getInstance(project).findFile(virtualFile); 94 | if (javaFile != null) { 95 | CodeStyleManager.getInstance(project).reformat(javaFile); 96 | JavaCodeStyleManager.getInstance(project).optimizeImports(javaFile); 97 | JavaCodeStyleManager.getInstance(project).shortenClassReferences(javaFile); 98 | } 99 | 100 | } catch (Exception e) { 101 | e.printStackTrace(); 102 | } 103 | } 104 | virtualFiles.clear(); 105 | } 106 | }.execute()); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /idea-study-01/src/org/xujin/idea/right/utils/PisFileByFreeMarkerUtil.java: -------------------------------------------------------------------------------- 1 | package org.xujin.idea.right.utils; 2 | 3 | import com.intellij.ide.projectView.ProjectView; 4 | import com.intellij.openapi.application.ApplicationManager; 5 | import com.intellij.openapi.fileEditor.FileEditorManager; 6 | import com.intellij.openapi.fileEditor.OpenFileDescriptor; 7 | import com.intellij.openapi.project.Project; 8 | import com.intellij.openapi.util.io.FileUtil; 9 | import com.intellij.openapi.util.text.StringUtil; 10 | import com.intellij.openapi.vfs.LocalFileSystem; 11 | import com.intellij.openapi.vfs.VirtualFile; 12 | import com.intellij.openapi.wm.ToolWindow; 13 | import com.intellij.openapi.wm.ToolWindowManager; 14 | import com.intellij.util.OpenSourceUtil; 15 | import freemarker.template.Template; 16 | import org.xujin.idea.right.model.NewRightModel; 17 | 18 | import java.io.StringWriter; 19 | 20 | /** 21 | * @author xujin 22 | */ 23 | public class PisFileByFreeMarkerUtil { 24 | 25 | public static FreemarkerConfiguration freemarker = new FreemarkerConfiguration("/templates"); 26 | 27 | /** 28 | * 右键创建扩展点 29 | * @param project 30 | * @param model 31 | * @param moduleRootPath 32 | * @throws Exception 33 | */ 34 | public static void createFile(Project project, Object model, String moduleRootPath,String ftlName) throws Exception { 35 | 36 | NewRightModel rightModel =(NewRightModel)model; 37 | VirtualFile vf = createPackageDir(rightModel.getSelectedPackage(),moduleRootPath); 38 | //可以使用virtualfile.createChildData()方法创建文件实例 39 | VirtualFile virtualFile=vf.createChildData(project, rightModel.getClassName()+".java"); 40 | StringWriter sw = new StringWriter(); 41 | Template template = PisFileByFreeMarkerUtil.freemarker.getTemplate(ftlName); 42 | template.process(model, sw); 43 | //使用VirtualFile.setBinaryContent()写一些数据到对应的文件中 44 | virtualFile.setBinaryContent(sw.toString().getBytes(HaloIdeaUtils.DEFAULT_CHARSET)); 45 | //HaloIdeaUtils.addWaitOptimizeFile(virtualFile); 46 | 47 | FileEditorManager fileEditorManager = FileEditorManager.getInstance(project); 48 | if (fileEditorManager.isFileOpen(virtualFile)) { 49 | OpenSourceUtil.navigate(true, new OpenFileDescriptor(project, virtualFile)); 50 | ProjectView.getInstance(project).select(null, virtualFile, true); 51 | return; 52 | } 53 | fileEditorManager.openFile(virtualFile, true); 54 | ProjectView.getInstance(project).select(null, virtualFile, true); 55 | ApplicationManager.getApplication().invokeLater(() -> { 56 | ToolWindow toolWindow = ToolWindowManager.getInstance(project).getToolWindow("Project"); 57 | toolWindow.activate(null, true); 58 | }); 59 | } 60 | 61 | 62 | 63 | private static VirtualFile createPackageDir(String packageName, String moduleRootPath) { 64 | packageName = "src/main/java/" + packageName; 65 | String path = FileUtil.toSystemIndependentName(moduleRootPath + "/" + StringUtil.replace(packageName, ".", "/")); 66 | //new File(path).mkdirs(); 67 | return LocalFileSystem.getInstance().refreshAndFindFileByPath(path); 68 | } 69 | 70 | 71 | 72 | 73 | } 74 | -------------------------------------------------------------------------------- /idea-study-02/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | maven { url 'http://dl.bintray.com/jetbrains/intellij-plugin-service' } 4 | } 5 | 6 | } 7 | 8 | plugins { 9 | id 'java' 10 | id 'org.jetbrains.intellij' version '0.4.9' 11 | } 12 | 13 | repositories { 14 | mavenLocal() 15 | mavenCentral() 16 | } 17 | 18 | dependencies { 19 | // compile group: 'commons-io', name: 'commons-io', version: '2.5' 20 | //compile group: 'com.alibaba', name: 'fastjson', version: '1.2.58' 21 | compile group: 'org.freemarker', name: 'freemarker', version: '2.3.28' 22 | //compile group: 'mysql', name: 'mysql-connector-java', version: '5.1.24' 23 | 24 | } 25 | 26 | apply plugin: 'java' 27 | 28 | sourceCompatibility = JavaVersion.VERSION_1_8 29 | targetCompatibility = JavaVersion.VERSION_1_8 30 | 31 | tasks.withType(JavaCompile) { 32 | options.encoding = "UTF-8" 33 | } 34 | 35 | sourceSets { 36 | main { 37 | java.srcDirs 'src' 38 | resources.srcDirs 'resources' 39 | } 40 | test { 41 | java.srcDirs 'test' 42 | resources.srcDirs 'test-resources' 43 | } 44 | } 45 | 46 | intellij { 47 | version ideaVersion //调试插件IDEA的版本 48 | pluginName 'HaloTools' 49 | updateSinceUntilBuild false 50 | sandboxDirectory = "${rootProject.projectDir}/idea-sandbox/idea-${ideaVersion}" 51 | plugins 'maven' 52 | } 53 | 54 | group 'org.xujin.idea' 55 | version pluginVersion 56 | 57 | -------------------------------------------------------------------------------- /idea-study-02/resources/META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.xujin.idea.plugin 4 | HaloTools 5 | 1.0 6 | xujin.org 7 | 8 | 9 | <p>Enhances your productivity when developing applications based on Halo Framework.</p> 10 | 11 | 12 | com.intellij.modules.lang 13 | com.intellij.modules.platform 14 | com.intellij.modules.java 15 | org.jetbrains.idea.maven 16 | 17 | 18 | 19 | 20 | 21 | 23 | 24 | 25 | 27 | 28 | 29 | 30 | 31 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /idea-study-02/resources/META-INF/pluginIcon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /idea-study-02/resources/META-INF/pluginIcon_dark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /idea-study-02/resources/icons/halo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareKing/idea-study/e7b085f4c75e49ada5d90360578832cbf11bd3f3/idea-study-02/resources/icons/halo.png -------------------------------------------------------------------------------- /idea-study-02/resources/icons/right/HaloBasic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareKing/idea-study/e7b085f4c75e49ada5d90360578832cbf11bd3f3/idea-study-02/resources/icons/right/HaloBasic.png -------------------------------------------------------------------------------- /idea-study-02/resources/icons/right/controller.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareKing/idea-study/e7b085f4c75e49ada5d90360578832cbf11bd3f3/idea-study-02/resources/icons/right/controller.png -------------------------------------------------------------------------------- /idea-study-02/resources/icons/right/mapper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareKing/idea-study/e7b085f4c75e49ada5d90360578832cbf11bd3f3/idea-study-02/resources/icons/right/mapper.png -------------------------------------------------------------------------------- /idea-study-02/resources/templates/Controller.java.ftl: -------------------------------------------------------------------------------- 1 | package ${selectedPackage}; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.web.bind.annotation.*; 5 | 6 | @RestController 7 | @RequestMapping("/") 8 | public class ${className} { 9 | 10 | 11 | } 12 | -------------------------------------------------------------------------------- /idea-study-02/src/org/xujin/idea/right/BasicActionOpenDialog.java: -------------------------------------------------------------------------------- 1 | package org.xujin.idea.right; 2 | 3 | import com.intellij.ide.util.projectWizard.ModuleWizardStep; 4 | import com.intellij.ide.wizard.AbstractWizard; 5 | import com.intellij.openapi.module.Module; 6 | import com.intellij.openapi.options.ConfigurationException; 7 | import com.intellij.openapi.project.Project; 8 | import com.intellij.openapi.ui.Messages; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | /** 12 | * Halo Basic组创建 13 | * @author xujin 14 | */ 15 | public class BasicActionOpenDialog extends AbstractWizard { 16 | 17 | private Project myProject; 18 | private Module myModule; 19 | 20 | public BasicActionOpenDialog(Project project, Module module) { 21 | super("Create Halo Basic Class", project); 22 | myProject = project; 23 | myModule = module; 24 | ModuleWizardStep[] wizardSteps = createWizardSteps(); 25 | for (ModuleWizardStep wizardStep : wizardSteps) { 26 | addStep(wizardStep); 27 | } 28 | init(); 29 | } 30 | 31 | public ModuleWizardStep[] createWizardSteps() { 32 | return new ModuleWizardStep[]{ 33 | new BasicCreateSelectInfoStep(myProject,myModule) 34 | }; 35 | } 36 | 37 | /** 38 | * 点击Ok,之后去生成对应的扩展点 39 | */ 40 | @Override 41 | protected void doOKAction() { 42 | ModuleWizardStep step = getCurrentStepObject(); 43 | try { 44 | if (step.validate()) { 45 | super.doOKAction(); 46 | } 47 | } catch (ConfigurationException e) { 48 | Messages.showErrorDialog(step.getComponent(), e.getMessage(), e.getTitle()); 49 | } 50 | } 51 | 52 | @Nullable 53 | @Override 54 | protected String getHelpID() { 55 | return BasicActionOpenDialog.class.getName(); 56 | } 57 | 58 | 59 | } 60 | 61 | -------------------------------------------------------------------------------- /idea-study-02/src/org/xujin/idea/right/BasicComBoxRenderer.java: -------------------------------------------------------------------------------- 1 | package org.xujin.idea.right; 2 | 3 | 4 | import org.xujin.idea.right.model.SelectedTypeModel; 5 | 6 | import javax.swing.*; 7 | import java.awt.*; 8 | import java.util.ArrayList; 9 | import java.util.HashMap; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | /** 14 | * 下拉列表渲染 15 | */ 16 | public class BasicComBoxRenderer extends DefaultListCellRenderer { 17 | private Map iconMap = new HashMap<>(); 18 | private Color background = new Color(0, 100, 255, 15); 19 | private Color defaultBackground = (Color) UIManager.get("List.background"); 20 | 21 | public BasicComBoxRenderer() { 22 | iconMap.put(HaloConstant.COMBOX_CONTROLLER,new ImageIcon(getClass().getResource("/icons/right/controller.png"))); 23 | iconMap.put(HaloConstant.COMBOX_MAPPER,new ImageIcon(getClass().getResource("/icons/right/mapper.png"))); 24 | 25 | } 26 | 27 | public static List getSelectedList(){ 28 | List list=new ArrayList(); 29 | SelectedTypeModel blank=new SelectedTypeModel(); 30 | blank.setName(""); 31 | blank.setValue(HaloConstant.COMBOX_BLANK); 32 | list.add(blank); 33 | 34 | SelectedTypeModel controller=new SelectedTypeModel(); 35 | controller.setName("Controller"); 36 | controller.setValue(HaloConstant.COMBOX_CONTROLLER); 37 | list.add(controller); 38 | 39 | SelectedTypeModel mapper=new SelectedTypeModel(); 40 | mapper.setName("Mapper"); 41 | mapper.setValue(HaloConstant.COMBOX_MAPPER); 42 | list.add(mapper); 43 | 44 | 45 | 46 | return list; 47 | } 48 | 49 | @Override 50 | public Component getListCellRendererComponent(JList list, Object value, int index, 51 | boolean isSelected, boolean cellHasFocus) { 52 | super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); 53 | SelectedTypeModel emp = (SelectedTypeModel) value; 54 | this.setText(emp.getName()); 55 | this.setIcon(iconMap.get(emp.getValue())); 56 | if (!isSelected) { 57 | this.setBackground(index % 2 == 0 ? background : defaultBackground); 58 | } 59 | return this; 60 | } 61 | } -------------------------------------------------------------------------------- /idea-study-02/src/org/xujin/idea/right/BasicCreateSelectInfoStep.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 |
101 | -------------------------------------------------------------------------------- /idea-study-02/src/org/xujin/idea/right/BasicCreateSelectInfoStep.java: -------------------------------------------------------------------------------- 1 | package org.xujin.idea.right; 2 | 3 | import com.intellij.ide.util.projectWizard.ModuleWizardStep; 4 | import com.intellij.openapi.module.Module; 5 | import com.intellij.openapi.options.ConfigurationException; 6 | import com.intellij.openapi.project.Project; 7 | import org.xujin.idea.right.model.NewRightContext; 8 | import org.xujin.idea.right.model.SelectedTypeModel; 9 | 10 | import javax.swing.*; 11 | import java.awt.event.ItemEvent; 12 | import java.awt.event.ItemListener; 13 | import java.util.List; 14 | 15 | /** 16 | * @author xujin 17 | */ 18 | public class BasicCreateSelectInfoStep extends ModuleWizardStep { 19 | 20 | private JPanel myMainPanel; 21 | 22 | private JPanel myPackagePanel; 23 | 24 | /** 25 | * 类名 26 | */ 27 | private JTextField className; 28 | 29 | /** 30 | * 下拉列表框 31 | */ 32 | private JComboBox kind; 33 | 34 | 35 | 36 | 37 | private Project myProject; 38 | private Module myModule; 39 | 40 | 41 | 42 | 43 | /** 44 | * 创建Mapper选择数据对象相关 45 | */ 46 | private JLabel dataObjectTip; 47 | private JTextField dataObjectValue; 48 | private JButton dataObjectChooseButton; 49 | 50 | /** 51 | * @param project 52 | * @param module 53 | */ 54 | public BasicCreateSelectInfoStep(Project project, Module module) { 55 | myProject = project; 56 | myModule = module; 57 | initComBox(); 58 | dataObjectTip.setVisible(false); 59 | dataObjectValue.setVisible(false); 60 | dataObjectChooseButton.setVisible(false); 61 | 62 | kind.addItemListener(new ItemListener() { 63 | @Override 64 | public void itemStateChanged(ItemEvent e) { 65 | SelectedTypeModel selectedTypeModel = (SelectedTypeModel) e.getItem(); 66 | switch (selectedTypeModel.getValue()) { 67 | case HaloConstant.COMBOX_CONTROLLER: 68 | NewRightContext.setClassType(HaloConstant.COMBOX_CONTROLLER); 69 | break; 70 | default: 71 | NewRightContext.setClassType(null); 72 | } 73 | 74 | } 75 | }); 76 | } 77 | 78 | 79 | 80 | private void initComBox() { 81 | 82 | List list = BasicComBoxRenderer.getSelectedList(); 83 | for (SelectedTypeModel seleType : list) { 84 | kind.addItem(seleType); 85 | } 86 | kind.setRenderer(new BasicComBoxRenderer()); 87 | //Trinity trinity=new Trinity<>("Class", IconUtil.HALO , JavaTemplateUtil.INTERNAL_CLASS_TEMPLATE_NAME); 88 | //comboBox1.addItem(trinity); 89 | 90 | 91 | } 92 | 93 | @Override 94 | public JComponent getComponent() { 95 | return myMainPanel; 96 | } 97 | 98 | @Override 99 | public boolean validate() throws ConfigurationException { 100 | if (className.getText().isEmpty()) { 101 | throw new ConfigurationException("Class name cannot be empty", "Create Class Tips"); 102 | } 103 | NewRightContext.setClassName(className.getText()); 104 | return super.validate(); 105 | } 106 | 107 | 108 | @Override 109 | public void updateDataModel() { 110 | 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /idea-study-02/src/org/xujin/idea/right/HaloConstant.java: -------------------------------------------------------------------------------- 1 | package org.xujin.idea.right; 2 | 3 | /** 4 | * Halo Constant 5 | * @author xujin 6 | */ 7 | public interface HaloConstant { 8 | 9 | String COMBOX_BLANK="0"; 10 | 11 | /** 12 | * 创建Controller 13 | */ 14 | String COMBOX_CONTROLLER="1"; 15 | 16 | 17 | /** 18 | * 创建Mapper 19 | */ 20 | String COMBOX_MAPPER="2"; 21 | 22 | 23 | } 24 | -------------------------------------------------------------------------------- /idea-study-02/src/org/xujin/idea/right/NewBasicExeAction.java: -------------------------------------------------------------------------------- 1 | package org.xujin.idea.right; 2 | 3 | import com.intellij.openapi.actionSystem.AnAction; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.actionSystem.DataKeys; 6 | import com.intellij.openapi.application.Result; 7 | import com.intellij.openapi.command.WriteCommandAction; 8 | import com.intellij.openapi.module.Module; 9 | import com.intellij.openapi.module.ModuleUtil; 10 | import com.intellij.openapi.project.DumbAwareRunnable; 11 | import com.intellij.openapi.project.DumbService; 12 | import com.intellij.openapi.project.Project; 13 | import com.intellij.openapi.roots.ModuleRootManager; 14 | import com.intellij.openapi.vfs.VirtualFile; 15 | import org.apache.commons.lang3.StringUtils; 16 | import org.jetbrains.annotations.NotNull; 17 | import org.jetbrains.idea.maven.project.MavenProjectsManager; 18 | import org.xujin.idea.right.model.NewRightContext; 19 | import org.xujin.idea.right.model.NewRightModel; 20 | import org.xujin.idea.right.utils.HaloIdeaUtils; 21 | import org.xujin.idea.right.utils.PisFileByFreeMarkerUtil; 22 | 23 | 24 | /** 25 | * 右键创建Basic Action 26 | * @author xujin 27 | */ 28 | public class NewBasicExeAction extends AnAction { 29 | 30 | @Override 31 | public void actionPerformed(AnActionEvent e) { 32 | 33 | Project project = e.getProject(); 34 | /** 35 | * 从Action中得到一个虚拟文件 36 | */ 37 | VirtualFile virtualFile = e.getData(DataKeys.VIRTUAL_FILE); 38 | if (!virtualFile.isDirectory()) { 39 | virtualFile = virtualFile.getParent(); 40 | } 41 | Module module = ModuleUtil.findModuleForFile(virtualFile, project); 42 | 43 | String moduleRootPath = ModuleRootManager.getInstance(module).getContentRoots()[0].getPath(); 44 | String actionDir = virtualFile.getPath(); 45 | String str = StringUtils.substringAfter(actionDir, moduleRootPath + "/src/main/java/"); 46 | //获取右键后的路径 47 | String basePackage = StringUtils.replace(str, "/", "."); 48 | NewRightContext.clearAllSet(); 49 | NewRightContext.setSelectedPackage(basePackage); 50 | BasicActionOpenDialog dialog = new BasicActionOpenDialog(project, module); 51 | if (!dialog.showAndGet()) { 52 | return; 53 | } 54 | 55 | DumbService.getInstance(project).runWhenSmart((DumbAwareRunnable) () -> new WriteCommandAction(project) { 56 | @Override 57 | protected void run(@NotNull Result result) { 58 | switch (NewRightContext.getClassType()) { 59 | case HaloConstant.COMBOX_CONTROLLER: 60 | createByFtl(project, moduleRootPath,"Controller.java.ftl"); 61 | break; 62 | } 63 | MavenProjectsManager manager = MavenProjectsManager.getInstance(project); 64 | //解决依赖 65 | manager.forceUpdateAllProjectsOrFindAllAvailablePomFiles(); 66 | //优化生成的所有Java类 67 | HaloIdeaUtils.doOptimize(project); 68 | 69 | } 70 | }.execute()); 71 | 72 | } 73 | 74 | 75 | /** 76 | * 通过ftl创建 Controller 77 | * @param project 78 | * @param moduleRootPath 79 | */ 80 | private void createByFtl(Project project, String moduleRootPath, String ftlName) { 81 | NewRightModel newRightModel= NewRightContext.copyToNewRightModel(); 82 | try { 83 | PisFileByFreeMarkerUtil.createFile(project, newRightModel, moduleRootPath,ftlName); 84 | NewRightContext.clearAllSet(); 85 | } catch (Exception ex) { 86 | ex.printStackTrace(); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /idea-study-02/src/org/xujin/idea/right/linemarker/AppMgmtNavigationHandler.java: -------------------------------------------------------------------------------- 1 | package org.xujin.idea.right.linemarker; 2 | 3 | import com.intellij.codeInsight.daemon.GutterIconNavigationHandler; 4 | import com.intellij.psi.PsiElement; 5 | 6 | import java.awt.event.MouseEvent; 7 | 8 | 9 | /** 10 | * Domain行标记修改 11 | * @author xujin 12 | */ 13 | public class AppMgmtNavigationHandler implements GutterIconNavigationHandler { 14 | 15 | @Override 16 | public void navigate(MouseEvent mouseEvent, PsiElement psiElement) { 17 | 18 | 19 | } 20 | 21 | 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /idea-study-02/src/org/xujin/idea/right/linemarker/FunctionTooltip.java: -------------------------------------------------------------------------------- 1 | package org.xujin.idea.right.linemarker; 2 | 3 | import com.intellij.util.Function; 4 | 5 | /** 6 | * 7 | * @author xujin 8 | */ 9 | public class FunctionTooltip implements Function { 10 | 11 | String msg = "点我快速切换至对应文件"; 12 | 13 | public FunctionTooltip() { 14 | } 15 | 16 | public FunctionTooltip(String msg) { 17 | this.msg = msg; 18 | } 19 | 20 | 21 | @Override 22 | public Object fun(Object o) { 23 | return msg; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /idea-study-02/src/org/xujin/idea/right/linemarker/HaloLineMarker.java: -------------------------------------------------------------------------------- 1 | package org.xujin.idea.right.linemarker; 2 | 3 | import com.intellij.codeInsight.daemon.LineMarkerInfo; 4 | import com.intellij.codeInsight.daemon.LineMarkerProvider; 5 | import com.intellij.openapi.editor.markup.GutterIconRenderer; 6 | import com.intellij.openapi.util.IconLoader; 7 | import com.intellij.psi.PsiAnnotation; 8 | import com.intellij.psi.PsiClass; 9 | import com.intellij.psi.PsiElement; 10 | import com.intellij.psi.impl.source.PsiClassImpl; 11 | import org.jetbrains.annotations.NotNull; 12 | import org.jetbrains.annotations.Nullable; 13 | 14 | import java.util.Collection; 15 | import java.util.List; 16 | 17 | public class HaloLineMarker implements LineMarkerProvider { 18 | 19 | @Nullable 20 | @Override 21 | public LineMarkerInfo getLineMarkerInfo(@NotNull PsiElement psiElement) { 22 | LineMarkerInfo lineMarkerInfo= null; 23 | try { 24 | lineMarkerInfo = null; 25 | String anno="org.springframework.boot.autoconfigure.SpringBootApplication"; 26 | if(!judgeHaveAnnotation(psiElement,anno)){ 27 | return lineMarkerInfo; 28 | } 29 | PsiClassImpl field = ((PsiClassImpl) psiElement); 30 | PsiAnnotation psiAnnotation = field.getAnnotation(anno); 31 | lineMarkerInfo = new LineMarkerInfo<>(psiAnnotation, psiAnnotation.getTextRange(), IconLoader.findIcon("/icons/right/HaloBasic.png"), 32 | new FunctionTooltip("快速导航"), 33 | new AppMgmtNavigationHandler(), 34 | GutterIconRenderer.Alignment.LEFT); 35 | //根据不同的行标记分配不同的行标记处理器 36 | } catch (Exception e) { 37 | e.printStackTrace(); 38 | } 39 | return lineMarkerInfo; 40 | } 41 | 42 | @Override 43 | public void collectSlowLineMarkers(@NotNull List list, @NotNull Collection collection) { 44 | } 45 | 46 | private boolean judgeHaveAnnotation(@NotNull PsiElement psiElement, String anno) { 47 | if (psiElement instanceof PsiClass) { 48 | PsiClassImpl field = ((PsiClassImpl) psiElement); 49 | PsiAnnotation psiAnnotation = field.getAnnotation(anno); 50 | if (null != psiAnnotation) { 51 | return true; 52 | } 53 | return false; 54 | } 55 | return false; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /idea-study-02/src/org/xujin/idea/right/model/NewRightContext.java: -------------------------------------------------------------------------------- 1 | package org.xujin.idea.right.model; 2 | 3 | public class NewRightContext { 4 | 5 | /** 6 | * 类名 7 | */ 8 | private static String className; 9 | 10 | /** 11 | * 所选择的类的类型 12 | */ 13 | private static String classType; 14 | 15 | /** 16 | * 创建java类所在的包 17 | */ 18 | private static String selectedPackage; 19 | 20 | 21 | public static String getClassType() { 22 | return classType; 23 | } 24 | 25 | public static void setClassType(String classType) { 26 | NewRightContext.classType = classType; 27 | } 28 | 29 | public static String getClassName() { 30 | return className; 31 | } 32 | 33 | public static void setClassName(String className) { 34 | NewRightContext.className = className; 35 | } 36 | 37 | public static String getSelectedPackage() { 38 | return selectedPackage; 39 | } 40 | 41 | public static void setSelectedPackage(String selectedPackage) { 42 | NewRightContext.selectedPackage = selectedPackage; 43 | } 44 | 45 | public static void clearAllSet() { 46 | classType = null; 47 | className = null; 48 | selectedPackage = null; 49 | } 50 | 51 | public static NewRightModel copyToNewRightModel() { 52 | NewRightModel newRightModel = new NewRightModel(); 53 | newRightModel.setClassName(className); 54 | newRightModel.setSelectedPackage(selectedPackage); 55 | return newRightModel; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /idea-study-02/src/org/xujin/idea/right/model/NewRightModel.java: -------------------------------------------------------------------------------- 1 | package org.xujin.idea.right.model; 2 | 3 | public class NewRightModel { 4 | 5 | /** 6 | * 类名 7 | */ 8 | private String className; 9 | 10 | /** 11 | * 所选择的类的类型 12 | */ 13 | private String classType; 14 | 15 | /** 16 | * 创建java类所在的包 17 | */ 18 | private String selectedPackage; 19 | 20 | public String getClassName() { 21 | return className; 22 | } 23 | 24 | public void setClassName(String className) { 25 | this.className = className; 26 | } 27 | 28 | public String getClassType() { 29 | return classType; 30 | } 31 | 32 | public void setClassType(String classType) { 33 | this.classType = classType; 34 | } 35 | 36 | public String getSelectedPackage() { 37 | return selectedPackage; 38 | } 39 | 40 | public void setSelectedPackage(String selectedPackage) { 41 | this.selectedPackage = selectedPackage; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /idea-study-02/src/org/xujin/idea/right/model/SelectedTypeModel.java: -------------------------------------------------------------------------------- 1 | package org.xujin.idea.right.model; 2 | 3 | /** 4 | * 下拉列表选中模型 5 | * @author xujin 6 | */ 7 | public class SelectedTypeModel { 8 | 9 | /** 10 | * 下拉列表显示的名称 11 | */ 12 | private String name; 13 | 14 | /** 15 | * 下拉列表的value 16 | */ 17 | private String value; 18 | 19 | public String getName() { 20 | return name; 21 | } 22 | 23 | public void setName(String name) { 24 | this.name = name; 25 | } 26 | 27 | public String getValue() { 28 | return value; 29 | } 30 | 31 | public void setValue(String value) { 32 | this.value = value; 33 | } 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /idea-study-02/src/org/xujin/idea/right/utils/FreemarkerConfiguration.java: -------------------------------------------------------------------------------- 1 | package org.xujin.idea.right.utils; 2 | 3 | import freemarker.template.Configuration; 4 | 5 | public class FreemarkerConfiguration extends Configuration { 6 | private String basePackagePath; 7 | 8 | public FreemarkerConfiguration() { 9 | this(""); 10 | } 11 | 12 | public FreemarkerConfiguration(String basePackagePath) { 13 | super(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); 14 | setClassForTemplateLoading(getClass(), basePackagePath); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /idea-study-02/src/org/xujin/idea/right/utils/HaloIdeaUtils.java: -------------------------------------------------------------------------------- 1 | package org.xujin.idea.right.utils; 2 | 3 | import com.intellij.openapi.application.ApplicationManager; 4 | import com.intellij.openapi.application.ModalityState; 5 | import com.intellij.openapi.application.Result; 6 | import com.intellij.openapi.command.WriteCommandAction; 7 | import com.intellij.openapi.project.DumbAwareRunnable; 8 | import com.intellij.openapi.project.DumbService; 9 | import com.intellij.openapi.project.Project; 10 | import com.intellij.openapi.startup.StartupManager; 11 | import com.intellij.openapi.vfs.VirtualFile; 12 | import com.intellij.psi.PsiJavaFile; 13 | import com.intellij.psi.PsiManager; 14 | import com.intellij.psi.codeStyle.CodeStyleManager; 15 | import com.intellij.psi.codeStyle.JavaCodeStyleManager; 16 | import com.intellij.util.DisposeAwareRunnable; 17 | import org.jetbrains.annotations.NotNull; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | /** 23 | * @author xujin 24 | */ 25 | public class HaloIdeaUtils { 26 | public static final String DEFAULT_CHARSET = "UTF-8"; 27 | 28 | public static void invokeAndWait(Project p, Runnable r) { 29 | invokeAndWait(p, ModalityState.defaultModalityState(), r); 30 | } 31 | 32 | public static void invokeAndWait(Project p, ModalityState state, Runnable r) { 33 | if (isNoBackgroundMode()) { 34 | r.run(); 35 | } else { 36 | ApplicationManager.getApplication().invokeAndWait(DisposeAwareRunnable.create(r, p), state); 37 | } 38 | } 39 | 40 | public static void invokeLater(Project p, Runnable r) { 41 | invokeLater(p, ModalityState.defaultModalityState(), r); 42 | } 43 | 44 | public static void invokeLater(Project p, ModalityState state, Runnable r) { 45 | if (isNoBackgroundMode()) { 46 | r.run(); 47 | } else { 48 | ApplicationManager.getApplication().invokeLater(DisposeAwareRunnable.create(r, p), state); 49 | } 50 | 51 | } 52 | 53 | public static void runWhenInitialized(final Project project, final Runnable r) { 54 | if (project.isDisposed()) { 55 | return; 56 | } 57 | if (isNoBackgroundMode()) { 58 | r.run(); 59 | return; 60 | } 61 | if (!project.isInitialized()) { 62 | StartupManager.getInstance(project).registerPostStartupActivity(DisposeAwareRunnable.create(r, project)); 63 | return; 64 | } 65 | runDumbAware(project, r); 66 | } 67 | 68 | public static boolean isNoBackgroundMode() { 69 | return (ApplicationManager.getApplication().isUnitTestMode() 70 | || ApplicationManager.getApplication().isHeadlessEnvironment()); 71 | } 72 | 73 | public static void runDumbAware(final Project project, final Runnable r) { 74 | if (DumbService.isDumbAware(r)) { 75 | r.run(); 76 | } else { 77 | DumbService.getInstance(project).runWhenSmart(DisposeAwareRunnable.create(r, project)); 78 | } 79 | } 80 | 81 | private static List virtualFiles = new ArrayList<>(); 82 | 83 | public static void addWaitOptimizeFile(VirtualFile virtualFile) { 84 | virtualFiles.add(virtualFile); 85 | } 86 | 87 | public static void doOptimize(Project project) { 88 | DumbService.getInstance(project).runWhenSmart((DumbAwareRunnable) () -> new WriteCommandAction(project) { 89 | @Override 90 | protected void run(@NotNull Result result) { 91 | for (VirtualFile virtualFile : virtualFiles) { 92 | try { 93 | PsiJavaFile javaFile = (PsiJavaFile) PsiManager.getInstance(project).findFile(virtualFile); 94 | if (javaFile != null) { 95 | CodeStyleManager.getInstance(project).reformat(javaFile); 96 | JavaCodeStyleManager.getInstance(project).optimizeImports(javaFile); 97 | JavaCodeStyleManager.getInstance(project).shortenClassReferences(javaFile); 98 | } 99 | 100 | } catch (Exception e) { 101 | e.printStackTrace(); 102 | } 103 | } 104 | virtualFiles.clear(); 105 | } 106 | }.execute()); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /idea-study-02/src/org/xujin/idea/right/utils/PisFileByFreeMarkerUtil.java: -------------------------------------------------------------------------------- 1 | package org.xujin.idea.right.utils; 2 | 3 | import com.intellij.ide.projectView.ProjectView; 4 | import com.intellij.openapi.application.ApplicationManager; 5 | import com.intellij.openapi.fileEditor.FileEditorManager; 6 | import com.intellij.openapi.fileEditor.OpenFileDescriptor; 7 | import com.intellij.openapi.project.Project; 8 | import com.intellij.openapi.util.io.FileUtil; 9 | import com.intellij.openapi.util.text.StringUtil; 10 | import com.intellij.openapi.vfs.LocalFileSystem; 11 | import com.intellij.openapi.vfs.VirtualFile; 12 | import com.intellij.openapi.wm.ToolWindow; 13 | import com.intellij.openapi.wm.ToolWindowManager; 14 | import com.intellij.util.OpenSourceUtil; 15 | import freemarker.template.Template; 16 | import org.xujin.idea.right.model.NewRightModel; 17 | 18 | import java.io.StringWriter; 19 | 20 | /** 21 | * @author xujin 22 | */ 23 | public class PisFileByFreeMarkerUtil { 24 | 25 | public static FreemarkerConfiguration freemarker = new FreemarkerConfiguration("/templates"); 26 | 27 | /** 28 | * 右键创建扩展点 29 | * @param project 30 | * @param model 31 | * @param moduleRootPath 32 | * @throws Exception 33 | */ 34 | public static void createFile(Project project, Object model, String moduleRootPath,String ftlName) throws Exception { 35 | 36 | NewRightModel rightModel =(NewRightModel)model; 37 | VirtualFile vf = createPackageDir(rightModel.getSelectedPackage(),moduleRootPath); 38 | //可以使用virtualfile.createChildData()方法创建文件实例 39 | VirtualFile virtualFile=vf.createChildData(project, rightModel.getClassName()+".java"); 40 | StringWriter sw = new StringWriter(); 41 | Template template = PisFileByFreeMarkerUtil.freemarker.getTemplate(ftlName); 42 | template.process(model, sw); 43 | //使用VirtualFile.setBinaryContent()写一些数据到对应的文件中 44 | virtualFile.setBinaryContent(sw.toString().getBytes(HaloIdeaUtils.DEFAULT_CHARSET)); 45 | //HaloIdeaUtils.addWaitOptimizeFile(virtualFile); 46 | 47 | FileEditorManager fileEditorManager = FileEditorManager.getInstance(project); 48 | if (fileEditorManager.isFileOpen(virtualFile)) { 49 | OpenSourceUtil.navigate(true, new OpenFileDescriptor(project, virtualFile)); 50 | ProjectView.getInstance(project).select(null, virtualFile, true); 51 | return; 52 | } 53 | fileEditorManager.openFile(virtualFile, true); 54 | ProjectView.getInstance(project).select(null, virtualFile, true); 55 | ApplicationManager.getApplication().invokeLater(() -> { 56 | ToolWindow toolWindow = ToolWindowManager.getInstance(project).getToolWindow("Project"); 57 | toolWindow.activate(null, true); 58 | }); 59 | } 60 | 61 | 62 | 63 | private static VirtualFile createPackageDir(String packageName, String moduleRootPath) { 64 | packageName = "src/main/java/" + packageName; 65 | String path = FileUtil.toSystemIndependentName(moduleRootPath + "/" + StringUtil.replace(packageName, ".", "/")); 66 | //new File(path).mkdirs(); 67 | return LocalFileSystem.getInstance().refreshAndFindFileByPath(path); 68 | } 69 | 70 | 71 | 72 | 73 | } 74 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'idea-study' 2 | include(':idea-study-01') 3 | include(':idea-study-02') 4 | 5 | 6 | --------------------------------------------------------------------------------