1.4 Find element right to left for end-of-line comment | 从右往左查找行末注释对象

This commit is contained in:
林万程
2022-02-21 03:13:26 +08:00
parent 74d1f9adf5
commit ef6a2c034f
9 changed files with 232 additions and 148 deletions

View File

@@ -6,16 +6,11 @@ import com.intellij.openapi.editor.EditorLinePainter;
import com.intellij.openapi.editor.LineExtensionInfo;
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.javadoc.PsiDocComment;
import com.intellij.psi.util.PsiTreeUtil;
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 io.github.linwancen.plugin.comment.utils.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -35,7 +30,7 @@ public class LineEnd extends EditorLinePainter {
return null;
}
FileViewProvider viewProvider = PsiManager.getInstance(project).findViewProvider(file);
PsiElement psiElement = psiElementFrom(viewProvider, lineNumber);
PsiElement psiElement = resolveElementFrom(viewProvider, lineNumber);
PsiDocComment docComment = psiDocCommentFrom(psiElement);
String comment = PsiDocCommentUtils.getCommentText(docComment);
if (comment == null) {
@@ -45,6 +40,25 @@ public class LineEnd extends EditorLinePainter {
return Collections.singletonList(info);
}
private static @Nullable PsiElement resolveElementFrom(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);
if (AppSettingsState.getInstance().findElementRightToLeft) {
return ResolveElementRightToLeftUtils.resolveElement(viewProvider, startOffset, endOffset);
}
return ResolveElementLeftToRightUtils.resolveElement(viewProvider, document, startOffset, endOffset);
}
@Nullable
private PsiDocComment psiDocCommentFrom(PsiElement psiElement) {
if (psiElement == null) {
@@ -73,135 +87,4 @@ public class LineEnd extends EditorLinePainter {
}
return null;
}
protected static final String[] KEYS = {
"=",
};
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);
PsiIdentifier psiIdentifier = psiIdentifier(endOffset, element);
if (psiIdentifier == null) {
return null;
}
return parentElementOf(psiIdentifier, startOffset, endOffset);
}
@Nullable
private static PsiIdentifier psiIdentifier(int endOffset, PsiElement element) {
if (element == null) {
return null;
}
while (!(element instanceof PsiIdentifier)) {
element = PsiTreeUtil.nextVisibleLeaf(element);
if (element == null) {
return null;
}
if (element.getTextRange().getEndOffset() > endOffset) {
return null;
}
}
return (PsiIdentifier) element;
}
@Nullable
private static PsiElement parentElementOf(PsiElement psiIdentifier, int startOffset, int endOffset) {
// method call
PsiMethodCallExpression call =
PsiTreeUtil.getParentOfType(psiIdentifier, 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
PsiElement newPsiElement = newMethodOrClass(psiIdentifier, startOffset);
if (newPsiElement != null) {
return newPsiElement;
}
// ::/class/field
PsiReference psiReference = parentPsiReference(psiIdentifier, endOffset);
if (psiReference != null) {
return psiReference.resolve();
}
return null;
}
@Nullable
private static PsiElement newMethodOrClass(PsiElement element, int startOffset) {
// new and Class should same line
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();
}
}
return null;
}
@Nullable
private static PsiReference parentPsiReference(PsiElement element, int endOffset) {
PsiElement parent;
while ((parent = element.getParent()) instanceof PsiReference) {
if (parent.getTextRange().getEndOffset() > endOffset) {
break;
}
element = parent;
}
if (element instanceof PsiReference) {
return (PsiReference) element;
}
return null;
}
}

View File

@@ -15,12 +15,13 @@ public class AppSettingsComponent extends AbstractSettingsComponent {
private final JBCheckBox showTreeComment = new JBCheckBox("Show tree comment ");
private final JBCheckBox showLineEndComment = new JBCheckBox("Show line end comment ");
private final ColorPanel lineEndColor = new ColorPanel();
private final JBCheckBox findElementRightToLeft = new JBCheckBox("Find element right to left");
public AppSettingsComponent() {
myMainPanel = FormBuilder.createFormBuilder()
.addComponent(showPanel(), 1)
.addComponent(colorPanel(), 1)
.addComponent(commonLineEndFilter(FormBuilder.createFormBuilder()), 1)
.addComponent(lineEndFilterPanel(), 1)
.addComponentFillVertically(new JPanel(), 0)
.getPanel();
}
@@ -44,6 +45,14 @@ public class AppSettingsComponent extends AbstractSettingsComponent {
return color;
}
@NotNull
protected JPanel lineEndFilterPanel() {
FormBuilder formBuilder = FormBuilder.createFormBuilder()
.addComponent(findElementRightToLeft)
.addSeparator();
return commonLineEndFilter(formBuilder);
}
public JPanel getPanel() {
return myMainPanel;
}
@@ -76,4 +85,12 @@ public class AppSettingsComponent extends AbstractSettingsComponent {
public void setLineEndColor(Color color) {
lineEndColor.setSelectedColor(color);
}
public boolean getFindElementRightToLeft() {
return findElementRightToLeft.isSelected();
}
public void setFindElementRightToLeft(boolean newStatus) {
findElementRightToLeft.setSelected(newStatus);
}
}

View File

@@ -40,6 +40,7 @@ public class AppSettingsConfigurable implements Configurable {
} else {
modified |= !mySettingsComponent.getLineEndColor().equals(settings.lineEndColorBright);
}
modified |= mySettingsComponent.getFindElementRightToLeft() != settings.findElementRightToLeft;
modified |= !mySettingsComponent.getLineEndInclude().equals(settings.lineEndInclude);
modified |= !mySettingsComponent.getLineEndExclude().equals(settings.lineEndExclude);
return modified;
@@ -57,6 +58,7 @@ public class AppSettingsConfigurable implements Configurable {
}
JBColor jbColor = new JBColor(settings.lineEndColorBright, settings.lineEndColorDark);
settings.lineEndTextAttr.setForegroundColor(jbColor);
settings.findElementRightToLeft = mySettingsComponent.getFindElementRightToLeft();
settings.lineEndInclude = mySettingsComponent.getLineEndInclude();
settings.lineEndExclude = mySettingsComponent.getLineEndExclude();
settings.lineEndIncludeArray = SplitUtils.split(settings.lineEndInclude);
@@ -73,6 +75,7 @@ public class AppSettingsConfigurable implements Configurable {
} else {
mySettingsComponent.setLineEndColor(settings.lineEndColorBright);
}
mySettingsComponent.setFindElementRightToLeft(settings.findElementRightToLeft);
mySettingsComponent.setLineEndInclude(settings.lineEndInclude);
mySettingsComponent.setLineEndExclude(settings.lineEndExclude);
}

