PSI targeting to multiple IDEs native languages and optional dependencies

Answered

Hello,

First of all, my plugin is not grandle based. And I would preffer to keep it that way.

How to ensure that optional dependencies in plugin.xml are compatible to all users that are about to download for first time or update the plugin ?

 

1. How do I know if the user has native ide plugin support for each language, so I can safely select the right visitor using the optional jetbrain's official plugin which provides api for this language ?

2. Is the plugin possible to crash to users in phpstorm for example because I am having a visitor for python ? even if it's not going to be used.

3. Can I know the compatibility earlier for all these IDEs that my plugin support, before I commit the plugin? Is the plugin verificator enough ? Is it going to be incompatible i.e. to phpstorm because it contains imports and api on a custom visitor class for com.jetbrains.python.psi ?

 

6 comments
Comment actions Permalink

Hi Alex,

Even if your plugin works despite the warnings from the plugin verifier, it may break if you introduce a bug to your condition, so it's not OK to leave it that way.

The recommended approach is to extract your language-specific logic to service and register this service in a language-specific XML file.

Once you register service ("projectService" or "applicationService" EP, see Services for details), just retrieve it in your code as described in Retrieving a Service section. If an IDE doesn't support a given language, a language-specific XML file won't be loaded and the service will be null. This is a safe way of handling your case.

1
Comment actions Permalink

Hi Alex,

Where do you use/register your visitors? If they are used from extensions registered with extension point, then you should register them in the appropriate XML file holding features depending on the plugin included in a given "depends" element. So you should keep them separate and not have a single class where you reference multiple APIs.

Example:

<depends optional="true" config-file="myPluginId-python.xml">com.intellij.modules.python</depends>

You should register your feature using visitor based on Python API in "myPluginId-python.xml" file. If an IDE the plugin is installed in supports Python, this XML file will be loaded. If an IDE doesn't support Python, the file just won't be loaded. So compatibility is handled automatically in this case.

0
Comment actions Permalink

Hello Karol once again,

thank you for your help so far, you have been very useful in my plugin development process. I am almost done!

 

I am using a generic Visitor custom class that instantiates those custom specific visitors under circumstances (depending on the file's type language).

The generic Visitor (custom class) does not have any targeted native language api or imports inside it.

Only the language-based visitors include the PSI API of each native language in them.

But what happens if an api going to be changed in future ide version.

1.If for example com.intellij.modules.python will be changed into com.jetbrains.modules.python

2. or com.intellij.modules.python.psi.PyClass will be renamed into PyClassCool (lets say)

 

Could you please be more precise on what to do in my xml files by giving me an example in my case?

Let's say for python

 

Because my plugin seem to work in all my IDEs even if I leave them empty.

But still, I have built my plugin using my located sdks and tested it on my ides and I'm not sure what is gonna happen to different situations on users.

(I don't know if I am using extensions, it's the first time I hear for them.)

0
Comment actions Permalink

Hi Alex,

How do you instantiate specific visitors for each language? This sounds like you may touch language API here.

How your main visitor is consumed by IDE? It is unclear to me what are you trying to achieve (inspections? something else?), so the use case, context, code snippets would be helpful to understand.

1. Such changes are rare and if they are introduced, they are usually backward-compatible (I mean both old and new ID used in dependency would work). In case it isn't, your plugin will stop loading the correct XML file, but this is a very rare situation and should never happen.

2. This should also never happen as this is a very core API and teams working on IDE are aware that it would break existing plugins. Don't worry about it.

Your XML files content depends on what you are trying to implement. They contain Extension Points definitions, actions, listeners, and more, see docs: https://plugins.jetbrains.com/docs/intellij/plugin-structure.html

0
Comment actions Permalink

My plugin is a toolwindow component.

public class MyToolWindow extends JComponent implements ToolWindowFactory, ComponentListener

in plugin.xml I have

    <extensions defaultExtensionNs="com.intellij">
        <toolWindow id="My Toolwindow Plugin" anchor="top" factoryClass="component.MyToolWindow" icon="/plugin.png"/>
    </extensions>

 

and also

    <project-components>
        <component>
            <implementation-class>component.MyCustomPlugin</implementation-class>
        </component>
    </project-components>

 

 

I just saw that Plugin's project components are deprecated but this is not what I have in mind right now.

 

By instantiating specific visitors I mean my custom made visitors which extends PsiRecursiveElementVisitor and implements visitElement

 

My issue is the multiple IDE/language support.

 
 
 
0
Comment actions Permalink

Plugin verificator found compatibility problems for all ides.

For example

MyPlugin depends on optional plugins com.jetbrains.php, org.jetbrains.plugins.go, org.jetbrains.kotlin, com.intellij.cidr.base and modules com.intellij.modules.java, com.intellij.modules.ruby that couldn't be resolved with respect to PyCharm Professional PY-183.6156.16 (2018.3.7)

PyCharm Professional PY-183.6156.16 (2018.3.7)
Package not found (5 problems)
Package 'com.goide' is not found (1 problem)
Package 'com.jetbrains.cidr' is not found (1 problem)
Package 'com.jetbrains.php' is not found (1 problem)
Package 'org.jetbrains.kotlin' is not found (1 problem)
Package 'org.jetbrains.plugins.ruby' is not found (1 problem)

Class not found (4 problems)
Access to unresolved class PsiClass (2 problems)

    Method VisitorJava.visitElement(PsiElement) references an unresolved class PsiClass. This can lead to NoSuchClassError exception at runtime.
    Method VisitorJava.getClassesAsStrings() references an unresolved class PsiClass. This can lead to NoSuchClassError exception at runtime.

Access to unresolved class PsiMethod (2 problems)

    Method VisitorJava.visitElement(PsiElement) references an unresolved class PsiMethod. This can lead to NoSuchClassError exception at runtime.
    Method VisitorJava.getMethodsAsStrings() references an unresolved class PsiMethod. This can lead to NoSuchClassError exception at runtime.

 
Is this ok? In my code I check if java is available for example to use my custom java visitor that depends on java imports. So it is not going to crash at runtime, right? Am I missing something?
 
I am getting file's language like following, so I guess java is never going to be touched in PyCharm
 
String language = psiFile.getFileType().getName();
if (language.equalsIgnoreCase("java")) {

VisitorJava java = new VisitorJava();
psiFile.acceptChildren(java);
ArrayList<String> classNames = java.getClassesAsStrings();
ArrayList<String> methodNames = java.getMethodsAsStrings();
}
My plugin has been successfully tested in PhpStorm, PyCharm, RubyMine, CLion, GoLand (trials) and IntelliJ IDEA by getting class and method names of all these languages without errors
 
 
0

Please sign in to leave a comment.