Can a plugin tell IDEA Ultimate Edition where to find additional JavaScript/CSS files?

When my custom language plugin is running in IntelliJ IDEA Ultimate Edition, I'd like to be able to tell the IDE to use some additional JavaScript and CSS files when in the JavaScript and CSS editors and HTML5 editor as appropriate.  My plugin also support Community Edition, so I'd like to do this in a way that works in Ultimate Edition but doesn't cause issues when running in Community Edition.

Are there extension points for resolving additional JavaScript/CSS source files when running in these editors so that the contained symbols/styles are available for completion, parameter info, etc.?

0
23 comments

It looks like if I set up my plugin SDK against Ultimate Edition and add the jars from the JavaScriptLanguage plugin, I can use JSLibraryManager to maintain JavaScript libraries against the additional files.  I'm going to see if I can do that in a way that works well in Ultimate Edition and doesn't cause any issues in Community Edition.  I'm also going to see if there's anything analogous in the CSS plugin for sourcing additional CSS files.

I'd be very interested to know if anyone has experience with these and knows whether this is a good(/supported!) option.

0

Well, that didn't work.  I get a NoClassDefFoundError from the PluginClassLoader, presumably because I'm trying to cross the plugin trust boundary.  Back to the proverbial drawing board...if anyone knows how I might be able to do this, I'd definitely appreciate the guidance!  Thanks!

0

Have you checked com.intellij.psi.ResolveScopeEnlarger?

1

Thanks for the lead, Konstantin.  I just tried it and it doesn't seem to be helping, but perhaps I'm doing something wrong.  I can see it calling into my implementation which in turn returns GlobalSearchScope.filesScope() with the list of JS files from my plugin that should be included when resolving, but it's still saying that references to JavaScript identifiers from those files are unresolved.  Furthermore I can see in the stack that's invoking my ResolveScopeEnlarger implementation that the request is originating in JSResolveUtil, so it seems like it's wired into the correct place.

Hopefully I'm just doing something wrong here and with a few adjustments things will just start working.  Any additional thoughts on why it might not be helping?  Thanks again!

0

Oh, forgot to mention it, also extension for com.intellij.util.indexing.IndexableSetContributor is required.

1

Aha!  That definitely helped!  Thanks!!!

One more question...it's working great now from JavaScript source files but not from HTML SCRIPT blocks or event handlers in my plugin's MultiplePsiFilesPerDocumentFileViewProvider-based files.  The scope enlarger is never actually called with those virtual files for me to enlarge the scope.  Any idea why that might be the case?

Thanks so much again!

0

I tried to debug the issue with SCRIPT blocks in my markup files.  I'm a bit limited by the fact that I can't debug into the JavaScript language libs, but what I am seeing is that in com.intellij.codeInsight.TargetElementUtil.doGetReferenceOrReferencedElement(), the following returns null in my file:

evaluator.getElementByReference(ref, flags)

whereas in a stock standard HTML file, it returns a non-null value.  In both cases "ref" is a JSReferenceExpression.

Note that completion/reference resolution against standard JavaScript libraries works just fine in my plugin's embedded markup.  It's just deciding not to send queries into my new resolve scope enlarger.

My guess is that I'm missing something in my MultiplePsiFilesPerDocumentFileViewProvider implementation that thus far hasn't been needed.  Any idea what that might be?

0

I've noticed something else peculiar here.  As I mentioned, the resolve scope enlarger and indexable set contributor both do allow code completion and reference resolution against my supplied JavaScript "libraries" from both JavaScript and HTML, but not from my plugin's own HTML-based markup.  Additionally it seems that while quick documentation works against these supplied JavaScript libs from JavaScript, it does not work from a stock standard HTML file:

HTML

JavaScript

Since this is all Ultimate Edition functionality, I'm not really able to debug it like I could with Community Edition functionality.  Is logging a bug the best way to proceed?

Thanks!

0

Can you please check if com.intellij.psi.impl.file.impl.ResolveScopeManagerImpl#getDefaultResolveScope is executed when JS reference inside HTML script is resolved? If not, we should make it do it on our side, but normally it does, in normal WebStorm instance without additional plugins. It may broke if file has type other than HtmlFileType.

0

Konstantin, I added a non-suspending/logging breakpoint there and here's what I see:

JavaScript file
getDefaultResolveScope() called for formController.js
getDefaultResolveScope() called for formHelper.js

HTML file
getDefaultResolveScope() called for htmlFile.html
getDefaultResolveScope() called for DHTML.js

Custom HTML-based markup file
getDefaultResolveScope() called for DHTML.js

Sounds like your suspicion may be correct.  Basically I see it get called for my JavaScript file(s) and HTML file but not for my custom HTML-based markup file.  In that case it just pulls in the standard JS include but doesn't seem to actually process the contents of my file.

