1.0.0
This commit is contained in:
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
**/.idea/*
|
||||||
|
!**/.idea/runConfigurations
|
||||||
|
!**/.idea/scopes
|
||||||
|
|
||||||
|
.gradle
|
||||||
|
build
|
||||||
|
|
||||||
|
.qodana
|
||||||
21
.idea/runConfigurations/buildPlugin.xml
generated
Normal file
21
.idea/runConfigurations/buildPlugin.xml
generated
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="buildPlugin" type="GradleRunConfiguration" factoryName="Gradle">
|
||||||
|
<ExternalSystemSettings>
|
||||||
|
<option name="executionName" />
|
||||||
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
|
<option name="externalSystemIdString" value="GRADLE" />
|
||||||
|
<option name="scriptParameters" value="buildPlugin -x test" />
|
||||||
|
<option name="taskDescriptions">
|
||||||
|
<list />
|
||||||
|
</option>
|
||||||
|
<option name="taskNames">
|
||||||
|
<list />
|
||||||
|
</option>
|
||||||
|
<option name="vmOptions" />
|
||||||
|
</ExternalSystemSettings>
|
||||||
|
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||||
|
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||||
|
<DebugAllEnabled>false</DebugAllEnabled>
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
21
.idea/runConfigurations/runIde.xml
generated
Normal file
21
.idea/runConfigurations/runIde.xml
generated
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="runIde" type="GradleRunConfiguration" factoryName="Gradle">
|
||||||
|
<ExternalSystemSettings>
|
||||||
|
<option name="executionName" />
|
||||||
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
|
<option name="externalSystemIdString" value="GRADLE" />
|
||||||
|
<option name="scriptParameters" value=":runIde" />
|
||||||
|
<option name="taskDescriptions">
|
||||||
|
<list />
|
||||||
|
</option>
|
||||||
|
<option name="taskNames">
|
||||||
|
<list />
|
||||||
|
</option>
|
||||||
|
<option name="vmOptions" />
|
||||||
|
</ExternalSystemSettings>
|
||||||
|
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||||
|
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||||
|
<DebugAllEnabled>false</DebugAllEnabled>
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
10
README.md
10
README.md
@@ -0,0 +1,10 @@
|
|||||||
|
# Show Comment Plugin
|
||||||
|
IDEA 智能注释插件
|
||||||
|
|
||||||
|
English Note:
|
||||||
|
- Show javadoc comments for calling methods at the end of the line.
|
||||||
|
- Show javadoc comments in the Project view Tree structure.
|
||||||
|
|
||||||
|
Chinese Note:
|
||||||
|
- 在行末显示调用方法的文档注释。
|
||||||
|
- 在结构树显示文档注释。
|
||||||
50
build.gradle
Normal file
50
build.gradle
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
plugins {
|
||||||
|
id 'org.jetbrains.intellij' version '1.3.1'
|
||||||
|
id 'java'
|
||||||
|
}
|
||||||
|
|
||||||
|
group 'io.github.linwancen'
|
||||||
|
version '1.0.0.' + (new Date().format('yyyy.MM.dd_HH.mm'))
|
||||||
|
|
||||||
|
apply plugin: 'java'
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
|
||||||
|
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
|
||||||
|
}
|
||||||
|
|
||||||
|
// See https://github.com/JetBrains/gradle-intellij-plugin/
|
||||||
|
intellij {
|
||||||
|
version = ideaVersion
|
||||||
|
plugins = ['java']
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType(JavaCompile) {
|
||||||
|
options.encoding = 'UTF-8'
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType(Javadoc) {
|
||||||
|
options.encoding = 'UTF-8'
|
||||||
|
}
|
||||||
|
|
||||||
|
patchPluginXml {
|
||||||
|
// The performance of 2019.3 has been greatly improved.
|
||||||
|
// change plugins without restarting the IDE in 2020.1.
|
||||||
|
sinceBuild = '201.1'
|
||||||
|
untilBuild = ''
|
||||||
|
changeNotes = """
|
||||||
|
Code optimization | 代码优化
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
|
|
||||||
|
publishPlugin {
|
||||||
|
token = System.getenv("PUBLISH_TOKEN")
|
||||||
|
}
|
||||||
1
gradle.properties
Normal file
1
gradle.properties
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ideaVersion=2020.1
|
||||||
2
settings.gradle
Normal file
2
settings.gradle
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
rootProject.name = 'show-comment'
|
||||||
|
|
||||||
187
src/main/java/io/github/linwancen/plugin/comment/LineEnd.java
Normal file
187
src/main/java/io/github/linwancen/plugin/comment/LineEnd.java
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
package io.github.linwancen.plugin.comment;
|
||||||
|
|
||||||
|
import com.intellij.lang.java.JavaLanguage;
|
||||||
|
import com.intellij.openapi.editor.DefaultLanguageHighlighterColors;
|
||||||
|
import com.intellij.openapi.editor.Document;
|
||||||
|
import com.intellij.openapi.editor.EditorLinePainter;
|
||||||
|
import com.intellij.openapi.editor.LineExtensionInfo;
|
||||||
|
import com.intellij.openapi.editor.colors.EditorColorsManager;
|
||||||
|
import com.intellij.openapi.editor.markup.TextAttributes;
|
||||||
|
import com.intellij.openapi.project.DumbService;
|
||||||
|
import com.intellij.openapi.project.Project;
|
||||||
|
import com.intellij.openapi.util.TextRange;
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
|
import com.intellij.psi.*;
|
||||||
|
import com.intellij.psi.impl.source.PsiJavaCodeReferenceElementImpl;
|
||||||
|
import com.intellij.psi.javadoc.PsiDocComment;
|
||||||
|
import com.intellij.psi.util.PsiTreeUtil;
|
||||||
|
import com.intellij.ui.Gray;
|
||||||
|
import com.intellij.ui.JBColor;
|
||||||
|
import io.github.linwancen.plugin.comment.settings.AppSettingsState;
|
||||||
|
import io.github.linwancen.plugin.comment.utils.CommentFactory;
|
||||||
|
import io.github.linwancen.plugin.comment.utils.PsiDocCommentUtils;
|
||||||
|
import io.github.linwancen.plugin.comment.utils.PsiMethodCommentFactory;
|
||||||
|
import io.github.linwancen.plugin.comment.utils.SkipUtils;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
public class LineEnd extends EditorLinePainter {
|
||||||
|
@Override
|
||||||
|
public @Nullable Collection<LineExtensionInfo> getLineExtensions(@NotNull Project project,
|
||||||
|
@NotNull VirtualFile file, int lineNumber) {
|
||||||
|
if (!AppSettingsState.getInstance().showLineEndComment) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (DumbService.isDumb(project)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
FileViewProvider viewProvider = PsiManager.getInstance(project).findViewProvider(file);
|
||||||
|
PsiElement psiElement = psiElementFrom(viewProvider, lineNumber);
|
||||||
|
PsiDocComment docComment = psiDocCommentFrom(psiElement);
|
||||||
|
String comment = PsiDocCommentUtils.getCommentText(docComment);
|
||||||
|
if (comment == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
LineExtensionInfo info = new LineExtensionInfo(" //" + comment, getNormalAttributes());
|
||||||
|
return Collections.singletonList(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private PsiDocComment psiDocCommentFrom(PsiElement psiElement) {
|
||||||
|
if (psiElement == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (psiElement instanceof PsiClass) {
|
||||||
|
PsiClass psiClass = (PsiClass) psiElement;
|
||||||
|
if (SkipUtils.skip(psiClass)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return CommentFactory.fromSrcOrByteCode(psiClass);
|
||||||
|
}
|
||||||
|
if (psiElement instanceof PsiMethod) {
|
||||||
|
PsiMethod psiMethod = (PsiMethod) psiElement;
|
||||||
|
if (SkipUtils.skip(psiMethod.getContainingClass())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return PsiMethodCommentFactory.from(psiMethod);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static final String[] KEYS = {
|
||||||
|
"if",
|
||||||
|
"for",
|
||||||
|
"new",
|
||||||
|
"=",
|
||||||
|
"return",
|
||||||
|
};
|
||||||
|
|
||||||
|
private static @Nullable PsiElement psiElementFrom(FileViewProvider viewProvider, int lineNumber) {
|
||||||
|
if (viewProvider == null || !viewProvider.hasLanguage(JavaLanguage.INSTANCE)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Document document = viewProvider.getDocument();
|
||||||
|
if (document == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (document.getLineCount() < lineNumber) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int startOffset = document.getLineStartOffset(lineNumber);
|
||||||
|
int endOffset = document.getLineEndOffset(lineNumber);
|
||||||
|
String text = document.getText(new TextRange(startOffset, endOffset));
|
||||||
|
int offset = 0;
|
||||||
|
for (String s : KEYS) {
|
||||||
|
int i = text.indexOf(s);
|
||||||
|
if (i > 0) {
|
||||||
|
offset += (i + s.length());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
text = text.substring(offset);
|
||||||
|
boolean startWithSymbol = false;
|
||||||
|
char[] chars = text.toCharArray();
|
||||||
|
// skip symbol and space
|
||||||
|
for (char c : chars) {
|
||||||
|
if (Character.isLetter(c)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!Character.isSpaceChar(c)) {
|
||||||
|
startWithSymbol = true;
|
||||||
|
}
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
offset += startOffset;
|
||||||
|
if (startWithSymbol) {
|
||||||
|
startOffset = 0;
|
||||||
|
}
|
||||||
|
PsiElement element = viewProvider.findElementAt(offset, JavaLanguage.INSTANCE);
|
||||||
|
if (!(element instanceof PsiIdentifier)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return parentElementOf(element, startOffset, endOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static PsiElement parentElementOf(PsiElement element, int startOffset, int endOffset) {
|
||||||
|
// method call
|
||||||
|
PsiMethodCallExpression call =
|
||||||
|
PsiTreeUtil.getParentOfType(element, PsiMethodCallExpression.class, false, startOffset);
|
||||||
|
if (call != null) {
|
||||||
|
// skip double comment when method call in new line:
|
||||||
|
// someObject // someMethodComment
|
||||||
|
// .someMethod(); // someMethodComment
|
||||||
|
if ((call.getNode().getStartOffset() + call.getNode().getTextLength()) > endOffset) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return call.resolveMethod();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// new
|
||||||
|
PsiNewExpression newExp = PsiTreeUtil.getParentOfType(element, PsiNewExpression.class, false, startOffset);
|
||||||
|
if (newExp != null) {
|
||||||
|
PsiMethod psiMethod = newExp.resolveMethod();
|
||||||
|
if (psiMethod != null) {
|
||||||
|
return psiMethod;
|
||||||
|
}
|
||||||
|
PsiJavaCodeReferenceElement classReference = newExp.getClassReference();
|
||||||
|
if (classReference != null) {
|
||||||
|
return classReference.resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ::
|
||||||
|
PsiMethodReferenceExpression ref =
|
||||||
|
PsiTreeUtil.getParentOfType(element, PsiMethodReferenceExpression.class, false, startOffset);
|
||||||
|
if (ref != null) {
|
||||||
|
return ref.resolve();
|
||||||
|
}
|
||||||
|
// SomeClass // SomeClassComment
|
||||||
|
PsiJavaCodeReferenceElementImpl code =
|
||||||
|
PsiTreeUtil.getParentOfType(element, PsiJavaCodeReferenceElementImpl.class, false, startOffset);
|
||||||
|
if (code != null) {
|
||||||
|
return code.resolve();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TextAttributes getNormalAttributes() {
|
||||||
|
EditorColorsManager colorsManager = EditorColorsManager.getInstance();
|
||||||
|
TextAttributes attributes = colorsManager.getGlobalScheme()
|
||||||
|
.getAttributes(DefaultLanguageHighlighterColors.LINE_COMMENT);
|
||||||
|
if (attributes == null || attributes.getForegroundColor() == null) {
|
||||||
|
JBColor jbColor = new JBColor(() -> Gray._183);
|
||||||
|
return new TextAttributes(jbColor, null, null, null, Font.ITALIC);
|
||||||
|
} else {
|
||||||
|
// Sometimes it becomes the same color as the end of the line char, so use italic to distinguish
|
||||||
|
attributes.setFontType(Font.ITALIC);
|
||||||
|
}
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
}
|
||||||
105
src/main/java/io/github/linwancen/plugin/comment/Tree.java
Normal file
105
src/main/java/io/github/linwancen/plugin/comment/Tree.java
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
package io.github.linwancen.plugin.comment;
|
||||||
|
|
||||||
|
import com.intellij.ide.projectView.PresentationData;
|
||||||
|
import com.intellij.ide.projectView.ProjectViewNode;
|
||||||
|
import com.intellij.ide.projectView.ProjectViewNodeDecorator;
|
||||||
|
import com.intellij.ide.projectView.impl.nodes.*;
|
||||||
|
import com.intellij.ide.util.treeView.PresentableNodeDescriptor.ColoredFragment;
|
||||||
|
import com.intellij.openapi.project.DumbService;
|
||||||
|
import com.intellij.openapi.project.Project;
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
|
import com.intellij.packageDependencies.ui.PackageDependenciesNode;
|
||||||
|
import com.intellij.psi.*;
|
||||||
|
import com.intellij.psi.javadoc.PsiDocComment;
|
||||||
|
import com.intellij.ui.ColoredTreeCellRenderer;
|
||||||
|
import com.intellij.ui.SimpleTextAttributes;
|
||||||
|
import io.github.linwancen.plugin.comment.settings.AppSettingsState;
|
||||||
|
import io.github.linwancen.plugin.comment.utils.CommentFactory;
|
||||||
|
import io.github.linwancen.plugin.comment.utils.PsiDocCommentUtils;
|
||||||
|
import io.github.linwancen.plugin.comment.utils.PsiMethodCommentFactory;
|
||||||
|
import io.github.linwancen.plugin.comment.utils.PsiPackageCommentFactory;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Tree implements ProjectViewNodeDecorator {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void decorate(ProjectViewNode node, PresentationData data) {
|
||||||
|
if (!AppSettingsState.getInstance().showTreeComment) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Project project = node.getProject();
|
||||||
|
if (project == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (DumbService.isDumb(project)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PsiDocComment docComment = psiDocCommentOf(node, project);
|
||||||
|
if (docComment == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String commentText = PsiDocCommentUtils.getCommentText(docComment);
|
||||||
|
if (commentText == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<ColoredFragment> coloredText = data.getColoredText();
|
||||||
|
if (coloredText.isEmpty()) {
|
||||||
|
data.addText(data.getPresentableText(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
|
||||||
|
}
|
||||||
|
data.addText(commentText, SimpleTextAttributes.GRAY_ATTRIBUTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private PsiDocComment psiDocCommentOf(ProjectViewNode<?> node, Project project) {
|
||||||
|
if (node instanceof PsiFileNode) {
|
||||||
|
PsiFile psiFile = ((PsiFileNode) node).getValue();
|
||||||
|
return CommentFactory.from(psiFile);
|
||||||
|
}
|
||||||
|
if (node instanceof PsiDirectoryNode) {
|
||||||
|
PsiDirectory psiDirectory = ((PsiDirectoryNode) node).getValue();
|
||||||
|
return PsiPackageCommentFactory.from(psiDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node instanceof PsiMethodNode) {
|
||||||
|
// On Show Members
|
||||||
|
PsiMethod psiMethod = ((PsiMethodNode) node).getValue();
|
||||||
|
return PsiMethodCommentFactory.from(psiMethod);
|
||||||
|
}
|
||||||
|
if (node instanceof PsiFieldNode) {
|
||||||
|
// On Show Members
|
||||||
|
PsiField psiField = ((PsiFieldNode) node).getValue();
|
||||||
|
return psiField.getDocComment();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node instanceof ClassTreeNode) {
|
||||||
|
// On Packages View, Project Files View, Show Members
|
||||||
|
PsiClass psiClass = ((ClassTreeNode) node).getValue();
|
||||||
|
return psiClass.getDocComment();
|
||||||
|
}
|
||||||
|
if (node instanceof PackageElementNode) {
|
||||||
|
// On Packages View
|
||||||
|
PsiPackage psiPackage = ((PackageElementNode) node).getValue().getPackage();
|
||||||
|
return PsiPackageCommentFactory.from(psiPackage);
|
||||||
|
}
|
||||||
|
|
||||||
|
// On Packages View, Project Files View
|
||||||
|
VirtualFile virtualFile = node.getVirtualFile();
|
||||||
|
if (virtualFile == null || !virtualFile.isDirectory()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
PsiDirectory psiDirectory = PsiManager.getInstance(project).findDirectory(virtualFile);
|
||||||
|
if (psiDirectory == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return PsiPackageCommentFactory.from(psiDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void decorate(PackageDependenciesNode node, ColoredTreeCellRenderer cellRenderer) {
|
||||||
|
// not need
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package io.github.linwancen.plugin.comment.settings;
|
||||||
|
|
||||||
|
import com.intellij.ui.IdeBorderFactory;
|
||||||
|
import com.intellij.ui.components.JBCheckBox;
|
||||||
|
import com.intellij.util.ui.FormBuilder;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
|
||||||
|
public class AppSettingsComponent {
|
||||||
|
|
||||||
|
private final JPanel myMainPanel;
|
||||||
|
private final JBCheckBox showTreeComment = new JBCheckBox("Show tree comment ");
|
||||||
|
private final JBCheckBox showLineEndComment = new JBCheckBox("Show line end comment ");
|
||||||
|
|
||||||
|
public AppSettingsComponent() {
|
||||||
|
JPanel comment = FormBuilder.createFormBuilder()
|
||||||
|
.addComponent(showTreeComment, 1)
|
||||||
|
.addComponent(showLineEndComment, 1)
|
||||||
|
.addComponentFillVertically(new JPanel(), 0)
|
||||||
|
.getPanel();
|
||||||
|
comment.setBorder(IdeBorderFactory.createTitledBorder("Comment"));
|
||||||
|
|
||||||
|
myMainPanel = FormBuilder.createFormBuilder()
|
||||||
|
.addComponent(comment, 1)
|
||||||
|
.addComponentFillVertically(new JPanel(), 0)
|
||||||
|
.getPanel();
|
||||||
|
}
|
||||||
|
|
||||||
|
public JPanel getPanel() {
|
||||||
|
return myMainPanel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JComponent getPreferredFocusedComponent() {
|
||||||
|
return showTreeComment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getShowTreeComment() {
|
||||||
|
return showTreeComment.isSelected();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShowTreeComment(boolean newStatus) {
|
||||||
|
showTreeComment.setSelected(newStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getShowLineEndComment() {
|
||||||
|
return showLineEndComment.isSelected();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShowLineEndComment(boolean newStatus) {
|
||||||
|
showLineEndComment.setSelected(newStatus);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package io.github.linwancen.plugin.comment.settings;
|
||||||
|
|
||||||
|
import com.intellij.openapi.options.Configurable;
|
||||||
|
import org.jetbrains.annotations.Nls;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
|
||||||
|
public class AppSettingsConfigurable implements Configurable {
|
||||||
|
|
||||||
|
private AppSettingsComponent mySettingsComponent;
|
||||||
|
|
||||||
|
@Nls(capitalization = Nls.Capitalization.Title)
|
||||||
|
@Override
|
||||||
|
public String getDisplayName() {
|
||||||
|
return "Show Comment.";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JComponent getPreferredFocusedComponent() {
|
||||||
|
return mySettingsComponent.getPreferredFocusedComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public JComponent createComponent() {
|
||||||
|
mySettingsComponent = new AppSettingsComponent();
|
||||||
|
return mySettingsComponent.getPanel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isModified() {
|
||||||
|
AppSettingsState settings = AppSettingsState.getInstance();
|
||||||
|
boolean modified = mySettingsComponent.getShowTreeComment() != settings.showTreeComment;
|
||||||
|
modified |= mySettingsComponent.getShowLineEndComment() != settings.showLineEndComment;
|
||||||
|
return modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply() {
|
||||||
|
AppSettingsState settings = AppSettingsState.getInstance();
|
||||||
|
settings.showTreeComment = mySettingsComponent.getShowTreeComment();
|
||||||
|
settings.showLineEndComment = mySettingsComponent.getShowLineEndComment();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset() {
|
||||||
|
AppSettingsState settings = AppSettingsState.getInstance();
|
||||||
|
mySettingsComponent.setShowTreeComment(settings.showTreeComment);
|
||||||
|
mySettingsComponent.setShowLineEndComment(settings.showLineEndComment);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disposeUIResources() {
|
||||||
|
mySettingsComponent = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package io.github.linwancen.plugin.comment.settings;
|
||||||
|
|
||||||
|
import com.intellij.openapi.application.ApplicationManager;
|
||||||
|
import com.intellij.openapi.components.PersistentStateComponent;
|
||||||
|
import com.intellij.openapi.components.State;
|
||||||
|
import com.intellij.openapi.components.Storage;
|
||||||
|
import com.intellij.util.xmlb.XmlSerializerUtil;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
@State(
|
||||||
|
name = "io.github.linwancen.plugin.comment.settings.AppSettingsState",
|
||||||
|
storages = @Storage("ShowCommentPlugin.xml")
|
||||||
|
)
|
||||||
|
public class AppSettingsState implements PersistentStateComponent<AppSettingsState> {
|
||||||
|
|
||||||
|
public boolean showLineEndComment = true;
|
||||||
|
public boolean showTreeComment = true;
|
||||||
|
|
||||||
|
public static AppSettingsState getInstance() {
|
||||||
|
return ApplicationManager.getApplication().getService(AppSettingsState.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public AppSettingsState getState() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadState(@NotNull AppSettingsState state) {
|
||||||
|
XmlSerializerUtil.copyBean(state, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package io.github.linwancen.plugin.comment.utils;
|
||||||
|
|
||||||
|
import com.intellij.psi.*;
|
||||||
|
import com.intellij.psi.javadoc.PsiDocComment;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public class CommentFactory {
|
||||||
|
|
||||||
|
private CommentFactory() {}
|
||||||
|
|
||||||
|
public static PsiDocComment fromSrcOrByteCode(PsiDocCommentOwner psiElement) {
|
||||||
|
PsiElement navElement = psiElement.getNavigationElement();
|
||||||
|
if (navElement instanceof PsiDocCommentOwner) {
|
||||||
|
psiElement = (PsiDocCommentOwner) navElement;
|
||||||
|
}
|
||||||
|
return psiElement.getDocComment();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static PsiDocComment from(PsiFile psiFile) {
|
||||||
|
if (!(psiFile instanceof PsiJavaFile)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
PsiJavaFile psiJavaFile = (PsiJavaFile) psiFile;
|
||||||
|
if (PsiPackage.PACKAGE_INFO_FILE.equals(psiFile.getName())) {
|
||||||
|
return PsiPackageCommentFactory.fromPackageInfoFile(psiFile);
|
||||||
|
}
|
||||||
|
PsiClass[] classes = psiJavaFile.getClasses();
|
||||||
|
if (classes.length == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
PsiClass psiClass = classes[0];
|
||||||
|
return fromSrcOrByteCode(psiClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package io.github.linwancen.plugin.comment.utils;
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
|
import com.intellij.psi.javadoc.PsiDocComment;
|
||||||
|
import com.intellij.psi.javadoc.PsiDocToken;
|
||||||
|
import com.intellij.psi.javadoc.PsiInlineDocTag;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class PsiDocCommentUtils {
|
||||||
|
|
||||||
|
private PsiDocCommentUtils() {}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static String getCommentText(@Nullable PsiDocComment psiDocComment) {
|
||||||
|
if (psiDocComment == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<String> comments = new ArrayList<>();
|
||||||
|
PsiElement[] elements = psiDocComment.getDescriptionElements();
|
||||||
|
for (PsiElement element : elements) {
|
||||||
|
if (element instanceof PsiDocToken) {
|
||||||
|
PsiDocToken psiDocToken = (PsiDocToken) element;
|
||||||
|
comments.add(psiDocToken.getText());
|
||||||
|
} else if (element instanceof PsiInlineDocTag) {
|
||||||
|
PsiInlineDocTag psiInlineDocTag = (PsiInlineDocTag) element;
|
||||||
|
PsiElement[] children = psiInlineDocTag.getChildren();
|
||||||
|
if (children.length > 2) {
|
||||||
|
comments.add(children[2].getText());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (comments.size() > 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (comments.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
StringBuilder sb = new StringBuilder(comments.get(0).trim());
|
||||||
|
if (sb.length() == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (comments.size() > 1) {
|
||||||
|
sb.append(" ").append(comments.get(1).trim().replace("<br>", ""));
|
||||||
|
}
|
||||||
|
sb.insert(0, " ");
|
||||||
|
sb.append(" ");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package io.github.linwancen.plugin.comment.utils;
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiClass;
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
|
import com.intellij.psi.PsiField;
|
||||||
|
import com.intellij.psi.PsiMethod;
|
||||||
|
import com.intellij.psi.javadoc.PsiDocComment;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public class PsiMethodCommentFactory {
|
||||||
|
|
||||||
|
private PsiMethodCommentFactory() {}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static PsiDocComment from(PsiMethod psiMethod) {
|
||||||
|
// .class
|
||||||
|
PsiElement navElement = psiMethod.getNavigationElement();
|
||||||
|
if (navElement instanceof PsiMethod) {
|
||||||
|
psiMethod = (PsiMethod) navElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
PsiDocComment docComment = psiMethod.getDocComment();
|
||||||
|
if (docComment != null) {
|
||||||
|
return docComment;
|
||||||
|
}
|
||||||
|
|
||||||
|
// supper
|
||||||
|
PsiDocComment superDoc = supperMethodComment(psiMethod);
|
||||||
|
if (superDoc != null) {
|
||||||
|
return superDoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get/set/is - PropertyDescriptor getReadMethod() getWriteMethod()
|
||||||
|
return propMethodComment(psiMethod, psiMethod.getContainingClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static PsiDocComment supperMethodComment(PsiMethod psiMethod) {
|
||||||
|
PsiMethod[] superMethods = psiMethod.findSuperMethods();
|
||||||
|
for (PsiMethod superMethod : superMethods) {
|
||||||
|
PsiDocComment superDoc = from(superMethod);
|
||||||
|
if (superDoc != null) {
|
||||||
|
return superDoc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static PsiDocComment propMethodComment(PsiMethod psiMethod, PsiClass psiClass) {
|
||||||
|
if (psiClass == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String name = psiMethod.getName();
|
||||||
|
if (name.length() > 3 && (name.startsWith("get") || name.startsWith("set"))) {
|
||||||
|
name = name.substring(3);
|
||||||
|
} else if (name.length() > 2 && name.startsWith("is")) {
|
||||||
|
name = name.substring(2);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
char[] chars = name.toCharArray();
|
||||||
|
chars[0] += 32;
|
||||||
|
name = String.valueOf(chars);
|
||||||
|
PsiField fieldByName = psiClass.findFieldByName(name, false);
|
||||||
|
if (fieldByName == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return fieldByName.getDocComment();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package io.github.linwancen.plugin.comment.utils;
|
||||||
|
|
||||||
|
import com.intellij.lang.ASTNode;
|
||||||
|
import com.intellij.psi.PsiDirectory;
|
||||||
|
import com.intellij.psi.PsiFile;
|
||||||
|
import com.intellij.psi.PsiPackage;
|
||||||
|
import com.intellij.psi.impl.source.tree.JavaDocElementType;
|
||||||
|
import com.intellij.psi.impl.source.tree.JavaElementType;
|
||||||
|
import com.intellij.psi.javadoc.PsiDocComment;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public class PsiPackageCommentFactory {
|
||||||
|
|
||||||
|
private PsiPackageCommentFactory() {}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static PsiDocComment from(PsiPackage psiPackage) {
|
||||||
|
PsiDirectory[] psiDirectories = psiPackage.getDirectories();
|
||||||
|
for (PsiDirectory psiDirectory : psiDirectories) {
|
||||||
|
PsiDocComment psiDocComment = from(psiDirectory);
|
||||||
|
if (psiDocComment != null) {
|
||||||
|
return psiDocComment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static PsiDocComment from(PsiDirectory psiDirectory) {
|
||||||
|
PsiFile packageInfoFile = psiDirectory.findFile(PsiPackage.PACKAGE_INFO_FILE);
|
||||||
|
return fromPackageInfoFile(packageInfoFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static PsiDocComment fromPackageInfoFile(PsiFile packageInfoFile) {
|
||||||
|
if (packageInfoFile == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ASTNode astNode = packageInfoFile.getNode();
|
||||||
|
if (astNode == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ASTNode docCommentNode = findRelevantCommentNode(astNode);
|
||||||
|
if (docCommentNode == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (PsiDocComment) docCommentNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ASTNode findRelevantCommentNode(@NotNull ASTNode fileNode) {
|
||||||
|
ASTNode node = fileNode.findChildByType(JavaElementType.PACKAGE_STATEMENT);
|
||||||
|
if (node == null) node = fileNode.getLastChildNode();
|
||||||
|
while (node != null && node.getElementType() != JavaDocElementType.DOC_COMMENT) {
|
||||||
|
node = node.getTreePrev();
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package io.github.linwancen.plugin.comment.utils;
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiClass;
|
||||||
|
|
||||||
|
public class SkipUtils {
|
||||||
|
|
||||||
|
private SkipUtils() {}
|
||||||
|
|
||||||
|
public static boolean skip(PsiClass psiClass) {
|
||||||
|
if (psiClass == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String name = psiClass.getQualifiedName();
|
||||||
|
return name == null || name.startsWith("java");
|
||||||
|
}
|
||||||
|
}
|
||||||
37
src/main/resources/META-INF/plugin.xml
Normal file
37
src/main/resources/META-INF/plugin.xml
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<idea-plugin>
|
||||||
|
<id>io.github.linwancen.show-comment</id>
|
||||||
|
<name>Show Comment</name>
|
||||||
|
<vendor email="1498425439@qq.com" url="https://github.com/LinWanCen/show-comment">林万程</vendor>
|
||||||
|
|
||||||
|
<description><![CDATA[
|
||||||
|
English Note:
|
||||||
|
<ul>
|
||||||
|
<li>Show javadoc comments for calling methods at the end of the line.
|
||||||
|
<li>Show javadoc comments in the Project view Tree structure.
|
||||||
|
</ul>
|
||||||
|
Chinese Note:
|
||||||
|
<ul>
|
||||||
|
<li>在行末显示调用方法的文档注释。
|
||||||
|
<li>在结构树显示文档注释。
|
||||||
|
</ul>
|
||||||
|
]]></description>
|
||||||
|
|
||||||
|
<!-- please see https://plugins.jetbrains.com/docs/intellij/plugin-compatibility.html
|
||||||
|
on how to target different products -->
|
||||||
|
<depends>com.intellij.modules.platform</depends>
|
||||||
|
<depends>com.intellij.modules.java</depends>
|
||||||
|
|
||||||
|
<extensions defaultExtensionNs="com.intellij">
|
||||||
|
<editor.linePainter implementation="io.github.linwancen.plugin.comment.LineEnd" />
|
||||||
|
<projectViewNodeDecorator implementation="io.github.linwancen.plugin.comment.Tree"/>
|
||||||
|
|
||||||
|
<applicationConfigurable parentId="tools"
|
||||||
|
instance="io.github.linwancen.plugin.comment.settings.AppSettingsConfigurable"
|
||||||
|
id="io.github.linwancen.plugin.comment.settings.AppSettingsConfigurable"
|
||||||
|
displayName="Show Comment"/>
|
||||||
|
<applicationService serviceImplementation="io.github.linwancen.plugin.comment.settings.AppSettingsState"/>
|
||||||
|
</extensions>
|
||||||
|
|
||||||
|
<actions>
|
||||||
|
</actions>
|
||||||
|
</idea-plugin>
|
||||||
Reference in New Issue
Block a user