MakeGroovyInNetBeansGreatAgain

Contents

Mission Statement

This is a initiative of a small group of highly motivated NetBeans / Groovy enthusiasts to Make Groovy in NetBeans Great Again (tm) by providing patches for some of the major issues in the Groovy support.

Motivation
We are currently using a lot of Gradle and Spock testing and discovered some issues in our favorite IDE and decided to give it a try fixing at least some of them (or provide better extension mechanism for others to use). We have a long standing IDE plugin and platform development history.
Goal
The focus is on editor / code completion improvements for DSL's based on Groovy and new Groovy features.
Non Goal
Improve Grails Support (Sorry, we are Gradle/DSL guys)

Team

  • Sven Reimers (sreimers at netbeans dot org)
  • Martin Klähn (mklaehn at netbeans dot org)
  • and support from the current maintainer of Groovy support in NetBeans Bruno Flavio.

Join the team now! We need all the help we can get!

Enhancements

DSL Support

Completion Provider

Issues

Status

The actual strategy for providing custom/enhanced code completion is to register additional
org.netbeans.modules.groovy.editor.spi.completion.CompletionProvider
in the global lookup (service declaration). This has a major drawback - all custom completions will be visible to all source files that are marked with text/x-groovy mime type. If you have a DSL you may come up with some special completion ideas (e.g. task names in Gradle) that are not applicable in other contexts.

Proposal

Allow discovery of CompletionProvider(s) from the mime lookup
MimeLookup.getLookup(MimePath.get(...getMIMEType())).lookupAll(CompletionProvider.class)
e.g. in groovy.editor/src/org/netbeans/modules/groovy/editor/completion/provider/CompletionProviderHandler.java the discover code could be enhanced like this.
    Collection<? extends CompletionProvider> mimeTypeBasedCompletionProvider = 
                  MimeLookup.getLookup(MimePath.get(context.getSourceFile().getMIMEType())).lookupAll(CompletionProvider.class);    
            
    for (CompletionProvider provider : mimeTypeBasedCompletionProvider) {
        for (Map.Entry<MethodSignature, CompletionItem> entry : provider.getMethods(context).entrySet()) {
            if (entry.getKey().getName().startsWith(context.getPrefix())) {
                result.put(entry.getKey(), entry.getValue());
            }
        }
    }

Impact

Low. There would be no change in behaviour for the current NetBeans distribution, just an additional extension point, which can be used by external supports e.g. Gradle plugin for NetBeans.

Default Imports

Issues

Status

The actual strategy for providing custom/enhanced code completion is to register additional
org.netbeans.modules.groovy.editor.spi.completion.DefaultImportsProvider
in the global lookup (service declaration). This has a major drawback - all custom default imports will be visible to all source files that are marked with text/x-groovy mime type. If you have a DSL you may come up with some special default imports that are not applicable in other contexts.

Proposal

Allow discovery of DefaultImportsProvider(s) from the mime lookup
MimeLookup.getLookup(MimePath.get(...getMIMEType())).lookupAll(DefaultImportsProvider.class)

e.g. methods could be introduced in groovy.editor/src/org/netbeans/modules/groovy/editor/imports/ImportUtils.java

    public static Set<String> getDefaultImportPackages(MimePath mimePath) {
        Set<String> defaultPackages = getDefaultImportPackages();
        
        for (DefaultImportsProvider importsProvider : MimeLookup.getLookup(mimePath).lookupAll(DefaultImportsProvider.class)) {
            defaultPackages.addAll(importsProvider.getDefaultImportPackages());
        }
        
        return defaultPackages;
    }

    public static Set<String> getDefaultImportClasses(MimePath mimePath) {
         Set<String> defaultClasses = getDefaultImportClasses();
        
         for (DefaultImportsProvider importsProvider : MimeLookup.getLookup(mimePath).lookupAll(DefaultImportsProvider.class)) {
            defaultClasses.addAll(importsProvider.getDefaultImportClasses());
         }
        
         return defaultClasses;
     }    

Impact

Low. There would be no change in behaviour for the current NetBeans distribution, just an additional extension point, which can be used by external supports e.g. Gradle plugin for NetBeans.

CompilerConfiguration

Groovy allows for customizing the compilation process by supplying a CompilerConfiguration (see GinA for an excellent description how this can be used for DSL building). The configuration allows for specification of the Script superclass, AST transformations, injection of bindings ...

Status

