Custom Language - Class Reference Contribution

Hi guys,

I am currently developing support for a custom language, which supports the ability to reference java Classes - such as below

     ${body} is 'java.lang.String'

I have created a lexer and parser for this language, and I would like to provide support for the usual suspects, error highlighting, variants, reference contribution for classes etc

Is it preferrable to
- create my own reference contribution implementation
- Use the so called 'chameleon' token types as described here and simply a java fragment - if this is a valid usecase

As a further twist on requirements, the language also supports shorthand for all java.lang.* classes, allowing the previous example also be written more concisely as

     ${body} is 'String'

It would be great to hear some thoughts on this matter :)


Comment actions Permalink

I may go for the custom approach; Is this the preferred method within IntelliJ's APIs?

Comment actions Permalink

Hi Alan,
it depends on the custom language. If you would reuse existing references you may get more actions ready for you but some of them would break your code. So I would probably advice you to create your own reference contributors then you'll get full control over the behaviour of your plugin.


Comment actions Permalink

Hi Anna,

Thanks for the clarification, it's much appreciated.

I am currently providing my own PsiReferenceBase implementation; For providing variants I am  currently using the PsiManager, DirectoryIndex and JavaDirectoryService classes to manually get both PsiPackages and PsiClasses.
As such when I provide completion I get 'poor' results, and not the same sort of results you'd expect 'natively' from IntelliJ.

For instance, i have attached my current vs IJ's Java completions

I can of course modify my current LookupElementBuilder to the same icon, tail, etc, but i'd like to be able to hook into any available APIs for the existing, smarter, code completion
Could you suggest the APIs which would be best suitable for this please?  :)


Comment actions Permalink

AFAIK this would be com.intellij.psi.impl.source.resolve.reference.impl.providers.JavaClassReferenceProvider

Comment actions Permalink

Alan, that depends on how you construct variants. You may pass psiElement there as target object and some rendering should appear automatically. Do you need an assistance there?

Comment actions Permalink

Thanks Anna, this was the exactly the problem for Icons not showing :)

For anyone passing by;

The PsiReference interface contains a method getVariants() which expects an array of Object, which can be either PsiElement or LookupElement.
To create a lookup element the following classes are useful;
  - LookupElementBuilder
  - JavaLookupElementBuilder

However, in this scenario simply returning the array of PsiPackage/PsiClass directly was easier

Comment actions Permalink

Thanks for the reply Yann, this was exactly what I needed to get going in the right direction!

For anyone passing by;
If you are writing a custom language, you do *not* need a PsiReferenceContributor. Instead you can simply provide either an implementation for getReference() or getReferences(), which will return your PsiReference implementations. If you are using grammar kit you can provide this interface + implementation logic using the mixin/implements attributes within your BNF file

Camel Completion

For the above scenario I provided an implementation of getReferences() and provided the TextRange to my PsiReference implementation,
The one small gotcha is to remember that this text range is within/relative to your element, and not the PsiFile itself.


Please sign in to leave a comment.