Intellij plugin: elements returned by PsiFile.findElementAt() providing very little language/syntax info

306 views Asked by At

I'm trying to create an Intellij plugin that does the same thing as a VSCode extension I recently created, Ligatures Limited, which is designed prevent font coding ligatures from fonts like Fira Code from being rendered out-of-context, so that they work for things like operators and punctuation, but don't show up in comments and strings.

I've tried to follow the code in this example: https://github.com/JetBrains/intellij-sdk-docs/tree/master/code_samples/psi_demo

...but when I create code that looks like this

    public void actionPerformed(AnActionEvent anActionEvent) {
        Editor editor = anActionEvent.getData(CommonDataKeys.EDITOR);
        PsiFile psiFile = anActionEvent.getData(CommonDataKeys.PSI_FILE);
        if (editor == null || psiFile == null) return;
        int offset = editor.getCaretModel().getOffset();

        final StringBuilder infoBuilder = new StringBuilder();
        PsiElement element = psiFile.findElementAt(offset);

...with three different file types, I find that only JSON files (of JSON, JavaScript, and TypeScript files) are being recognized by language, and being tokenized as far as my extension is allowed to see. Syntax coloring and other language-specific support are clearly functioning at some level, but not in a way my extension seems to be able to access.

psiFile.language is JSON for JSON, but it's only TEXT for JavaScript, and textmate for TypeScript.

I can see all of the different token types for JSON (JsonObject, JsonStringLiteral, JsonProperty, etc), but JavaScript files come back as one big TEXT token with all of the text of the JavaScript file inside of it, and TypeScript only yields PsiElement(empty token)

Here's my current plugin.xml file:

<idea-plugin>
  <id>com.shetline.ligatures-limited</id>
  <name>Ligatures Limited</name>
  <vendor email="[email protected]" url="http://github.com/kshetline/ligatures-limited-idea">Kerry Shetline</vendor>

  <description><![CDATA[
    Code ligatures <i>only where you want them</i>, not where you don't
    ]]></description>

  <depends>com.intellij.modules.lang</depends>
  <depends>com.intellij.modules.platform</depends>
  <depends optional="true">JavaScript</depends>

  <applicationListeners>
    <listener class="com.shetline.lligatures.LigaturesLimited" topic="com.intellij.ide.AppLifecycleListener"/>
  </applicationListeners>

  <extensions defaultExtensionNs="com.intellij">
    <applicationService serviceImplementation="com.shetline.lligatures.LigaturesLimited"/>
    <highlightVisitor implementation="com.shetline.lligatures.LigaturesLimited"/>
    <highlightingPassFactory implementation="com.shetline.lligatures.LigaturesLimited"/>
  </extensions>

  <actions>
  </actions>
</idea-plugin>

I'm a bit worried that I might need to explicitly add dependencies for every language I want to parse. But then again, adding <depends optional="true">JavaScript</depends> didn't help me getting any further parsing JavaScript, so maybe that wouldn't help anyway.

Is it a timing thing perhaps, like maybe I'm getting a callback from highlightVisitor before the file has been parsed?

1

There are 1 answers

1
kshetline On

I was snagged by something which is automatically done by the wizard that creates starter Intellij plug-in projects.

My default build.gradle.kts file contained this:

intellij {
  version = "2020.1.1"
}

Little did I know that, even though I was running the Ultimate Edition of IDEA, this configuration caused my plugin to launch inside a Community Edition wrapper, which of course had no idea about all of the languages I was trying to handle.

Changing to this:

intellij {
  version = "IU-2019.3.3"
}

...fixed the problem. Ideally I'd like to find a way to programmatically use the current version of my development environment, but this definitely fixes the essential problem I was having.