Creating a new ctrl-clickable element in the editor
Hey folks,
I'm new to the plugin development here, so please be patient with me ;)
What I want to do:
Given is a string in a PHP source file, which I want to tokenize and parse. The info from the tokes will point to a specific, unique file location, which I want to reveal in the editor on a ctrl+click action on the string.
Questions:
- What kind of plugin is this?
- How do I register that kind of plugin?
- What interface / class must I implement to achieve my goal?
What I already discovered:
- How to resolve the file via the index / virtual file system
- I've read the "how to implement a custom language" tutorial / faq, pointing me to an interface named "PsiScopeProcessor" - sadly this didn't make me get the point.
Any kind of help or hint is appriciated!
Regards,
Mario
Please sign in to leave a comment.
What you need is a PsiReferenceContributor. You register it in the com.intellij.psi.referenceContributor extension point, implement your own PsiReferenceProvider that will return a reference instance for a particular string literal, and implement your own PsiReference which will return the target element from its resolve() method.
Thank you, this keeps me going. I'm on the impl. right now
and some other questions came up.
- What should "public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context)" - from my extension of the PsiReferenceProvider return, when it is not a reference to my kind of string? As the method is annotated with @NotNull, would an empty array be correct?
- What about the other methods of my PsiReference impl.? Is there any documentation what those methods do and who I have to implement them? (e.x. getRangeInElement or getVariants ?!)
Ok, the first question of me seems to become clearer.... (but please tell me if I got it right ;))
The Reference Provider returns the custom PsiReference, which's resolve() method can return null. This is the way of indicating a non-existing reference?
If it's not your kind of string, you need to return an empty array of references.
Other methods are documented in the javadoc of the PsiReference class.
No. Returning null from resolve() indicates an unresolved reference (for example, if your kind of string is the name of a file and the file does not exist).
Hopefully the last question:
How do those ElementPatterns work? Is there a documentation how to use the patterns? I obviously need an PsiElementPattern to register the provider with the registrar. I've assebled a StringPattern from the StandardPattern package, but I do not understand how to use it.
Sorry for the ongoing questions, but I want to understand all aspects...
Regards!
The patterns are simply a concise way of expressing conditions on PSI elements. I'm afraid we don't have any dedicated documentation for them, but if you can describe the conditions that your reference provider needs to match, I can probably help you express this as a pattern.
The pattern is quite easy ;)
The element must be of type PHP-String (single or double quoted) and must match the following conditions concerning the content of the string:
example: "AcmeBundle:Default:index.html.twig"
required conditions
- must contain two times a colon
- must end with ".twig"
Optional conditions:
- can contain a char sequence between index 0 and indexOf(":",0)
- can contain a char sequence between indexOf(":", indexOf(":",0))
HTH.
This should help:
PlatformPatterns.psiElement(StringLiteralExpression.class).withText(StandardPatterns.string().matches())
with the argument to matches() being the regular expression that the text of the string literal (including the surrounding quotes) should match.
Hm, the StringLiteralExpression.class is missing for me (wether I use PHPStorm as SDK or Idea)... any clues?
Make sure you have the jar of the PHP plugin to the classpath of your IntelliJ IDEA plugin SDK.
Ok, this helped.
I now encounter a log message, that says my plugins are disabled (like in http://youtrack.jetbrains.com/issue/WI-8719)
Both seem to be enabled in the plugin manager, but nothing happens. I've added some breakpoints to debug and learn, but as the plugins are obviously not executed I'm stuck.
http://confluence.jetbrains.net/display/IDEADEV/Plugin+Compatibility+with+IntelliJ+Platform+Products
You should make this sentence in bold: If a plugin does not include any module dependency tags in its plugin.xml, it's assumed to be a legacy plugin and it's loaded only in IntelliJ IDEA.
Thanks for you great patience and help!
Hey ;)
I've managed to get the plugin running and it's reference implementation gets fired on ctrl+hover and on ctrl+click. The resolve() method even returns the correct file :D. But! There is no jump made to the other file, even if the resolving process was successful.
I do not understand what is missing ... The sources are located here, if you might want to have a look: https://github.com/xenji/phpstorm-symfony2-plugin/tree/master/ClickableViews/src/com/xenji/php/symfony2/clickableviews
I don't see anything wrong with the code. One thing to note is that IntelliJ IDEA normally doesn't store references anywhere, so there's no point in caching the resolve result in an instance field of the reference.
The problem was the TextRange, which I took from the StringLiteralExpression. This was a value of (4005,4015) in my case. This is completely useless, as the TextRange of the reference means the range between 0 and the end of the string (or whatever you need in your marker).
Finally done! ;)