The current NetBeans compilation unit does not allow for customizing the configuration. The code reads:

        FileObject fo = context.snapshot.getSource().getFileObject();
        ClassPath bootPath = fo == null ? ClassPath.EMPTY : ClassPath.getClassPath(fo, ClassPath.BOOT);
        ClassPath compilePath = fo == null ? ClassPath.EMPTY : ClassPath.getClassPath(fo, ClassPath.COMPILE);
        ClassPath sourcePath = fo == null ? ClassPath.EMPTY : ClassPath.getClassPath(fo, ClassPath.SOURCE);
        ClassPath cp = ClassPathSupport.createProxyClassPath(bootPath, compilePath, sourcePath);

        CompilerConfiguration configuration = new CompilerConfiguration();
        final ClassNodeCache classNodeCache = ClassNodeCache.get();
        final GroovyClassLoader classLoader = classNodeCache.createResolveLoader(cp, configuration);
        final GroovyClassLoader transformationLoader = classNodeCache.createTransformationLoader(cp,configuration);        
        ClasspathInfo cpInfo = ClasspathInfo.create(
                // we should try to load everything by javac instead of classloader,
                // but for now it is faster to use javac only for sources - not true

                // null happens in GSP
                bootPath == null ? ClassPath.EMPTY : bootPath,
                compilePath == null ? ClassPath.EMPTY : compilePath,
                sourcePath);        
        CompilationUnit compilationUnit = new CompilationUnit(this, configuration,
                null, classLoader, transformationLoader, cpInfo, classNodeCache);

Proposal

Add a new extension point

    package org.netbeans.modules.groovy.editor.spi.parser.;

    public interface CompilerConfigurationProvider {
        public CompilerConfiguration getCompilerConfiguration(GroovyParser.Context context /*TBD is this really needed?*/);
    }   

which can be registered and retrieved via mime type lookup, so that the upper snippet may read like this (just brainstorming here)

        FileObject fo = context.snapshot.getSource().getFileObject();
        ClassPath bootPath = fo == null ? ClassPath.EMPTY : ClassPath.getClassPath(fo, ClassPath.BOOT);
        ClassPath compilePath = fo == null ? ClassPath.EMPTY : ClassPath.getClassPath(fo, ClassPath.COMPILE);
        ClassPath sourcePath = fo == null ? ClassPath.EMPTY : ClassPath.getClassPath(fo, ClassPath.SOURCE);
        ClassPath cp = ClassPathSupport.createProxyClassPath(bootPath, compilePath, sourcePath);

        CompilerConfigurationProvider ccp = MimeLookup.getLookup(MimePath.get(context.snapshot.getSource().getMIMEType())).lookup(CompilerConfigurationProvider.class);

        CompilerConfiguration configuration = ccp == null? new CompilerConfiguration() : ccp.getCompilerConfiguration();
        final ClassNodeCache classNodeCache = ClassNodeCache.get();
        final GroovyClassLoader classLoader = classNodeCache.createResolveLoader(cp, configuration);
        final GroovyClassLoader transformationLoader = classNodeCache.createTransformationLoader(cp,configuration);        
        ClasspathInfo cpInfo = ClasspathInfo.create(
                // we should try to load everything by javac instead of classloader,
                // but for now it is faster to use javac only for sources - not true

                // null happens in GSP
                bootPath == null ? ClassPath.EMPTY : bootPath,
                compilePath == null ? ClassPath.EMPTY : compilePath,
                sourcePath);        
        CompilationUnit compilationUnit = new CompilationUnit(this, configuration,
                null, classLoader, transformationLoader, cpInfo, classNodeCache);

Not sure this will be sensible for all DSL's due to scope of compilation occuring here. Open issue here is how this may work for a whole compilation unit in case of compiling multiple scripts. Assumption is that this may work beautifully for single files, but not in a larger project context. Needs probably more prototyping.

Impact

Low. There would be no change in behaviour for the current NetBeans distribution, just an additional extension point, which can be used by external supports e.g. Gradle plugin for NetBeans.

Language Features

Traits

Issues

Status

Not supported at all, throws Assertions/Exception (root cause is probably the misterious Annotation added by the parser/compiler that has no "location" in the source file and causes hiccups in the caret position detection.

Proposal

  • Fix occuring exceptions (started)
  • Add to Groovy Keywords (started)
  • Fix Completion for traits
    • traits can only be used in implements clause
    • traits only support extends clause
    • method and field completion should work out of the box (Assumption to be verified)
  • Add file template for new "Groovy Trait"

Impact

Medium. Maybe even Low but changes to critical parts of the code completion / typing required. The underlying groovy version / lexer / parser already supports traits.

Editor

Code Completion

Navigator

  • Add NavigatorPanel Trees (NetBeans Development) showing the Tokens from the lexing (compare to Java) - should be helpful in debugging code completion

Support for Spock

  • Test Long and Prosper with Spock in NetBeans
  • Templates / Wizards
  • Fix edge cases from "huge" ASTTransformation Spock applies
  • TestResult Window is already working out-of-the-box (nice!)

Misc

  • [GradleProject] Renaming the file is not renaming the class in the file. Refactoring support.
  • Import is not working. (sometimes - Spock Tests?)
  • Go to type is not working. (sometimes - Spock Tests?)
  • Hyperlink navigation from output window is not working. (sometimes - Spock Tests?)

To be continued...

Not logged in. Log in, Register

By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2012, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo