RSTALanguageSupport icon indicating copy to clipboard operation
RSTALanguageSupport copied to clipboard

Add things to default JavaScriptLanguageSupport

Open iberck opened this issue 12 years ago • 10 comments

Hello first of all thanks for your effort making this magnificent library.

I'm using the latest version of library (rsyntaxtextarea, autocomplete, languagesupport) and I have been researching all weekend adding stuff to support javascript autocomplete but my snippets not work.

I'm using the autocomplete javascript support language and I want to add code templates and support of autocomplete of my own classes to the default javascript default autocomplete support.

My base code is:

    private RSyntaxTextArea createTextAreaEditor() {
        textAreaEditor = new RSyntaxTextArea();
        textAreaEditor.setCaretPosition(0);
        textAreaEditor.requestFocusInWindow();
        textAreaEditor.setMarkOccurrences(true);
        textAreaEditor.setTabsEmulated(true);
        textAreaEditor.setTabSize(4);
        ToolTipManager.sharedInstance().registerComponent(textAreaEditor);

        textAreaEditor.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT);
        textAreaEditor.setCodeFoldingEnabled(true);
        textAreaEditor.setAntiAliasingEnabled(true);

        return textAreaEditor;
    }

    private void createLanguageSupport() {
        LanguageSupportFactory lsf = LanguageSupportFactory.get();
        lsf.register(textAreaEditor);
        LanguageSupport support = lsf.getSupportFor(SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT);
        JavaScriptLanguageSupport languageSupport = (JavaScriptLanguageSupport) support;
        try {
            languageSupport.getJarManager().addCurrentJreClassFileSource();
        } catch (IOException ex) {
            Logger.getLogger(ScriptEditorJDialog.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

with the the above code the javascript autocomplete default support works fine, when I press "ctrl+." appears a autocomplete with javascript basic functions however I don't know how can add something to autocomplete javascript default support.

My first doubt (add codetemplates to javascript elements): How can I archive press "Ctrl +.​" and add the new item "log" with the default autocomplete javascript elements?

My second doubt (autocomplete my own classes): I use in my scripts the java class: "com.example.MyClass" wich is in the "client.jar" file, My problem is when I define a var of type "MyClass", the autocomplete of membes/methods of var MyClass does not work. Y define the vars like:

    var n = new Packages.com.example.MyClass();
    n. (autocomplete does not work)
    var r = new MyClass();
    r. (autocomplete does not work)

How can I archive this? I tried with several examples I've found in the forums but I can not make it work, for example I have tried to add class file source to the jarManager but does not do what I want:

    LanguageSupportFactory lsf = LanguageSupportFactory.get();
    lsf.register(textAreaEditor);
    LanguageSupport support = lsf.getSupportFor(SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT);
    JavaScriptLanguageSupport languageSupport = (JavaScriptLanguageSupport) support;
    JarManager jarManager = languageSupport.getJarManager();
    try {
        jarManager.addClassFileSource(new JarLibraryInfo("d:/projects/client.jar"));
    } catch (IOException ex) {
        Logger.getLogger(ScriptEditorJDialog.class.getName()).log(Level.SEVERE, null, ex);
    }       

I'm using netbeans rcp framework. Thank you very much for your time and help.

iberck avatar Nov 12 '13 15:11 iberck

anyone can help me ?

iberck avatar Dec 03 '13 01:12 iberck

Hi iberck

To enabled this you need to enable the Rhino Engine support for the SourceCompletionProvider. To do this you need to override the JavaScriptLanguageSupport class and register this instead of the regular JavaScript support.

Firstly you will need to write a class like this:

 import org.fife.rsta.ac.LanguageSupport;
 import org.fife.rsta.ac.js.JavaScriptCompletionProvider;
 import org.fife.rsta.ac.js.JavaScriptLanguageSupport;
 import org.fife.rsta.ac.js.SourceCompletionProvider;
 import org.fife.rsta.ac.js.ast.type.ecma.v5.TypeDeclarationsECMAv5;
 import org.fife.rsta.ac.js.engine.RhinoJavaScriptEngine;
 import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
 import org.fife.ui.rsyntaxtextarea.modes.JavaScriptTokenMaker;

public class RhinoJavaScriptLanguageSupport extends JavaScriptLanguageSupport
{
    private static final String ENGINE = RhinoJavaScriptEngine.RHINO_ENGINE;

public RhinoJavaScriptLanguageSupport()
{
    JavaScriptTokenMaker.setJavaScriptVersion("1.7");
    setECMAVersion(TypeDeclarationsECMAv5.class.getName(), getJarManager());
}

@Override
protected JavaScriptCompletionProvider createJavaScriptCompletionProvider()
{
    return new JavaScriptCompletionProvider(new MySourceCompletionProvider(), getJarManager(), this);
}
public void install(RSyntaxTextArea textArea)
{
    //remove javascript support and replace with Rhino support
    LanguageSupport support = (LanguageSupport)textArea.getClientProperty("org.fife.rsta.ac.LanguageSupport");
    if (support!=null) {
        support.uninstall(textArea);
    }
    super.install(textArea);
}
private class MySourceCompletionProvider extends SourceCompletionProvider
{
   public MySourceCompletionProvider()
    {
        super(ENGINE, false);
    }
}
}

You will need to register the class with the RSyntaxTextArea like this:

private RSyntaxTextArea createTextAreaEditor() {
    textAreaEditor = new RSyntaxTextArea();
    textAreaEditor.setCaretPosition(0);
    textAreaEditor.requestFocusInWindow();
    textAreaEditor.setMarkOccurrences(true);
    textAreaEditor.setTabsEmulated(true);
    textAreaEditor.setTabSize(4);
    ToolTipManager.sharedInstance().registerComponent(textAreaEditor);

    textAreaEditor.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT);
    textAreaEditor.setCodeFoldingEnabled(true);
    textAreaEditor.setAntiAliasingEnabled(true);

    configureLanguageSupport(textAreaEditor);
    return textAreaEditor;
}

private void configureLanguageSupport(RSyntaxTextArea textArea) throws IOException
{

    RhinoJavaScriptLanguageSupport support1 = new RhinoJavaScriptLanguageSupport();
    JarManager jarManager = support1.getJarManager();
    jarManager.addCurrentJreClassFileSource();
    //add additional libraries and classes
    jarManager.addClassFileSource(new JarLibraryInfo("d:/projects/client.jar"));
    support1.install(textArea);
}

Note that if you have the source file in the library archive also, you will also see the Javadoc comments for the methods and fields.

Also you will be able to import package using the syntax:

package(java.io);
var myFile = new File();
.....

The auto complete for Java classes should really be implemented in the JSR223JavaScriptEngine, but has not been moved yet. Also it needs to be easier to switch modes between the engines instead of overriding an entire class.

Anyway. I hope this helps.

Steve

stevenupton avatar Dec 03 '13 11:12 stevenupton

thanks for your answer Mr. Steve Upton, I will try with the above code. Regards.

iberck avatar Dec 03 '13 16:12 iberck

Steve:

I have tried with your example and it works, thank you very much !

Can you help me with another question?

How can I add custom completions to JavaScriptCompletionProvider, for example add a code template for insert a predefined constant when press ctrl + space ?

I have tried adding a basic completion in constructor of MySourceCompletionProvider but it does not work:

private class MySourceCompletionProvider extends SourceCompletionProvider {

        public MySourceCompletionProvider() {
            super(ENGINE, false);
            addCompletion(new BasicCompletion(this, "abstract", "this is the description", "this is the summary"));
        }
}

Thanks in advance.

iberck avatar Dec 07 '13 16:12 iberck

Hi iberck,

The object you really need is the ShotHandCompletionCache inside the Source completion provider. But you cannot access this because it is not protected and does not have a getter. A bit of an oversight.

The whole API needs a bit of work.

Anyway, you can get round it by modifying your overridden SourceCompletion class as before and intercepting the getAlreadyEnteredText method... e.g

private class MySourceCompletionProvider extends SourceCompletionProvider {
    private ArrayList<Completion> myCompletions = new ArrayList<Completion>();

    public MySourceCompletionProvider()
    {
        super(ENGINE, false);
        createMyCompletions();
    }

    private void createMyCompletions()
    {
        //add my completions here
        myCompletions.add( new MyBasicCompletion(this, "abstract", "this is the description", "this is the summary"));
    }


    public String getAlreadyEnteredText(JTextComponent comp) {

        String text = super.getAlreadyEnteredText(comp);
        if(text != null && text.length() > 0) //only add the completions if text is entered, remove this check to always add them
            completions.addAll(myCompletions);
        return text;
    }

    private  class MyBasicCompletion extends BasicCompletion implements JSCompletionUI
    {

        public MyBasicCompletion(CompletionProvider provider, String replacementText, String shortDesc, String summary)
        {
            super(provider, replacementText, shortDesc, summary);
        }

        @Override
        public int getRelevance()
        {
            //keep me to the bottom of the completions
            return TEMPLATE_RELEVANCE;
        }


    }
}

This is not pretty, but there is not other way to add the completions. Looks like a big hole in the API.

Kind regards

Steve

stevenupton avatar Dec 09 '13 11:12 stevenupton

Hi Steve:

Thank you for your answer and your time, I will try with it.

iberck avatar Dec 09 '13 18:12 iberck

Thanks again Steve, the example works fine for my purposes, are there any way to add custom highlight to default javascript highlight, for example highlight the "importPackage" sentence?

I have tried modifing JavaScriptTokenMaker.flex, are there any best way ?

Kind regards.

iberck avatar Dec 10 '13 01:12 iberck

The only way I have changed this is to modify the flex and recompile it.

The importPackage is Rhino specific, so maybe there needs to be a RhinoJavaScript.flax file?

I originally added the JavaScript syntax/autocomplete as I needed it for a project at work. It is loosely based on the Java completions. It is not completely finished and some bits needs reworking as inner functions do not work that well. I have written all the JavaScript API as Java classes and pass them, but I would like to replace this with pure JavaScript files once I (or someone else) have fixed the inner functions and other areas I have missed.

On the whole, I would expect it to support most autocomplete/syntax.

Steve

stevenupton avatar Dec 10 '13 10:12 stevenupton

Thank you steve, it works !!!

iberck avatar Dec 20 '13 17:12 iberck

Hi ,

I want to know how to apply custom javascript library to language support?

rashmijl avatar Feb 13 '18 09:02 rashmijl