Search code examples
eclipseeclipse-pluginjsdt

Add IncludePathEntry to JavaScriptProject programmatically


I have a eclipse plugin contributing a project nature requiring the jsdt javaScriptNature. I now like to add a javascript library contained in my plugin to the includepath of the project programatically. Is there a way i can do this?

I read something about JsGlobalScopeContainer and JsGlobalScopeContainerInitializer and tried them but that seems very confusing. I just want to add a library containing some .js files from my plugin. I just can't get my head around this concept.

This is what i came up with so far:

IJavaScriptProject jsProj = JavaScriptCore.create(p);
Path pa = new Path("/src/de/otris/eclipse/portalscripting/psLibrary/library.js");
IIncludePathEntry entry = JavaScriptCore.newProjectEntry(pa);               
IIncludePathEntry[] ipaths = jsProj.getRawIncludepath();
IIncludePathEntry[] newpaths = new IIncludePathEntry[ipaths.length +1];
System.arraycopy(ipaths, 0, newpaths, 0, ipaths.length);
newpaths[ipaths.length] = entry;
jsProj.setRawIncludepath(newpaths, null);

Solution

  • I finally found a way to add my library directly from my plugin. Allthough the answer of Eugene wasn't to wrong, it lacked some explainations. I'll try to show how to do this.

    If you want to add a library containing several files you can do it this way:

    1. Create a Class extending JsGlobalScopeContainerInitializer
    2. Contribute an extension to the extension point org.eclipse.wst.jsdt.core.JsGlobalScopeContainerInitializer
    3. Add an IIncludePathEntry, pointing to the JsGlobalScopeContainer using its id, to the Project that you want to use the library in

    1. Create a Class extending JsGlobalScopeContainerInitializer

    There are a few very confusing tutorials out there (including the one on the eclipse wiki) that at first made it harder to understand this. I came up with something like the following:

    [... package and imports ommited ...]
    public class LibInitializer extends JsGlobalScopeContainerInitializer {
    
        private static final String LIBRARY_ID = "com.testvendor.testplugin.library";
    
         public IPath getPath() {    
             return new Path(LIBRARY_ID);
         }
    
        @Override
        public LibraryLocation getLibraryLocation() {   
            return null;
        }
    
        @Override
        public String getDescription() {
            return "Test Library";
        }
    
        @Override
        public String getDescription(IPath containerPath, IJavaScriptProject project) {
            return getDescription();
        }
    
        @Override
        public IIncludePathEntry[] getIncludepathEntries() {
    
            try {
                //get the Bundle object of the plugin
                Bundle bundle = Platform.getBundle("com.testvendor.testplugin");
                //get the java.io.File object corresponding to the root of the bundles installation directory
                File bundleFile = FileLocator.getBundleFile(bundle);
                //add the location pointing to the library relative to that bundle root
                File libraryLocation = new File(bundleFile, "bin/com/testvendor/testplugin/library/");              
                //create a Path object from it
                IPath pa = new Path(libraryLocation.getAbsolutePath());
    
                /* create an IIncludePathEntry of the type "library" from this path
                my library only contains one folder (for now) so this is it */
                IIncludePathEntry entry = JavaScriptCore.newLibraryEntry(pa, pa, pa);
                //put the entry (or entries if you had more) into an array and return
                IIncludePathEntry[] entries = {entry};
                return entries;
    
            } catch (IOException e) { 
                e.printStackTrace();
            }       
            return null;
        }   
    }
    

    The most interesting part is the method getIncludepathEntries() where the actual entries will be retrieved from the container. Since an IIncludePathEntry will not work with an URL of the "file://" pseudo-protocol the method "toFileURL" suggested by Eugene will not work here.

    2. Contribute an extension to the JSGlobalScope... extension Point

    To tell Projects containing an container entry with the id com.testvendor.testplugin.library the easiest way is to contribute to the extension point *org.eclipse.wst.jsdt.core.JsGlobalScopeContainerInitializer** like this:

    <extension point="org.eclipse.wst.jsdt.core.JsGlobalScopeContainerInitializer">            
      <JsGlobalScopeContainerInitializer                                          
         id="com.testvendor.testplugin.library"                                                        
         class="com.testvendor.testplugin.library.LibInitializer"/>                           
    </extension>
    

    Where class of course refers to the JsGlobalScopeContainerInitializer from step 1.

    3. adding the IIncludePathEntry to the Project

    IJavaScriptProject jsProj = ... get your project object from somewhere ...
    //create an instance of the container from step 1.
    JsGlobalScopeContainerInitializer container = new LibInitializer();
    //create an includepath entry refering to the container         
    IIncludePathEntry entry = JavaScriptCore.newContainerEntry(container.getPath());
    
    IIncludePathEntry[] ipaths = jsProj.getRawIncludepath();    
    IIncludePathEntry[] newpaths = new IIncludePathEntry[ipaths.length +1];
    
    System.arraycopy(ipaths, 0, newpaths, 0, ipaths.length);
    //add the new entry
    newPaths[ipaths.length] = enty;
    // set the new includepath to the project
    jsProj.setRawIncludepath(newpaths, null);
    

    If you're lucky now you'll have a library entry in your JavaScript Resources containing all JavaScript objects and classes which are contained in the library folder you added with the ContainerIntitializer. And all this objects and classes will be available in the code completion suggestions.

    Finally a library!

    I hope that prevents someone else from spending hours of frustration on a topic that really could be simpler than it is.