Javascript dialects, dialectSpecificHandlersFactory

Hello,

I'm working on language plugin for template engine based on Nashorn. I've got some dialect-specific handlers (JavaScript.dialectSpecificHandlersFactory) and my language class looks like this:

public class MyTemplateInnerJs extends JSLanguageDialect
{
    protected MyTemplateInnerJs()
    {
        super("MyTemplateInnerJs", DialectOptionHolder.OTHER);
    }

}

I'd like to use it with DialectOptionHolder.NASHORN because of some features, e.g. this one. But if I use that (or anything else than DialectOptionHolder,OTHER), my dialect-specific handlers for some reason just stop working.  Am I missing something?

16 comments
Comment actions Permalink

Hello Peter.
Did you try using DialectOptionHolder.OTHER with your dialectSpecificHandlersFactory extending NashornJSSpecificHandlersFactory?

0
Comment actions Permalink

That helped, thanks a lot!

0
Comment actions Permalink

Actually it's not totally perfect. If I extend my reference expression resolver from NashornJSReferenceExpressionResolver or if I use NashornJSSpecificHandlersFactory as is, references resolve just fine, but there is no autocompletion for packages / classes / class members. Autocompletion works only together with DialectOptionHolder.NASHORN.  Any ideas?

0
Comment actions Permalink

There's one more thing, which may be a bug. Let's have the following class:

package pcg;

public class AClass {
     public static enum AEnum {
          A, B, C
     }

     private AEnum aEnum;
}

and js:

var a = Packages.pcg.AClass.AEnum.A

The AEnum resolves to private property aEnum and A is unresolved variable.

0
Comment actions Permalink

AEnum in

var a = Packages.pcg.AClass.AEnum.A

resolves properly to enum class for me. Could you please recheck it?
0
Comment actions Permalink

I'm sorry, the example I provided really works well, so one more try:

 
package pcg;

public class
AClass {
    private AEnum aEnum;

    public
AEnum getAEnum() {
        return aEnum;
    
}

    public static enum AEnum {
        A, B, C
    
}

}

The getter must be 'get' + exact enum name (not getaEnum...). So what happens here is the following:

 
var a = Packages.pcg.AClass.aEnum; // resolves to aEnum private property and has error annotation 'Instance membes is not accessible'
 
var b = Packages.pcg.AClass.AEnum; // resolves to getAEnum getter and has the same annotation as before
 
var c = Packages.pcg.AClass.AEnum.A; // A is left unresolved

From my experience with rhino-js I'd expect the first case to resolve to getter. Annotation shouldn't appear, while it is regular access to private property via getter. Second case should resolve to enum declaration (public static enum AEnum).
I see this behavior in 140.2683.2 as well as in 139.1117.1 (same situation but without Packages prefix).

update: Here's link to the issue: https://youtrack.jetbrains.com/issue/IDEA-138078

0
Comment actions Permalink

Thanks for the issue!

0
Comment actions Permalink

I'm still not really clear about nashorn dialect in Idea. If I choose language version NashornJS in idea settings for .js file, I do get all the features like for each support for example. If I set DialectOptionHolder.NASHORN for my language, I don't get any of these. If I use DialectOptionHolder.NASHORN, my dialectSpecificHandlersFactory is never instantiated - I've done some research and is seems, that nashorn acts in this case just as a different language and javascript extension namespace is not working for it. If I use DialectOptionHolder.OTHER and my factory / handlers extend appropriate nashorn classes, I still don't get any for each support, java class / package autocompletion etc. Why's that?

0
Comment actions Permalink

I think you should use DialectOptionHolder.NASHORN language and extend NashornJSSpecificHandlersFactory. I'm not sure if it helps, but please try order="first" attribute for your JSDialectSpecificHandlersFactory in plugin.xml file. BTW, is your plugin open-source?

0
Comment actions Permalink

Thanks, order="first" is something, that always gets me. So now I do have nashorn dialect set, java package / class completion works very well, but still there is no for each support. You can find my code here. I've created lexer layer which treats 'for each' as if it was 'for', but that code is commented out.

edit: I've been just overjoyed with the idea that it would be so simple. So no, it's not working even with order="first".

0
Comment actions Permalink

So finally I got it. For each support is achieved by extending NashornJSParserDefinition instead of base JavascriptParserDefinition, class / package completion is done in NashornJSCompletionHelper (javascript completionHelper extension point) and  using DialectOptionHolder.NASHORN is just not possible. I'm using DialectOptionHolder.OTHER and my dialectSpecificHandlersFactory extend NashornJSSpecificHandlersFactory.

0
Comment actions Permalink

The 'each' keyword is not highlighted as a keyword in my templates anymore. Unfortunately I'm not able to tell since which version this happens. The structure is described in my previous comment and the code is here. This is strange, because the for each works just fine (PSI element JSForInStatement, type resolver works, no syntax errors...). Any ideas?

0
Comment actions Permalink

Using DialectOptionHolder.OTHER instead of NASHORN makes lexer interpret 'each' as JSTokenTypes.IDENTIFIER, not EACH_KEYWORD. I suggest to highlight 'each' manually, e.g. by adding an extension to JavaScript.analysisHandlersFactory extension point and overriding createKeywordHighlighterVisitor method.

0
Comment actions Permalink

That is not true actually, it doesn't make any difference if I use DialectOptionHolder.OTHER or DialectOptionHolder.NASHORN, the PSI is the same in both cases and looks like this:

I have tried to override the createKeywordHighlighterVisitor in my InnerJsAnalysisHandlersFactory, however this method is never called. I can see that the JSSemanticKeywordHighlighter in JSSemanticKeywordHighlighterFactory is instantiated (quite often) and the JSSemanticKeywordHighlighter#doCollectInformation() is called, but the condition 'this.myFile instanceof JSFile' is false, therefore the JSAnalysisHandlersFactory.forElement(this.myFile) is never called. So what would you suggest for template languages?

0
Comment actions Permalink

Do you have JSEmbeddedContent, like in .vue files? If not, you may register com.intellij.lang.annotation.Annotator and highlight 'each' in it.

0
Comment actions Permalink

Ok thanks, here is the solution. 

0

Please sign in to leave a comment.