├── MvpAutoCode ├── .gitignore ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── lkl │ │ │ └── plugin │ │ │ └── Utils.java │ │ ├── kotlin │ │ └── com │ │ │ └── lkl │ │ │ └── plugin │ │ │ ├── Extfun.kt │ │ │ ├── config │ │ │ └── ItemConfigBean.kt │ │ │ ├── Cons.kt │ │ │ ├── maker │ │ │ ├── ComponentRegister.kt │ │ │ ├── CodeMaker.kt │ │ │ ├── TemplateMaker.kt │ │ │ └── FileMaker.kt │ │ │ └── TemplateCons.java │ │ └── resources │ │ └── META-INF │ │ └── plugin.xml └── build.gradle ├── .gitignore ├── ComparingReferencesInspection ├── .gitignore ├── src │ ├── test │ │ ├── testData │ │ │ ├── Neq.java │ │ │ ├── Eq.after.java │ │ │ ├── Eq.java │ │ │ └── Neq.after.java │ │ └── java │ │ │ └── com │ │ │ └── lkl │ │ │ └── plugin │ │ │ └── ComparingReferencesInspectionTest.java │ └── main │ │ └── resources │ │ ├── inspectionDescriptions │ │ └── ComparingReferences.html │ │ └── META-INF │ │ └── plugin.xml └── build.gradle ├── IdeaPluginStudy ├── .gitignore ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── lkl │ │ │ └── plugin │ │ │ ├── codegenerator │ │ │ ├── ConflictResolutionPolicy.java │ │ │ ├── util │ │ │ │ ├── MemberEntry.java │ │ │ │ ├── EntryFactory.java │ │ │ │ └── EntryUtils.java │ │ │ ├── config │ │ │ │ ├── PipelineStep.java │ │ │ │ ├── ClassSelectionConfig.java │ │ │ │ ├── CodeTemplateList.java │ │ │ │ ├── CodeGeneratorSettings.java │ │ │ │ ├── CodeTemplate.java │ │ │ │ └── MemberSelectionConfig.java │ │ │ ├── ui │ │ │ │ ├── PipelineStepConfig.java │ │ │ │ ├── ClassSelectionPane.form │ │ │ │ ├── CodeGeneratorConfigurable.java │ │ │ │ ├── ClassSelectionPane.java │ │ │ │ └── SelectionPane.form │ │ │ ├── CodeGenerator.java │ │ │ ├── worker │ │ │ │ └── JavaCaretWorker.java │ │ │ └── action │ │ │ │ └── CodeGeneratorGroup.java │ │ │ ├── tostring │ │ │ ├── template │ │ │ │ ├── toString │ │ │ │ └── TemplatesState.java │ │ │ ├── GenerateToStringInterfaceFilter.java │ │ │ ├── GenerateToStringAction.java │ │ │ ├── exception │ │ │ │ └── TemplateResourceException.java │ │ │ ├── GenerateToStringClassFilter.java │ │ │ ├── config │ │ │ │ ├── DuplicatePolicy.java │ │ │ │ ├── InsertAtCaretStrategy.java │ │ │ │ ├── ReplacePolicy.java │ │ │ │ └── InsertAfterEqualsHashCodeStrategy.java │ │ │ ├── element │ │ │ │ ├── ElementComparator.java │ │ │ │ ├── FieldElement.java │ │ │ │ ├── GenerationHelper.java │ │ │ │ ├── MethodElement.java │ │ │ │ └── ElementUtils.java │ │ │ ├── view │ │ │ │ ├── MethodExistsDialog.java │ │ │ │ └── TemplatesPanel.java │ │ │ ├── GenerateToStringConfigurable.java │ │ │ └── velocity │ │ │ │ └── VelocityFactory.java │ │ │ ├── base │ │ │ ├── MyAction.java │ │ │ ├── SecondAction.java │ │ │ ├── MyGroup1.java │ │ │ ├── InsertCharAction.java │ │ │ ├── HelloWorldPlugin.java │ │ │ ├── MyGroup.java │ │ │ ├── MyTypedActionHandler.java │ │ │ └── GetterAndSetter.java │ │ │ ├── PsiAugmentProvider │ │ │ └── CustomPsiAugmentProvider.java │ │ │ ├── configurable │ │ │ ├── SingleFileExecutionConfigurable.java │ │ │ ├── SingleFileExecutionConfig.java │ │ │ └── ExeOverwriteConfirmDialog.form │ │ │ └── StructureViewExtension │ │ │ └── CustomStructureViewExtension.java │ │ └── resources │ │ ├── template │ │ ├── to-string.xml │ │ ├── getters-and-setters.xml │ │ └── default.vm │ │ └── META-INF │ │ └── plugin.xml └── build.gradle ├── docs ├── base │ ├── imgs │ │ ├── log.png │ │ ├── action │ │ │ ├── openEditor.png │ │ │ ├── closeEditor.png │ │ │ ├── codeCreateGroup.png │ │ │ ├── groupIdMainMenu.png │ │ │ ├── defaultActionGroup.png │ │ │ ├── groupActionPopupTrue.png │ │ │ ├── groupActionPopupFalse.png │ │ │ ├── groupIdEditorPopupMenu.png │ │ │ └── groupIdProjectViewPopupMenu.png │ │ ├── helloWorld │ │ │ ├── helpMenu.png │ │ │ ├── message.png │ │ │ ├── welcome.png │ │ │ ├── newPlugin1.png │ │ │ ├── newPlugin2.png │ │ │ ├── createAction.png │ │ │ ├── installPlugin.png │ │ │ ├── buildDeployment.png │ │ │ ├── buildDeployment1.png │ │ │ ├── projectStructure.png │ │ │ └── uninstallPlugin.png │ │ ├── editor │ │ │ └── caretModelPosition.png │ │ └── gradlePlugin │ │ │ ├── step1_new_gradle_project.png │ │ │ └── gradle_tasks_in_tool_window.png │ ├── log.md │ ├── kotlinPlugin.md │ └── helloWorld.md ├── psi │ ├── imgs │ │ └── structureView.png │ ├── structureViewExtension.md │ └── psiAugmentProvider.md └── advanced │ ├── imgs │ ├── configurable │ │ ├── newGuiForm.png │ │ ├── pluginConfigurationDisplay.png │ │ └── singlefileexecutionconfigurable_setting2.png │ └── codeInspections │ │ ├── comparingReferences.png │ │ └── comparingReferences_options.png │ ├── generateTostring.md │ └── persistStateComponent.md ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── settings.gradle ├── gradle.properties ├── README.md └── gradlew.bat /MvpAutoCode/.gitignore: -------------------------------------------------------------------------------- 1 | build/ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle/ 2 | .idea/ 3 | out/ -------------------------------------------------------------------------------- /ComparingReferencesInspection/.gitignore: -------------------------------------------------------------------------------- 1 | build/ -------------------------------------------------------------------------------- /IdeaPluginStudy/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle/ 2 | .idea/ 3 | out/ 4 | build/ 5 | IdeaPluginStudy.jar -------------------------------------------------------------------------------- /docs/base/imgs/log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/base/imgs/log.png -------------------------------------------------------------------------------- /docs/psi/imgs/structureView.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/psi/imgs/structureView.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /docs/base/imgs/action/openEditor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/base/imgs/action/openEditor.png -------------------------------------------------------------------------------- /docs/base/imgs/action/closeEditor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/base/imgs/action/closeEditor.png -------------------------------------------------------------------------------- /docs/base/imgs/helloWorld/helpMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/base/imgs/helloWorld/helpMenu.png -------------------------------------------------------------------------------- /docs/base/imgs/helloWorld/message.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/base/imgs/helloWorld/message.png -------------------------------------------------------------------------------- /docs/base/imgs/helloWorld/welcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/base/imgs/helloWorld/welcome.png -------------------------------------------------------------------------------- /docs/base/imgs/action/codeCreateGroup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/base/imgs/action/codeCreateGroup.png -------------------------------------------------------------------------------- /docs/base/imgs/action/groupIdMainMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/base/imgs/action/groupIdMainMenu.png -------------------------------------------------------------------------------- /docs/base/imgs/helloWorld/newPlugin1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/base/imgs/helloWorld/newPlugin1.png -------------------------------------------------------------------------------- /docs/base/imgs/helloWorld/newPlugin2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/base/imgs/helloWorld/newPlugin2.png -------------------------------------------------------------------------------- /docs/base/imgs/helloWorld/createAction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/base/imgs/helloWorld/createAction.png -------------------------------------------------------------------------------- /docs/base/imgs/helloWorld/installPlugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/base/imgs/helloWorld/installPlugin.png -------------------------------------------------------------------------------- /docs/advanced/imgs/configurable/newGuiForm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/advanced/imgs/configurable/newGuiForm.png -------------------------------------------------------------------------------- /docs/base/imgs/action/defaultActionGroup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/base/imgs/action/defaultActionGroup.png -------------------------------------------------------------------------------- /docs/base/imgs/action/groupActionPopupTrue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/base/imgs/action/groupActionPopupTrue.png -------------------------------------------------------------------------------- /docs/base/imgs/editor/caretModelPosition.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/base/imgs/editor/caretModelPosition.png -------------------------------------------------------------------------------- /docs/base/imgs/helloWorld/buildDeployment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/base/imgs/helloWorld/buildDeployment.png -------------------------------------------------------------------------------- /docs/base/imgs/helloWorld/buildDeployment1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/base/imgs/helloWorld/buildDeployment1.png -------------------------------------------------------------------------------- /docs/base/imgs/helloWorld/projectStructure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/base/imgs/helloWorld/projectStructure.png -------------------------------------------------------------------------------- /docs/base/imgs/helloWorld/uninstallPlugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/base/imgs/helloWorld/uninstallPlugin.png -------------------------------------------------------------------------------- /docs/base/imgs/action/groupActionPopupFalse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/base/imgs/action/groupActionPopupFalse.png -------------------------------------------------------------------------------- /docs/base/imgs/action/groupIdEditorPopupMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/base/imgs/action/groupIdEditorPopupMenu.png -------------------------------------------------------------------------------- /docs/base/imgs/action/groupIdProjectViewPopupMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/base/imgs/action/groupIdProjectViewPopupMenu.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'IntellijPluginStudy' 2 | include 'IdeaPluginStudy' 3 | include 'MvpAutoCode' 4 | include 'ComparingReferencesInspection' 5 | 6 | -------------------------------------------------------------------------------- /docs/base/imgs/gradlePlugin/step1_new_gradle_project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/base/imgs/gradlePlugin/step1_new_gradle_project.png -------------------------------------------------------------------------------- /docs/advanced/imgs/codeInspections/comparingReferences.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/advanced/imgs/codeInspections/comparingReferences.png -------------------------------------------------------------------------------- /docs/base/imgs/gradlePlugin/gradle_tasks_in_tool_window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/base/imgs/gradlePlugin/gradle_tasks_in_tool_window.png -------------------------------------------------------------------------------- /docs/advanced/imgs/configurable/pluginConfigurationDisplay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/advanced/imgs/configurable/pluginConfigurationDisplay.png -------------------------------------------------------------------------------- /docs/advanced/imgs/codeInspections/comparingReferences_options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/advanced/imgs/codeInspections/comparingReferences_options.png -------------------------------------------------------------------------------- /ComparingReferencesInspection/src/test/testData/Neq.java: -------------------------------------------------------------------------------- 1 | public class Neq { 2 | public boolean compare2Dates(java.util.Date dt1, java.util.Date dt2){ 3 | return (dt1 != dt2); 4 | } 5 | 6 | } -------------------------------------------------------------------------------- /docs/advanced/imgs/configurable/singlefileexecutionconfigurable_setting2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lkl22/IntellijPluginStudy/HEAD/docs/advanced/imgs/configurable/singlefileexecutionconfigurable_setting2.png -------------------------------------------------------------------------------- /ComparingReferencesInspection/src/test/testData/Eq.after.java: -------------------------------------------------------------------------------- 1 | public class Eq { 2 | public boolean compare2Strings(java.lang.String s1, java.lang.String s2) { 3 | return (s1.equals(s2)); 4 | } 5 | 6 | } -------------------------------------------------------------------------------- /ComparingReferencesInspection/src/test/testData/Eq.java: -------------------------------------------------------------------------------- 1 | public class Eq { 2 | public boolean compare2Strings(java.lang.String s1, java.lang.String s2) { 3 | return (s1 == s2); 4 | } 5 | 6 | } -------------------------------------------------------------------------------- /ComparingReferencesInspection/src/test/testData/Neq.after.java: -------------------------------------------------------------------------------- 1 | public class Neq { 2 | public boolean compare2Dates(java.util.Date dt1, java.util.Date dt2){ 3 | return (!dt1.equals(dt2)); 4 | } 5 | 6 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/codegenerator/ConflictResolutionPolicy.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.codegenerator; 2 | 3 | public enum ConflictResolutionPolicy { 4 | CANCEL, 5 | DUPLICATE, 6 | DUPLICATE_ALL, 7 | REPLACE, 8 | REPLACE_ALL, 9 | } 10 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/template/toString/DefaultGuava.vm: -------------------------------------------------------------------------------- 1 | public java.lang.String toString() { 2 | return com.google.common.base.Objects.toStringHelper(this) 3 | #foreach ($member in $members) 4 | .add("$member.name", $member.accessor) 5 | #end 6 | .toString(); 7 | } -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/template/toString/DefaultGuava18.vm: -------------------------------------------------------------------------------- 1 | public java.lang.String toString() { 2 | return com.google.common.base.MoreObjects.toStringHelper(this) 3 | #foreach ($member in $members) 4 | .add("$member.name", $member.accessor) 5 | #end 6 | .toString(); 7 | } -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/template/toString/DefaultToStringBuilder.vm: -------------------------------------------------------------------------------- 1 | public java.lang.String toString() { 2 | return new org.apache.commons.lang.builder.ToStringBuilder(this) 3 | #foreach ($member in $members) 4 | .append("$member.name", $member.accessor) 5 | #end 6 | .toString(); 7 | } -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/template/toString/DefaultToStringBuilder3.vm: -------------------------------------------------------------------------------- 1 | public java.lang.String toString() { 2 | return new org.apache.commons.lang3.builder.ToStringBuilder(this) 3 | #foreach ($member in $members) 4 | .append("$member.name", $member.accessor) 5 | #end 6 | .toString(); 7 | } -------------------------------------------------------------------------------- /docs/advanced/generateTostring.md: -------------------------------------------------------------------------------- 1 | # generate-tostring 2 | 3 | ## 参考文献 4 | 5 | [CodeGenerator](https://github.com/lotabout/CodeGenerator) 6 | 7 | [https://github.com/JetBrains/intellij-community/tree/master/plugins/generate-tostring](https://github.com/JetBrains/intellij-community/tree/master/plugins/generate-tostring) -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/codegenerator/util/MemberEntry.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.codegenerator.util; 2 | 3 | import com.intellij.psi.PsiMember; 4 | import org.jetbrains.java.generate.element.Element; 5 | 6 | public interface MemberEntry extends Element { 7 | T getRaw(); 8 | } 9 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/codegenerator/config/PipelineStep.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.codegenerator.config; 2 | 3 | public interface PipelineStep { 4 | String type(); 5 | String postfix(); 6 | void postfix(String postfix); 7 | boolean enabled(); 8 | void enabled(boolean enabled); 9 | } 10 | -------------------------------------------------------------------------------- /docs/base/log.md: -------------------------------------------------------------------------------- 1 | # 打印日志,查看日志 2 | 3 | ## 创建log对象 4 | ```java 5 | import com.intellij.openapi.diagnostic.Logger; 6 | 7 | protected static final Logger log = Logger.getInstance(xxx.class); 8 | ``` 9 | 10 | ## 查看日志 11 | 12 | 点击`『showlog in finder』`,会打开一个目录,里面有很多的log文件,你在plugin工程中使用Logger.info打印的日志都会存储在该log文件中,打开即可 13 | 14 | ![](./imgs/log.png) -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/codegenerator/ui/PipelineStepConfig.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.codegenerator.ui; 2 | 3 | import com.lkl.plugin.codegenerator.config.PipelineStep; 4 | 5 | import javax.swing.*; 6 | 7 | public interface PipelineStepConfig { 8 | PipelineStep getConfig(); 9 | JComponent getComponent(); 10 | } 11 | -------------------------------------------------------------------------------- /MvpAutoCode/src/main/java/com/lkl/plugin/Utils.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin; 2 | 3 | /** 4 | * Created by XQ Yang on 2018/6/25 18:14. 5 | * Description : 6 | */ 7 | 8 | public class Utils { 9 | public Utils() { 10 | } 11 | 12 | public static boolean isEmpty(CharSequence s) { 13 | if (s == null) { 14 | return true; 15 | } else { 16 | return s.length() == 0; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /MvpAutoCode/src/main/kotlin/com/lkl/plugin/Extfun.kt: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin 2 | 3 | /** 4 | * Created by XQ Yang on 2018/6/25 19:17. 5 | * Description : 6 | */ 7 | 8 | fun MutableSet.eAdd(vararg e: E): Set { 9 | if (e.size > 1) { 10 | this.addAll(e) 11 | } else if (e.isNotEmpty()) { 12 | this.add(e[0]) 13 | } 14 | return this 15 | } 16 | 17 | fun String.lastDotContent() = this.substring(this.lastIndexOf(".") + 1, this.length) -------------------------------------------------------------------------------- /MvpAutoCode/src/main/kotlin/com/lkl/plugin/config/ItemConfigBean.kt: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.config 2 | 3 | import com.intellij.ide.util.PropertiesComponent 4 | 5 | /** 6 | * Created by XQ Yang on 2018/6/28 16:20. 7 | * Description : 8 | */ 9 | data class ItemConfigBean(val name: String, val isJava: Boolean = true, val isActivity: Boolean = true, val vImpl: String, val pImpl: String, val mImpl: String, 10 | val state: PropertiesComponent, val generateModel: Boolean = true) -------------------------------------------------------------------------------- /ComparingReferencesInspection/src/main/resources/inspectionDescriptions/ComparingReferences.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SDK: This inspection reports when the '==' or '!=' operator was used between expressions of 6 | reference types.
7 | Classes to be inspected are controlled by a semi-colon separated Options list in the preferences panel for this inspection. 8 | 9 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/codegenerator/CodeGenerator.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.codegenerator; 2 | 3 | import com.intellij.openapi.components.ApplicationComponent; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | public class CodeGenerator implements ApplicationComponent { 7 | public CodeGenerator() { 8 | } 9 | 10 | @Override 11 | public void initComponent() {} 12 | 13 | @Override 14 | public void disposeComponent() { 15 | } 16 | 17 | @Override 18 | @NotNull 19 | public String getComponentName() { 20 | return "me.lotabout.codegenerator.CodeGenerator"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/template/toString/StringJoiner.vm: -------------------------------------------------------------------------------- 1 | public java.lang.String toString() { 2 | return new java.util.StringJoiner(", ", $classname## 3 | .class.getSimpleName() + "[", "]") 4 | #foreach ($member in $members) 5 | #if(!$member.modifierStatic) 6 | .add("$member.name=## 7 | #if ($member.primitiveArray || $member.objectArray) 8 | " + java.util.Arrays.toString($member.name)## 9 | #elseif ($member.string) 10 | '" + $member.accessor + "'"## 11 | #else 12 | " + $member.accessor ## 13 | #end 14 | ) 15 | #end 16 | #end 17 | .toString(); 18 | } -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/base/MyAction.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.base; 2 | 3 | import com.intellij.openapi.actionSystem.AnAction; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.actionSystem.PlatformDataKeys; 6 | import com.intellij.openapi.project.Project; 7 | import com.intellij.openapi.ui.Messages; 8 | 9 | /** 10 | * Created by likunlun on 2020/7/11. 11 | */ 12 | public class MyAction extends AnAction { 13 | 14 | @Override 15 | public void actionPerformed(AnActionEvent anActionEvent) { 16 | Project project = anActionEvent.getData(PlatformDataKeys.PROJECT); 17 | Messages.showMessageDialog(project, "Hello Action!", "Information", Messages.getInformationIcon()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/base/SecondAction.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.base; 2 | 3 | import com.intellij.openapi.actionSystem.AnAction; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.actionSystem.PlatformDataKeys; 6 | import com.intellij.openapi.project.Project; 7 | import com.intellij.openapi.ui.Messages; 8 | 9 | /** 10 | * Created by likunlun on 2020/7/11. 11 | */ 12 | public class SecondAction extends AnAction { 13 | 14 | @Override 15 | public void actionPerformed(AnActionEvent anActionEvent) { 16 | Project project = anActionEvent.getData(PlatformDataKeys.PROJECT); 17 | Messages.showMessageDialog(project, "Hello Second Action!", "Information", Messages.getInformationIcon()); 18 | } 19 | } -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/base/MyGroup1.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.base; 2 | 3 | import com.intellij.icons.AllIcons; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.actionSystem.CommonDataKeys; 6 | import com.intellij.openapi.actionSystem.DefaultActionGroup; 7 | import com.intellij.openapi.editor.Editor; 8 | 9 | /** 10 | * Created by likunlun on 2020/7/11. 11 | */ 12 | public class MyGroup1 extends DefaultActionGroup { 13 | @Override 14 | public void update(AnActionEvent e) { 15 | Editor editor = e.getData(CommonDataKeys.EDITOR); 16 | e.getPresentation().setVisible(true); 17 | e.getPresentation().setEnabled(editor != null); 18 | e.getPresentation().setIcon(AllIcons.General.Error); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/template/toString/DefaultBuilder.vm: -------------------------------------------------------------------------------- 1 | public java.lang.String toString() { 2 | final java.lang.StringBuilder sb = new java.lang.StringBuilder("$classname{"); 3 | #set ($i = 0) 4 | #foreach ($member in $members) 5 | #if ($i == 0) 6 | sb.append("## 7 | #else 8 | sb.append(", ## 9 | #end 10 | #if ($member.string) 11 | $member.name='")## 12 | #else 13 | $member.name=")## 14 | #end 15 | #if ($member.primitiveArray || $member.objectArray) 16 | .append(java.util.Arrays.toString($member.name)); 17 | #elseif ($member.string) 18 | .append($member.accessor).append('\''); 19 | #else 20 | .append($member.accessor); 21 | #end 22 | #set ($i = $i + 1) 23 | #end 24 | sb.append('}'); 25 | return sb.toString(); 26 | } -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/template/toString/DefaultConcatMemberGroovy.vm: -------------------------------------------------------------------------------- 1 | public java.lang.String toString() { 2 | #if ( $members.size() > 0 ) 3 | #set ( $i = 0 ) 4 | return """\ 5 | $classname{ 6 | #foreach( $member in $members ) 7 | #if ( $i > 0 ), 8 | #end 9 | #set($d = "$") 10 | #if ( $member.objectArray ) 11 | $member.name=${d}{java.util.Arrays.toString($member.accessor)}## 12 | #elseif ( $member.primitiveArray) 13 | $member.name=${d}{java.util.Arrays.toString($member.accessor)}## 14 | #elseif ( $member.string ) 15 | $member.name='$d$member.accessor'## 16 | #else 17 | $member.name=$d${member.accessor}## 18 | #end 19 | #set ( $i = $i + 1 ) 20 | #end 21 | 22 | }""" 23 | #else 24 | return "$classname{}" 25 | #end 26 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | -Dfile.encoding=UTF-8 2 | # Copy this file as gradle.properties 3 | # It will be used for both compiling and running the plugin. 4 | 5 | 6 | # Path to a downloaded instance of Android Studio 7 | # This is used to add the android plugin dependencies to the project. 8 | # must point to the latest version of Android Studio. 9 | # You'll know it's right if you can find "$StudioCompilePath/lib/idea.jar" 10 | StudioCompilePath=/Applications/Android Studio.app/Contents/ 11 | IntellijCompilePath=/Applications/IntelliJ IDEA CE.app/Contents/ 12 | 13 | 14 | # Determines which IDE to run when using the "./gradlew runIdea" command. 15 | # This is useful to test the plugin on older versions of Android Studio or Intellij 16 | # Default value: $StudioCompilePath 17 | StudioRunPath=/Applications/Android Studio.app/Contents/ 18 | IntellijRunPath=/Applications/IntelliJ IDEA CE.app/Contents/ -------------------------------------------------------------------------------- /ComparingReferencesInspection/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.jetbrains.intellij' version '0.4.21' 4 | } 5 | 6 | group 'com.lkl.plugin' 7 | version '1.0.0' 8 | 9 | sourceCompatibility = 1.8 10 | 11 | repositories { 12 | mavenCentral() 13 | } 14 | 15 | test { 16 | // Set idea.home.path to the absolute path to the intellij-community source 17 | // on your local machine. 18 | // systemProperty "idea.home.path", "/Users/jhake/Documents/source/comm" 19 | } 20 | 21 | dependencies { 22 | testCompile group: 'junit', name: 'junit', version: '4.12' 23 | } 24 | 25 | // See https://github.com/JetBrains/gradle-intellij-plugin/ 26 | intellij { 27 | version = '2020.1' 28 | plugins = ['java'] 29 | } 30 | 31 | buildSearchableOptions { 32 | enabled = false 33 | } 34 | 35 | patchPluginXml { 36 | version = project.version 37 | sinceBuild = '201' 38 | untilBuild = '201.*' 39 | } -------------------------------------------------------------------------------- /IdeaPluginStudy/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.jetbrains.intellij' version '0.4.21' 4 | } 5 | 6 | group 'com.lkl.plugin' 7 | version '1.0.0' 8 | 9 | repositories { 10 | mavenCentral() 11 | } 12 | 13 | dependencies { 14 | compileOnly fileTree(dir: "$IntellijCompilePath/plugins/java/lib", include: ['*.jar']) 15 | compileOnly fileTree(dir: "$IntellijCompilePath/lib", include: ['*.jar']) 16 | 17 | testCompile fileTree(dir: "$IntellijCompilePath/plugins/java/lib", include: ['*.jar']) 18 | testCompile fileTree(dir: "$IntellijCompilePath/lib", include: ['*.jar']) 19 | testCompile group: 'junit', name: 'junit', version: '4.12' 20 | } 21 | 22 | // See https://github.com/JetBrains/gradle-intellij-plugin/ 23 | intellij { 24 | version '2019.3' 25 | plugins 'java' 26 | } 27 | patchPluginXml { 28 | changeNotes """ 29 | Add change notes here.
30 | most HTML tags may be used""" 31 | } -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/template/toString/DefaultConcatMember.vm: -------------------------------------------------------------------------------- 1 | public java.lang.String toString() { 2 | #if ( $members.size() > 0 ) 3 | #set ( $i = 0 ) 4 | return "$classname{" + 5 | #foreach( $member in $members ) 6 | #if ( $i == 0 ) 7 | "## 8 | #else 9 | ", ## 10 | #end 11 | #if ( $member.objectArray ) 12 | #if ($java_version < 5) 13 | $member.name=" + ($member.accessor == null ? null : java.util.Arrays.asList($member.accessor)) + 14 | #else 15 | $member.name=" + java.util.Arrays.toString($member.accessor) + 16 | #end 17 | #elseif ( $member.primitiveArray && $java_version >= 5) 18 | $member.name=" + java.util.Arrays.toString($member.accessor) + 19 | #elseif ( $member.string ) 20 | $member.name='" + $member.accessor + '\'' + 21 | #else 22 | $member.name=" + $member.accessor + 23 | #end 24 | #set ( $i = $i + 1 ) 25 | #end 26 | '}'; 27 | #else 28 | return "$classname{}"; 29 | #end 30 | } -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/GenerateToStringInterfaceFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2000-2014 JetBrains s.r.o. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lkl.plugin.tostring; 17 | 18 | import com.intellij.psi.PsiClass; 19 | 20 | /** 21 | * Nikolay.Tropin 22 | * 2014-12-01 23 | */ 24 | public class GenerateToStringInterfaceFilter implements GenerateToStringClassFilter { 25 | 26 | @Override 27 | public boolean canGenerateToString(PsiClass psiClass) { 28 | return !psiClass.isInterface(); 29 | } 30 | } -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/template/toString/DefaultBuffer.vm: -------------------------------------------------------------------------------- 1 | public java.lang.String toString() { 2 | final java.lang.StringBuffer sb = new java.lang.StringBuffer("$classname{"); 3 | #set ($i = 0) 4 | #foreach ($member in $members) 5 | #if ($i == 0) 6 | sb.append("## 7 | #else 8 | sb.append(", ## 9 | #end 10 | #if ($member.string) 11 | $member.name='")## 12 | #else 13 | $member.name=")## 14 | #end 15 | #if ($member.primitiveArray) 16 | ; 17 | if ($member.name == null) ## 18 | sb.append("null"); 19 | else { 20 | sb.append('['); 21 | for (int i = 0; i < $member.name .length; ++i) 22 | sb.append(i == 0 ? "" : ", ").append($member.name [i]); 23 | sb.append(']'); 24 | } 25 | #elseif ($member.objectArray) 26 | .append($member.name == null ? "null" : java.util.Arrays.asList($member.name).toString()); 27 | #elseif ($member.string) 28 | .append($member.accessor).append('\''); 29 | #else 30 | .append($member.accessor); 31 | #end 32 | #set ($i = $i + 1) 33 | #end 34 | sb.append('}'); 35 | return sb.toString(); 36 | } -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/template/toString/DefaultConcatMemberSuperGroovy.vm: -------------------------------------------------------------------------------- 1 | public java.lang.String toString() { 2 | #set($d = "$") 3 | #if ( $members.size() > 0 ) 4 | #set ( $i = 0 ) 5 | return """\ 6 | $classname{ 7 | #foreach( $member in $members ) 8 | #if( $i > 0 ), 9 | #end 10 | #if ( $member.objectArray ) 11 | $member.name=${d}{java.util.Arrays.toString($member.accessor)}## 12 | #elseif ( $member.primitiveArray) 13 | $member.name=${d}{java.util.Arrays.toString($member.accessor)}## 14 | #elseif ( $member.string ) 15 | $member.name='$d$member.accessor'## 16 | #else 17 | $member.name=$d${member.accessor}## 18 | #end 19 | #set( $i = $i + 1 ) 20 | #end 21 | #if( $class.hasSuper ) 22 | #if( $i > 0 ), 23 | #end 24 | super=${d}{super.toString()}## 25 | #end 26 | 27 | }""" 28 | #else 29 | #if( $class.hasSuper ) 30 | return "$classname{## 31 | super=${d}{super.toString()}## 32 | }" 33 | #else 34 | return "$classname{}" 35 | #end 36 | #end 37 | } -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/base/InsertCharAction.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.base; 2 | 3 | import com.intellij.openapi.actionSystem.AnAction; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.editor.actionSystem.EditorActionManager; 6 | import com.intellij.openapi.editor.actionSystem.TypedAction; 7 | import com.intellij.openapi.editor.actionSystem.TypedActionHandler; 8 | 9 | /** 10 | * Created by likunlun on 2020/7/11. 11 | */ 12 | public class InsertCharAction extends AnAction { 13 | public InsertCharAction() { 14 | final EditorActionManager actionManager = EditorActionManager.getInstance(); 15 | final TypedAction typedAction = actionManager.getTypedAction(); 16 | MyTypedActionHandler handler = new MyTypedActionHandler(); 17 | //将自定义的TypedActionHandler设置进去后, 18 | //返回旧的TypedActionHandler,即IDEA自身的TypedActionHandler 19 | TypedActionHandler oldHandler = typedAction.setupHandler(handler); 20 | handler.setOldHandler(oldHandler); 21 | } 22 | 23 | @Override 24 | public void actionPerformed(AnActionEvent e) { 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/GenerateToStringAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001-2007 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lkl.plugin.tostring; 17 | 18 | import com.intellij.codeInsight.generation.actions.BaseGenerateAction; 19 | 20 | /** 21 | * This action handles the generation of a {@code toString()} method that dumps the fields 22 | * of the class. 23 | */ 24 | public class GenerateToStringAction extends BaseGenerateAction { 25 | 26 | public GenerateToStringAction() { 27 | super(new GenerateToStringActionHandlerImpl()); 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/base/HelloWorldPlugin.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.base; 2 | 3 | import com.intellij.openapi.actionSystem.AnAction; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.actionSystem.PlatformDataKeys; 6 | import com.intellij.openapi.editor.Editor; 7 | import com.intellij.openapi.project.Project; 8 | import com.intellij.openapi.ui.Messages; 9 | import org.jetbrains.annotations.Nls; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | /** 13 | * Created by likunlun on 2020/7/11. 14 | */ 15 | public class HelloWorldPlugin extends AnAction { 16 | @Override 17 | public void update(AnActionEvent e) { 18 | Editor editor = e.getData(PlatformDataKeys.EDITOR); 19 | 20 | if (editor != null) 21 | e.getPresentation().setEnabled(true); 22 | else 23 | e.getPresentation().setEnabled(false); 24 | 25 | } 26 | 27 | @Override 28 | public void actionPerformed(AnActionEvent e) { 29 | // TODO: insert action logic here 30 | Project project = e.getData(PlatformDataKeys.PROJECT); 31 | Messages.showMessageDialog(project, "Hello World111!", "Information", Messages.getInformationIcon()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/codegenerator/util/EntryFactory.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.codegenerator.util; 2 | 3 | import com.intellij.psi.PsiClass; 4 | import com.intellij.psi.PsiField; 5 | import com.intellij.psi.PsiMethod; 6 | import org.jetbrains.java.generate.element.ElementFactory; 7 | import org.jetbrains.java.generate.element.FieldElement; 8 | 9 | public class EntryFactory { 10 | public static FieldEntry of(PsiField field, boolean useAccessor) { 11 | if (field == null) return null; 12 | return new FieldEntry(field, ElementFactory.newFieldElement(field, useAccessor)); 13 | } 14 | 15 | public static FieldEntry of(PsiClass clazz, FieldElement element) { 16 | if (clazz == null || element == null) return null; 17 | 18 | PsiField field = clazz.findFieldByName(element.getName(), true); 19 | return new FieldEntry(field, element); 20 | } 21 | 22 | public static MethodEntry of(PsiMethod method) { 23 | if (method == null) return null; 24 | return new MethodEntry(method, ElementFactory.newMethodElement(method)); 25 | } 26 | 27 | public static ClassEntry of(PsiClass clazz) { 28 | if (clazz == null) return null; 29 | return ClassEntry.of(clazz, ElementFactory.newClassElement(clazz)); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/template/toString/DefaultConcatMemberSuper.vm: -------------------------------------------------------------------------------- 1 | public java.lang.String toString() { 2 | #if ( $members.size() > 0 ) 3 | #set ( $i = 0 ) 4 | return "$classname{" + 5 | #foreach( $member in $members ) 6 | #if ( $i == 0 ) 7 | "## 8 | #else 9 | ", ## 10 | #end 11 | #if ( $member.objectArray ) 12 | #if ($java_version < 5) 13 | $member.name=" + ($member.accessor == null ? null : java.util.Arrays.asList($member.accessor)) + 14 | #else 15 | $member.name=" + java.util.Arrays.toString($member.accessor) + 16 | #end 17 | #elseif ( $member.primitiveArray && $java_version >= 5) 18 | $member.name=" + java.util.Arrays.toString($member.accessor) + 19 | #elseif ( $member.string ) 20 | $member.name='" + $member.accessor + '\'' + 21 | #else 22 | $member.name=" + $member.accessor + 23 | #end 24 | #set ( $i = $i + 1 ) 25 | #end 26 | #if ( $class.hasSuper ) 27 | "} " + super.toString(); 28 | #else 29 | '}'; 30 | #end 31 | #else 32 | #if ( $class.hasSuper ) 33 | return "$classname{} " + super.toString(); 34 | #else 35 | return "$classname{}"; 36 | #end 37 | #end 38 | } -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/exception/TemplateResourceException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001-2007 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lkl.plugin.tostring.exception; 17 | 18 | import org.jetbrains.java.generate.exception.PluginException; 19 | 20 | /** 21 | * Template resource related exceptions. 22 | *

23 | * Usually error loading or saving template resources. 24 | */ 25 | public class TemplateResourceException extends PluginException { 26 | 27 | /** 28 | * Create template exception (error saving template, loading template etc.) 29 | * 30 | * @param msg message description. 31 | * @param cause the caused exception. 32 | */ 33 | public TemplateResourceException(String msg, Throwable cause) { 34 | super(msg, cause); 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/base/MyGroup.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.base; 2 | 3 | import com.intellij.openapi.actionSystem.ActionGroup; 4 | import com.intellij.openapi.actionSystem.AnAction; 5 | import com.intellij.openapi.actionSystem.AnActionEvent; 6 | import com.intellij.openapi.actionSystem.PlatformDataKeys; 7 | import com.intellij.openapi.editor.CaretModel; 8 | import com.intellij.openapi.editor.Editor; 9 | import com.intellij.openapi.editor.SelectionModel; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.jetbrains.annotations.Nullable; 12 | 13 | /** 14 | * Created by likunlun on 2020/7/11. 15 | */ 16 | public class MyGroup extends ActionGroup { 17 | @NotNull 18 | @Override 19 | public AnAction[] getChildren(@Nullable AnActionEvent anActionEvent) { 20 | return new AnAction[]{new CustomAction("first"),new CustomAction("second")}; 21 | } 22 | 23 | class CustomAction extends AnAction { 24 | public CustomAction(String text) { 25 | super(text); 26 | } 27 | @Override 28 | public void actionPerformed(@NotNull AnActionEvent e) { 29 | Editor editor = e.getData(PlatformDataKeys.EDITOR); 30 | if (editor == null) 31 | return; 32 | 33 | SelectionModel selectionModel = editor.getSelectionModel(); 34 | CaretModel caretModel=editor.getCaretModel(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/template/TemplatesState.java: -------------------------------------------------------------------------------- 1 | // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. 2 | package com.lkl.plugin.tostring.template; 3 | 4 | import com.intellij.openapi.util.Comparing; 5 | import com.intellij.openapi.util.text.StringUtil; 6 | import com.intellij.util.xmlb.annotations.Attribute; 7 | import com.intellij.util.xmlb.annotations.OptionTag; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | import java.util.Objects; 12 | 13 | final class TemplatesState { 14 | @SuppressWarnings("SpellCheckingInspection") 15 | @OptionTag("defaultTempalteName") 16 | String oldDefaultTemplateName; 17 | 18 | @Attribute 19 | String defaultTemplateName = ""; 20 | 21 | public final List templates = new ArrayList<>(); 22 | 23 | @Override 24 | public boolean equals(Object o) { 25 | if (this == o) return true; 26 | if (o == null || getClass() != o.getClass()) return false; 27 | TemplatesState state = (TemplatesState)o; 28 | return Comparing.strEqual(defaultTemplateName, state.defaultTemplateName) && 29 | Objects.equals(templates, state.templates); 30 | } 31 | 32 | @Override 33 | public int hashCode() { 34 | return Objects.hash(StringUtil.nullize(defaultTemplateName), templates); 35 | } 36 | } -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/GenerateToStringClassFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2000-2014 JetBrains s.r.o. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lkl.plugin.tostring; 17 | 18 | import com.intellij.openapi.extensions.ExtensionPointName; 19 | import com.intellij.psi.PsiClass; 20 | import org.jetbrains.annotations.Contract; 21 | 22 | /** 23 | * An extension which allows to prohibit toString generation for some classes 24 | */ 25 | public interface GenerateToStringClassFilter { 26 | ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.generation.toStringClassFilter"); 27 | 28 | /** 29 | * @param psiClass class to check 30 | * @return return false if toString should not be generated for the class 31 | */ 32 | @Contract(pure = true) 33 | boolean canGenerateToString(PsiClass psiClass); 34 | } -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/codegenerator/ui/ClassSelectionPane.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 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/base/MyTypedActionHandler.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.base; 2 | 3 | import com.intellij.openapi.actionSystem.DataContext; 4 | import com.intellij.openapi.editor.CaretModel; 5 | import com.intellij.openapi.editor.Document; 6 | import com.intellij.openapi.editor.Editor; 7 | import com.intellij.openapi.editor.actionSystem.TypedActionHandler; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | /** 11 | * Created by likunlun on 2020/7/11. 12 | */ 13 | public class MyTypedActionHandler implements TypedActionHandler { 14 | private TypedActionHandler oldHandler; 15 | private boolean isBegin = true; 16 | private int caretLine = 0; 17 | 18 | @Override 19 | public void execute(@NotNull Editor editor, char c, @NotNull DataContext dataContext) { 20 | if (oldHandler != null) 21 | oldHandler.execute(editor, c, dataContext); 22 | 23 | Document document = editor.getDocument(); 24 | CaretModel caretModel = editor.getCaretModel(); 25 | int caretOffset = caretModel.getOffset(); 26 | int line = document.getLineNumber(caretOffset); 27 | if (isBegin) { 28 | document.insertString(document.getLineStartOffset(line), String.valueOf(c) + "\n"); 29 | caretLine = line + 1; 30 | isBegin = false; 31 | } else { 32 | if (line != caretLine) { 33 | isBegin = true; 34 | execute(editor, c, dataContext); 35 | } else { 36 | document.insertString(document.getLineEndOffset(line - 1), String.valueOf(c)); 37 | } 38 | } 39 | System.out.println(caretLine + "," + line); 40 | 41 | } 42 | 43 | public void setOldHandler(TypedActionHandler oldHandler) { 44 | this.oldHandler = oldHandler; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/codegenerator/config/ClassSelectionConfig.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.codegenerator.config; 2 | 3 | import javax.xml.bind.annotation.XmlAccessType; 4 | import javax.xml.bind.annotation.XmlAccessorType; 5 | import javax.xml.bind.annotation.XmlRootElement; 6 | 7 | @XmlRootElement(name = "classSelection") 8 | @XmlAccessorType(XmlAccessType.FIELD) 9 | public class ClassSelectionConfig implements PipelineStep { 10 | public String initialClass = "$class0.qualifiedName"; 11 | public boolean enabled = true; 12 | public String postfix = ""; 13 | @Override public String type() { 14 | return "class-selection"; 15 | } 16 | 17 | @Override 18 | public String postfix() { 19 | return postfix; 20 | } 21 | 22 | @Override 23 | public void postfix(String postfix) { 24 | this.postfix = postfix; 25 | } 26 | 27 | @Override 28 | public boolean enabled() { 29 | return enabled; 30 | } 31 | 32 | @Override 33 | public void enabled(boolean enabled) { 34 | this.enabled = enabled; 35 | } 36 | 37 | @Override 38 | public boolean equals(Object o) { 39 | if (this == o) return true; 40 | if (o == null || getClass() != o.getClass()) return false; 41 | 42 | ClassSelectionConfig that = (ClassSelectionConfig) o; 43 | 44 | if (enabled != that.enabled) return false; 45 | if (initialClass != null ? !initialClass.equals(that.initialClass) : that.initialClass != null) return false; 46 | return postfix != null ? postfix.equals(that.postfix) : that.postfix == null; 47 | } 48 | 49 | @Override 50 | public int hashCode() { 51 | int result = initialClass != null ? initialClass.hashCode() : 0; 52 | result = 31 * result + (enabled ? 1 : 0); 53 | result = 31 * result + (postfix != null ? postfix.hashCode() : 0); 54 | return result; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/PsiAugmentProvider/CustomPsiAugmentProvider.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.PsiAugmentProvider; 2 | 3 | import com.intellij.lang.java.JavaLanguage; 4 | import com.intellij.psi.PsiElement; 5 | import com.intellij.psi.PsiManager; 6 | import com.intellij.psi.PsiModifier; 7 | import com.intellij.psi.PsiType; 8 | import com.intellij.psi.augment.PsiAugmentProvider; 9 | import com.intellij.psi.impl.light.LightFieldBuilder; 10 | import com.intellij.psi.impl.light.LightMethodBuilder; 11 | import com.intellij.psi.impl.light.LightModifierList; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | import java.util.List; 15 | 16 | public class CustomPsiAugmentProvider extends PsiAugmentProvider { 17 | @NotNull 18 | @Override 19 | protected List getAugments(@NotNull PsiElement element, @NotNull Class type) { 20 | 21 | // PsiManager manager = psiField.getAugmentsManager(); 22 | // LightMethodBuilder method = new LightMethodBuilder(manager, JavaLanguage.INSTANCE, methodName); 23 | // method.addModifier(PsiModifier.PUBLIC); 24 | // method.setContainingClass(psiClass); 25 | // method.setNavigationElement(psiField); 26 | // method.addParameter(psiField.getName(), psiField.getType()); 27 | // method.setMethodReturnType(PsiType.VOID); 28 | // 29 | // PsiType psiLoggerType = psiElementFactory.createTypeFromText(LOGGER_TYPE, psiClass); 30 | // LightFieldBuilder loggerField = new LightFieldBuilder(manager, LOGGER_NAME, psiLoggerType); 31 | // LightModifierList modifierList = (LightModifierList) loggerField.getModifierList(); 32 | // modifierList.addModifier(PsiModifier.PRIVATE); 33 | // modifierList.addModifier(PsiModifier.STATIC); 34 | // modifierList.addModifier(PsiModifier.FINAL); 35 | // loggerField.setContainingClass(psiClass); 36 | // loggerField.setNavigationElement(psiAnnotation); 37 | 38 | return super.getAugments(element, type); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/codegenerator/config/CodeTemplateList.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.codegenerator.config; 2 | 3 | import javax.xml.bind.JAXB; 4 | import javax.xml.bind.annotation.XmlAccessType; 5 | import javax.xml.bind.annotation.XmlAccessorType; 6 | import javax.xml.bind.annotation.XmlElement; 7 | import javax.xml.bind.annotation.XmlElementWrapper; 8 | import java.io.StringReader; 9 | import java.io.StringWriter; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | @XmlAccessorType(XmlAccessType.FIELD) 14 | public class CodeTemplateList { 15 | @XmlElement(type = CodeTemplate.class) 16 | @XmlElementWrapper 17 | private List templates = new ArrayList<>(); 18 | 19 | public CodeTemplateList() {} 20 | public CodeTemplateList(List templates) { 21 | this.templates.addAll(templates); 22 | } 23 | public CodeTemplateList(CodeTemplate template) { 24 | this.templates.add(template); 25 | } 26 | 27 | public List getTemplates() { 28 | templates.forEach(CodeTemplate::regenerateId); 29 | return templates; 30 | } 31 | 32 | public void setTemplates(List templates) { 33 | this.templates = templates; 34 | } 35 | 36 | public static List fromXML(String xml) { 37 | CodeTemplateList list = JAXB.unmarshal(new StringReader(xml), CodeTemplateList.class); 38 | return list.getTemplates(); 39 | } 40 | 41 | public static String toXML(List templates) { 42 | CodeTemplateList templateList = new CodeTemplateList(templates); 43 | StringWriter sw = new StringWriter(); 44 | JAXB.marshal(templateList, sw); 45 | return sw.toString(); 46 | } 47 | public static String toXML(CodeTemplate templates) { 48 | CodeTemplateList templateList = new CodeTemplateList(templates); 49 | StringWriter sw = new StringWriter(); 50 | JAXB.marshal(templateList, sw); 51 | return sw.toString(); 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/config/DuplicatePolicy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lkl.plugin.tostring.config; 17 | 18 | import com.intellij.openapi.editor.Editor; 19 | import com.intellij.psi.PsiClass; 20 | import com.intellij.psi.PsiMethod; 21 | import org.jetbrains.annotations.NotNull; 22 | import org.jetbrains.java.generate.config.ConflictResolutionPolicy; 23 | import org.jetbrains.java.generate.config.InsertNewMethodStrategy; 24 | 25 | /** 26 | * This policy is to create a duplicate {@code toString} method. 27 | */ 28 | public final class DuplicatePolicy implements ConflictResolutionPolicy { 29 | 30 | private static final DuplicatePolicy instance = new DuplicatePolicy(); 31 | private InsertNewMethodStrategy newMethodStrategy = InsertAtCaretStrategy.getInstance(); 32 | 33 | private DuplicatePolicy() {} 34 | 35 | public static DuplicatePolicy getInstance() { 36 | return instance; 37 | } 38 | 39 | @Override 40 | public void setNewMethodStrategy(InsertNewMethodStrategy strategy) { 41 | newMethodStrategy = strategy; 42 | } 43 | 44 | @Override 45 | public PsiMethod applyMethod(PsiClass clazz, PsiMethod existingMethod, @NotNull PsiMethod newMethod, Editor editor) { 46 | return newMethodStrategy.insertNewMethod(clazz, newMethod, editor); 47 | } 48 | 49 | public String toString() { 50 | return "Duplicate"; 51 | } 52 | } -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/configurable/SingleFileExecutionConfigurable.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.configurable; 2 | 3 | import com.intellij.openapi.options.ConfigurationException; 4 | import com.intellij.openapi.options.SearchableConfigurable; 5 | import com.intellij.openapi.project.Project; 6 | import org.jetbrains.annotations.Nls; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | import javax.swing.*; 11 | 12 | public class SingleFileExecutionConfigurable implements SearchableConfigurable { 13 | private SingleFileExecutionConfigurableGUI mGUI; 14 | private final SingleFileExecutionConfig mConfig; 15 | 16 | @SuppressWarnings("FieldCanBeLocal") 17 | private final Project mProject; 18 | 19 | public SingleFileExecutionConfigurable(@NotNull Project project) { 20 | mProject = project; 21 | mConfig = SingleFileExecutionConfig.getInstance(project); 22 | } 23 | 24 | @Nls 25 | @Override 26 | public String getDisplayName() { 27 | return "Single File Execution Plugin"; 28 | } 29 | 30 | @Nullable 31 | @Override 32 | public String getHelpTopic() { 33 | return "preference.SingleFileExecutionConfigurable"; 34 | } 35 | 36 | @NotNull 37 | @Override 38 | public String getId() { 39 | return "preference.SingleFileExecutionConfigurable"; 40 | } 41 | 42 | @Nullable 43 | @Override 44 | public Runnable enableSearch(String s) { 45 | return null; 46 | } 47 | 48 | @Nullable 49 | @Override 50 | public JComponent createComponent() { 51 | mGUI = new SingleFileExecutionConfigurableGUI(); 52 | mGUI.createUI(mProject); 53 | return mGUI.getRootPanel(); 54 | } 55 | 56 | @Override 57 | public boolean isModified() { 58 | return mGUI.isModified(); 59 | } 60 | 61 | @Override 62 | public void apply() throws ConfigurationException { 63 | mGUI.apply(); 64 | } 65 | 66 | @Override 67 | public void reset() { 68 | mGUI.reset(); 69 | } 70 | 71 | @Override 72 | public void disposeUIResources() { 73 | mGUI = null; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/config/InsertAtCaretStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lkl.plugin.tostring.config; 17 | 18 | import com.intellij.codeInsight.generation.GenerateMembersUtil; 19 | import com.intellij.codeInsight.generation.PsiGenerationInfo; 20 | import com.intellij.openapi.editor.Editor; 21 | import com.intellij.psi.PsiClass; 22 | import com.intellij.psi.PsiMethod; 23 | import org.jetbrains.annotations.NotNull; 24 | import org.jetbrains.java.generate.config.InsertNewMethodStrategy; 25 | 26 | import java.util.Collections; 27 | 28 | /** 29 | * Inserts the method at the caret position. 30 | */ 31 | public final class InsertAtCaretStrategy implements InsertNewMethodStrategy { 32 | 33 | private static final InsertAtCaretStrategy instance = new InsertAtCaretStrategy(); 34 | 35 | private InsertAtCaretStrategy() {} 36 | 37 | public static InsertAtCaretStrategy getInstance() { 38 | return instance; 39 | } 40 | 41 | @Override 42 | public PsiMethod insertNewMethod(PsiClass clazz, @NotNull PsiMethod newMethod, Editor editor) { 43 | int offset = (editor != null) ? editor.getCaretModel().getOffset() : (clazz.getTextRange().getEndOffset() - 1); 44 | final PsiGenerationInfo generationInfo = new PsiGenerationInfo<>(newMethod, false); 45 | GenerateMembersUtil.insertMembersAtOffset(clazz, offset, Collections.singletonList(generationInfo)); 46 | return generationInfo.getPsiMember(); 47 | } 48 | 49 | public String toString() { 50 | return "At caret"; 51 | } 52 | } -------------------------------------------------------------------------------- /MvpAutoCode/src/main/kotlin/com/lkl/plugin/Cons.kt: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin 2 | 3 | /** 4 | * Created by XQ Yang on 2018/6/26 11:14. 5 | * Description : 常量 6 | */ 7 | 8 | fun getContractName(name: String) = "I${name}Contract" 9 | 10 | fun getViewInfName(name: String) = "I${name}View" 11 | fun getPresenterInfName(name: String) = "I${name}Presenter" 12 | fun getModelInfName(name: String) = "I${name}Model" 13 | 14 | const val USE_PROJECT_CONFIG = "use_project_config" 15 | const val GENERATE_MODEL_CONFIG = "generate_model_config" 16 | const val GOTO_SETTING = "Please go to File-> Settings -> OtherSettings -> MvpAutoCodePlus set." 17 | const val IS_NOT_SET = "Is not set" 18 | const val NO_SUPER_CLASS = "The implementation class will have no superclass" 19 | 20 | const val CONTRACT = "contract" 21 | const val VIEW = "view" 22 | const val PRESENTER = "presenter" 23 | const val MODEL = "model" 24 | 25 | 26 | const val SUPER_VIEW = "super_view" 27 | const val SUPER_PRESENTER = "super_presenter" 28 | const val SUPER_MODEL = "super_model" 29 | const val SUPER_VIEW_ACTIVITY = "super_view_activity" 30 | const val SUPER_VIEW_FRAGMENT = "super_view_fragment" 31 | const val SUPER_PRESENTER_IMPL = "super_presenter_impl" 32 | const val SUPER_MODEL_IMPL = "super_model_impl" 33 | const val COMMENT_AUTHOR = "comment_author" 34 | 35 | 36 | const val CONTRACT_TP_NAME_JAVA = "JavaMvpAutoCodePlusContract" 37 | const val CONTRACT_TP_NAME_KOTLIN = "KotlinMvpAutoCodePlusContract" 38 | const val CONTRACT_TP_NO_MODEL_NAME_JAVA = "JavaMvpAutoCodePlusContractNoModel" 39 | const val CONTRACT_TP_NO_MODEL_NAME_KOTLIN = "KotlinMvpAutoCodePlusContractNoModel" 40 | const val VIEW_IMPL_TP_ACTIVITY_JAVA = "JavaMvpAutoCodePlusViewActivityImpl" 41 | const val VIEW_IMPL_TP_ACTIVITY_KOTLIN = "KotlinMvpAutoCodePlusViewActivityImpl" 42 | const val VIEW_IMPL_TP_FRAGMENT_JAVA = "JavaMvpAutoCodePlusViewFragmentImpl" 43 | const val VIEW_IMPL_TP_FRAGMENT_KOTLIN = "KotlinMvpAutoCodePlusViewFragmentImpl" 44 | const val PRESENTER_IMPL_TP_JAVA = "JavaMvpAutoCodePlusPresenterImpl" 45 | const val PRESENTER_IMPL_TP_KOTLIN = "KotlinMvpAutoCodePlusPresenterImpl" 46 | const val MODEL_IMPL_TP_JAVA = "JavaMvpAutoCodePlusModelImpl" 47 | const val MODEL_IMPL_TP_KOTLIN = "KotlinMvpAutoCodePlusModelImpl" -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/config/ReplacePolicy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001-2007 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lkl.plugin.tostring.config; 17 | 18 | import com.intellij.openapi.editor.Editor; 19 | import com.intellij.psi.PsiClass; 20 | import com.intellij.psi.PsiMethod; 21 | import com.intellij.util.IncorrectOperationException; 22 | import org.jetbrains.annotations.NotNull; 23 | import org.jetbrains.java.generate.config.ConflictResolutionPolicy; 24 | import org.jetbrains.java.generate.config.InsertNewMethodStrategy; 25 | 26 | /** 27 | * This policy is to replace the existing {@code toString} method. 28 | */ 29 | public final class ReplacePolicy implements ConflictResolutionPolicy { 30 | 31 | private static final ReplacePolicy instance = new ReplacePolicy(); 32 | 33 | private ReplacePolicy() { 34 | } 35 | 36 | public static ReplacePolicy getInstance() { 37 | return instance; 38 | } 39 | 40 | @Override 41 | public void setNewMethodStrategy(InsertNewMethodStrategy strategy) { 42 | DuplicatePolicy.getInstance().setNewMethodStrategy(strategy); 43 | } 44 | 45 | @Override 46 | public PsiMethod applyMethod(PsiClass clazz, PsiMethod existingMethod, @NotNull PsiMethod newMethod, Editor editor) throws IncorrectOperationException { 47 | PsiMethod generatedMethod = DuplicatePolicy.getInstance().applyMethod(clazz, null, newMethod, editor); 48 | if (existingMethod != null) { 49 | existingMethod.delete(); 50 | } 51 | return generatedMethod; 52 | } 53 | 54 | public String toString() { 55 | return "Replace existing"; 56 | } 57 | 58 | } -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/element/ElementComparator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001-2007 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lkl.plugin.tostring.element; 17 | 18 | import java.util.Comparator; 19 | 20 | /** 21 | * Comparator to sort elements by it's name. 22 | */ 23 | public class ElementComparator implements Comparator { 24 | 25 | private final int sort; 26 | 27 | /** 28 | * Construts a comparator that sorts by element name. 29 | * 30 | * @param sort the sorting order (0 = none, 1 = asc, 2 = desc) 31 | */ 32 | public ElementComparator(int sort) { 33 | this.sort = sort; 34 | } 35 | 36 | @Override 37 | public int compare(Element e1, Element e2) { 38 | if (sort == 0) { 39 | return 0; 40 | } 41 | 42 | String name1 = getElementNameNoLeadingUnderscore(e1); 43 | String name2 = getElementNameNoLeadingUnderscore(e2); 44 | 45 | int res = name1.compareToIgnoreCase(name2); 46 | if (sort == 2) { 47 | res = -1 * res; // flip result if desc 48 | } 49 | 50 | return res; 51 | } 52 | 53 | /** 54 | * Get's the element name without any leading underscores. 55 | *

56 | * Examples: "_age" => "age", "birthday" => "birthday", "year_" => "year_" 57 | * 58 | * @param e the element 59 | * @return the name without _ in the start of the name. 60 | */ 61 | private static String getElementNameNoLeadingUnderscore(Element e) { 62 | String name = e.getName(); 63 | if (name.startsWith("_")) { 64 | return name.substring(1); 65 | } else { 66 | return name; 67 | } 68 | } 69 | 70 | } -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/codegenerator/worker/JavaCaretWorker.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.codegenerator.worker; 2 | 3 | import com.intellij.openapi.command.WriteCommandAction; 4 | import com.intellij.openapi.diagnostic.Logger; 5 | import com.intellij.openapi.editor.Document; 6 | import com.intellij.openapi.editor.Editor; 7 | import com.intellij.openapi.editor.SelectionModel; 8 | import com.intellij.openapi.project.Project; 9 | import com.intellij.psi.PsiClass; 10 | import com.intellij.psi.PsiDocumentManager; 11 | import com.intellij.psi.PsiElement; 12 | import com.intellij.psi.PsiJavaFile; 13 | import com.intellij.psi.codeStyle.JavaCodeStyleManager; 14 | import com.intellij.psi.util.PsiTreeUtil; 15 | import com.lkl.plugin.codegenerator.config.CodeTemplate; 16 | import com.lkl.plugin.codegenerator.util.GenerationUtil; 17 | import org.jetbrains.annotations.NotNull; 18 | 19 | import java.util.Map; 20 | 21 | public class JavaCaretWorker { 22 | private static final Logger logger = Logger.getInstance(JavaCaretWorker.class); 23 | 24 | public static void execute(@NotNull CodeTemplate codeTemplate, @NotNull PsiJavaFile file, @NotNull Editor editor, @NotNull Map context) { 25 | final Project project = file.getProject(); 26 | String content = GenerationUtil.velocityEvaluate(project, context, null, codeTemplate.template); 27 | if (logger.isDebugEnabled()) 28 | logger.debug("Method body generated from Velocity:\n" + content); 29 | 30 | //Access document, caret, and selection 31 | final Document document = editor.getDocument(); 32 | final SelectionModel selectionModel = editor.getSelectionModel(); 33 | 34 | final int start = selectionModel.getSelectionStart(); 35 | final int end = selectionModel.getSelectionEnd(); 36 | WriteCommandAction.runWriteCommandAction(project, () -> { 37 | document.replaceString(start, end, content); 38 | PsiDocumentManager.getInstance(project).commitDocument(document); 39 | PsiElement element = file.findElementAt(editor.getCaretModel().getOffset()); 40 | PsiClass clazz = PsiTreeUtil.getParentOfType(element, PsiClass.class, false); 41 | JavaCodeStyleManager.getInstance(project).shortenClassReferences(clazz.getContainingFile()); 42 | }); 43 | selectionModel.removeSelection(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /MvpAutoCode/src/main/kotlin/com/lkl/plugin/maker/ComponentRegister.kt: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.maker 2 | 3 | import com.intellij.openapi.command.WriteCommandAction 4 | import com.intellij.openapi.project.Project 5 | import com.intellij.openapi.vfs.ReadonlyStatusHandler 6 | import com.intellij.psi.PsiClass 7 | import com.intellij.psi.PsiPackage 8 | import org.jetbrains.android.dom.manifest.Application 9 | import org.jetbrains.android.dom.manifest.ApplicationComponent 10 | import org.jetbrains.android.dom.manifest.Manifest 11 | import org.jetbrains.android.dom.resources.ResourceValue 12 | import org.jetbrains.android.facet.AndroidFacet 13 | import org.jetbrains.android.facet.AndroidRootUtil 14 | import org.jetbrains.android.util.AndroidUtils 15 | 16 | /** 17 | * @describe 18 | * @author longforus 19 | * @date 2020/3/18 15:11 20 | */ 21 | object ComponentRegister { 22 | 23 | fun registerActivity(project: Project, aClass: PsiClass?, aPackage: PsiPackage?, facet: AndroidFacet, label: String?) { 24 | val manifestFile = AndroidRootUtil.getPrimaryManifestFile(facet) 25 | if (manifestFile != null && ReadonlyStatusHandler.ensureFilesWritable(facet.module.project, manifestFile)) { 26 | val manifest = AndroidUtils.loadDomElement(facet.module, manifestFile, 27 | Manifest::class.java) 28 | if (manifest != null) { 29 | val packageName = manifest.getPackage().value 30 | if (packageName == null || packageName.isEmpty()) { 31 | manifest.getPackage().value = aPackage?.qualifiedName 32 | } 33 | val application = manifest.application 34 | if (application != null) { 35 | WriteCommandAction.writeCommandAction(project, aClass!!.containingFile).run { 36 | val component = addToManifest(aClass, application) 37 | if (component != null && !label.isNullOrEmpty()) { 38 | component.label.value = ResourceValue.literal(label) 39 | } 40 | } 41 | 42 | } 43 | } 44 | } 45 | } 46 | 47 | 48 | fun addToManifest(aClass: PsiClass, application: Application): ApplicationComponent? { 49 | val activity = application.addActivity() 50 | activity.activityClass.value = aClass 51 | return activity 52 | } 53 | 54 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IntellijPluginStudy 2 | Intellij plugin开发研究 3 | 4 | open第三方开源plugin项目时,需要在项目根目录下的*.iml文件修改一下module type为`` 5 | 6 | ## Intellij plugin基础 7 | 8 | * [编写你的第一个plugin Hello World](./docs/base/helloWorld.md) 9 | * [Building Plugins with Gradle](./docs/base/gradlePlugin.md) 10 | * [Kotlin for Plugin Developers](./docs/base/kotlinPlugin.md) 11 | * [Action机制](./docs/base/action.md) 12 | * [插件开发之Editor](./docs/base/editor.md) 13 | * [打印日志,查看日志](./docs/base/log.md) 14 | 15 | ## Program Structure Interface (PSI) 16 | 17 | 程序结构接口(通常称为PSI)是IntelliJ平台中的一层,负责解析文件并创建语法和语义代码模型,以支持该平台的许多功能。 18 | 19 | * [介绍](./docs/psi/introduction.md) 20 | * [PSI使用](./docs/psi/use.md) 21 | * [PsiAugmentProvider](./docs/psi/psiAugmentProvider.md) 22 | * [StructureViewExtension](./docs/psi/structureViewExtension.md) 23 | 24 | ## Intellij plugin进阶 25 | 26 | * [IntelliJ Plugin Development introduction: PersistStateComponent](./docs/advanced/persistStateComponent.md) 27 | * [IntelliJ Plugin Development introduction: ApplicationConfigurable, ProjectConfigurable](./docs/advanced/applicationConfigurable.md) 28 | * [generate-tostring](./docs/advanced/generateTostring.md) 29 | * [代码检查 Code Inspections](./docs/advanced/codeInspections.md) 30 | 31 | ## 参考文献 32 | 33 | [[Intellij Idea 插件 番外] Api讲解(类、方法等)](https://blog.csdn.net/guohaiyang1992/article/details/79019094) 34 | 35 | [AndroidStudio插件开发(进阶篇之Action机制)](https://blog.csdn.net/huachao1001/article/details/53883500) 36 | 37 | [IntelliJ IDEA插件开发](https://blog.csdn.net/O4dC8OjO7ZL6/article/details/79722289) 38 | 39 | [AS插件开发:根据特定格式的文本自动生成Java Bean文件或字段](https://blog.csdn.net/qq_27258799/article/details/79295251) 40 | 41 | [https://www.cnblogs.com/liqiking/p/6792991.html](https://www.cnblogs.com/liqiking/p/6792991.html) 42 | 43 | [震惊!!!编码速度提高10倍的秘诀是....](https://blog.csdn.net/y4x5M0nivSrJaY3X92c/article/details/106131947) 44 | 45 | [https://github.com/longforus/MvpAutoCodePlus](https://github.com/longforus/MvpAutoCodePlus) 46 | 47 | [lombok-intellij-plugin](https://github.com/mplushnikov/lombok-intellij-plugin) 48 | 49 | [IntelliJ Platform SDK](https://www.jetbrains.org/intellij/sdk/docs/intro/welcome.html) 50 | 51 | [https://www.jetbrains.com/help/idea/getting-started.html](https://www.jetbrains.com/help/idea/getting-started.html) 52 | 53 | [https://www.jetbrains.org/intellij/sdk/docs/tutorials/editor_basics.html](https://www.jetbrains.org/intellij/sdk/docs/tutorials/editor_basics.html) 54 | 55 | [http://velocity.apache.org/](http://velocity.apache.org/) 56 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/StructureViewExtension/CustomStructureViewExtension.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.StructureViewExtension; 2 | 3 | import com.intellij.ide.structureView.StructureViewExtension; 4 | import com.intellij.ide.structureView.StructureViewTreeElement; 5 | import com.intellij.ide.structureView.impl.java.JavaClassTreeElement; 6 | import com.intellij.ide.structureView.impl.java.PsiFieldTreeElement; 7 | import com.intellij.ide.structureView.impl.java.PsiMethodTreeElement; 8 | import com.intellij.openapi.editor.Editor; 9 | import com.intellij.psi.PsiClass; 10 | import com.intellij.psi.PsiElement; 11 | import com.intellij.psi.PsiField; 12 | import com.intellij.psi.PsiMethod; 13 | import org.jetbrains.annotations.Nullable; 14 | 15 | import java.util.ArrayList; 16 | import java.util.Collection; 17 | 18 | public class CustomStructureViewExtension implements StructureViewExtension { 19 | @Override 20 | public Class getType() { 21 | return null; 22 | } 23 | 24 | @Nullable 25 | @Override 26 | public Object getCurrentEditorElement(Editor editor, PsiElement psiElement) { 27 | return null; 28 | } 29 | 30 | @Override 31 | public StructureViewTreeElement[] getChildren(PsiElement parent) { 32 | Collection result = new ArrayList(); 33 | final PsiClass psiClass = (PsiClass) parent; 34 | 35 | // for (PsiField psiField : psiClass.getFields()) { 36 | // if (psiField instanceof LombokLightFieldBuilder) { 37 | // result.add(new PsiFieldTreeElement(psiField, false)); 38 | // } 39 | // } 40 | // 41 | // for (PsiMethod psiMethod : psiClass.getMethods()) { 42 | // if (psiMethod instanceof LombokLightMethodBuilder) { 43 | // result.add(new PsiMethodTreeElement(psiMethod, false)); 44 | // } 45 | // } 46 | // 47 | // for (PsiClass psiInnerClass : psiClass.getInnerClasses()) { 48 | // if (psiInnerClass instanceof LombokLightClassBuilder) { 49 | // result.add(new JavaClassTreeElement(psiInnerClass, false, new HashSet() {{ 50 | // add(psiClass); 51 | // }})); 52 | // } 53 | // } 54 | 55 | if (!result.isEmpty()) { 56 | return result.toArray(new StructureViewTreeElement[result.size()]); 57 | } else { 58 | return StructureViewTreeElement.EMPTY_ARRAY; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /docs/psi/structureViewExtension.md: -------------------------------------------------------------------------------- 1 | # StructureViewExtension 2 | 3 | 顾名思义,IDEA提供的这个扩展接口就是为了对其提供的Structure功能进行扩展,同样以lombok项目为例,Structcture中能够清晰明了的显示当前类的结构,如下图所示: 4 | 5 | ![](./imgs/structureView.png) 6 | 7 | `Structcture`中详细显示当前类中的字段和方法,如果我们通过PsiAugmentProvider提供了相关的字段和方法,如果没有继承`StructureViewExtension`并重写其相关的方法,那么在如图所示的structure结构中就不会显示相关的字段和方法。所以一般使用了`PsiAugmentProvider`都需要再继承`StructureViewExtension`并重写相应的方法。 8 | 9 | `StructureViewExtension`接口中字段和方法如下: 10 | ```java 11 | ExtensionPointName EXTENSION_POINT_NAME = ExtensionPointName.create("com.intellij.lang.structureViewExtension"); 12 | 13 | Class getType(); 14 | 15 | StructureViewTreeElement[] getChildren(PsiElement parent); 16 | 17 | @Nullable 18 | Object getCurrentEditorElement(Editor editor, PsiElement parent); 19 | ``` 20 | * **EXTENSION_POINT_NAME**字段是创建一个扩展点,用于在plugin.xml中配置使用 21 | * **getType()**:获得具体的类型,一般为PsiClass.class 22 | * **getCurrentEditorElement()**:由于只查看相应的结构,不需要获得编辑对象,返回nulll即可 23 | * **getChildren()**:获得子元素,还记得在PsiAugmentProvider中我们通过LightFieldBuilder或者LightMethodBuilder来创建字段或者对象么;如果需要扩展StructureViewExtension,这里可以继承LightFieldBuilder或者LightMethodBuilder来创建相应的方法,getChildren()中遍历字段和方法,通过instanceof判断是否是为具体的对象,如果是则加入到result列表中即可 24 | 25 | ```java 26 | @Override 27 | public StructureViewTreeElement[] getChildren(PsiElement parent) { 28 | Collection result = new ArrayList(); 29 | final PsiClass psiClass = (PsiClass) parent; 30 | 31 | for (PsiField psiField : psiClass.getFields()) { 32 | if (psiField instanceof LombokLightFieldBuilder) { 33 | result.add(new PsiFieldTreeElement(psiField, false)); 34 | } 35 | } 36 | 37 | for (PsiMethod psiMethod : psiClass.getMethods()) { 38 | if (psiMethod instanceof LombokLightMethodBuilder) { 39 | result.add(new PsiMethodTreeElement(psiMethod, false)); 40 | } 41 | } 42 | 43 | for (PsiClass psiInnerClass : psiClass.getInnerClasses()) { 44 | if (psiInnerClass instanceof LombokLightClassBuilder) { 45 | result.add(new JavaClassTreeElement(psiInnerClass, false, new HashSet() {{ 46 | add(psiClass); 47 | }})); 48 | } 49 | } 50 | 51 | if (!result.isEmpty()) { 52 | return result.toArray(new StructureViewTreeElement[result.size()]); 53 | } else { 54 | return StructureViewTreeElement.EMPTY_ARRAY; 55 | } 56 | } 57 | ``` 58 | 59 | ## 参考文献 60 | 61 | [IntelliJ IDEA插件开发指南(二)](https://blog.csdn.net/ExcellentYuXiao/article/details/80273347) 62 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/view/MethodExistsDialog.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001-2007 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lkl.plugin.tostring.view; 17 | 18 | import com.intellij.java.JavaBundle; 19 | import com.intellij.openapi.ui.Messages; 20 | import org.jetbrains.java.generate.config.CancelPolicy; 21 | import org.jetbrains.java.generate.config.ConflictResolutionPolicy; 22 | import org.jetbrains.java.generate.config.DuplicatePolicy; 23 | import org.jetbrains.java.generate.config.ReplacePolicy; 24 | 25 | /** 26 | * This is a dialog when the {@code toString()} method already exists. 27 | *

28 | * The user now has the choices to either: 29 | *

    30 | *
  • Replace existing method 31 | *
  • Create a duplicate method 32 | *
  • Cancel 33 | *
34 | */ 35 | public final class MethodExistsDialog { 36 | private MethodExistsDialog() { 37 | } 38 | 39 | /** 40 | * Shows this dialog. 41 | *

42 | * The user now has the choices to either: 43 | *

    44 | *
  • Replace existing method 45 | *
  • Create a duplicate method 46 | *
  • Cancel 47 | *
48 | * 49 | * @param targetMethodName the name of the target method (toString) 50 | * @return the chosen conflict resolution policy (never null) 51 | */ 52 | public static ConflictResolutionPolicy showDialog(String targetMethodName) { 53 | int exit = Messages.showYesNoCancelDialog( 54 | JavaBundle.message("generate.tostring.method.already.exists.dialog.me=ssage", targetMethodName), 55 | JavaBundle.message("generate.tostring.method.already.exists.dialog.title"), Messages.getQuestionIcon()); 56 | if (exit == Messages.CANCEL) { 57 | return CancelPolicy.getInstance(); 58 | } 59 | if (exit == Messages.YES) { 60 | return ReplacePolicy.getInstance(); 61 | } 62 | if (exit == Messages.NO) { 63 | return DuplicatePolicy.getInstance(); 64 | } 65 | 66 | throw new IllegalArgumentException("exit code [" + exit + "] from YesNoCancelDialog not supported"); 67 | } 68 | 69 | } -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/configurable/SingleFileExecutionConfig.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.configurable; 2 | 3 | import com.intellij.openapi.components.*; 4 | import com.intellij.openapi.project.Project; 5 | import com.intellij.util.xmlb.XmlSerializerUtil; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | @State( 9 | name="SingleFileExecutionConfig", 10 | storages = { 11 | @Storage("SingleFileExecutionConfig.xml")} 12 | ) 13 | @Service 14 | public class SingleFileExecutionConfig implements PersistentStateComponent { 15 | /* NOTE: member should be "public" to be saved in xml */ 16 | /* add_executable(): exe name */ 17 | static final String EXECUTABLE_NAME_FILENAME = "%FILENAME%"; 18 | public static final String DEFAULT_EXECUTABLE_NAME = EXECUTABLE_NAME_FILENAME; 19 | public String executableName = DEFAULT_EXECUTABLE_NAME; // persistent member should be public 20 | /* set_target_properties(): runtime output directory */ 21 | static final String PROJECTDIR = "%PROJECTDIR%"; 22 | static final String FILEDIR = "%FILEDIR%"; 23 | public static final String DEFAULT_RUNTIME_OUTPUT_DIRECTORY = ""; 24 | public String runtimeOutputDirectory = ""; // set empty string as default, persistent member should be public 25 | private static final boolean DEFAULT_NOT_SHOW_OVERWRITE_CONFIRM_DIALOG = false; 26 | public boolean notShowOverwriteConfirmDialog = DEFAULT_NOT_SHOW_OVERWRITE_CONFIRM_DIALOG; // persistent member should be public 27 | 28 | SingleFileExecutionConfig() { } 29 | 30 | String getExecutableName() { 31 | if (executableName == null) { 32 | // Error, it should not happen 33 | executableName = ""; 34 | } 35 | return executableName; 36 | } 37 | 38 | void setExecutableName(String executableName) { 39 | this.executableName = executableName; 40 | } 41 | 42 | public String getRuntimeOutputDirectory() { 43 | return runtimeOutputDirectory; 44 | } 45 | 46 | public void setRuntimeOutputDirectory(String runtimeOutputDirectory) { 47 | this.runtimeOutputDirectory = runtimeOutputDirectory; 48 | } 49 | 50 | @Nullable 51 | @Override 52 | public SingleFileExecutionConfig getState() { 53 | return this; 54 | } 55 | 56 | @Override 57 | public void loadState(SingleFileExecutionConfig singleFileExecutionConfig) { 58 | XmlSerializerUtil.copyBean(singleFileExecutionConfig, this); 59 | } 60 | 61 | @Nullable 62 | public static SingleFileExecutionConfig getInstance(Project project) { 63 | SingleFileExecutionConfig sfec = ServiceManager.getService(project, SingleFileExecutionConfig.class); 64 | return sfec; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /ComparingReferencesInspection/src/test/java/com/lkl/plugin/ComparingReferencesInspectionTest.java: -------------------------------------------------------------------------------- 1 | // Copyright 2000-2020 JetBrains s.r.o. and other contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. 2 | 3 | package com.lkl.plugin; 4 | 5 | import com.intellij.codeInsight.daemon.impl.HighlightInfo; 6 | import com.intellij.codeInsight.intention.IntentionAction; 7 | import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * Class for testing ComparingReferencesInspection. 14 | * Requires idea.home.path to be set in build.gradle 15 | * doTest() does the work for individual test cases. 16 | */ 17 | public class ComparingReferencesInspectionTest extends LightJavaCodeInsightFixtureTestCase { 18 | 19 | /** 20 | * Defines path to files used for running tests 21 | * 22 | * @return The path from this module's root directory ($MODULE_WORKING_DIR$) to the 23 | * directory containing files for these tests. 24 | */ 25 | @Override 26 | protected String getTestDataPath() { 27 | return "src/test/testData"; 28 | } 29 | 30 | /** 31 | * Given the name of a test file, runs comparing references inspection quick fix and tests 32 | * the results against a reference outcome file. File name pattern 'foo.java' and 'foo.after.java' 33 | * are matching before and after files in the testData directory. 34 | * 35 | * @param testName The name of the test file before comparing references inspection. 36 | */ 37 | protected void doTest(@NotNull String testName) { 38 | // Initialize the test based on the testData file 39 | myFixture.configureByFile(testName + ".java"); 40 | // Initialize the inspection and get a list of highlighted 41 | myFixture.enableInspections(new ComparingReferencesInspection()); 42 | List highlightInfos = myFixture.doHighlighting(); 43 | assertFalse(highlightInfos.isEmpty()); 44 | // Get the quick fix action for comparing references inspection and apply it to the file 45 | final IntentionAction action = myFixture.findSingleIntention(ComparingReferencesInspection.QUICK_FIX_NAME); 46 | assertNotNull(action); 47 | myFixture.launchAction(action); 48 | // Verify the results 49 | myFixture.checkResultByFile(testName + ".after.java"); 50 | } 51 | 52 | /** 53 | * Test the "==" case 54 | */ 55 | public void testRelationalEq() throws Throwable { 56 | doTest("Eq"); 57 | } 58 | 59 | /** 60 | * Test the "!=" case 61 | */ 62 | public void testRelationalNeq() throws Throwable { 63 | doTest("Neq"); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/GenerateToStringConfigurable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2000-2012 JetBrains s.r.o. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lkl.plugin.tostring; 17 | 18 | import com.intellij.java.JavaBundle; 19 | import com.intellij.openapi.diagnostic.Logger; 20 | import com.intellij.openapi.options.Configurable; 21 | import com.intellij.openapi.options.ConfigurationException; 22 | import com.intellij.openapi.project.Project; 23 | import org.jetbrains.java.generate.GenerateToStringContext; 24 | import org.jetbrains.java.generate.config.Config; 25 | import org.jetbrains.java.generate.view.ConfigUI; 26 | 27 | import javax.swing.*; 28 | 29 | /** 30 | * @author yole 31 | */ 32 | public class GenerateToStringConfigurable implements Configurable { 33 | private static final Logger log = Logger.getInstance("#GenerateToStringConfigurable"); 34 | 35 | private ConfigUI configUI; 36 | private final Project myProject; 37 | 38 | public GenerateToStringConfigurable(Project project) { 39 | myProject = project; 40 | } 41 | 42 | @Override 43 | public String getDisplayName() { 44 | return JavaBundle.message("configurable.GenerateToStringConfigurable.display.name"); 45 | } 46 | 47 | @Override 48 | public String getHelpTopic() { 49 | return "editing.altInsert.tostring.settings"; 50 | } 51 | 52 | @Override 53 | public JComponent createComponent() { 54 | return configUI = new ConfigUI(GenerateToStringContext.getConfig(), myProject); 55 | } 56 | 57 | @Override 58 | public boolean isModified() { 59 | return ! GenerateToStringContext.getConfig().equals(configUI.getConfig()); 60 | } 61 | 62 | @Override 63 | public void apply() throws ConfigurationException { 64 | Config config = configUI.getConfig(); 65 | GenerateToStringContext.setConfig(config); // update context 66 | 67 | if (log.isDebugEnabled()) log.debug("Config updated:\n" + config); 68 | } 69 | 70 | @Override 71 | public void reset() { 72 | configUI.setConfig(GenerateToStringContext.getConfig()); 73 | } 74 | 75 | @Override 76 | public void disposeUIResources() { 77 | configUI = null; 78 | } 79 | } -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/codegenerator/ui/CodeGeneratorConfigurable.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.codegenerator.ui; 2 | 3 | import com.intellij.openapi.components.ServiceManager; 4 | import com.intellij.openapi.options.ConfigurationException; 5 | import com.intellij.openapi.options.SearchableConfigurable; 6 | import com.lkl.plugin.codegenerator.config.CodeGeneratorSettings; 7 | import com.lkl.plugin.codegenerator.config.CodeTemplate; 8 | import org.jetbrains.annotations.Nls; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | import javax.swing.*; 13 | import java.util.List; 14 | import java.util.Optional; 15 | 16 | public class CodeGeneratorConfigurable implements SearchableConfigurable { 17 | private CodeGeneratorSettings settings; 18 | private CodeGeneratorConfig config; 19 | 20 | public CodeGeneratorConfigurable() { 21 | this.settings = ServiceManager.getService(CodeGeneratorSettings.class); 22 | } 23 | 24 | @NotNull @Override public String getId() { 25 | return "plugins.codegenerator"; 26 | } 27 | 28 | @Nls @Override public String getDisplayName() { 29 | return "CodeGenerator"; 30 | } 31 | 32 | @Nullable 33 | @Override 34 | public String getHelpTopic() { 35 | return null; 36 | } 37 | 38 | @Nullable @Override public JComponent createComponent() { 39 | if (config == null) { 40 | config = new CodeGeneratorConfig(settings); 41 | } 42 | return config.getMainPane(); 43 | } 44 | 45 | @Override public boolean isModified() { 46 | if (config == null) { 47 | return false; 48 | } 49 | 50 | List templates = config.getTabTemplates(); 51 | if (settings.getCodeTemplates().size() != templates.size()) { 52 | return true; 53 | } 54 | 55 | for (CodeTemplate template: templates) { 56 | Optional codeTemplate = settings.getCodeTemplate(template.getId()); 57 | if (!codeTemplate.isPresent() || !codeTemplate.get().equals(template)) { 58 | return true; 59 | } 60 | } 61 | 62 | return false; 63 | } 64 | 65 | @Override public void apply() throws ConfigurationException { 66 | List templates = config.getTabTemplates(); 67 | for (CodeTemplate template : templates) { 68 | if (!template.isValid()) { 69 | throw new ConfigurationException( 70 | "Not property can be empty and classNumber should be a number"); 71 | } 72 | } 73 | 74 | settings.setCodeTemplates(templates); 75 | config.refresh(templates); 76 | } 77 | 78 | @Override 79 | public void reset() { 80 | 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/codegenerator/ui/ClassSelectionPane.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.codegenerator.ui; 2 | 3 | import com.intellij.uiDesigner.core.GridConstraints; 4 | import com.intellij.uiDesigner.core.GridLayoutManager; 5 | import com.intellij.uiDesigner.core.Spacer; 6 | import com.lkl.plugin.codegenerator.config.ClassSelectionConfig; 7 | 8 | import javax.swing.*; 9 | import javax.swing.border.TitledBorder; 10 | import java.awt.*; 11 | 12 | public class ClassSelectionPane implements PipelineStepConfig { 13 | private JPanel topPane; 14 | private JTextField initialClassText; 15 | 16 | public ClassSelectionPane(ClassSelectionConfig config) { 17 | initialClassText.setText(config.initialClass); 18 | } 19 | 20 | @Override 21 | public ClassSelectionConfig getConfig() { 22 | ClassSelectionConfig config = new ClassSelectionConfig(); 23 | config.initialClass = initialClassText.getText(); 24 | return config; 25 | } 26 | 27 | @Override 28 | public JPanel getComponent() { 29 | return topPane; 30 | } 31 | 32 | { 33 | // GUI initializer generated by IntelliJ IDEA GUI Designer 34 | // >>> IMPORTANT!! <<< 35 | // DO NOT EDIT OR ADD ANY CODE HERE! 36 | $$$setupUI$$$(); 37 | } 38 | 39 | /** 40 | * Method generated by IntelliJ IDEA GUI Designer 41 | * >>> IMPORTANT!! <<< 42 | * DO NOT edit this method OR call it in your code! 43 | * 44 | * @noinspection ALL 45 | */ 46 | private void $$$setupUI$$$() { 47 | topPane = new JPanel(); 48 | topPane.setLayout(new GridLayoutManager(2, 2, new Insets(0, 0, 0, 0), -1, -1)); 49 | topPane.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(), null, TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, null, null)); 50 | initialClassText = new JTextField(); 51 | topPane.add(initialClassText, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false)); 52 | final Spacer spacer1 = new Spacer(); 53 | topPane.add(spacer1, new GridConstraints(1, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1, GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false)); 54 | final JLabel label1 = new JLabel(); 55 | label1.setText("Initial Class"); 56 | topPane.add(label1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); 57 | } 58 | 59 | /** 60 | * @noinspection ALL 61 | */ 62 | public JComponent $$$getRootComponent$$$() { 63 | return topPane; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/config/InsertAfterEqualsHashCodeStrategy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lkl.plugin.tostring.config; 17 | 18 | import com.intellij.openapi.editor.Editor; 19 | import com.intellij.psi.PsiClass; 20 | import com.intellij.psi.PsiMethod; 21 | import org.jetbrains.annotations.NotNull; 22 | import org.jetbrains.java.generate.config.InsertNewMethodStrategy; 23 | import org.jetbrains.java.generate.psi.PsiAdapter; 24 | 25 | /** 26 | * Inserts the method after the hashCode/equals methods in the javafile. 27 | */ 28 | public final class InsertAfterEqualsHashCodeStrategy implements InsertNewMethodStrategy { 29 | 30 | private static final InsertAfterEqualsHashCodeStrategy instance = new InsertAfterEqualsHashCodeStrategy(); 31 | 32 | private InsertAfterEqualsHashCodeStrategy() {} 33 | 34 | public static InsertAfterEqualsHashCodeStrategy getInstance() { 35 | return instance; 36 | } 37 | 38 | @Override 39 | public PsiMethod insertNewMethod(PsiClass clazz, @NotNull PsiMethod newMethod, Editor editor) { 40 | PsiMethod methodHashCode = PsiAdapter.findHashCodeMethod(clazz); 41 | PsiMethod methodEquals = PsiAdapter.findEqualsMethod(clazz); 42 | 43 | // if both methods exist determine the last method in the javafile 44 | PsiMethod method; 45 | if (methodEquals != null && methodHashCode != null) { 46 | if (methodEquals.getTextOffset() > methodHashCode.getTextOffset()) { 47 | method = methodEquals; 48 | } else { 49 | method = methodHashCode; 50 | } 51 | } else { 52 | method = methodHashCode != null ? methodHashCode : methodEquals; 53 | } 54 | 55 | if (method != null) { 56 | // insert after the equals/hashCode method 57 | newMethod = (PsiMethod) clazz.addAfter(newMethod, method); 58 | } else { 59 | // no equals/hashCode so insert at caret 60 | newMethod = InsertAtCaretStrategy.getInstance().insertNewMethod(clazz, newMethod, editor); 61 | } 62 | 63 | return newMethod; 64 | } 65 | 66 | public String toString() { 67 | return "After equals/hashCode"; 68 | } 69 | } -------------------------------------------------------------------------------- /MvpAutoCode/src/main/resources/META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.lkl.plugin.MvpAutoCode 4 | MvpAutoCode 5 | lkl 6 | 7 | MvpAutoCodePlus 9 |
10 |

11 | 12 | Website | 13 | GitHub | 14 | Issues | 15 | Blog 16 | 17 |

18 |
19 |

An plugin that automatically generates an MVP template code.

20 |
21 |

Features: 22 |

    23 |
  • Automatically generate Contract Interface based on the specified super Interface.
  • 24 |
  • Automatically generate implements class based on the Contract Interface and specified superclass.Add the default implementation of the abstract method.
  • 25 |
  • Supports generics(currently only have M,V,P).
  • 26 |
  • Supports Java and Kotlin.
  • 27 |
28 |

29 |
30 |

Send feedback

31 | ]]>
32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | org.jetbrains.kotlin 44 | 46 | 47 | com.intellij.modules.lang 48 | com.intellij.modules.java 49 | org.jetbrains.android 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 |
-------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/codegenerator/config/CodeGeneratorSettings.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.codegenerator.config; 2 | 3 | import com.intellij.openapi.components.PersistentStateComponent; 4 | import com.intellij.openapi.components.State; 5 | import com.intellij.openapi.components.Storage; 6 | import com.intellij.openapi.diagnostic.Logger; 7 | import com.intellij.openapi.util.io.FileUtil; 8 | import com.intellij.util.xmlb.XmlSerializerUtil; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | import java.io.IOException; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | import java.util.Optional; 15 | 16 | @State(name = "CodeGeneratorSettings", storages = {@Storage("$APP_CONFIG$/CodeGeneratorSettings.xml")}) 17 | public class CodeGeneratorSettings implements PersistentStateComponent { 18 | 19 | private static final Logger LOGGER = Logger.getInstance(CodeGeneratorSettings.class); 20 | private List codeTemplates; 21 | 22 | public CodeGeneratorSettings() { 23 | 24 | } 25 | 26 | public CodeGeneratorSettings setCodeTemplates(List codeTemplates) { 27 | this.codeTemplates = codeTemplates; 28 | return this; 29 | } 30 | 31 | 32 | @Nullable @Override public CodeGeneratorSettings getState() { 33 | if (codeTemplates == null) { 34 | codeTemplates = loadDefaultTemplates(); 35 | } 36 | return this; 37 | } 38 | 39 | @Override public void loadState(CodeGeneratorSettings codeGeneratorSettings) { 40 | XmlSerializerUtil.copyBean(codeGeneratorSettings, this); 41 | } 42 | 43 | public List getCodeTemplates() { 44 | if (codeTemplates == null) { 45 | codeTemplates = loadDefaultTemplates(); 46 | } 47 | return codeTemplates; 48 | } 49 | 50 | public Optional getCodeTemplate(String templateId) { 51 | return codeTemplates.stream() 52 | .filter(t -> t!= null && t.getId().equals(templateId)) 53 | .findFirst(); 54 | } 55 | 56 | public void removeCodeTemplate(String templateId) { 57 | codeTemplates.removeIf(template -> template.name.equals(templateId)); 58 | } 59 | 60 | private List loadDefaultTemplates() { 61 | List templates = new ArrayList<>(); 62 | try { 63 | templates.addAll(loadTemplates("getters-and-setters.xml")); 64 | templates.addAll(loadTemplates("to-string.xml")); 65 | templates.addAll(loadTemplates("HUE-Serialization.xml")); 66 | } catch (Exception e) { 67 | LOGGER.error("loadDefaultTemplates failed", e); 68 | } 69 | return templates; 70 | } 71 | 72 | private List loadTemplates(String templateFileName) throws IOException { 73 | return CodeTemplateList.fromXML(FileUtil.loadTextAndClose(CodeGeneratorSettings.class.getResourceAsStream("/template/" + templateFileName))); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /docs/psi/psiAugmentProvider.md: -------------------------------------------------------------------------------- 1 | # PsiAugmentProvider 2 | 3 | * [简介](#简介) 4 | * [重写getAugments方法](#重写getaugments方法) 5 | * [参考文献](#参考文献) 6 | 7 | ## 简介 8 | 对于这个类,IDEA中提供的说明是:有些代码不是它看起来的样子!这种扩展允许插件增强现实,改变Java PSI元素的行为。 9 | 10 | IDEA中所有文件以及文件中的内容都是用PSI树来表示的,比如类表示为PsiClass,方法表示为PsiMethod,字段表示为PsiField。我们可以通过更改PSI来做到动态的添加字段,方法等。 11 | 12 | 上面说的比较抽象,我们来举一个简单的例子,还是以Lombok为例。了解Lombok原理的同学都知道,Lombok利用的是javac技术,就是在java文件编译的时候动态的将getter,setter等方法生成到class文件中。 13 | 14 | 这种方式就出带来一个问题,由于getter和setter方法在编译的时候才会动态生成,实际运行时不会有任务问题;但是在IDEA中,编译检查时会发现没有对应的setter或者getter方法,就会出现“标红”,提示没有该字段或者方法。 15 | 16 | 其实这时就应该清楚了,我们可以通过继承PsiAugmentProvider这个类,通过扩展PSI,动态的为该类中新增相应的“虚拟”的getter或者setter方法。以此来解决“标红”问题。 17 | 18 | 这时在编辑框中是没有通过PsiAugmentProvider扩展的这些方法,但是实际调用的时候却有,这也就是上述所说的:有些代码不是它看起来的样子! 19 | 20 | > 动态扩展的PSI方法或者字段,在编译时不会生成。在进行扩展方法时,只需要生成具体的方法签名即可~不需要关注具体的实现细节。 21 | 22 | ## 重写getAugments方法 23 | 24 | 通过重写`getAugments`方法可以扩展每个文件的`PSI`,即实现动态的扩展相应的方法或者字段。 25 | 26 | `getAugments`中会传入两个参数,分别为`PsiElement psiElement`和`Class type`: 27 | 28 | * **PsiElement**是PSI系统下不同类型对象的一个统称,是基类;比如之前提到的`PsiMethod`、`PsiClass`等等都是一个个具体的`PsiElement`的实现。 29 | * **Class type**,type类型可以用于判断具体是`PsiMethod`还是`PsiClass`,进行分开处理。 30 | 31 | 在getAugments中进行扩展相应方法时,需要借助IDEA中提供的`LightMethodBuilder`类。通过设置方法名,方法的修饰符,方法的返回值,方法的传入即可添加一个方法。 32 | 33 | 比如现在需要为`mobile`字段,添加set方法,那么具体的代码为: 34 | ```java 35 | PsiManager manager = psiField.getManager(); 36 | LightMethodBuilder method = new LightMethodBuilder(manager, JavaLanguage.INSTANCE, methodName); 37 | method.addModifier(PsiModifier.PUBLIC); 38 | method.setContainingClass(psiClass); 39 | method.setNavigationElement(psiField); 40 | method.addParameter(psiField.getName(), psiField.getType()); 41 | method.setMethodReturnType(PsiType.VOID); 42 | ``` 43 | 44 | 在getAugments中进行扩展相应字段时,需要借助IDEA中提供的`LightFieldBuilder`类。同样通过设置字段名,字段的修饰符即可添加一个字段。 45 | 46 | 比如现在需要添加 `private static final Logger logger`字段,那么具体的代码为: 47 | ```java 48 | PsiType psiLoggerType = psiElementFactory.createTypeFromText(LOGGER_TYPE, psiClass); 49 | LightFieldBuilder loggerField = new LightFieldBuilder(manager, LOGGER_NAME, psiLoggerType); 50 | LightModifierList modifierList = (LightModifierList) loggerField.getModifierList(); 51 | modifierList.addModifier(PsiModifier.PRIVATE); 52 | modifierList.addModifier(PsiModifier.STATIC); 53 | modifierList.addModifier(PsiModifier.FINAL); 54 | loggerField.setContainingClass(psiClass); 55 | loggerField.setNavigationElement(psiAnnotation); 56 | ``` 57 | 58 | 在`PsiAugmentProvider`中,对于每个生成的`method`和`field`,都需要加入到`Cache`当中,以此来保证每次获取时候的性能~在IDEA插件开发当中可以选择其提供的`CachedValuesManager`~ 59 | 60 | ## 参考文献 61 | 62 | [IntelliJ IDEA插件开发指南(二)](https://blog.csdn.net/ExcellentYuXiao/article/details/80273347) 63 | 64 | [Class PsiAugmentProvider](https://dploeger.github.io/intellij-api-doc/com/intellij/psi/augment/PsiAugmentProvider.html) 65 | 66 | [Java Code Examples for com.intellij.psi.augment.PsiAugmentProvider](https://www.programcreek.com/java-api-examples/index.php?api=com.intellij.psi.augment.PsiAugmentProvider) 67 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/velocity/VelocityFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001-2007 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lkl.plugin.tostring.velocity; 17 | 18 | import com.intellij.codeInsight.generation.VelocityIncludesClassLoader; 19 | import com.intellij.openapi.util.ClassLoaderUtil; 20 | import org.apache.commons.collections.ExtendedProperties; 21 | import org.apache.velocity.app.VelocityEngine; 22 | import org.apache.velocity.runtime.RuntimeConstants; 23 | import org.apache.velocity.runtime.log.SimpleLog4JLogSystem; 24 | 25 | /** 26 | * Velocity factory. 27 | *

28 | * Creating instances of the VelocityEngine. 29 | */ 30 | public final class VelocityFactory { 31 | private static class Holder { 32 | private static final VelocityEngine engine = newVelocityEngine(); 33 | } 34 | 35 | /** 36 | * Privte constructor. 37 | */ 38 | private VelocityFactory() { 39 | } 40 | 41 | /** 42 | * Returns a new instance of the VelocityEngine. 43 | *

44 | * The engine is initialized and outputs its logging to IDEA logging. 45 | * 46 | * @return a new velocity engine that is initialized. 47 | */ 48 | private static VelocityEngine newVelocityEngine() { 49 | ExtendedProperties prop = new ExtendedProperties(); 50 | prop.addProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, SimpleLog4JLogSystem.class.getName()); 51 | prop.addProperty("runtime.log.logsystem.log4j.category", "GenerateToString"); 52 | prop.addProperty(RuntimeConstants.RESOURCE_LOADER, "includes"); 53 | prop.addProperty("includes.resource.loader.class", VelocityIncludesClassLoader.class.getName()); 54 | prop.addProperty(RuntimeConstants.VM_PERM_ALLOW_INLINE_REPLACE_GLOBAL, "true"); 55 | 56 | VelocityEngine velocity = new VelocityEngine(); 57 | velocity.setExtendedProperties(prop); 58 | ClassLoaderUtil.runWithClassLoader(VelocityIncludesClassLoader.class.getClassLoader(), () -> velocity.init()); 59 | return velocity; 60 | } 61 | 62 | /** 63 | * Get's a shared instance of the VelocityEngine. 64 | *

65 | * The engine is initialized and outputs its logging to IDEA logging. 66 | * 67 | * @return a shared instance of the engine that is initialized. 68 | */ 69 | public static VelocityEngine getVelocityEngine() { 70 | return Holder.engine; 71 | } 72 | } -------------------------------------------------------------------------------- /MvpAutoCode/src/main/kotlin/com/lkl/plugin/maker/CodeMaker.kt: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.maker 2 | 3 | import com.intellij.ide.actions.CreateFileAction 4 | import com.intellij.ide.fileTemplates.FileTemplate 5 | import com.intellij.ide.fileTemplates.FileTemplateManager 6 | import com.intellij.ide.fileTemplates.FileTemplateUtil 7 | import com.intellij.ide.fileTemplates.actions.CreateFromTemplateActionBase 8 | import com.intellij.ide.util.PropertiesComponent 9 | import com.intellij.openapi.fileEditor.FileEditorManager 10 | import com.intellij.psi.PsiDirectory 11 | import com.intellij.psi.PsiFile 12 | import com.intellij.psi.SmartPointerManager 13 | import com.intellij.util.IncorrectOperationException 14 | import org.apache.velocity.runtime.parser.ParseException 15 | 16 | /** 17 | * Created by XQ Yang on 2018/6/28 15:34. 18 | * Description : 创建对应的源文件 19 | */ 20 | fun createFileFromTemplate(fileName: String?, 21 | template: FileTemplate, 22 | d: PsiDirectory, 23 | defaultTemplateProperty: String?, 24 | openFile: Boolean, 25 | liveTemplateDefaultValues: Map, 26 | author: String?): PsiFile? { 27 | var name = fileName 28 | var dir = d 29 | if (name != null) { 30 | val mkdirs = CreateFileAction.MkDirs(name, dir) 31 | name = mkdirs.newName 32 | dir = mkdirs.directory 33 | } 34 | 35 | val project = dir.project 36 | try { 37 | val defaultProperties = FileTemplateManager.getInstance(dir.project).defaultProperties 38 | defaultProperties.putAll(liveTemplateDefaultValues) 39 | if (!author.isNullOrEmpty()) { 40 | defaultProperties["USER"] = author 41 | } 42 | val psiFile = FileTemplateUtil.createFromTemplate(template, name, defaultProperties, dir) 43 | .containingFile 44 | val pointer = SmartPointerManager.getInstance(project).createSmartPsiElementPointer(psiFile) 45 | 46 | val virtualFile = psiFile.virtualFile 47 | if (virtualFile != null) { 48 | if (openFile) { 49 | if (template.isLiveTemplateEnabled) { 50 | CreateFromTemplateActionBase.startLiveTemplate(psiFile, liveTemplateDefaultValues) 51 | } else { 52 | FileEditorManager.getInstance(project).openFile(virtualFile, true) 53 | } 54 | } 55 | if (defaultTemplateProperty != null) { 56 | PropertiesComponent.getInstance(project).setValue(defaultTemplateProperty, template.name) 57 | } 58 | return pointer.element 59 | } 60 | } catch (e: ParseException) { 61 | throw IncorrectOperationException("Error parsing Velocity template: " + e.message, e as Throwable) 62 | } catch (e: IncorrectOperationException) { 63 | throw e 64 | } catch (e: Exception) { 65 | e.printStackTrace() 66 | } 67 | 68 | return null 69 | } 70 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/codegenerator/util/EntryUtils.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.codegenerator.util; 2 | 3 | import com.intellij.psi.PsiField; 4 | import com.intellij.psi.PsiMember; 5 | import com.intellij.psi.PsiMethod; 6 | 7 | import java.util.ArrayList; 8 | import java.util.Collection; 9 | import java.util.List; 10 | 11 | public class EntryUtils { 12 | public static List getOnlyAsFieldAndMethodElements(Collection members, 13 | Collection selectedNotNullMembers, 14 | boolean useAccessors) { 15 | List 16 | entryList = new ArrayList<>(); 17 | 18 | for (PsiMember member : members) { 19 | MemberEntry entry = null; 20 | if (member instanceof PsiField) { 21 | FieldEntry fieldEntry= EntryFactory.of((PsiField) member, useAccessors); 22 | if (selectedNotNullMembers.contains(member)) { 23 | fieldEntry.setNotNull(true); 24 | } 25 | entry = fieldEntry; 26 | } else if (member instanceof PsiMethod) { 27 | MethodEntry methodEntry = EntryFactory.of((PsiMethod) member); 28 | if (selectedNotNullMembers.contains(member)) { 29 | methodEntry.setNotNull(true); 30 | } 31 | entry = methodEntry; 32 | } 33 | 34 | if (entry != null) { 35 | entryList.add(entry); 36 | } 37 | } 38 | return entryList; 39 | } 40 | 41 | public static List getOnlyAsFieldEntries(Collection members, 42 | Collection selectedNotNullMembers, 43 | boolean useAccessors) { 44 | List fieldEntryList = new ArrayList<>(); 45 | 46 | for (PsiMember member : members) { 47 | if (member instanceof PsiField) { 48 | PsiField field = (PsiField) member; 49 | FieldEntry fe = EntryFactory.of(field, useAccessors); 50 | if (selectedNotNullMembers.contains(member)) { 51 | fe.setNotNull(true); 52 | } 53 | fieldEntryList.add(fe); 54 | } 55 | } 56 | 57 | return fieldEntryList; 58 | } 59 | 60 | public static List getOnlyAsMethodEntrys(Collection members) { 61 | List methodEntryList = new ArrayList<>(); 62 | 63 | for (PsiMember member : members) { 64 | if (member instanceof PsiMethod) { 65 | PsiMethod method = (PsiMethod) member; 66 | MethodEntry me = EntryFactory.of(method); 67 | methodEntryList.add(me); 68 | } 69 | } 70 | 71 | return methodEntryList; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/codegenerator/ui/SelectionPane.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 | -------------------------------------------------------------------------------- /MvpAutoCode/src/main/kotlin/com/lkl/plugin/maker/TemplateMaker.kt: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.maker 2 | 3 | import com.intellij.ide.fileTemplates.FileTemplate 4 | import com.intellij.ide.fileTemplates.FileTemplateManager 5 | import com.intellij.ide.fileTemplates.FileTemplateUtil 6 | import com.intellij.ide.fileTemplates.impl.FileTemplateManagerImpl 7 | import com.intellij.openapi.project.Project 8 | import com.lkl.plugin.* 9 | 10 | /** 11 | * Created by XQ Yang on 2018/6/28 10:46. 12 | * Description : template管理类 13 | */ 14 | 15 | object TemplateMaker { 16 | 17 | var tpManager: FileTemplateManagerImpl? = null 18 | val cacheTemplate = HashMap() 19 | 20 | 21 | private fun createContractTemplate(name: String, type: String, content: String) { 22 | val template = FileTemplateUtil.createTemplate(name, type, content, 23 | tpManager!!.getTemplates(FileTemplateManager.DEFAULT_TEMPLATES_CATEGORY)) 24 | template.isLiveTemplateEnabled = false 25 | //保存到ide中,这里就不保存了 26 | // tpManager.setTemplates(FileTemplateManager.DEFAULT_TEMPLATES_CATEGORY, listOf(template)) 27 | cacheTemplate[name] = template 28 | } 29 | 30 | fun getTemplate(templateName: String, project: Project): FileTemplate? { 31 | if (cacheTemplate.contains(templateName)) { 32 | return cacheTemplate[templateName] as FileTemplate 33 | } else if (tpManager == null) { 34 | tpManager = FileTemplateManagerImpl.getInstanceImpl(project) 35 | } 36 | 37 | when (templateName) { 38 | CONTRACT_TP_NAME_JAVA -> createContractTemplate(templateName, "java", TemplateCons.CONTRACT_TP_CONTENT_JAVA) 39 | CONTRACT_TP_NAME_KOTLIN -> createContractTemplate(templateName, "kt", TemplateCons.CONTRACT_TP_CONTENT_KOTLIN) 40 | CONTRACT_TP_NO_MODEL_NAME_JAVA -> createContractTemplate(templateName, "java", TemplateCons.CONTRACT_TP_CONTENT_NO_MODEL_JAVA) 41 | CONTRACT_TP_NO_MODEL_NAME_KOTLIN -> createContractTemplate(templateName, "kt", TemplateCons.CONTRACT_TP_CONTENT_NO_MODEL_KOTLIN) 42 | VIEW_IMPL_TP_ACTIVITY_JAVA -> createContractTemplate(templateName, "java", TemplateCons.COMMON_IMPL_TP_CONTENT_JAVA) 43 | VIEW_IMPL_TP_FRAGMENT_JAVA -> createContractTemplate(templateName, "java", TemplateCons.COMMON_IMPL_TP_CONTENT_JAVA) 44 | PRESENTER_IMPL_TP_JAVA -> createContractTemplate(templateName, "java", TemplateCons.COMMON_IMPL_TP_CONTENT_JAVA) 45 | MODEL_IMPL_TP_JAVA -> createContractTemplate(templateName, "java", TemplateCons.COMMON_IMPL_TP_CONTENT_JAVA) 46 | VIEW_IMPL_TP_ACTIVITY_KOTLIN -> createContractTemplate(templateName, "kt", TemplateCons.COMMON_IMPL_TP_CONTENT_KOTLIN) 47 | VIEW_IMPL_TP_FRAGMENT_KOTLIN -> createContractTemplate(templateName, "kt", TemplateCons.COMMON_IMPL_TP_CONTENT_KOTLIN) 48 | PRESENTER_IMPL_TP_KOTLIN -> createContractTemplate(templateName, "kt", TemplateCons.COMMON_IMPL_TP_CONTENT_KOTLIN) 49 | MODEL_IMPL_TP_KOTLIN -> createContractTemplate(templateName, "kt", TemplateCons.COMMON_IMPL_TP_CONTENT_KOTLIN) 50 | } 51 | 52 | return if (cacheTemplate.containsKey(templateName)) cacheTemplate[templateName] as FileTemplate else null 53 | } 54 | 55 | 56 | } 57 | 58 | 59 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/resources/template/to-string.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | df5bbb3e-4465-4474-8920-2316a5df67c4 6 | ToString 7 | .*\.java$ 8 | body 9 | false 10 | 40 | UTF-8 41 | 42 | 43 | true 44 | false 45 | false 46 | true 47 | true 48 | 49 | 50 | 51 | 52 | false 53 | ## set `availableMembers` to provide the members to select 54 | ## set `selectedMembers` to select the members initially, set nothing to select all 55 | ## Note that it should be type List<PsiMember> or List<MemberEntry> 56 | ## And the selected result will be 57 | ## - fields1: List<FieldEntry> where `1` is the step number that you specified 58 | ## - methods1: List<MethodEntry> 59 | ## - members: List<MemberEntry> 60 | #set($availableMembers = $class0.members) 61 | 62 | true 63 | true 64 | 0 65 | 1 66 | true 67 | 68 | 69 | AT_CARET 70 | ASK 71 | true 72 | $class0.name 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/codegenerator/action/CodeGeneratorGroup.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.codegenerator.action; 2 | 3 | import com.intellij.openapi.actionSystem.*; 4 | import com.intellij.openapi.components.ServiceManager; 5 | import com.intellij.openapi.editor.Caret; 6 | import com.intellij.openapi.project.DumbAware; 7 | import com.intellij.openapi.project.Project; 8 | import com.intellij.psi.PsiClass; 9 | import com.intellij.psi.PsiElement; 10 | import com.intellij.psi.PsiFile; 11 | import com.intellij.psi.util.PsiTreeUtil; 12 | import com.lkl.plugin.codegenerator.config.CodeGeneratorSettings; 13 | import com.lkl.plugin.codegenerator.config.CodeTemplate; 14 | import org.jetbrains.annotations.NotNull; 15 | import org.jetbrains.annotations.Nullable; 16 | 17 | import java.util.List; 18 | import java.util.stream.Collectors; 19 | 20 | public class CodeGeneratorGroup extends ActionGroup implements DumbAware { 21 | private CodeGeneratorSettings settings; 22 | 23 | public CodeGeneratorGroup() { 24 | settings = ServiceManager.getService(CodeGeneratorSettings.class); 25 | } 26 | 27 | @Override 28 | public boolean hideIfNoVisibleChildren() { 29 | return false; 30 | } 31 | 32 | @NotNull @Override public AnAction[] getChildren(@Nullable AnActionEvent anActionEvent) { 33 | if (anActionEvent == null) { 34 | return AnAction.EMPTY_ARRAY; 35 | } 36 | 37 | Project project = PlatformDataKeys.PROJECT.getData(anActionEvent.getDataContext()); 38 | if (project == null) { 39 | return AnAction.EMPTY_ARRAY; 40 | } 41 | 42 | PsiFile file = anActionEvent.getData(CommonDataKeys.PSI_FILE); 43 | if (file == null) { 44 | return AnAction.EMPTY_ARRAY; 45 | } 46 | 47 | Caret caret = anActionEvent.getDataContext().getData(LangDataKeys.CARET); 48 | boolean isProjectView = caret == null; 49 | 50 | if (!isProjectView) { 51 | // EditorPopup menu 52 | PsiElement element = file.findElementAt(caret.getOffset()); 53 | PsiClass clazz = PsiTreeUtil.getParentOfType(element, PsiClass.class, false); 54 | if (clazz == null) { 55 | // not inside a class 56 | return AnAction.EMPTY_ARRAY; 57 | } 58 | } 59 | 60 | 61 | String fileName = file.getName(); 62 | final List children = settings.getCodeTemplates().stream() 63 | .filter(t -> !isProjectView || (t.type.equals("class") && isProjectView)) 64 | .filter(t -> t.enabled && fileName.matches(t.fileNamePattern)) 65 | .map(CodeGeneratorGroup::getOrCreateAction) 66 | .collect(Collectors.toList()); 67 | 68 | return children.toArray(new AnAction[children.size()]); 69 | } 70 | 71 | private static AnAction getOrCreateAction(CodeTemplate template) { 72 | final String actionId = "CodeMaker.Menu.Action." + template.getId(); 73 | AnAction action = ActionManager.getInstance().getAction(actionId); 74 | if (action == null) { 75 | action = new CodeGeneratorAction(template.getId(), template.name); 76 | ActionManager.getInstance().registerAction(actionId, action); 77 | } 78 | return action; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 34 | 35 | @rem Find java.exe 36 | if defined JAVA_HOME goto findJavaFromJavaHome 37 | 38 | set JAVA_EXE=java.exe 39 | %JAVA_EXE% -version >NUL 2>&1 40 | if "%ERRORLEVEL%" == "0" goto init 41 | 42 | echo. 43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 44 | echo. 45 | echo Please set the JAVA_HOME variable in your environment to match the 46 | echo location of your Java installation. 47 | 48 | goto fail 49 | 50 | :findJavaFromJavaHome 51 | set JAVA_HOME=%JAVA_HOME:"=% 52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 53 | 54 | if exist "%JAVA_EXE%" goto init 55 | 56 | echo. 57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 58 | echo. 59 | echo Please set the JAVA_HOME variable in your environment to match the 60 | echo location of your Java installation. 61 | 62 | goto fail 63 | 64 | :init 65 | @rem Get command-line arguments, handling Windows variants 66 | 67 | if not "%OS%" == "Windows_NT" goto win9xME_args 68 | 69 | :win9xME_args 70 | @rem Slurp the command line arguments. 71 | set CMD_LINE_ARGS= 72 | set _SKIP=2 73 | 74 | :win9xME_args_slurp 75 | if "x%~1" == "x" goto execute 76 | 77 | set CMD_LINE_ARGS=%* 78 | 79 | :execute 80 | @rem Setup the command line 81 | 82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 83 | 84 | @rem Execute Gradle 85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 86 | 87 | :end 88 | @rem End local scope for the variables with windows NT shell 89 | if "%ERRORLEVEL%"=="0" goto mainEnd 90 | 91 | :fail 92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 93 | rem the _cmd.exe /c_ return code! 94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 95 | exit /b 1 96 | 97 | :mainEnd 98 | if "%OS%"=="Windows_NT" endlocal 99 | 100 | :omega 101 | -------------------------------------------------------------------------------- /MvpAutoCode/src/main/kotlin/com/lkl/plugin/TemplateCons.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin; 2 | 3 | /** 4 | * Created by XQ Yang on 2018/6/28 11:02. 5 | * @describe 模版常量 6 | */ 7 | 8 | public interface TemplateCons { 9 | 10 | String CONTRACT_TP_CONTENT_JAVA = 11 | "#if (${PACKAGE_NAME} != \"\")package ${PACKAGE_NAME};#end\n" + "\n" + "import ${V};\n" + "import ${P};\n" + "import ${M};\n" + "/**\n" + " * @describe \n" + 12 | " * @author ${USER}\n" + " * @date ${DATE} ${TIME}\n" + " * \t\t\t\t\t\t\t\t - generate by MvpAutoCodePlus plugin.\n" + " */\n" + "\n" + 13 | "public interface I${NAME}Contract {\n" + " interface View extends ${VN}${VG}{}\n" + " interface ${P_OR_M} extends ${PN}${PG}{}\n" + 14 | " interface Model extends ${MN}${MG}{}\n" + "}\n"; 15 | String CONTRACT_TP_CONTENT_NO_MODEL_JAVA = 16 | "#if (${PACKAGE_NAME} != \"\")package ${PACKAGE_NAME};#end\n" + "\n" + "import ${V};\n" + "import ${P};\n" + "/**\n" + " * @describe \n" + " * @author ${USER}\n" + 17 | " * @date ${DATE} ${TIME}\n" + " * \t\t\t\t\t\t\t\t - generate by MvpAutoCodePlus plugin.\n" + " */\n" + "\n" + "public interface I${NAME}Contract {\n" + 18 | " interface View extends ${VN}${VG}{}\n" + " interface ${P_OR_M} extends ${PN}${PG}{}\n" + "}\n"; 19 | 20 | String CONTRACT_TP_CONTENT_KOTLIN = 21 | "#if (${PACKAGE_NAME} != \"\")package ${PACKAGE_NAME}#end\n" + "\n" + "import ${V}\n" + "import ${P}\n" + "import ${M}\n" + "/**\n" + " * @describe \n" + 22 | " * @author ${USER}\n" + " * @date ${DATE} ${TIME}\n" + " * \t\t\t\t\t\t\t\t - generate by MvpAutoCodePlus plugin.\n" + " */\n" + "\n" + "interface ${NAME} {\n" + 23 | " interface View : ${VN}${VG}{}\n" + " interface ${P_OR_M} : ${PN}${PG}{}\n" + " interface Model : ${MN}${MG}{}\n" + "}\n"; 24 | String CONTRACT_TP_CONTENT_NO_MODEL_KOTLIN = 25 | "#if (${PACKAGE_NAME} != \"\")package ${PACKAGE_NAME}#end\n" + "\n" + "import ${V}\n" + "import ${P}\n" + "/**\n" + " * @describe \n" + " * @author ${USER}\n" + 26 | " * @date ${DATE} ${TIME}\n" + " * \t\t\t\t\t\t\t\t - generate by MvpAutoCodePlus plugin.\n" + " */\n" + "\n" + "interface ${NAME} {\n" + 27 | " interface View : ${VN}${VG}{}\n" + " interface ${P_OR_M} : ${PN}${PG}{}\n" + "}\n"; 28 | 29 | String COMMON_IMPL_TP_CONTENT_JAVA = 30 | "#if (${PACKAGE_NAME} != \"\")package ${PACKAGE_NAME};#end\n" + "\n" + "import ${CONTRACT};\n" + "import ${PACKAGE_NAME}.R;\n" + "#if (${IMPL} != \"\")import ${IMPL};#end\n" + "\n" + "\n" + "/**\n" + 31 | " * @describe \n" + " * @author ${USER}\n" + " * @date ${DATE} ${TIME}\n" + " * \t\t\t\t\t\t\t\t - generate by MvpAutoCodePlus plugin.\n" + " */\n" + "\n" + 32 | "public class ${NAME}${IMPL_TYPE} #if(${IMPL}!=\"\") extends ${IMPL}${VG}#end implements I${NAME}Contract.${TYPE} {\n" + "\n" + "}\n" + "\n"; 33 | 34 | //todo R文件的报名应该是清单里面的报名 35 | 36 | String COMMON_IMPL_TP_CONTENT_KOTLIN = 37 | "#if (${PACKAGE_NAME} != \"\")package ${PACKAGE_NAME}#end\n" + "\n" + "import ${CONTRACT}\n" + "import ${PACKAGE_NAME}.R\n" + "#if (${IMPL} != \"\")import ${IMPL}#end\n" + "\n" + "/**\n" + 38 | " * @describe \n" + " * @author ${USER}\n" + " * @date ${DATE} ${TIME}\n" + " * \t\t\t\t\t\t\t\t - generate by MvpAutoCodePlus plugin.\n" + " */\n" + "\n" + 39 | "class ${NAME}${IMPL_TYPE} :#if (${IMPL_NP} != \"\") ${IMPL_NP}${VG}(),#end ${CONTRACT_NP}.${TYPE} {\n" + "\n" + "}\n" + "\n"; 40 | } 41 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/resources/template/getters-and-setters.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 58a3b5d1-3621-43b8-9c17-e725ceaedbdd 6 | Getter and Setter 7 | .*\.java$ 8 | body 9 | false 10 | 41 | UTF-8 42 | 43 | 44 | true 45 | false 46 | false 47 | true 48 | true 49 | 50 | 51 | 52 | 53 | false 54 | #set($availableMembers = []) 55 | #set($methodNames = []) 56 | #foreach($method in $class0.methods) 57 | $methodNames.add($method.methodName) 58 | #end 59 | #foreach($field in $class0.fields) 60 | #set($name = $StringUtil.capitalizeWithJavaBeanConvention($StringUtil.sanitizeJavaIdentifier($helper.getPropertyName($field.element, $project)))) 61 | #if ($field.boolean && $field.primitive) 62 | #set($getter = "is${name}") 63 | #else 64 | #set($getter = "get${name}") 65 | #end 66 | #set($setter = "set${name}") 67 | #if (!$methodNames.contains($getter) || !$methodNames.contains($setter)) 68 | $availableMembers.add($field) 69 | #end 70 | #end 71 | 72 | true 73 | false 74 | 0 75 | 1 76 | true 77 | 78 | 79 | AT_CARET 80 | ASK 81 | true 82 | $class0.name 83 | false 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /MvpAutoCode/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.72' 3 | repositories { 4 | maven { url 'https://maven.aliyun.com/repository/public' } 5 | google() 6 | mavenCentral() 7 | } 8 | dependencies { 9 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 10 | } 11 | } 12 | 13 | plugins { 14 | id 'org.jetbrains.intellij' version '0.4.2' 15 | } 16 | 17 | version '1.4.3' 18 | group 'com.lkl.plugin' 19 | 20 | apply plugin: 'java' 21 | apply plugin: 'kotlin' 22 | apply plugin: 'kotlin-kapt' 23 | apply plugin: 'org.jetbrains.intellij' 24 | 25 | sourceCompatibility = 1.8 26 | targetCompatibility = 1.8 27 | 28 | //sourceSets { 29 | // main { 30 | // java { 31 | // srcDir "${project.rootDir.absolutePath}/thirdParty/javapoet/java/src" 32 | // } 33 | // } 34 | //} 35 | 36 | repositories { 37 | maven { url 'https://maven.aliyun.com/repository/public' } 38 | google() 39 | mavenCentral() 40 | } 41 | 42 | compileKotlin { 43 | kotlinOptions.jvmTarget = "1.8" 44 | } 45 | compileTestKotlin { 46 | kotlinOptions.jvmTarget = "1.8" 47 | } 48 | 49 | if (!hasProperty('StudioCompilePath')) { 50 | throw new GradleException("No StudioCompilePath value was set, please create gradle.properties file") 51 | } 52 | 53 | intellij { 54 | version '2019.3' 55 | plugins 'java' 56 | plugins 'org.jetbrains.kotlin:1.3.72-release-IJ2019.3-1' //here 57 | // plugins 'org.jetbrains.kotlin:1.3.21-release-IJ2018.2-1' //here 58 | // version '2018.2' 59 | // plugins 'org.jetbrains.kotlin:1.2.61-release-IJ2018.2-1' //here 60 | // version '2018.1' 61 | // plugins 'org.jetbrains.kotlin:1.2.60-release-IJ2018.1-1' //here 62 | // version '2017.3' 63 | // plugins 'org.jetbrains.kotlin:1.2.61-release-IJ2017.3-1' //here 64 | intellij.updateSinceUntilBuild false 65 | // intellij.localPath = project.hasProperty("StudioRunPath") ? StudioRunPath : StudioCompilePath 66 | } 67 | 68 | dependencies { 69 | compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" 70 | compileOnly fileTree(dir: "$StudioCompilePath/plugins/android/lib", include: ['*.jar']) 71 | compileOnly fileTree(dir: "$StudioCompilePath/plugins/java/lib", include: ['*.jar']) 72 | compileOnly fileTree(dir: "$StudioCompilePath/lib", include: ['*.jar']) 73 | 74 | testCompile fileTree(dir: "$StudioCompilePath/plugins/android/lib", include: ['*.jar']) 75 | testCompile fileTree(dir: "$StudioCompilePath/plugins/java/lib", include: ['*.jar']) 76 | testCompile fileTree(dir: "$StudioCompilePath/lib", include: ['*.jar']) 77 | // compile "com.jetbrains.intellij.java:java-psi:192.7142.36" 78 | compileOnly "com.android.tools.build:gradle:3.6.1" 79 | // compileOnly "com.jetbrains.intellij.java:java:192.7142.36" 80 | // compile 'com.squareup:javapoet:1.11.0' 81 | // testCompile group: 'junit', name: 'junit', version: '4.12' 82 | } 83 | 84 | patchPluginXml { 85 | changeNotes """

Adapte Android studio 4.0.

86 |
87 | Full Changelog History""" 88 | } 89 | 90 | //publishPlugin { 91 | // token publishToken 92 | //} 93 | 94 | //指定编译的编码 95 | tasks.withType(JavaCompile) { 96 | options.encoding = "UTF-8" 97 | } 98 | 99 | task verifySetup() { 100 | doLast { 101 | def ideaJar = "$StudioCompilePath/lib/idea.jar" 102 | if (!file(ideaJar).exists()) { 103 | throw new GradleException("$ideaJar not found, set StudioCompilePath in gradle.properties") 104 | } 105 | } 106 | } 107 | 108 | compileJava.dependsOn verifySetup -------------------------------------------------------------------------------- /ComparingReferencesInspection/src/main/resources/META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | com.lkl.plugin.ComparingReferencesInspection 7 | 8 | 9 | demo SDK: Comparing References Inspection Sample 10 | 11 | 12 | com.intellij.modules.java 13 | 14 | 15 | 16 | Adds entries to Preferences | Editor | Inspections | Java | Probable Bugs. 18 | ]]> 19 | 20 | 21 | 23 |
  • 2.0.0 Convert to Gradle-based plugin.
  • 24 |
  • 1.1.0 Refactor resources, register this inspection.
  • 25 |
  • 1.0.0 Release 2018.3 and earlier.
  • 26 | 27 | ]]> 28 |
    29 | 30 | 31 | IntelliJ Platform SDK 32 | 33 | 34 | 35 | 58 | 66 | 67 | 68 | 69 |
    -------------------------------------------------------------------------------- /MvpAutoCode/src/main/kotlin/com/lkl/plugin/maker/FileMaker.kt: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.maker 2 | 3 | import java.text.SimpleDateFormat 4 | 5 | /** 6 | * Created by XQ Yang on 2018/6/26 13:55. 7 | * Description : 8 | */ 9 | @Deprecated("使用模版方式生成更简单") 10 | val mDateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss") 11 | 12 | 13 | /* 14 | fun make(name: String, type: String, dir: PsiDirectory, project: Project?): PsiFile? { 15 | return when (type) { 16 | "1" -> javaNoImpl(name, dir, project) 17 | else -> null 18 | } 19 | } 20 | 21 | fun javaNoImpl(createName: String, dir: PsiDirectory, project: Project?): PsiFile? { 22 | val fileName = "${getContractName(createName)}.java" 23 | val file = dir.findFile(fileName) 24 | if (file != null) { 25 | return null 26 | } 27 | val path = dir.virtualFile.path 28 | val packageName = path.substring(path.indexOf("com"), path.length).replace("/", ".") 29 | 30 | val state = ServiceManager.getService(PersistentState::class.java) 31 | val vClassName = createTypeName(state.getValue(SUPER_VIEW), packageName, createName) 32 | val pClassName = createTypeName(state.getValue(SUPER_PRESENTER), packageName, createName) 33 | val mClassName = createTypeName(state.getValue(SUPER_MODEL), packageName, createName) 34 | 35 | val viewType = TypeSpec.interfaceBuilder("View").addModifiers(Modifier.PUBLIC, Modifier.STATIC) 36 | .addSuperinterface(vClassName).build() 37 | val presenterType = TypeSpec.interfaceBuilder("Presenter").addModifiers(Modifier 38 | .PUBLIC, Modifier.STATIC) 39 | .addSuperinterface(pClassName).build() 40 | val mType = TypeSpec.interfaceBuilder("Model").addModifiers(Modifier.PUBLIC, Modifier.STATIC).addSuperinterface(mClassName).build() 41 | val contract = TypeSpec.interfaceBuilder(getContractName(createName)).addModifiers(Modifier.PUBLIC).addType(viewType).addType(presenterType) 42 | .addType(mType) 43 | .build() 44 | val javaFile = JavaFile.builder(packageName, contract).addFileComment("This class generate by mvpAutoCodePlus . Void Young - " + mDateFormat.format(Date())).build() 45 | val sb = StringBuilder() 46 | javaFile.writeTo(sb) 47 | val result = PsiFileFactory.getInstance(project).createFileFromText(fileName, JavaLanguage.INSTANCE, sb.toString(), true, false, true) 48 | dir.add(result) 49 | return result 50 | } 51 | 52 | 53 | private fun createTypeName(spValue: String?, curPackageName: String, createName: String): TypeName { 54 | if (spValue.isNullOrEmpty()) { 55 | throw IllegalArgumentException("Super Interface name is null !") 56 | } 57 | val indexOf = spValue!!.lastIndexOf(".") 58 | var spName = spValue.substring(indexOf + 1, spValue.length) 59 | var sPPackageName = spValue.substring(0, indexOf) 60 | var typeName = "" 61 | if (spName.contains("<")) { 62 | val endIndex = spName.indexOf("<") 63 | typeName = spName.substring(endIndex + 1, spName.indexOf(">")) 64 | spName = spName.substring(0, endIndex) 65 | } 66 | 67 | var pClassName: TypeName = ClassName.get(sPPackageName, spName) 68 | val typeClassNames = mutableListOf() 69 | if (typeName.isNotEmpty()) { 70 | val types = typeName.split(",") 71 | for (s in types) { 72 | typeClassNames.add(when (s) { 73 | "V" -> ClassName.get(curPackageName, "${getContractName(createName)}.View") 74 | "P" -> ClassName.get(curPackageName, "${getContractName(createName)}.Presenter") 75 | "M" -> ClassName.get(curPackageName, "${getContractName(createName)}.Model") 76 | else -> throw IllegalArgumentException("$s is not support type") 77 | }) 78 | } 79 | if (typeClassNames.isNotEmpty()) { 80 | pClassName = ParameterizedTypeName.get(pClassName as ClassName, typeClassNames as List?) 81 | } 82 | } 83 | return pClassName 84 | } 85 | */ 86 | 87 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/base/GetterAndSetter.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.base; 2 | 3 | import com.intellij.openapi.actionSystem.AnAction; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.actionSystem.PlatformDataKeys; 6 | import com.intellij.openapi.command.WriteCommandAction; 7 | import com.intellij.openapi.editor.Document; 8 | import com.intellij.openapi.editor.Editor; 9 | import com.intellij.openapi.editor.SelectionModel; 10 | import com.intellij.openapi.project.Project; 11 | 12 | /** 13 | * Created by likunlun on 2020/7/11. 14 | */ 15 | public class GetterAndSetter extends AnAction { 16 | @Override 17 | public void actionPerformed(AnActionEvent e) { 18 | //获取Editor和Project对象 19 | Editor editor = e.getData(PlatformDataKeys.EDITOR); 20 | Project project = e.getData(PlatformDataKeys.PROJECT); 21 | if (editor == null||project==null) 22 | return; 23 | 24 | //获取SelectionModel和Document对象 25 | SelectionModel selectionModel = editor.getSelectionModel(); 26 | Document document = editor.getDocument(); 27 | 28 | //拿到选中部分字符串 29 | String selectedText = selectionModel.getSelectedText(); 30 | 31 | //得到选中字符串的起始和结束位置 32 | int startOffset = selectionModel.getSelectionStart(); 33 | int endOffset = selectionModel.getSelectionEnd(); 34 | 35 | //得到最大插入字符串(即生成的Getter和Setter函数字符串)位置 36 | int maxOffset = document.getTextLength() - 1; 37 | 38 | //计算选中字符串所在的行号,并通过行号得到下一行的第一个字符的起始偏移量 39 | int curLineNumber = document.getLineNumber(endOffset); 40 | int nextLineStartOffset = document.getLineStartOffset(curLineNumber + 1); 41 | 42 | //计算字符串的插入位置 43 | int insertOffset = maxOffset > nextLineStartOffset ? nextLineStartOffset : maxOffset; 44 | 45 | //得到选中字符串在Java类中对应的字段的类型 46 | String type = getSelectedType(document, startOffset); 47 | 48 | //对文档进行操作部分代码,需要放入Runnable接口中实现,由IDEA在内部将其通过一个新线程执行 49 | Runnable runnable = new Runnable() { 50 | @Override 51 | public void run() { 52 | //genGetterAndSetter为生成getter和setter函数部分 53 | document.insertString(insertOffset, genGetterAndSetter(selectedText, type)); 54 | } 55 | }; 56 | 57 | //加入任务,由IDEA调度执行这个任务 58 | WriteCommandAction.runWriteCommandAction(project, runnable); 59 | 60 | } 61 | 62 | @Override 63 | public void update(AnActionEvent e) { 64 | Editor editor = e.getData(PlatformDataKeys.EDITOR); 65 | SelectionModel selectionModel = editor.getSelectionModel(); 66 | 67 | //如果没有字符串被选中,那么无需显示该Action 68 | e.getPresentation().setVisible(editor != null && selectionModel.hasSelection()); 69 | } 70 | 71 | private String getSelectedType(Document document, int startOffset) { 72 | 73 | String text = document.getText().substring(0, startOffset).trim(); 74 | int startIndex = text.lastIndexOf(' '); 75 | 76 | return text.substring(startIndex + 1); 77 | } 78 | 79 | private String genGetterAndSetter(String field, String type) { 80 | if (field == null || (field = field.trim()).equals("")) 81 | return ""; 82 | String upperField = field; 83 | char first = field.charAt(0); 84 | if (first <= 'z' && first >= 'a') { 85 | upperField = String.valueOf(first).toUpperCase() + field.substring(1); 86 | } 87 | String getter = "\tpublic TYPE getUpperField(){ \n\t\treturn this.FIELD;\n\t}"; 88 | String setter = "\tpublic void setUpperField(TYPE FIELD){\n\t\tthis.FIELD=FIELD;\n\t}"; 89 | 90 | String myGetter = getter.replaceAll("TYPE", type).replaceAll("UpperField", upperField).replaceAll("FIELD", field); 91 | String mySetter = setter.replaceAll("TYPE", type).replaceAll("UpperField", upperField).replaceAll("FIELD", field); 92 | 93 | return "\n"+myGetter + "\n" + mySetter + "\n"; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/element/FieldElement.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lkl.plugin.tostring.element; 17 | 18 | import com.intellij.openapi.util.text.StringUtil; 19 | 20 | /** 21 | * This is a field element containing information about the field. 22 | * 23 | * @see ElementFactory 24 | */ 25 | public class FieldElement extends AbstractElement implements Element { 26 | 27 | private boolean isConstant; 28 | private boolean isEnum; 29 | private boolean isRecordComponent; 30 | 31 | private boolean isModifierTransient; 32 | private boolean isModifierVolatile; 33 | private String accessor; 34 | 35 | @Override 36 | public String getAccessor() { 37 | return accessor; 38 | } 39 | 40 | /** 41 | * Is the field a constant type? 42 | */ 43 | public boolean isConstant() { 44 | return isConstant; 45 | } 46 | 47 | /** 48 | * Does the field have a transient modifier? 49 | */ 50 | public boolean isModifierTransient() { 51 | return isModifierTransient; 52 | } 53 | 54 | /** 55 | * Does the field have a volatile modifier? 56 | */ 57 | public boolean isModifierVolatile() { 58 | return isModifierVolatile; 59 | } 60 | 61 | /** 62 | * Is the field an enum type (JDK1.5)? 63 | */ 64 | public boolean isEnum() { 65 | return isEnum; 66 | } 67 | 68 | /** 69 | * Is the field a record component (JDK14)? 70 | */ 71 | public boolean isRecordComponent() { 72 | return isRecordComponent; 73 | } 74 | 75 | public void setRecordComponent(boolean recordComponent) { 76 | isRecordComponent = recordComponent; 77 | } 78 | 79 | void setConstant(boolean constant) { 80 | isConstant = constant; 81 | } 82 | 83 | void setModifierTransient(boolean modifierTransient) { 84 | isModifierTransient = modifierTransient; 85 | } 86 | 87 | void setModifierVolatile(boolean modifierVolatile) { 88 | this.isModifierVolatile = modifierVolatile; 89 | } 90 | 91 | public void setEnum(boolean anEnum) { 92 | isEnum = anEnum; 93 | } 94 | 95 | /** 96 | * Performs a regular expression matching the fieldname. 97 | * 98 | * @param regexp regular expression. 99 | * @return true if the fieldname matches the regular expression. 100 | * @throws IllegalArgumentException is throw if the given input is invalid (an empty String) or a pattern matching error. 101 | */ 102 | public boolean matchName(String regexp) throws IllegalArgumentException { 103 | if (StringUtil.isEmpty(regexp)) { 104 | throw new IllegalArgumentException( 105 | "Can't perform regular expression since the given input is empty. Check the Method body velocity code: regexp='" + regexp + "'"); 106 | } 107 | 108 | return name.matches(regexp); 109 | } 110 | 111 | public String toString() { 112 | return super.toString() + " ::: FieldElement{" + 113 | "isConstant=" + isConstant + 114 | ", isEnum=" + isEnum + 115 | ", isModifierTransient=" + isModifierTransient + 116 | ", isModifierVolatile=" + isModifierVolatile + 117 | "}"; 118 | } 119 | 120 | public void setAccessor(String accessor) { 121 | this.accessor = accessor; 122 | } 123 | } -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/template/toString/ToStringTemplatesManager.java: -------------------------------------------------------------------------------- 1 | // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. 2 | package com.lkl.plugin.tostring.template.toString; 3 | 4 | import com.intellij.openapi.components.ServiceManager; 5 | import com.intellij.openapi.components.State; 6 | import com.intellij.openapi.components.Storage; 7 | import com.lkl.plugin.tostring.exception.TemplateResourceException; 8 | import com.lkl.plugin.tostring.template.TemplateResource; 9 | import com.lkl.plugin.tostring.template.TemplatesManager; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | 13 | import java.io.IOException; 14 | import java.util.Arrays; 15 | import java.util.List; 16 | 17 | @State(name = "ToStringTemplates", storages = @Storage("toStringTemplates.xml")) 18 | public final class ToStringTemplatesManager extends TemplatesManager { 19 | private static final String DEFAULT_CONCAT = "DefaultConcatMember.vm"; 20 | private static final String DEFAULT_CONCAT_GROOVY = "/com/lkl/plugin/tostring/template/toString/DefaultConcatMemberGroovy.vm"; 21 | private static final String DEFAULT_CONCAT_SUPER = "/com/lkl/plugin/tostring/template/toString/DefaultConcatMemberSuper.vm"; 22 | private static final String DEFAULT_CONCAT_SUPER_GROOVY = "/com/lkl/plugin/tostring/template/toString/DefaultConcatMemberSuperGroovy.vm"; 23 | private static final String DEFAULT_BUFFER = "/com/lkl/plugin/tostring/template/toString/DefaultBuffer.vm"; 24 | private static final String DEFAULT_BUILDER = "/com/lkl/plugin/tostring/template/toString/DefaultBuilder.vm"; 25 | private static final String DEFAULT_TOSTRINGBUILDER = "/com/lkl/plugin/tostring/template/toString/DefaultToStringBuilder.vm"; 26 | private static final String DEFAULT_TOSTRINGBUILDER3 = "/com/lkl/plugin/tostring/template/toString/DefaultToStringBuilder3.vm"; 27 | private static final String DEFAULT_GUAVA = "/com/lkl/plugin/tostring/template/toString/DefaultGuava.vm"; 28 | private static final String DEFAULT_GUAVA_18 = "/com/lkl/plugin/tostring/template/toString/DefaultGuava18.vm"; 29 | private static final String DEFAULT_STRING_JOINER = "/com/lkl/plugin/tostring/template/toString/StringJoiner.vm"; 30 | 31 | public static TemplatesManager getInstance() { 32 | return ServiceManager.getService(ToStringTemplatesManager.class); 33 | } 34 | 35 | @Override 36 | public @NotNull List getDefaultTemplates() { 37 | try { 38 | return Arrays.asList(new TemplateResource("String concat (+)", readFile(DEFAULT_CONCAT), true), 39 | new TemplateResource("String concat (+) and super.toString()", readFile(DEFAULT_CONCAT_SUPER), true), 40 | new TemplateResource("StringBuffer", readFile(DEFAULT_BUFFER), true), 41 | new TemplateResource("StringBuilder (JDK 1.5)", readFile(DEFAULT_BUILDER), true), 42 | new TemplateResource("ToStringBuilder (Apache commons-lang)", readFile(DEFAULT_TOSTRINGBUILDER), true, "org.apache.commons.lang.builder.ToStringBuilder"), 43 | new TemplateResource("ToStringBuilder (Apache commons-lang 3)", readFile(DEFAULT_TOSTRINGBUILDER3), true, "org.apache.commons.lang3.builder.ToStringBuilder"), 44 | new TemplateResource("Objects.toStringHelper (Guava)", readFile(DEFAULT_GUAVA), true, "com.google.common.base.Objects"), 45 | new TemplateResource("MoreObjects.toStringHelper (Guava 18+)", readFile(DEFAULT_GUAVA_18), true, "com.google.common.base.MoreObjects"), 46 | new TemplateResource("StringJoiner (JDK 1.8)", readFile(DEFAULT_STRING_JOINER), true), 47 | new TemplateResource("Groovy: String concat (+)", readFile(DEFAULT_CONCAT_GROOVY), true), 48 | new TemplateResource("Groovy: String concat (+) and super.toString()", readFile(DEFAULT_CONCAT_SUPER_GROOVY), true)); 49 | } 50 | catch (IOException e) { 51 | throw new TemplateResourceException("Error loading default templates", e); 52 | } 53 | } 54 | 55 | protected static String readFile(String resource) throws IOException { 56 | return readFile(resource, ToStringTemplatesManager.class); 57 | } 58 | } -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/element/GenerationHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2000-2015 JetBrains s.r.o. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lkl.plugin.tostring.element; 17 | 18 | import com.intellij.openapi.project.Project; 19 | import com.intellij.openapi.util.text.StringUtil; 20 | import com.intellij.psi.JavaPsiFacade; 21 | import com.intellij.psi.PsiClass; 22 | import com.intellij.psi.PsiFile; 23 | import com.intellij.psi.PsiJavaFile; 24 | import com.intellij.psi.codeStyle.JavaCodeStyleManager; 25 | import com.intellij.psi.codeStyle.JavaCodeStyleSettings; 26 | import com.intellij.psi.codeStyle.VariableKind; 27 | import com.intellij.psi.search.GlobalSearchScope; 28 | 29 | import java.util.List; 30 | 31 | public class GenerationHelper { 32 | 33 | //used in generate equals/hashCode 34 | @SuppressWarnings("unused") 35 | public static String getUniqueLocalVarName(String base, List elements, JavaCodeStyleSettings settings) { 36 | base = settings.LOCAL_VARIABLE_NAME_PREFIX + base; 37 | String id = base; 38 | int index = 0; 39 | while (true) { 40 | if (index > 0) { 41 | id = base + index; 42 | } 43 | index++; 44 | boolean anyEqual = false; 45 | for (Element equalsField : elements) { 46 | if (id.equals(equalsField.getName())) { 47 | anyEqual = true; 48 | break; 49 | } 50 | } 51 | if (!anyEqual) break; 52 | } 53 | 54 | 55 | return id; 56 | } 57 | 58 | /** 59 | * To be used from generate templates 60 | */ 61 | @SuppressWarnings("unused") 62 | public static String getClassNameWithOuters(ClassElement classElement, Project project) { 63 | String qualifiedName = classElement.getQualifiedName(); 64 | PsiClass aClass = JavaPsiFacade.getInstance(project).findClass(qualifiedName, GlobalSearchScope.projectScope(project)); 65 | if (aClass != null) { 66 | PsiFile containingFile = aClass.getContainingFile(); 67 | if (containingFile instanceof PsiJavaFile) { 68 | String packageName = ((PsiJavaFile)containingFile).getPackageName(); 69 | if (qualifiedName.startsWith(packageName)) { 70 | if (packageName.isEmpty()) return qualifiedName; 71 | return qualifiedName.substring(packageName.length() + 1); 72 | } 73 | } 74 | } 75 | return classElement.getName(); 76 | } 77 | 78 | public static String getParamName(FieldElement fieldElement, Project project) { 79 | JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project); 80 | return codeStyleManager.propertyNameToVariableName(getPropertyName(fieldElement, project), VariableKind.PARAMETER); 81 | } 82 | 83 | public static String getPropertyName(FieldElement fieldElement, Project project) { 84 | final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project); 85 | final VariableKind variableKind = fieldElement.isModifierStatic() ? VariableKind.STATIC_FIELD : VariableKind.FIELD; 86 | final String propertyName = codeStyleManager.variableNameToPropertyName(fieldElement.getName(), variableKind); 87 | if (!fieldElement.isModifierStatic() && fieldElement.isBoolean()) { 88 | if (propertyName.startsWith("is") && 89 | propertyName.length() > "is".length() && 90 | Character.isUpperCase(propertyName.charAt("is".length()))) { 91 | return StringUtil.decapitalize(propertyName.substring("is".length())); 92 | } 93 | } 94 | return propertyName; 95 | } 96 | } -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/element/MethodElement.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lkl.plugin.tostring.element; 17 | 18 | import com.intellij.openapi.util.text.StringUtil; 19 | 20 | /** 21 | * This is a method element containing information about the method. 22 | * 23 | * @see ElementFactory 24 | */ 25 | @SuppressWarnings({"UnusedDeclaration"}) 26 | public class MethodElement extends AbstractElement implements Element { 27 | 28 | private String methodName; 29 | private String fieldName; 30 | private boolean modifierAbstract; 31 | private boolean modifierSynchronized; 32 | private boolean returnTypeVoid; 33 | private boolean getter; 34 | private boolean deprecated; 35 | 36 | public String getMethodName() { 37 | return methodName; 38 | } 39 | 40 | public void setMethodName(String methodName) { 41 | this.methodName = methodName; 42 | } 43 | 44 | public String getFieldName() { 45 | return fieldName; 46 | } 47 | 48 | public void setFieldName(String fieldName) { 49 | this.fieldName = fieldName; 50 | } 51 | 52 | @Override 53 | public String getAccessor() { 54 | return methodName + "()"; 55 | } 56 | 57 | public boolean isModifierAbstract() { 58 | return modifierAbstract; 59 | } 60 | 61 | public void setModifierAbstract(boolean modifierAbstract) { 62 | this.modifierAbstract = modifierAbstract; 63 | } 64 | 65 | /** 66 | * Exists for compatibility with old templates 67 | */ 68 | public boolean isModifierSynchronzied() { 69 | return isModifierSynchronized(); 70 | } 71 | 72 | public boolean isModifierSynchronized() { 73 | return modifierSynchronized; 74 | } 75 | 76 | public void setModifierSynchronized(boolean modifierSynchronized) { 77 | this.modifierSynchronized = modifierSynchronized; 78 | } 79 | 80 | public boolean isReturnTypeVoid() { 81 | return returnTypeVoid; 82 | } 83 | 84 | public void setReturnTypeVoid(boolean returnTypeVoid) { 85 | this.returnTypeVoid = returnTypeVoid; 86 | } 87 | 88 | public boolean isGetter() { 89 | return getter; 90 | } 91 | 92 | public void setGetter(boolean getter) { 93 | this.getter = getter; 94 | } 95 | 96 | public boolean isDeprecated() { 97 | return deprecated; 98 | } 99 | 100 | public void setDeprecated(boolean deprecated) { 101 | this.deprecated = deprecated; 102 | } 103 | 104 | /** 105 | * Performs a regular expression matching the methodname. 106 | * 107 | * @param regexp regular expression. 108 | * @return true if the methodname matches the regular expression. 109 | * @throws IllegalArgumentException is throw if the given input is invalid (an empty String) or a pattern matching error. 110 | */ 111 | public boolean matchName(String regexp) throws IllegalArgumentException { 112 | if (StringUtil.isEmpty(regexp)) { 113 | throw new IllegalArgumentException("Can't perform regular expression since the given input is empty. Check the Method body velocity code: regexp='" + regexp + "'"); 114 | } 115 | 116 | return methodName.matches(regexp); 117 | } 118 | 119 | public String toString() { 120 | return super.toString() + " ::: MethodElement{" + 121 | "fieldName='" + fieldName + "'" + 122 | ", methodName='" + methodName + "'" + 123 | ", modifierAbstract=" + modifierAbstract + 124 | ", modifierSynchronized=" + modifierSynchronized + 125 | ", returnTypeVoid=" + returnTypeVoid + 126 | ", getter=" + getter + 127 | ", deprecated=" + deprecated + 128 | "}"; 129 | } 130 | } -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/configurable/ExeOverwriteConfirmDialog.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 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/element/ElementUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.lkl.plugin.tostring.element; 17 | 18 | import com.intellij.psi.PsiField; 19 | import com.intellij.psi.PsiMember; 20 | import com.intellij.psi.PsiMethod; 21 | 22 | import java.util.ArrayList; 23 | import java.util.Collection; 24 | import java.util.List; 25 | 26 | /** 27 | * Element utilities. 28 | */ 29 | public final class ElementUtils { 30 | 31 | private ElementUtils() {} 32 | 33 | /** 34 | * Gets the list of members to be put in the VelocityContext. 35 | * 36 | * @param members a list of {@link PsiMember} objects. 37 | * @param selectedNotNullMembers 38 | * @param useAccessors 39 | * @return a filtered list of only the fields as {@link FieldElement} objects. 40 | */ 41 | public static List getOnlyAsFieldElements(Collection members, 42 | Collection selectedNotNullMembers, 43 | boolean useAccessors) { 44 | List fieldElementList = new ArrayList<>(); 45 | 46 | for (PsiMember member : members) { 47 | if (member instanceof PsiField) { 48 | PsiField field = (PsiField) member; 49 | FieldElement fe = ElementFactory.newFieldElement(field, useAccessors); 50 | if (selectedNotNullMembers.contains(member)) { 51 | fe.setNotNull(true); 52 | } 53 | fieldElementList.add(fe); 54 | } 55 | } 56 | 57 | return fieldElementList; 58 | } 59 | 60 | /** 61 | * Gets the list of members to be put in the VelocityContext. 62 | * 63 | * @param members a list of {@link PsiMember} objects. 64 | * @return a filtered list of only the methods as a {@link MethodElement} objects. 65 | */ 66 | public static List getOnlyAsMethodElements(Collection members) { 67 | List methodElementList = new ArrayList<>(); 68 | 69 | for (PsiMember member : members) { 70 | if (member instanceof PsiMethod) { 71 | PsiMethod method = (PsiMethod) member; 72 | MethodElement me = ElementFactory.newMethodElement(method); 73 | methodElementList.add(me); 74 | } 75 | } 76 | 77 | return methodElementList; 78 | } 79 | 80 | /** 81 | * Gets the list of members to be put in the VelocityContext. 82 | * 83 | * @param members a list of {@link PsiMember} objects. 84 | * @param selectedNotNullMembers a list of @NotNull objects 85 | * @param useAccessors 86 | * @return a filtered list of only the methods as a {@link FieldElement} or {@link MethodElement} objects. 87 | */ 88 | public static List getOnlyAsFieldAndMethodElements(Collection members, 89 | Collection selectedNotNullMembers, 90 | boolean useAccessors) { 91 | List elementList = new ArrayList<>(); 92 | 93 | for (PsiMember member : members) { 94 | AbstractElement element = null; 95 | if (member instanceof PsiField) { 96 | element = ElementFactory.newFieldElement((PsiField) member, useAccessors); 97 | } else if (member instanceof PsiMethod) { 98 | element = ElementFactory.newMethodElement((PsiMethod) member); 99 | } 100 | 101 | if (element != null) { 102 | if (selectedNotNullMembers.contains(member)) { 103 | element.setNotNull(true); 104 | } 105 | elementList.add(element); 106 | } 107 | } 108 | return elementList; 109 | } 110 | } -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/resources/META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | com.lkl.plugin.IdeaPluginStudy 3 | IdeaPluginStudy 4 | 1.0 5 | YourCompany 6 | 7 | 9 | most HTML tags may be used 10 | ]]> 11 | 12 | 14 | most HTML tags may be used 15 | ]]> 16 | 17 | 18 | 19 | 20 | 21 | 23 | 26 | 27 | 28 | 29 | 34 | 37 | 38 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 63 | 64 | 65 | 66 | 68 | 69 | 71 | 72 | 73 | 74 | 75 | 79 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /docs/advanced/persistStateComponent.md: -------------------------------------------------------------------------------- 1 | # IntelliJ Plugin Development introduction: PersistStateComponent 2 | 3 | * [为IntelliJ插件保存值](#为intellij插件保存值) 4 | * [使类实现PersistentStateComponent](#使类实现persistentstatecomponent) 5 | * [@State注解–指定要保存的存储位置](#指定要保存的存储位置) 6 | * [在plugin.xml中声明PersistentStateComponent](#声明PersistentStateComponent) 7 | * [从其他模块使用PersistentStateComponent](#从其他模块使用persistentstatecomponent) 8 | 9 | ## 为IntelliJ插件保存值 10 | 11 | 如果您的插件想要保留一些配置值,并且希望将这些值保存在存储器中,则可以在IntelliJ IDEA插件开发中使用`PersistentStateComponent`。 12 | 13 | * [Persisting State of Components](https://www.jetbrains.org/intellij/sdk/docs/basics/persisting_state_of_components.html) 14 | 15 | ## 使类实现PersistentStateComponent 16 | 17 | 创建新的Java类`SingleFileExecutionConfig`实现`PersistentStateComponent`。 18 | 19 | 该类实现了`PersistentStateComponent`。因此,状态类型T与创建的类相同。 20 | 21 | 要实现此接口`PersistentStateComponent`,我们需要重写 22 | 23 | * **getState()** 每次保存设置时调用。如果从`getState()`返回的状态不同于默认构造函数获得的默认状态,则返回的状态将以XML序列化并存储。 24 | * **loadState(T)** 在创建组件时以及在外部更改具有持久状态的XML文件之后调用。 25 | 26 | 并且实现`getInstance`方法。 27 | 28 | 对于这三种方法的实现,您无需记住上述行为。 只需实现如下模板即可: 29 | ```java 30 | /** 31 | * PersistentStateComponent keeps project config values. 32 | */ 33 | @State( 34 | name="SingleFileExecutionConfig", 35 | storages = { 36 | @Storage("SingleFileExecutionConfig.xml")} 37 | ) 38 | public class SingleFileExecutionConfig implements PersistentStateComponent { 39 | 40 | @Nullable 41 | @Override 42 | public SingleFileExecutionConfig getState() { 43 | return this; 44 | } 45 | 46 | @Override 47 | public void loadState(SingleFileExecutionConfig singleFileExecutionConfig) { 48 | XmlSerializerUtil.copyBean(singleFileExecutionConfig, this); 49 | } 50 | 51 | @Nullable 52 | public static SingleFileExecutionConfig getInstance(Project project) { 53 | return ServiceManager.getService(project, SingleFileExecutionConfig.class); 54 | } 55 | } 56 | ``` 57 | 58 | > 请注意,当`PersistentStateComponent`为项目级别时,对于`getInstance`中的`getService`方法,`project`变量是必需的。如果您的Service是应用程序级别的,则不需要`project`实例。 59 | 60 | * [Plugin Services](https://www.jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_services.html) 61 | 62 | ## @State注解–指定要保存的存储位置 63 | 64 | 您可能会注意到,@State注解写在顶部。这是用来指定将存储持久值的位置。 65 | 66 | For the fields: 67 | * name (required) – specifies the name of the state. 68 | * storages – specify the storage locations 69 | 70 | Example: 71 | @Storage("yourName.xml") If component is project-level 72 | @Storage(StoragePathMacros.WORKSPACE_FILE) for values stored in the workspace file. 73 | 74 | 有关更多详细信息,请参见官方文档的[“定义存储位置”](https://www.jetbrains.org/intellij/sdk/docs/basics/persisting_state_of_components.html) 75 | 76 | 之后,您只需声明将要保存的变量,以及这些变量的Getter和Setter。 例如,要声明一个String变量executableName,请将以下代码添加到此类。 77 | ```java 78 | String executableName; 79 | 80 | public String getExecutableName() { 81 | return executableName; 82 | } 83 | 84 | public void setExecutableName(String executableName) { 85 | this.executableName = executableName; 86 | } 87 | ``` 88 | 89 | ## 在plugin.xml中声明PersistentStateComponent 90 | 91 | 要使用此PersistentStateComponent,需要在plugin.xml中进行声明 92 | ```xml 93 | 94 | 95 | ... 96 | 99 | 100 | ``` 101 | 102 | ## 从其他模块使用PersistentStateComponent 103 | 104 | 可以通过调用getInstance方法获得实例。例如: 105 | ```java 106 | private final SingleFileExecutionConfig mConfig; 107 | 108 | @SuppressWarnings("FieldCanBeLocal") 109 | private final Project mProject; 110 | 111 | public SingleFileExecutionConfigurable(@NotNull Project project) { 112 | mProject = project; 113 | mConfig = SingleFileExecutionConfig.getInstance(project); 114 | } 115 | ``` 116 | 要更新值,您可以直接更新此实例的字段变量`(mConfig)`。不需要显式的`“save”`方法调用!下次获取值时,该值将自动保存。 117 | 118 | > **注意**:`public SingleFileExecutionConfigurable(@NotNull Project project)` 接收project作为参数时,在 `plugin.xml` 中一定要声明为 `projectConfigurable` 119 | 120 | 下面的代码是变量更新部分的示例。 当用户在“设置”对话框中更改配置时,将调用此`apply()`方法。 121 | ```java 122 | public void apply() { 123 | mConfig.setExecutableName(exeNameTextField.getText()); 124 | mConfig.notShowOverwriteConfirmDialog = notShowDialogCheckBox.isSelected(); 125 | } 126 | ``` 127 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/codegenerator/config/CodeTemplate.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.codegenerator.config; 2 | 3 | import com.intellij.openapi.util.io.FileUtil; 4 | import com.intellij.util.xmlb.annotations.AbstractCollection; 5 | import org.apache.commons.lang.builder.EqualsBuilder; 6 | import org.apache.commons.lang.builder.HashCodeBuilder; 7 | import org.jetbrains.java.generate.config.DuplicationPolicy; 8 | import org.jetbrains.java.generate.config.InsertWhere; 9 | 10 | import javax.xml.bind.annotation.*; 11 | import java.io.IOException; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | import java.util.UUID; 15 | 16 | @XmlRootElement(name = "codeTemplate") 17 | @XmlAccessorType(XmlAccessType.FIELD) 18 | public class CodeTemplate { 19 | @XmlAttribute 20 | public static final String VERSION = "1.3"; 21 | 22 | private UUID id; 23 | public String name = "Untitled"; 24 | public String fileNamePattern = ".*\\.java$"; 25 | public String type = "body"; 26 | public boolean enabled = true; 27 | public String template = DEFAULT_TEMPLATE; 28 | public String fileEncoding = DEFAULT_ENCODING; 29 | @XmlElements({ 30 | @XmlElement(name="memberSelection", type=MemberSelectionConfig.class), 31 | @XmlElement(name="classSelection", type=ClassSelectionConfig.class) 32 | }) 33 | @XmlElementWrapper 34 | @AbstractCollection(elementTypes = {MemberSelectionConfig.class, ClassSelectionConfig.class}) 35 | public List pipeline = new ArrayList<>(); 36 | 37 | public InsertWhere insertNewMethodOption = InsertWhere.AT_CARET; 38 | public DuplicationPolicy whenDuplicatesOption = DuplicationPolicy.ASK; 39 | public boolean jumpToMethod = true; // jump cursor to toString method 40 | public String classNameVm = "${class0.qualifiedName}Test"; 41 | public boolean alwaysPromptForPackage = false; 42 | 43 | public CodeTemplate(UUID id) { 44 | this.id = id; 45 | } 46 | public CodeTemplate(String id) { 47 | this.id = UUID.fromString(id); 48 | } 49 | 50 | public CodeTemplate() { 51 | this(UUID.randomUUID()); 52 | } 53 | 54 | public void regenerateId() { 55 | this.id = UUID.randomUUID(); 56 | } 57 | 58 | public String getId() { 59 | return this.id.toString(); 60 | } 61 | 62 | public boolean isValid() { 63 | return true; 64 | } 65 | 66 | public static final String DEFAULT_ENCODING = "UTF-8"; 67 | 68 | private static final String DEFAULT_TEMPLATE; 69 | 70 | static { 71 | String default_template; 72 | try { 73 | default_template = FileUtil.loadTextAndClose(CodeTemplate.class.getResourceAsStream("/template/default.vm")); 74 | } catch (IOException e) { 75 | default_template = ""; 76 | e.printStackTrace(); 77 | } 78 | DEFAULT_TEMPLATE = default_template; 79 | } 80 | 81 | @Override public boolean equals(Object o) { 82 | if (this == o) 83 | return true; 84 | 85 | if (o == null || getClass() != o.getClass()) 86 | return false; 87 | 88 | CodeTemplate template1 = (CodeTemplate)o; 89 | 90 | return new EqualsBuilder() 91 | .append(enabled, template1.enabled) 92 | .append(jumpToMethod, template1.jumpToMethod) 93 | .append(alwaysPromptForPackage, template1.alwaysPromptForPackage) 94 | .append(id, template1.id) 95 | .append(name, template1.name) 96 | .append(fileNamePattern, template1.fileNamePattern) 97 | .append(type, template1.type) 98 | .append(template, template1.template) 99 | .append(fileEncoding, template1.fileEncoding) 100 | .append(pipeline, template1.pipeline) 101 | .append(insertNewMethodOption, template1.insertNewMethodOption) 102 | .append(whenDuplicatesOption, template1.whenDuplicatesOption) 103 | .append(classNameVm, template1.classNameVm) 104 | .isEquals(); 105 | } 106 | 107 | @Override public int hashCode() { 108 | return new HashCodeBuilder(17, 37) 109 | .append(id) 110 | .append(name) 111 | .append(fileNamePattern) 112 | .append(type) 113 | .append(enabled) 114 | .append(template) 115 | .append(fileEncoding) 116 | .append(pipeline) 117 | .append(insertNewMethodOption) 118 | .append(whenDuplicatesOption) 119 | .append(jumpToMethod) 120 | .append(classNameVm) 121 | .append(alwaysPromptForPackage) 122 | .toHashCode(); 123 | } 124 | 125 | 126 | } 127 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/resources/template/default.vm: -------------------------------------------------------------------------------- 1 | ## Tutorial for writing your templates 2 | ## 3 | ## 1. First you need to know basic syntax of velocity[1]. 4 | ## 2. Then it is necessary to understand the variable that CodeGenerator provides 5 | ## and its inner structure for retrieving the information you need for generating code. 6 | ## 3. Learn to use the utils provided so that you can ask for further information 7 | ## or reduce your workload. 8 | ## 9 | ## Variables Provided (Class Mode) 10 | ## ------------------------------- 11 | ## Class mode means you want to create new classes(file). 12 | ## 13 | ## - ClassName: String The name spcified by `Target Class Name` 14 | ## - PackageName: String The package name specified by `Target Class Name` 15 | ## - class0: ClassEntry The class that the action is triggered upon 16 | ## - raw: PsiClass 17 | ## - String packageName 18 | ## - importList: List 19 | ## - fields: List 20 | ## - allFields: List 21 | ## - methods: List 22 | ## - allMethods: List 23 | ## - innerClasses: List 24 | ## - allInnerClasses: List 25 | ## - typeParamList: List 26 | ## - name: String 27 | ## - superName: String 28 | ## - superQualifiedName: String 29 | ## - qualifiedName: String 30 | ## - typeParams: int 31 | ## - hasSuper: boolean 32 | ## - deprecated: boolean 33 | ## - enum: boolean 34 | ## - exception: boolean 35 | ## - abstract: boolean 36 | ## - implementNames: String[] 37 | ## - isImplements(String): bool 38 | ## - isExtends(String): bool 39 | ## - matchName(String): bool 40 | ## 41 | ## - class1: ClassEntry The first selected class, where `1` is the postfix 42 | ## you specify in pipeline 43 | ## ... 44 | ## 45 | ## - MemberEntry (FieldEntry/MethodEntry common properties) 46 | ## - raw: PsiField(for field), PsiMethod(for method) 47 | ## - name: String 48 | ## - accessor: String 49 | ## - array: boolean 50 | ## - nestedArray: boolean 51 | ## - collection: boolean 52 | ## - map: boolean 53 | ## - primitive: boolean 54 | ## - string: boolean 55 | ## - primitiveArray: boolean 56 | ## - objectArray: boolean 57 | ## - numeric: boolean 58 | ## - object: boolean 59 | ## - date: boolean 60 | ## - set: boolean 61 | ## - list: boolean 62 | ## - stringArray: boolean 63 | ## - calendar: boolean 64 | ## - typeName: String 65 | ## - typeQualifiedName: String 66 | ## - type: String 67 | ## - boolean: boolean 68 | ## - long: boolean 69 | ## - float: boolean 70 | ## - double: boolean 71 | ## - void: boolean 72 | ## - notNull: boolean 73 | ## - char: boolean 74 | ## - byte: boolean 75 | ## - short: boolean 76 | ## - modifierStatic: boolean 77 | ## - modifierPublic: boolean 78 | ## - modifierProtected: boolean 79 | ## - modifierPackageLocal: boolean 80 | ## - modifierPrivate: boolean 81 | ## - modifierFinal: boolean 82 | ## 83 | ## - FieldEntry 84 | ## - constant: boolean 85 | ## - modifierTransient: boolean 86 | ## - modifierVolatile: boolean 87 | ## - enum: boolean 88 | ## - matchName(String): bool 89 | ## 90 | ## - MethodEntry 91 | ## - methodName: String 92 | ## - fieldName: String 93 | ## - modifierAbstract: boolean 94 | ## - modifierSynchronzied: boolean 95 | ## - modifierSynchronized: boolean 96 | ## - returnTypeVoid: boolean 97 | ## - getter: boolean 98 | ## - deprecated: boolean 99 | ## - matchName(String): bool 100 | ## 101 | ## Variables for Body Mode 102 | ## ----------------------- 103 | ## - class0: ClassEntry The current class 104 | ## - fields: List All selected fields 105 | ## - methods: List All selected methods 106 | ## - members: List selected fields+methods 107 | ## - parentMethod: MethodEntry The nearest method that surround the current cursor 108 | ## 109 | ## Utilities 110 | ## --------- 111 | ## - settings: CodeStyleSettings settings of code style 112 | ## - project: Project The project instance, normally used by Psi related utilities 113 | ## - helper: GenerationHelper 114 | ## - StringUtil: Class 115 | ## - NameUtil: Class 116 | ## - PsiShortNamesCache: Class utility to search classes 117 | ## - PsiJavaPsiFacade: Class Java specific utility to search classes 118 | ## - GlobalSearchScope: Class class to create search scopes, used by above utilities 119 | ## - EntryFactory: Class EntryFactory.of(...) to turn PsiXXX to XXXEntry. 120 | ## 121 | ## Other feature 122 | ## ------------- 123 | ## - Auto import. If the generated code contains full qualified name, Code Generator will try to 124 | ## import the packages automatically and shorten the name. 125 | ## For example `java.util.List<>` -> `List<>` 126 | ## 127 | ## References 128 | ## ---------- 129 | ## - Velocity syntax: http://velocity.apache.org/engine/1.7/user-guide.html 130 | 131 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/tostring/view/TemplatesPanel.java: -------------------------------------------------------------------------------- 1 | // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. 2 | 3 | /* 4 | * @author max 5 | */ 6 | package com.lkl.plugin.tostring.view; 7 | 8 | import com.intellij.java.JavaBundle; 9 | import com.intellij.openapi.options.ConfigurationException; 10 | import com.intellij.openapi.options.UnnamedConfigurable; 11 | import com.intellij.openapi.project.Project; 12 | import com.intellij.openapi.ui.NamedItemsListEditor; 13 | import com.intellij.openapi.ui.Namer; 14 | import com.intellij.openapi.util.Cloner; 15 | import com.intellij.openapi.util.Comparing; 16 | import com.intellij.openapi.util.Factory; 17 | import com.lkl.plugin.tostring.template.TemplateResource; 18 | import com.lkl.plugin.tostring.template.TemplatesManager; 19 | import com.lkl.plugin.tostring.template.toString.ToStringTemplatesManager; 20 | import gnu.trove.Equality; 21 | import org.jetbrains.annotations.Nls; 22 | import org.jetbrains.annotations.NonNls; 23 | import org.jetbrains.annotations.Nullable; 24 | 25 | import java.util.ArrayList; 26 | import java.util.Collections; 27 | import java.util.Objects; 28 | 29 | public class TemplatesPanel extends NamedItemsListEditor { 30 | private static final Namer NAMER = new Namer() { 31 | @Override 32 | public String getName(TemplateResource templateResource) { 33 | return templateResource.getFileName(); 34 | } 35 | 36 | @Override 37 | public boolean canRename(TemplateResource item) { 38 | return !item.isDefault(); 39 | } 40 | 41 | @Override 42 | public void setName(TemplateResource templateResource, String name) { 43 | templateResource.setFileName(name); 44 | } 45 | }; 46 | 47 | private static final Factory FACTORY = () -> new TemplateResource(); 48 | 49 | private static final Cloner CLONER = new Cloner() { 50 | @Override 51 | public TemplateResource cloneOf(TemplateResource templateResource) { 52 | if (templateResource.isDefault()) return templateResource; 53 | return copyOf(templateResource); 54 | } 55 | 56 | @Override 57 | public TemplateResource copyOf(TemplateResource templateResource) { 58 | TemplateResource result = new TemplateResource(); 59 | result.setFileName(templateResource.getFileName()); 60 | result.setTemplate(templateResource.getTemplate()); 61 | return result; 62 | } 63 | }; 64 | 65 | private static final Equality COMPARER = 66 | (o1, o2) -> Objects.equals(o1.getTemplate(), o2.getTemplate()) && Objects.equals(o1.getFileName(), o2.getFileName()); 67 | private final Project myProject; 68 | private final TemplatesManager myTemplatesManager; 69 | private String myHint; 70 | 71 | public TemplatesPanel(Project project) { 72 | this(project, ToStringTemplatesManager.getInstance()); 73 | } 74 | 75 | public TemplatesPanel(Project project, TemplatesManager templatesManager) { 76 | super(NAMER, FACTORY, CLONER, COMPARER, 77 | new ArrayList<>(templatesManager.getAllTemplates())); 78 | 79 | //ServiceManager.getService(project, MasterDetailsStateService.class).register("ToStringTemplates.UI", this); 80 | myProject = project; 81 | myTemplatesManager = templatesManager; 82 | } 83 | 84 | public void setHint(String hint) { 85 | myHint = hint; 86 | } 87 | 88 | @Override 89 | @Nls 90 | public String getDisplayName() { 91 | return JavaBundle.message("configurable.TemplatesPanel.display.name"); 92 | } 93 | 94 | @Override 95 | protected String subjDisplayName() { 96 | return "template"; 97 | } 98 | 99 | @Override 100 | @Nullable 101 | @NonNls 102 | public String getHelpTopic() { 103 | return "Templates_Dialog"; 104 | } 105 | 106 | @Override 107 | public boolean isModified() { 108 | return super.isModified() || !Comparing.equal(myTemplatesManager.getDefaultTemplate(), getSelectedItem()); 109 | } 110 | 111 | @Override 112 | protected boolean canDelete(TemplateResource item) { 113 | return !item.isDefault(); 114 | } 115 | 116 | @Override 117 | protected UnnamedConfigurable createConfigurable(TemplateResource item) { 118 | final GenerateTemplateConfigurable configurable = 119 | new GenerateTemplateConfigurable(item, Collections.emptyMap(), myProject, onMultipleFields()); 120 | configurable.setHint(myHint); 121 | return configurable; 122 | } 123 | 124 | protected boolean onMultipleFields() { 125 | return true; 126 | } 127 | 128 | @Override 129 | public void apply() throws ConfigurationException { 130 | super.apply(); 131 | myTemplatesManager.setTemplates(getItems()); 132 | final TemplateResource selection = getSelectedItem(); 133 | if (selection != null) { 134 | myTemplatesManager.setDefaultTemplate(selection); 135 | } 136 | } 137 | } -------------------------------------------------------------------------------- /docs/base/kotlinPlugin.md: -------------------------------------------------------------------------------- 1 | # Kotlin for Plugin Developers 2 | 3 | * [Why Kotlin?](#WhyKotlin?) 4 | * [Adding Kotlin Support](#AddingKotlinSupport) 5 | * [Kotlin Gradle Plugin](#KotlinGradlePlugin) 6 | * [Use Kotlin to Write Gradle Script](#UseKotlintoWriteGradleScript) 7 | * [UI in Kotlin](#UIinKotlin) 8 | * [Handling Kotlin Code](#HandlingKotlinCode) 9 | * [警告](#警告) 10 | * [Examples](#Examples) 11 | * [参考文献](#参考文献) 12 | 13 | ## Why Kotlin? 14 | 15 | 使用Kotlin为IntelliJ平台编写插件与使用Java编写插件非常相似。 现有的插件开发人员可以通过使用与IntelliJ平台捆绑在一起的[J2K编译器](https://kotlinlang.org/docs/tutorials/mixing-java-kotlin-intellij.html#converting-an-existing-java-file-to-kotlin-with-j2k)(版本143. +)将样板Java类转换为Kotlin等效类来开始使用,并且开发人员可以轻松地将Kotlin类与现有Java代码混合和匹配。 16 | 17 | 除了[null安全](https://kotlinlang.org/docs/reference/null-safety.html)和[类型安全构建器](https://kotlinlang.org/docs/reference/type-safe-builders.html)之外,Kotlin语言还为插件开发提供了许多方便的功能,这些功能使插件更易于阅读和维护。 就像Android的Kotlin一样,IntelliJ平台大量使用了回调,这些回调很容易在Kotlin中表示为[lambda](https://kotlinlang.org/docs/reference/lambdas.html)。 18 | 19 | 同样,通过扩展在IntelliJ IDEA中自定义内部类的行为很容易。 例如,通常的做法是保护日志记录语句以避免参数构造的开销,从而在使用日志时导致以下情况: 20 | ```java 21 | if (logger.isDebugEnabled()) { 22 | logger.debug("..."); 23 | } 24 | ``` 25 | 通过声明以下扩展方法,我们可以在Kotlin中更简洁地实现相同的结果: 26 | ```kotlin 27 | inline fun Logger.debug(lazyMessage: () -> String) { 28 | if (isDebugEnabled) { 29 | debug(lazyMessage()) 30 | } 31 | } 32 | ``` 33 | 34 | 现在,我们可以直接编写`logger.debug { "..." }`来获得轻量级日志记录的所有好处,而无需赘述。 通过实践,您将能够识别IntelliJ平台中的许多惯用法,这些惯用法可以用Kotlin简化。 35 | 36 | ## Adding Kotlin Support 37 | 38 | > Tip: [GitHub模板](https://jetbrains.org/intellij/sdk/docs/tutorials/github_template.html)使用Kotlin提供了一个预配置的项目。 39 | 40 | 面向IntelliJ平台143及更高版本的插件易于迁移:只需开始编写Kotlin。 IDE已经捆绑了必要的Kotlin插件和库,无需进一步配置。 有关详细说明,请参阅[Kotlin文档](https://kotlinlang.org/docs/tutorials/getting-started.html)。 41 | 42 | ## Kotlin Gradle Plugin 43 | 44 | 对于已经使用Gradle构建系统的插件,或者需要对Kotlin构建过程进行精确控制的插件,我们建议使用`kotlin-gradle-plugin`。 这个Gradle插件以可控和可复制的方式极大地简化了Kotlin项目的构建。 45 | 46 | 您的build.gradle文件可能如下所示: 47 | ```groovy 48 | plugins { 49 | id "java" 50 | id "org.jetbrains.kotlin.jvm" version "1.3.72" 51 | id "org.jetbrains.intellij" version "0.4.21" 52 | } 53 | 54 | apply plugin: "kotlin" 55 | apply plugin: "org.jetbrains.intellij" 56 | 57 | group "com.example" 58 | version "0.0.1" 59 | 60 | sourceCompatibility = 1.8 61 | targetCompatibility = 1.8 62 | 63 | compileKotlin { 64 | kotlinOptions.jvmTarget = "1.8" 65 | } 66 | compileTestKotlin { 67 | kotlinOptions.jvmTarget = "1.8" 68 | } 69 | 70 | repositories { 71 | mavenCentral() 72 | } 73 | 74 | dependencies { 75 | implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72") 76 | } 77 | 78 | intellij { 79 | version = "2020.1" 80 | pluginName = "Example" 81 | updateSinceUntilBuild = false 82 | } 83 | ``` 84 | 85 | ### Use Kotlin to Write Gradle Script 86 | 87 | 从4.4开始,Gradle支持build.gradle.kts,这是用Kotlin编写的build.gradle的替代方案。 88 | 89 | 有很多不错的资源可供您学习如何使用Kotlin脚本为IntelliJ插件编写构建脚本,例如intellij-rust,julia-intellij,covscript-intellij或zig-intellij。 90 | 91 | build.gradle.kts基本上看起来像: 92 | ```groovy 93 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 94 | 95 | plugins { 96 | id("java") 97 | id("org.jetbrains.kotlin.jvm") version "1.3.72" 98 | id("org.jetbrains.intellij") version "0.4.21" 99 | } 100 | 101 | group = "com.your.company.name" 102 | version = "0.1-SNAPSHOT" 103 | 104 | tasks.withType { 105 | sourceCompatibility = "1.8" 106 | targetCompatibility = "1.8" 107 | } 108 | listOf("compileKotlin", "compileTestKotlin").forEach { 109 | tasks.getByName(it) { 110 | kotlinOptions.jvmTarget = "1.8" 111 | } 112 | } 113 | 114 | repositories { 115 | mavenCentral() 116 | } 117 | 118 | dependencies { 119 | implementation(kotlin("stdlib-jdk8")) 120 | } 121 | 122 | intellij { 123 | version = "2020.1" 124 | pluginName = 'Example' 125 | updateSinceUntilBuild = false 126 | } 127 | ``` 128 | 129 | ## UI in Kotlin 130 | 131 | 用Kotlin创建用户界面的最佳方法是使用[类型安全的DSL](https://jetbrains.org/intellij/sdk/docs/user_interface_components/kotlin_ui_dsl.html)来构建forms。 当前不支持与Kotlin一起使用GUI设计器 132 | 133 | ## Handling Kotlin Code 134 | 135 | 如果插件处理Kotlin代码(例如提供检查),则需要添加对Kotlin插件(Plugin ID `org.jetbrains.kotlin`)的依赖。 136 | 137 | ## 警告 138 | 139 | 插件必须使用Kotlin类在插件配置文件中实现声明。 在注册extension时,平台使用依赖项注入框架来实例化这些类。 因此,插件不得使用Kotlin对象来实现任何`plugin.xml`声明。 140 | 141 | ## Examples 142 | 143 | 有许多基于IntelliJ平台构建的开源Kotlin项目。 有关可利用IntelliJ平台构建开发人员工具的Kotlin语言的最新示例和应用程序的现成资源,开发人员可以从以下项目中获得启发: 144 | 145 | [IntelliJ-presentation-assistant](https://github.com/chashnikov/IntelliJ-presentation-assistant) 146 | 147 | [Rust](https://github.com/intellij-rust/intellij-rust) 148 | 149 | [HashiCorp Terraform / HCL language support](https://github.com/VladRassokhin/intellij-hcl) 150 | 151 | [TeXiFy IDEA](https://github.com/Hannah-Sten/TeXiFy-IDEA) 152 | 153 | [Makefile support](https://github.com/kropp/intellij-makefile) 154 | 155 | ## 参考文献 156 | 157 | [Kotlin for Plugin Developers](https://jetbrains.org/intellij/sdk/docs/tutorials/kotlin.html) 158 | 159 | [MvpAutoCodePlus](https://github.com/longforus/MvpAutoCodePlus) 160 | -------------------------------------------------------------------------------- /IdeaPluginStudy/src/main/java/com/lkl/plugin/codegenerator/config/MemberSelectionConfig.java: -------------------------------------------------------------------------------- 1 | package com.lkl.plugin.codegenerator.config; 2 | 3 | import javax.xml.bind.annotation.XmlAccessType; 4 | import javax.xml.bind.annotation.XmlAccessorType; 5 | import javax.xml.bind.annotation.XmlRootElement; 6 | 7 | @XmlRootElement(name = "memberSelection") 8 | @XmlAccessorType(XmlAccessType.FIELD) 9 | public class MemberSelectionConfig implements PipelineStep { 10 | public boolean filterConstantField = true; 11 | public boolean filterEnumField = false; 12 | public boolean filterTransientModifier = false; 13 | public boolean filterStaticModifier = true; 14 | public boolean filterLoggers = true; 15 | public String filterFieldName = ""; 16 | public String filterFieldType = ""; 17 | public String filterMethodName = ""; 18 | public String filterMethodType = ""; 19 | public boolean enableMethods = false; 20 | public String providerTemplate = DEFAULT_TEMPLATE; 21 | public boolean allowMultiSelection = true; 22 | public boolean allowEmptySelection = true; 23 | public int sortElements = 0; 24 | public String postfix = ""; 25 | public boolean enabled = true; 26 | 27 | @Override public String type() { 28 | return "member-selection"; 29 | } 30 | 31 | @Override 32 | public String postfix() { 33 | return postfix; 34 | } 35 | 36 | @Override 37 | public void postfix(String postfix) { 38 | this.postfix = postfix; 39 | } 40 | 41 | @Override 42 | public boolean enabled() { 43 | return enabled; 44 | } 45 | 46 | @Override 47 | public void enabled(boolean enabled) { 48 | this.enabled = enabled; 49 | } 50 | 51 | @Override 52 | public boolean equals(Object o) { 53 | if (this == o) return true; 54 | if (o == null || getClass() != o.getClass()) return false; 55 | 56 | MemberSelectionConfig that = (MemberSelectionConfig) o; 57 | 58 | if (filterConstantField != that.filterConstantField) return false; 59 | if (filterEnumField != that.filterEnumField) return false; 60 | if (filterTransientModifier != that.filterTransientModifier) return false; 61 | if (filterStaticModifier != that.filterStaticModifier) return false; 62 | if (filterLoggers != that.filterLoggers) return false; 63 | if (enableMethods != that.enableMethods) return false; 64 | if (allowMultiSelection != that.allowMultiSelection) return false; 65 | if (allowEmptySelection != that.allowEmptySelection) return false; 66 | if (sortElements != that.sortElements) return false; 67 | if (enabled != that.enabled) return false; 68 | if (filterFieldName != null ? !filterFieldName.equals(that.filterFieldName) : that.filterFieldName != null) 69 | return false; 70 | if (filterFieldType != null ? !filterFieldType.equals(that.filterFieldType) : that.filterFieldType != null) 71 | return false; 72 | if (filterMethodName != null ? !filterMethodName.equals(that.filterMethodName) : that.filterMethodName != null) 73 | return false; 74 | if (filterMethodType != null ? !filterMethodType.equals(that.filterMethodType) : that.filterMethodType != null) 75 | return false; 76 | if (providerTemplate != null ? !providerTemplate.equals(that.providerTemplate) : that.providerTemplate != null) 77 | return false; 78 | return postfix != null ? postfix.equals(that.postfix) : that.postfix == null; 79 | } 80 | 81 | @Override 82 | public int hashCode() { 83 | int result = (filterConstantField ? 1 : 0); 84 | result = 31 * result + (filterEnumField ? 1 : 0); 85 | result = 31 * result + (filterTransientModifier ? 1 : 0); 86 | result = 31 * result + (filterStaticModifier ? 1 : 0); 87 | result = 31 * result + (filterLoggers ? 1 : 0); 88 | result = 31 * result + (filterFieldName != null ? filterFieldName.hashCode() : 0); 89 | result = 31 * result + (filterFieldType != null ? filterFieldType.hashCode() : 0); 90 | result = 31 * result + (filterMethodName != null ? filterMethodName.hashCode() : 0); 91 | result = 31 * result + (filterMethodType != null ? filterMethodType.hashCode() : 0); 92 | result = 31 * result + (enableMethods ? 1 : 0); 93 | result = 31 * result + (providerTemplate != null ? providerTemplate.hashCode() : 0); 94 | result = 31 * result + (allowMultiSelection ? 1 : 0); 95 | result = 31 * result + (allowEmptySelection ? 1 : 0); 96 | result = 31 * result + sortElements; 97 | result = 31 * result + (postfix != null ? postfix.hashCode() : 0); 98 | result = 31 * result + (enabled ? 1 : 0); 99 | return result; 100 | } 101 | 102 | private static String DEFAULT_TEMPLATE = "## set `availableMembers` to provide the members to select\n" 103 | + "## set `selectedMembers` to select the members initially, set nothing to select all\n" 104 | + "## Note that it should be type List or List\n" 105 | + "## And the selected result will be\n" 106 | + "## - fields1: List where `1` is the step number that you specified\n" 107 | + "## - methods1: List\n" 108 | + "## - members: List\n" 109 | + "#set($availableMembers = $class0.members)\n"; 110 | 111 | } 112 | -------------------------------------------------------------------------------- /docs/base/helloWorld.md: -------------------------------------------------------------------------------- 1 | # 编写你的第一个plugin Hello World 2 | 3 | 编程入门从Hello World开始。 4 | 5 | * [下载IntelliJ IDEA](#下载IntelliJIDEA) 6 | * [创建项目](#创建项目) 7 | * [创建Action](#创建Action) 8 | * [plugin.xml](#pluginxml) 9 | * [运行](#运行) 10 | * [卸载插件](#卸载插件) 11 | * [打包插件并在AndroidStudio中安装](#打包插件并在AndroidStudio中安装) 12 | 13 | 通常我们开发的IntelliJ平台插件主要分为如下几类: 14 | 15 | * **自定义编程语言的支持(Custom language support)**:包括语法高亮、文件类型识别、代码格式化、代码查看和自动补全等等 16 | * **框架集成(Framework integration)**:其实就是类似基于IntelliJ开发一个IDE出来,比如AndroidStudio 将Android SDK集成进IntelliJ。其他的插件如Java EE中的Spring、Struts等framework集成到IntelliJ。使用户在IntelliJ上面使用特定的框架更方便。 17 | * **工具集成(Tool integration)**:对IntelliJ定制一些个性化或者是实用的工具。 18 | * **附加UI(User interface add-ons)**:对标准的UI界面进行修改,如在编辑框里加一个背景图片等。 19 | 20 | ## 下载IntelliJ IDEA 21 | 22 | > https://www.jetbrains.com/idea/ 23 | 24 | ## 创建项目 25 | 26 | 选择“**File>New>Project…**”,将Project选择为**IntelliJ Platform Plugin**,然后再点击Next。如下图所示: 27 | 28 | ![](imgs/helloWorld/newPlugin1.png) 29 | 30 | 填写Project名称及项目保存路径,其中Project Name可以认为是插件名称。点击Finish,如下图所示: 31 | 32 | ![](imgs/helloWorld/newPlugin2.png) 33 | 34 | 完成后,创建的项目结构如下所示: 35 | 36 | ![](imgs/helloWorld/projectStructure.png) 37 | 38 | 我们比较关心的主要是`src`目录和`resources/META-INF/plugin.xml`文件。`src`目录存放的是插件对应的Java源码,`resources/META-INF/plugin.xml`是配置Action的文件,关于Action后面讲,现在暂时可以将`resources/META-INF/plugin.xml`看成是插件的配置文件。 39 | 40 | ## 创建Action 41 | 42 | 我们在IntelliJ自定义的插件可以添加到菜单项目(如右键菜单中)或者是放在工具栏中。当用户点击时触发一个动作事件,IntelliJ则会回调`AnAction`类的`actionPerformed`函数。因此我们只需重写`actionPerformed`函数即可。 43 | 在`src`目录中创建包名:`com.lkl.plugin`,然后,在`com.lkl.plugin`中右键 New -> Action 创建一个Action,类为HelloWorldPlugin.java,如下图所示: 44 | 45 | ![](imgs/helloWorld/createAction.png) 46 | 47 | HelloWorldPlugin继承`AnAction`类,并重写`actionPerformed`函数 48 | 49 | ```java 50 | package com.lkl.plugin.base; 51 | 52 | import com.intellij.openapi.actionSystem.AnAction; 53 | import com.intellij.openapi.actionSystem.AnActionEvent; 54 | import com.intellij.openapi.actionSystem.PlatformDataKeys; 55 | import com.intellij.openapi.project.Project; 56 | import com.intellij.openapi.ui.Messages; 57 | 58 | /** 59 | * Created by likunlun on 2020/7/11. 60 | */ 61 | public class HelloWorldPlugin extends AnAction { 62 | 63 | @Override 64 | public void actionPerformed(AnActionEvent e) { 65 | // TODO: insert action logic here 66 | Project project = e.getData(PlatformDataKeys.PROJECT); 67 | Messages.showMessageDialog(project, "Hello World!", "Information", Messages.getInformationIcon()); 68 | } 69 | } 70 | ``` 71 | 72 | ## plugin.xml 73 | 74 | 通过上一步生成的Action会在`plugin.xml`中的``标签中添加``子标签,如下所示: 75 | 76 | ```xml 77 | 78 | 79 | 81 | 82 | 83 | 84 | 85 | ``` 86 | 87 | ``标签属性的简单说明: 88 | 89 | > **id**:作为``标签的唯一标识。一般以`<项目名>.<类名>`方式。 90 | > 91 | > **class**:即我们自定义的`AnAction`类 92 | > 93 | > **text**:显示的文字,如我们自定义的插件放在菜单列表中,这个文字就是对应的菜单项 94 | > 95 | > **description**:对这个`AnAction`的描述 96 | 97 | 98 | 另外还有``标签,这个标签指定我们自定义的插件应该放入到哪个菜单下面。在IntelliJ IDEA菜单栏中有很多菜单如File、Edit、View、Navigate、Code、……、Help等。他们的ID一般是菜单名+Menu的方式。比如,我们想将我们自定义的插件放到Help菜单中,作为Help菜单的子选项。那么在``标签中指定`group-id="HelpMenu"`。``标签的anchor属性用于描述位置,主要有四个选项:`first、last、before、after`。他们的含义如下: 99 | 100 | > first:放在最前面 101 | > 102 | > last:放在最后 103 | > 104 | > before:放在relative-to-action属性指定的ID的前面 105 | > 106 | > after:放在relative-to-action属性指定的ID的后面 107 | 108 | `relative-to-action`也是``的属性。 109 | 110 | ``标签用于描述快捷键,主要关注2个属性:`keymap`和`first-keystroke`。`keymap`使用默认值(`$default`)就好,`first-keystroke`用于指定快捷键。 111 | 112 | ## 运行 113 | 114 | 点击运行。会发现,运行时是自动再启动新的IntelliJ IDEA。而新启动的IntelliJ IDEA由于没有可打开的项目会停留在如下界面: 115 | 116 | ![](imgs/helloWorld/welcome.png) 117 | 118 | 为了能查看到我们的插件,可以点击Create New Project或者是导入项目,总之,让它正确进入到开发界面就好。 119 | 120 | 接下来,点击help菜单,会看到如下: 121 | 122 | ![](imgs/helloWorld/helpMenu.png) 123 | 124 | 点击·”HelloWorld”项,运行如下: 125 | 126 | ![](imgs/helloWorld/message.png) 127 | 128 | ## 卸载插件 129 | 130 | 当我们按照上面的方面再创建一个插件时,发现上一次的插件还会出现。而且我们创建的新的插件不会出现,这是什么原因呢?这主要是,我们没有修改插件名称,并且没有修改版本。这样的话自然就没有覆盖原先的插件了。 131 | 132 | 因此我们有2种方法: 133 | * 第一种就是将原来的插件卸载 134 | * 第二种就是将新建的插件名称与原先的区分开来(在plugin.xml中 标签中指定) 135 | 136 | 将原来的插件卸载,首先,点击“File>Settings>Plugins”,如下图: 137 | 138 | ![](imgs/helloWorld/uninstallPlugin.png) 139 | 140 | 找到插件名称,这里也就是`“Plugin display name here”`,因为一开始我们没有修改插件名称,这个名词是自动生成的。然后点击`Uninstall`,最后重启或者是关闭IntelliJ IDEA完成卸载。 141 | 142 | ## 打包插件并在AndroidStudio中安装 143 | 144 | 在IntelliJ中打包。点击`“Build > Prepare Plugin Module 'IdeaPluginStudy' For Deployment”`,如下图: 145 | 146 | ![](imgs/helloWorld/buildDeployment.png) 147 | 148 | 这时在 IdeaPluginStudy 项目中多了一个`IdeaPluginStudy.jar`文件,如下图: 149 | 150 | ![](imgs/helloWorld/buildDeployment1.png) 151 | 152 | 这个文件即为我们导出的插件。接下来打开AndroidStudio,点击`“File>Settings>Plugins”` 153 | 154 | ![](imgs/helloWorld/installPlugin.png) 155 | 156 | 点击“install plugin from disk…”,将 IdeaPluginStudy.jar包加入即可完成安装。 --------------------------------------------------------------------------------