Please let me know if there's anything else I can do to help out here.  Oh, and any thoughts on why the quick documentation isn't showing JSDoc from even standard HTML files?

Thanks much for all the help!

0

The quick documentation doesn't show anything because resolve doesn't work, fixing resolve is enough. 

I've made getDefaultResolveScope() to be called on JS resolve in custom file too, so this should be fixed in the next EAP.

0

Konstantin, resolve does work for SCRIPT blocks in real HTML files, but at least for me, quick doc doesn't work there.  I'll provide an example...

Here's JavaScript:

and here's HTML:

As you can see, in both cases "getParams" is highlighted because it has valid references that can be navigated to the same backing source, but quick doc only works properly in JavaScript and not HTML.

Please let me know if you're unable to reproduce this.

0

Konstantin, should I expect this same approach to work for CSS?  I've updated my indexed roots provider(/indexable set contributor) and resolve scope enlarger to include a CSS file that I include, but I'm not seeing the contained styles being offered as completions or being included as references.  Is there something else I'd need to do for this to work for CSS, in particular when used in "class" attributes of XHTML elements?

In an ideal world I'd like to tell the CSS plugin additional URIs that it should pull in for a given VirtualFile.  The reason for this is that in my plugin's markup, it's possible to reference a CSS that's contained in an archive in the same project, so it's not just a matter of including the containing archive file in a resolve scope enlarger.  My guess is that there's not a way to do this, so I'll need to continue to include an additional completion contributor for those styles in my plugin.  It's not quite as seamless as having Ultimate Edition's CSS plugin take care of it for me, but it does work.

Thanks yet again for all the help!

0

Konstantin, just thought I'd check in and see if you had any thoughts on my questions about quick documentation not working for JavaScript in HTML and what approach might work to make Ultimate Edition's CSS support aware of additional CSS files both packaged with my plugin and inside of archive files in the source roots.

Thanks!

Scott

0

Sorry, I can't guess why quick doc may not work when reference is resolved.

0

Hi Scott,

Some of the issues with CSS you can try to fix by implementing com.intellij.psi.css.resolve.CssInclusionContext extension, provide additional CSS files that you want to be in a context there.

1

Thanks, Alexander.  I'll take a look in a bit.  Hopefully that will give me exactly what I need!

0

Yep, at a quick glance this looks like EXACTLY what I was wanting.  Thanks so much, Alexander!

0

Alexander, that did work very well for me.  Of course, it just led to another question!  My plugin also brings its own markup elements and attributes into HTML, and some of those attributes are intended to take CSS classes as values.  Is there some way to tell Ultimate Edition's CSS support to provide completions in certain element/attribute pairs?  I didn't see any obvious EP for that.

Thanks again!

0

You should add HtmlCssClassOrIdReference to attribute values. To do this you should register a PsiReferenceContributor and register xml-attribute reference provider in its contructor

XmlUtil.registerXmlAttributeValueReferenceProvider

As an example of reference provider you can see at CssInHtmlClassOrIdReferenceProvider, or you can just extend it and substitute applicable attribute names.

 

Here is how id/class references are registered by CSS plugin

XmlUtil.registerXmlAttributeValueReferenceProvider(registrar, new String[]{HtmlUtil.ID_ATTRIBUTE_NAME, HtmlUtil.CLASS_ATTRIBUTE_NAME}, 
htmlClassOrIdReferenceProvider.getFilter(), false, htmlClassOrIdReferenceProvider);

 

More about references you can find here: http://www.jetbrains.org/intellij/sdk/docs/tutorials/custom_language_support/reference_contributor.html

1

Worked perfectly, Alexander!  I already had a reference contributor for Community Edition.  I just added logic for Ultimate Edition to register an XML attribute value ref provider as you described above filtering just for the attributes of my plugin's elements and things work wonderfully.

Aside from the issue with quick doc not rendering properly for otherwise properly resolved JavaScript identifiers in HTML and the issue with getDefaultResolveScope() against custom file types that Konstantin has resolved for the upcoming release, I think I have this all wired in very well.

Thanks for all the help!

0

Alexander, has something changed recently in this area?  My implementation of CssInclusionContext is no longer being called on 2017.1.1.  Unfortunately I'm not sure if this change occurred very recently or only somewhat recently, but when I implemented it and it was definitely working, I was using 2016.2 or 2016.3, I think.

I can set a breakpoint on the first executable line of getContextFiles() and it's never hit.  I don't see any exceptions in idea.log indicating that there's an issue with my implementation (which hasn't changed at all since the first working submission).  As a reminder, this is happening in a MultiplePsiFilesPerDocumentFileViewProvider where the base language is from my plugin and the template data language is HTML.

Thanks!

UPDATE: Ugh...please disregard.  There was a bad file type association in my install.  Once corrected, everything works as expected.  Sorry!

0

No problem. Thank you for the update!

0

Please sign in to leave a comment.