一、介绍
LineMarkerProvider
是 IntelliJ 平台插件开发中的一个接口,它的作用是在编辑器左侧的“行标记区域”(就是代码行号左边那一栏)添加各种图标、标记或导航链接。比如Java 类中看到的:
-
小绿色三角形(可以点击运行 main 方法)
-
方法重写的箭头图标(点击能跳到父类方法)
-
自定义的注解标识
-
各种插件加的导航小图标
这些都是通过 LineMarkerProvider
或其变种(如 RelatedItemLineMarkerProvider
)来实现的。
二、使用方法
实现 LineMarkerProvider
接口主要是为了提供行标记的行为。具体步骤如下:
1、实现 LineMarkerProvider
接口
创建一个类来实现 LineMarkerProvider
接口,并在其中定义如何生成和处理行标记。
package com.example;
import com.intellij.codeInsight.daemon.LineMarkerProvider;
import com.intellij.codeInsight.daemon.LineMarkerInfo;
import com.intellij.codeInsight.daemon.impl.LineMarkerRenderer;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class MyLineMarkerProvider implements LineMarkerProvider {
@Override
public List<LineMarkerInfo<?>> getLineMarkerInfo(@NotNull PsiElement element) {
// 判断这个元素是否是需要标记的元素
if (element instanceof MyTargetElement) {
// 创建行标记
return List.of(createLineMarkerInfo(element));
}
return List.of();
}
private LineMarkerInfo<PsiElement> createLineMarkerInfo(PsiElement element) {
// 在这里你可以自定义行标记的图标和行为
return new LineMarkerInfo<>(element, element.getTextRange(),
MyIcons.MY_ICON,
LineMarkerInfo.ColorMode.COLOR_FOR_ITEM,
null,
null);
}
}
2、注册 LineMarkerProvider
在 plugin.xml
文件中注册该实现类
<idea-plugin>
<id>com.example.myplugin</id>
<name>My Plugin</name>
<description>My custom plugin for IntelliJ IDEA</description>
<vendor>My Vendor</vendor>
<extensions defaultExtensionNs="com.intellij">
<!-- 注册 LineMarkerProvider -->
<codeInsight.lineMarkerProvider implementation="com.example.MyLineMarkerProvider"/>
</extensions>
</idea-plugin>
三、主要接口
LineMarkerProvider有两个接口:
方法名 | 场景 | 适合做的事 |
---|---|---|
getLineMarkerInfo | 轻量级 | 针对单个元素快速标记(无跳转关系、处理快) |
collectSlowLineMarkers | 重度分析 | 批量处理元素、涉及跳转、关系图、慢速处理等 |
1、getLineMarkerInfo(PsiElement element)
1.1 用途
这个方法适合用于“轻量级的、单个元素的标记”,比如:
-
一个特定方法名、类名、字段名出现时加一个图标
-
处理非常快(不耗时)的判断逻辑
1.2 返回值
-
返回一个
LineMarkerInfo
,表示某个 PsiElement 对应的行加上图标/提示/点击跳转等。 -
返回
null
表示不加标记。
1.3 LineMarkerInfo
通过 LineMarkerInfo
对象,你可以自定义行标记的外观、行为以及交互方式。
LineMarkerInfo
是 IntelliJ IDEA 中用于描述行标记的核心类。它可以包括多个重要的元素:
element
:标记的目标元素,通常是一个PsiElement
,即代码的某一部分。textRange
:该元素在源代码中的范围。icon
:行标记显示的图标(通常是一个Icon
对象)。colorMode
:标记的颜色模式,可以是COLOR_FOR_ITEM
(根据元素颜色来决定颜色)等。navigationHandler
:点击图标时执行的操作(可以是打开文件、跳转到某个位置等)。tooltip
:当用户悬停在图标上时显示的提示文本。
1.4 demo
@Override
public LineMarkerInfo<?> getLineMarkerInfo(@NotNull PsiElement element) {
if (element instanceof PsiMethod method && method.getName().equals("call")) {
return new LineMarkerInfo<>(
element,
element.getTextRange(),
AllIcons.Gutter.ImplementedMethod,
psi -> "这是 call 方法",
(mouseEvent, elt) -> {
// 点击行为,比如弹窗、跳转等
},
GutterIconRenderer.Alignment.RIGHT
);
}
return null;
}
2、collectSlowLineMarkers(List<PsiElement> elements, Collection<LineMarkerInfo> result)
2.1、用途
这个方法是用于“批量、慢速处理”的场景,比如:
-
遍历整个文件的所有方法,找出所有加了特定注解的方法
-
多个元素之间有关联,比如导航关系
2.2、使用场景
-
比如你想实现:点击某个类的图标可以跳转到它的所有实现类
-
或者在方法上显示它的调用方、被调用者
2.3、demo
@Override
public void collectSlowLineMarkers(
@NotNull List<? extends PsiElement> elements,
@NotNull Collection<? super LineMarkerInfo<?>> result
) {
for (PsiElement element : elements) {
if (element instanceof PsiMethod method && method.getName().equals("process")) {
result.add(new LineMarkerInfo<>(
element,
element.getTextRange(),
AllIcons.General.Information,
psi -> "跳转到处理逻辑",
(mouseEvent, elt) -> {
// 点击行为,比如跳转到某个 helper 方法
},
GutterIconRenderer.Alignment.LEFT
));
}
}
}
四、demo
1、简单打标
两个接口我都实现了下,看下效果
package com.test;
import com.intellij.codeInsight.daemon.LineMarkerInfo;
import com.intellij.codeInsight.daemon.LineMarkerProvider;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.editor.markup.GutterIconRenderer;
import com.intellij.openapi.util.IconLoader;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiIdentifier;
import com.intellij.psi.PsiMethod;
import groovy.util.logging.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*;
import java.util.Collection;
import java.util.List;
//provider测试demo
@Slf4j
public class MyTestProvider implements LineMarkerProvider {
private static final Logger log = LoggerFactory.getLogger(MyTestProvider.class);
@Override
public LineMarkerInfo<?> getLineMarkerInfo(@NotNull PsiElement element) {
Icon customIcon = IconLoader.getIcon("/icons/Line.svg", MyTestProvider.class);
if (element instanceof PsiMethod method && method.getName().contains("User")) {
return new LineMarkerInfo<>(
element,
element.getTextRange(),
//AllIcons.Gutter.Unique,
customIcon,
psi -> "这是wtyy target method",
(mouseEvent, elt) -> {
// 点击行为
},
GutterIconRenderer.Alignment.RIGHT
);
}
return null;
}
@Override
public void collectSlowLineMarkers(@NotNull List<? extends PsiElement> elements, @NotNull Collection<? super LineMarkerInfo<?>> result) {
for (PsiElement element : elements) {
if (element instanceof PsiIdentifier && element.getParent() instanceof PsiMethod) {
PsiMethod method = (PsiMethod) element.getParent();
Icon customIcon = IconLoader.getIcon("/icons/pluginIcon.svg", MyTestProvider.class);
if (method.getName().startsWith("insert") || method.getName().startsWith("update")) {
result.add(new LineMarkerInfo<>(
element,
element.getTextRange(),
customIcon,
psi -> "提示信息",
null,
GutterIconRenderer.Alignment.LEFT
));
}
}
}
}
}
<extensions defaultExtensionNs="com.intellij">
<!-- 注册 LineMarkerProvider -->
<codeInsight.lineMarkerProvider language="JAVA" implementationClass="com.test.MyTestProvider"/>
</extensions>
启动测试:打开一个java文件,可以看到打上了自定义的标签