Child pages
  • Scripting IDE for DSL awareness

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

GroovyDSL scripting framework

GroovyDSL is a framework with a domain-specific language designed to define the behaviour of end-user DSLs as script files which are executed by the IDE on the fly, bringing new reference resolution and code completion logic into the scope of a project. GroovyDSL relies on the Program Structure Interface (PSI), a set of internal classes and interfaces of IntelliJ IDEA, which allow all programming languages to be described in a uniform way. Due to Groovy's meta-programming capabilities, the developer of DSL descriptions in GroovyDSL need not be aware of how PSI works. All interoperation with PSI is covered by calls to methods and properties of GroovyDSL scripts.

Stable builds of IntelliJ IDEA with embedded JetGroovy plugin and GroovyDSL support are available at http://www.jetbrains.net/confluence/display/IDEADEV/Maia+EAP.

Writing a simple GroovyDSL script

Let's write a simple GroovyDSL script to add a piece of new behavior to an existing class. If you create a new Java project in IntelliJ IDEA, make sure, that you attach Groovy facet to it. For existing projects Groovy facet may be adjusted via Project Structure settings. Also don't forget to attach Java SDK to your project.

...


 
Switching back to the DayCounter script we'll see that `daysFromNow' is highlighted now as a class property, and, moreover, it's available for completion. This works pretty like Dynamic Properties feature, but GroovyDSL scripting gives much larger freedom in defining context. For example, by script we just have written, `daysFromNow' property will be available only on top of DayCounter scripts, not in others, whereas being defined with dynamic properties it would be available in all Groovy files in project. Of course, there are various scopes to define contexts of different granularity.

More examples of GroovyDSL scripts.

GroovyDSL internal language relies on the IntelliJ IDEA open API, namely the set of Program Structure Interfaces (PSI). All GroovyDSL functions and properties are nothing but wrappers around existing PSI interfaces. To get an adequate code assistance with code completion it's strongly recommended to attach openapi.jar from $IDEA_DIR/lib folder as a library to an actual project. GroovyDSL scripts will be working fine even without it being attached, but in this cases some references will be marked as unresolved. In light of said above, all standard PSI methods are available in GroovyDSL as well as synthetic ones, described below.

...

Several predefined GroovyDSL methods are used in this code fragment. enclosingCall(methodName) call returns a mathod invocation expression of a given context with a name, matching methodName or null otherwise. delegatesTo method takes an expression and adds all member of its type to the augmented class reference. In the given example this is enclosing closure, since the context's scope is defined as closureScope().

Contexts and contributors

In this section we give an overview of two main GroovyDSL concepts: contexts and contributors
In GroovyDSL context is an entity which is supposed to give an answer to the question ``Where?''. In other words, defining context one describes a place, where some behavior will be available without any reference to the kind of this behavior. The context may be considered as a groovy program with a ``hole'', which stays for a method or property invocation. Contexts are first-order citizens in GroovyDSL, so they may be stored in local script variables and passed as parameters.

...

Code Block
contributor [ctx1, ctx2], {
 method name: "foo",
         params: [s: "java.lang.String"],
         type: "int"
}

Extending GroovyDSL.

The core of GroovyDSL functionality is concentrated in a body of closures, passed to the contributor() method as a second parameter. All invocations of functions and properties inside of it are calls to wrappers around internal IntelliJ IDEA's PSI. There are two kinds of such wrappers. The first kind is unqualified ones, such as findClass(). The second kind is methods, added to the original PSI classes via the mix-in categories mechanism. For example, methods property is added externally by a GroovyDSL environment to the PsiClass class.

...

Code Block
public class PsiClassCategory implements PsiEnhancerCategory {

  @Nullable
  public static String getQualName(PsiClass clazz) {
    return clazz.getQualifiedName();
  }
// Other category methods
...
}

Describing GroovyDSL internal language in its own terms

Since GroovyDSL language is freely extensible in terms of IDEA PSI, here we list all GroovyDSL methods, available to invoke on the top-level of scripts or in the body of a closure, passes to contributor as a parameter. The code below is an actual script, describing the semantics of GroovyDSL build-up atop of IDEA PSI.

...