2

我正在开发一个 IDEA 插件,它应该提供不同 XML 文件之间以及 XML 和 Java 源之间的导航。它有点类似于 Spring 支持。

待支持的 XML 标签有一个 <name> 子标签(与 Spring 中的 id 属性相反),引用就像 spring: ref="..." 导航到 Java 源代码将是稍后的步骤。xml 文件还有一个命名约定以支持新插件:*-definitions.xml

目前,我陷入了第一步:LineMarkerProvider 和 ReferenceContributor。

我使用“自定义语言支持”示例作为起点。但是因为我没有自定义语言而是想扩展 xml 功能,所以我删除了词法分析器、解析器、文件工厂等......并且只包含了 LineMarkerProvider 和 ReferenceContributor。

所以我现在所拥有的是:

  • 类 DefinitionsReference 扩展 PsiReferenceBase
  • 类 DefinitionsUtil(类似于 SimplePsiImplUtil)
  • 类 DefinitionsLineMarkerProvider 扩展了 RelatedItemLineMarkerProvider
  • 类 DefinitionsReferenceContributor 扩展 PsiReferenceContributor

我在 plugin.xml 中注册了 LineMarkerProvider (language=XML) 和 ReferenceContributor,并添加了一些日志输出来验证它们是否被调用以及结果是否为空。

尽管 ReferenceContributor.PsiReferenceProvider.getReferencesByElement() 以及 DefinitionsReference.multiResolve() 和 reslove() 确实返回了一些非空结果,并且 LineMarkerProvider.collectNavigationMarkers() 确实找到了一些要标记的地方,但我既没有得到导航栏图标也不能从 ref= 导航到相应的标签。它说“找不到要前往的声明”。

似乎我错过了一些重要的细节。

我应该首先寻找什么?

还是完全错误的方法?

编辑:

这是要支持的 XML 文件之一:

<?xml version="1.0" ?>
<event-definitions>
  <data-source-definition>
    <name>event.eventDataSource</name>
    <class>...</class>
  </data-source-definition>

  <plugin-definition>
    <name>event.taskPlugin</name>
    <class>...</class>
    <title>...</title>

    <data-source ref="event.eventDataSource">
      <property>eventDataSource</property>
    </data-source>
    <data-source ref="personDataSource"/> <!-- defined in other XML file -->
    ... more data-sources ...
  </plugin-definition>

  <editor-definition>
    <name>event.admin.Editor</name>
    <editor>...</editor>
    <title>...</title>
    <editor-view>...</editor-view>

    <data-source ref="event.eventDataSource"/>
    <data-source ref="personDataSource"/> <!-- defined in other XML file -->
    ... more data-sources ...

    <plugin ref="event.taskPlugin">
      ...
    </plugin>
    <plugin ref="assignment.ratingPlugin"> <!-- defined in other XML file -->
      ...
    </plugin>
    ... more plugins ...
  </editor-definition>
</event-definitions>

这是我的参考贡献者:

public class DefinitionsReferenceContributor extends PsiReferenceContributor {
    @Override
    public void registerReferenceProviders(PsiReferenceRegistrar registrar) {
        registrar.registerReferenceProvider(PlatformPatterns.psiElement(XmlTag.class),
                new PsiReferenceProvider() {
                    @NotNull
                    @Override
                    public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) {
                        XmlTag tag = (XmlTag) element;
                        final String localName = tag.getLocalName();
                        if ("name".equals(localName)) {
                            final PsiReference[] psiReferences = DefinitionsUtil.matchTag((XmlTag) element);
                            return psiReferences;
                        } else {
                            return new PsiReference[0];
                        }
                    }
                });
    }
}

我的 LineMarkerProvider:

public class DefinitionsLineMarkerProvider extends RelatedItemLineMarkerProvider {

    @Override
    protected void collectNavigationMarkers(@NotNull PsiElement element, Collection<? super RelatedItemLineMarkerInfo> result) {
        if (element instanceof XmlTag) {
            XmlTag tag = (XmlTag) element;
            final String localName = tag.getLocalName();
            if ("name".equals(localName)) {
                final Project project = element.getProject();
                final String tagName = DefinitionsUtil.getTagName(tag);
                if (tagName != null) {
                    final List<XmlTag> matchingTags = DefinitionsUtil.findMatchingReferences(project, tagName);
                    if (matchingTags.size() > 0) {
                      NavigationGutterIconBuilder<PsiElement> builder =
                              NavigationGutterIconBuilder.create(SmotiveDefinitionsIcons.FILE).
                                      setTargets(matchingTags).
                                      setTooltipText("Navigate to a sMOTIVE Definition");
                      result.add(builder.createLineMarkerInfo(element));
                    }
                }
            } else {
                final String ref = DefinitionsUtil.getRefValue(tag);
                if (ref != null) {
                    final Project project = element.getProject();
                    final List<XmlTag> matchingTags = DefinitionsUtil.findMatchingTags(project, ref);
                    if (matchingTags.size() > 0) {
                        NavigationGutterIconBuilder<PsiElement> builder =
                              NavigationGutterIconBuilder.create(SmotiveDefinitionsIcons.FILE).
                                    setTargets(matchingTags).
                                    setTooltipText("Navigate to a sMOTIVE Definition");
                        result.add(builder.createLineMarkerInfo(element));
                    }
                }
            }
        }
    }
}

最后,我的 plugin.xml 的扩展部分:

<extensions defaultExtensionNs="com.intellij">
    <codeInsight.lineMarkerProvider language="XML" implementationClass="de.smotive.tools.navigation.definitions.DefinitionsLineMarkerProvider"/>
    <psi.referenceContributor implementation="de.smotive.tools.navigation.definitions.DefinitionsReferenceContributor"/>
</extensions>

我省略了 DefinitionsUtil 因为它的大小。如果发现解决方案需要它,我稍后会添加它。

4

0 回答 0