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

17 comments
Comment actions Permalink

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.

0
Comment actions Permalink

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 ?!)

0
Comment actions Permalink

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?

0
Comment actions Permalink

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.

0
Comment actions Permalink

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).

0
Comment actions Permalink

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!

0
Comment actions Permalink

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.

0
Comment actions Permalink

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.

0
Comment actions Permalink

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.

0
Comment actions Permalink

Hm, the StringLiteralExpression.class is missing for me (wether I use PHPStorm as SDK or Idea)... any clues?

0
Comment actions Permalink

Make sure you have the jar of the PHP plugin to the classpath of your IntelliJ IDEA plugin SDK.

0
Comment actions Permalink

Ok, this helped.

I now encounter a log message, that says my plugins are disabled (like in http://youtrack.jetbrains.com/issue/WI-8719)

2012-06-04 14:45:31,624 [      0]   INFO -        #com.intellij.idea.Main - ------------------------------------------------------ IDE STARTED ------------------------------------------------------ 2012-06-04 14:45:31,636 [     12]   INFO -        #com.intellij.idea.Main - IDE: JetBrains PhpStorm (build #PS-117.501, 31 May 2012 00:00) 2012-06-04 14:45:31,636 [     12]   INFO -        #com.intellij.idea.Main - JRE: 1.7.0_03-b04 (Oracle Corporation) 2012-06-04 14:45:31,636 [     12]   INFO -        #com.intellij.idea.Main - JVM: 22.1-b02 (Oracle Corporation) 2012-06-04 14:45:31,695 [     71]   INFO - .intellij.idea.IdeaApplication - WM detected: Compiz 2012-06-04 14:45:32,934 [   1310]   INFO - j.ide.plugins.PluginDescriptor - Cannot find plugin com.intellij resource-bundle: messages.WebIdeBundle 2012-06-04 14:45:33,565 [   1941]   INFO - llij.ide.plugins.PluginManager - 39 plugins initialized in 1614 ms 2012-06-04 14:45:33,566 [   1942]   INFO - llij.ide.plugins.PluginManager - Loaded plugins:IDEA CORE, Remote Hosts Access (0.1), CSS Support, UML Support (1.0), XPathView + XSLT Support (4), JavaScript Support (1.0), IntelliLang (8.0), PHP (117.501), Phing Support (117.501), YAML, JavaScript Intention Power Pack (0.9.4), Apache config (.htaccess) support (117.501), JavaScript Debugger (1.0), W3C Validators (2.0), Database Support (1.0), Subversion Integration (1.1), QuirksMode, SASS support, Git Integration (8.1), HTML Tools (2.0), Java Server Pages Integration (1.0), ASP (0.1), TFS Integration (1.0), Command Line Tool Support (117.501), LESS support, Task Management (1.0), GitHub, Inspection-JS (2.0), CoffeeScript (2.0), Cucumber (1.0), Perforce Integration (2.0), Refactor-X (2.01), CVS Integration (11), SQL support (1.0), HAML, XSLT-Debugger (1.4), hg4idea (10.0) 2012-06-04 14:45:33,566 [   1942]   INFO - llij.ide.plugins.PluginManager - Disabled plugins: Services (1.0), Clickable Views (0.1)



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.
0
Comment actions Permalink

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!

0
Comment actions Permalink

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

0
Comment actions Permalink

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.

0
Comment actions Permalink

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! ;)

0

Please sign in to leave a comment.