View File

@@ -28,6 +28,7 @@ public class AppSettingsState implements PersistentStateComponent<AppSettingsSta
public final TextAttributes lineEndTextAttr = new TextAttributes(new JBColor(lineEndColorBright, lineEndColorDark),
null, null, null, Font.ITALIC);
public boolean findElementRightToLeft = true;
public String lineEndInclude = "";
public String lineEndExclude = "java.";
public String[] lineEndIncludeArray = {};

View File

@@ -0,0 +1,73 @@
package io.github.linwancen.plugin.comment.utils;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.FileViewProvider;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiIdentifier;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.Nullable;
public class ResolveElementLeftToRightUtils {
private ResolveElementLeftToRightUtils() {}
protected static final String[] KEYS = {
"=",
};
@Nullable
public static PsiElement resolveElement(FileViewProvider viewProvider, Document document, int startOffset,
int endOffset) {
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);
PsiIdentifier psiIdentifier = psiIdentifier(endOffset, element);
if (psiIdentifier == null) {
return null;
}
return ResolveElementUtils.resolveElementOf(psiIdentifier, psiIdentifier, startOffset, endOffset);
}
@Nullable
private static PsiIdentifier psiIdentifier(int endOffset, PsiElement element) {
if (element == null) {
return null;
}
while (!(element instanceof PsiIdentifier)) {
element = PsiTreeUtil.nextVisibleLeaf(element);
if (element == null) {
return null;
}
if (element.getTextRange().getEndOffset() > endOffset) {
return null;
}
}
return (PsiIdentifier) element;
}
}

View File

@@ -0,0 +1,32 @@
package io.github.linwancen.plugin.comment.utils;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.psi.FileViewProvider;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiIdentifier;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.Nullable;
public class ResolveElementRightToLeftUtils {
private ResolveElementRightToLeftUtils() {}
@Nullable
public static PsiElement resolveElement(FileViewProvider viewProvider, int startOffset, int endOffset) {
if (startOffset == endOffset) {
return null;
}
PsiElement element = viewProvider.findElementAt(endOffset, JavaLanguage.INSTANCE);
if (element == null) {
return null;
}
PsiElement identifier;
while (!((identifier = PsiTreeUtil.prevVisibleLeaf(element)) instanceof PsiIdentifier)) {
if (identifier == null || identifier.getTextRange().getStartOffset() < startOffset) {
break;
}
element = identifier;
}
return ResolveElementUtils.resolveElementOf(element, identifier, startOffset, endOffset);
}
}

View File

@@ -0,0 +1,74 @@
package io.github.linwancen.plugin.comment.utils;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.Nullable;
public class ResolveElementUtils {
private ResolveElementUtils() {}
@Nullable
public static PsiElement resolveElementOf(PsiElement element, PsiElement psiIdentifier,
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
PsiElement newPsiElement = newMethodOrClass(element, startOffset);
if (newPsiElement != null) {
return newPsiElement;
}
// ::/class/field
PsiReference psiReference = parentPsiReference(psiIdentifier, endOffset);
if (psiReference != null) {
return psiReference.resolve();
}
return null;
}
@Nullable
private static PsiElement newMethodOrClass(PsiElement element, int startOffset) {
// new and Class should same line
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();
}
}
return null;
}
@Nullable
private static PsiReference parentPsiReference(PsiElement element, int endOffset) {
PsiElement parent;
while ((parent = element.getParent()) instanceof PsiReference) {
if (parent.getTextRange().getEndOffset() > endOffset) {
break;
}
element = parent;
}
if (element instanceof PsiReference) {
return (PsiReference) element;
}
return null;
}
}