Table of Contents


IntelliLang is a combination of three basic kinds of functionality that are meant to support the developer in dealing with certain tasks that relate to (custom) languages in IntelliJ IDEA:

Following an old tradition, IntelliLang and Regular Expression Support have been inspired by an open IntelliJ IDEA feature request: IDEADEV-2599

Language Injection

This makes use of the new possibilities IntelliJ IDEA 6.0 to treat String literals, XML text and attributes as fragments of an arbitrary language (called "Language Injection"). The plugin makes this newly introduced API readily available to everybody for their daily use through two very simple means: Either by using some Java annotations to mark String fields, local variables, method parameters and methods returning Strings as containing a certain language, or by just using a simple UI configuration. There is a set of annotations provided by the plugin, but the actual annotations are freely configurable to avoid any unwanted dependencies.

This enables the developer to get the benefit of a wide range of edit-time features, such as syntax error highlighting, completion, inspections and a lot more while editing fragments of e.g. JavaScript inside regular Java code or in XML files of custom schemas that IntelliJ IDEA usually doesn't know about.

Pattern Validation

Additionally, the plugin allows to annotate Java elements of type String to have them checked for compliance with certain Regular Expressions. This can be useful for very simple "languages" where the developer needs to make sure that an expression conforms to a certain syntax, e.g. that a String is a legal Java identifier or a valid printf-like pattern used by java.util.Formatter.

This can both be validated on-the-fly while editing the code as well as during runtime (method parameters and return value only, like the @NotNull instrumentation of IDEA core) by instrumenting the compiled classes with assertions that match the value against the supplied pattern.

Regular Expression Support

This part of the plugin implements language-support for java.util.regex.Pattern and has been mainly created to support the IntelliLang plugin by adding support for the micro-language that is probably one of the most often used one inside Strings. It features complete support for the syntax of the JDK's regular expression implementation and adds some further features, such as

General Usage

The plugin's usage is simple and straightforward, yet very flexible. Either add the provided set of annotations to your project and start using them, configure the plugin to use a custom set of annotations or simply use the UI configuration to make IDEA learn that e.g. the String argument of Pattern.compile() should be treated as a regular expression.

Using the Annotations

IntelliLang makes use of three base-annotations: @Language, @Pattern and @Subst

The annotations supplied with IntelliLang are located in the file annotations.jar which can be found in %IDEA-CONFIG%/plugins/IntelliLang/lib.


The @Language annotation can be used to annotate String fields, local variables, method parameters and methods returning Strings. This will cause String-literals that are assigned to a field/variable, passed as a parameter or are used as a method's return value to be interpreted as the specified language.

Additionally, there's the Language Mismatch inspection which checks for clashes between the "expected language" and the "actual language" when a field/variable is assigned or a value returned from a method.

The plugin supports "direct" and "indirect" annotations, i.e. you can either directly use the annotation like this:

String code = "var x = 1 + 2";

or annotate another annotation class like this:

public @interface XPath { }

which can then simply be used to annotate elements as @XPath.

It's very easy to obtain the language-id that must be supplied as the annotation's value attribute: IntelliLang provides the list of available language via the regular code-completion action. Just select the appropriate language from the ctrl-space popup:


The @Pattern annotation is responsible for marking Strings that have to comply with a certain regular expression and can be used in just the same way as the @Language annotation. That means, it's possible to create derived annotations, such as an @Number annotation that requires a String to consist of one or more digits:

public @interface Number { } 

In fact, the predefined annotations already contain two of such derived annotations: The first one, @PrintFormat, matches the printf-like pattern used by java.util.Formatter and another one, @Identifier, describes a valid Java identifier. These are ready to use without having to specify any additional pattern.


The @Subst annotation is used to substitute references that are not compile-time constant which enables the plugin to do Pattern Validation based on the assumption that the substituted value is compatible with the values that are expected during runtime. The plugin will complain if the value does not match the expected pattern.

It also helps to build a valid context of prefix/suffix (see next section) for the Language Injection feature. Consider this example:

final String font = new JLabel().getFont().getName();

String message = "<html><span style='font: " + font + "; font-size:smaller'>" + ... + "</span></html>";

Without substituting the value of the variable font with the value "Tahoma" (actually it could just be a single character here), the injected fragment would be syntactically incorrect, causing the error "a term expected" to be displayed after the "font:" instruction.

Supplying Context: Prefix and Suffix

When annotating an element, it's possible to supply a prefix and a suffix that should be prepended/appended when the language fragment is being parsed. This can be used to supply context information, i.e. if the prefix for a JavaScript injection is "var someContextVariable;", IDEA will know that the variable "someContextVariable" is declared and will not warn about it being undeclared when it's used.

Apart from the manual possibility to supply a prefix and suffix, IntelliLang dynamically determines those values from the context a String literal is being used in:

@Language(value = "JavaScript", prefix = "function doSomethingElse(a){ }")
String code = "function doSomething() {\n" +
"  var x = 1;\n" +
"  doSomethingElse(x);\n" +

In this example, the JavaScript language will be injected into each of the three String literals, and each one's prefix and suffix will be calculated from the preceding and following expressions so that the resulting text that's being parsed is valid JavaScript syntax:

There are some issues with the IDEA Language Injection API that impose certain restrictions on the prefix/suffix of an injected language fragment. For instance, it's not allowed that a token of the language spans across the prefix/suffix of an element. This could e.g. happen if the prefix ends with a whitespace character and the fragment starts with whitespace. The plugin deals with this special situation in the way that it trims the prefix/suffix and inserts exactly one space character as a separator. However, this doesn't work if a space character is no token separator, which e.g. applies to JavaScript string literals. Such cases cannot be automatically dealt with and IDEA core will produce an assertion.

Even though the dynamic prefix/suffix calculation provides a proper context for the language fragment, some things  may not work as expected. Most notably this are the refactoring (rename) and navigation functions. See also the known issues below.


The configuration dialog provides the following options:


The screenshots below show come of the configuration options that can be tweaked and will be described in the following sections.

Language Injection

This tab allows to configure the language injection feature for XML text, attributes and method parameters. Use the buttons in the toolbar or the context menu actions to add, remove, copy or import new entries. To add a new entry, the appropriate group has to be selected first.

Reordering the entries is possible with the Move Up and Move Down buttons. This can be important to define the precedence of different XML-injection entries. If an entry matches, no more injections are applied unless the injection specifies a value pattern.

XML Text

After adding a new XML text injection, select the ID of the Language to inject and optionally specify the prefix/suffix that make up the injection's context.

In the "XML Tag" panel, specify the local name (i.e. the name without any namespace prefix) and the namespace URI of the XML tag surrounding the text that should be treated as the selected language. The "name" field should not be empty, however the "namespace" field is optional.

The "Local Name" field takes a regular expression which makes it is possible to specify e.g. multiple tag names (name1|name2), case-insensitive names (e.g. (?i)tagname matches "tagname" as well as "TagName"), etc. Be sure not to enter any whitespace characters as they would be significant for the match.

XML Attributes

This is similar to the XML text configuration. However, it is possible to leave the "name" of the "XML Tag" empty which means that the configuration will apply to any attribute that matches the configured name, regardless of its containing XML tag.

The attribute's name takes the local name of the attribute and is also specified as a regular expression. This can be e.g. used to match e.g. HTML event handler attributes by specifying the name "on.*". The attribute name may also be empty (unless the tag name is empty as well) which means that the configuration applies to all attributes of the containing tag.

Advanced XML Options

The "Advanced" panel for XML Text and Attributes allows an even more fine-grained control over the injection process.

Value Pattern

This field takes a regular expression that determines what part of the XML text's or attribute's value the language should be injected into. This can be used to inject the language only into values that match a certain pattern or to inject it into multiple parts that match the pattern. This is done by using the first capturing group of the pattern as the target for the injection.



This matches the pattern used by the JSP/JSF Expression Language. Injecting Expression Language (EL) doesn't work currently, but will be available with IntelliJ IDEA 6.0.2.


This matches the "javascript"-protocol that can be used in hyperlink-hrefs to execute JS code.

XPath Condition

This field takes an XPath expression that can be used to address the injection-target more precisely than just by supplying its name and namespace URI. The context the expression is evaluated in is the surrounding XML tag for XML Text injection and the attribute itself for XML Attribute injection.



This limits the injection to tags whose type attribute contains the value "text/javascript".

It's possible to use the XPath extension functions that are provided by the Jaxen XPath engine, e.g. lower-case(). Also, there are three additional functions that can be used to determine the current file's name, extension and file type: file-name(), file-ext() and file-type(). You can also use normal code-completion to get a list of available functions.

For performance reasons, it's recommended to keep these expressions as simple as possible. Especially expressions that cause the whole document to be scanned, such as //foo/bar might cause performance problems with large files.

Method Parameters

This is a possibility to make use of IntelliLang's features, if, for any reason, the injection annotations cannot be used. This mainly applies to configuring 3rd party/library methods as well as projects that still have to use Java 1.4.

The language selection is identical to the one described above. To select one or more parameters of a certain method, first choose its containing class either by typing in the name (the textfield supports completion) or by using the class chooser available through the [...] button. Next, select a method using the [...] button inside the "Method-Name" panel (it's not possible to edit the method name manually). Once a method has been chosen, the table in the "Parameters" panel is populated with the parameters of the selected method. Select the checkbox in the first column to have the selected language injected into arguments passed for this parameter. Note that only parameters of type String can be selected.

There's already an IDEA-core (Inspection Gadgets rather) inspection that checks the arguments of some well-known methods to be a valid regular expression. However, IntelliLang can provide more detailed error messages and all the features of the Regular Expression Support plugin.

The XPath language that is configured by default for some of the standard XPath-APIs is provided by the XPathView + XSLT-Support plugin, which is available here.

Importing Configuration Entries

To import the injection configuration from another IDEA installation use the "Import" button from the toolbar and select the file "IntelliLang.xml" from %IDEA-CONFIG-HOME%/options or from a JAR file that contains some exported (via File | Export Settings) IDEA settings. After selecting the file, a new dialog displays the entries contained in that file. Use the Delete-button to remove all entries you don't want to import. Note that this will not change the selected configuration file.

This selective import-feature makes it easy to share certain configurations in a team without losing any local entries like when importing settings via the core File | Import Settings action.

To prevent inconsistent data, the import is only possible if the existing configuration is unchanged or has been saved with the "Apply" button.

Advanced Settings

The advanced configuration tab allows to specify different names for the base-annotations that should be used. This helps to avoid any dependencies on foreign code where this is not desired or possible. The custom annotations should just provide the same properties as the original ones, i.e. value for all of them and an optional (default = "") prefix and suffix for the @Language replacement.

Here it's also possible to configure the kind of runtime checks the plugin should generate for the @Pattern validation:

Contributed Configurations

Additional configurations can be downloaded and imported from here. This community effect can help to minimize the configuration efforts and make IntelliLang even easier to use.



Contributed By

JavaScript-Support for HTML Event-Handler Attributes of Struts Taglibs


Yann Cébron

Struts/JSF-Support will eventually be added to IDEA itself. Once this is done, this configuration should be removed to avoid any potential conflicts.

Got a configuration for a popular framework or API that should be listed here? Just post a comment with configuration instructions or attach an exported XML config file (make sure it contains only those entries that should be listed).

Code Inspections

IntelliLang contains a set of inspections that validate the correct use of the supplied annotations (or custom configured ones). These inspections can be configured through the regular Settings | Errors configuration dialog.

Language Injection

The inspections in this category apply to the language injection feature related to the @Language annotation

Unknown Language ID

This inspection provides validation for the use of non-existing Language-IDs. It flags usages of incorrect values of the @Language's value attribute, such as @Language("NonExistingID")

Language Mismatch

Validation for using references to elements that are annotated as containing different languages or are not annotated at all. The inspection offers a QuickFix to annotate such elements with the right annotation for the expected language.

Injection not applicable

This inspection checks whether an @Language or any derived annotation is used for anything other than elements of type String or String[].

Pattern Validation

This category contains inspections about validating the use of the @Pattern or its derived annotations.

Validate Annotated Patterns

This inspection validates that expressions (String literals, as well as other compile-time constant or substituted expressions) match the pattern required by the @Pattern annotation. The inspection has an option to ignore non-constant expressions that contain non-substituted references and offers a QuickFix to add a substitution where applicable.

Pattern Annotation not applicable

Checks whether a pattern-validation annotation (@Pattern or derived ones) is valid to be applied to the annotated element. Only elements of type String may be annotated.

Non-annotated Method overrides @Pattern Method

This inspection checks whether a method without any @Pattern or derived annotation overrides an annotated method from its base classes. This is not necessary for the error-highlighting inside the editor, however the runtime-check instrumentation doesn't pick up annotations from base-class methods.

A QuickFix is provided to add an annotation that matches the one from the base-class method. This ensures that the runtime-check instrumentation works correctly.

Quick Edit Language

This is an experimental feature that can be extremely helpful, especially for editing Regular Expression patterns inside String literals due to the "double escaping" requirement. For example, in a regular expression, a literal backslash character has to be written as a double backslash and each of them has to be escaped with another backslash when written inside a String literal.

The Quick Edit function that appears as an Intention Action for any injected language fragment displays a popup dialog that allows to edit the string's value without the double escaping requirement. The dialog also shows the particular prefix/suffix of the fragment in a non-editable area.

The popup can be dismissed by pressing Escape or clicking somewhere outside the popup. Any changes made in the popup are committed by pressing Ctrl-Enter.

Please note that the formatting of the non-editable prefix/suffix may differ from the actual value due to the problems described here. However, even though the formatting/alignment of the editable text may differ from the expected text, making changes to the text still works as expected.

Accepting Inspection QuickFixes inside the QuickEdit popup may cause strange things to happen when the QuickFix attempts to open an Editor for the element being edited. The "Create Method" QuickFix of the JavaScript language is an example for that.

Usage Examples

Among the rather simple use-cases, like having detailed syntax checks for all kinds of "micro-languages" that are used e.g. in Pattern.compile(), XPath.compile() and so on, here are some less obvious, yet very useful examples how IntelliLang can leverage IDEA's support for a much better coding assistance.

The new scripting support in the upcoming Java 1.6 is another case where it will be important to get as much as possible edit-time assistance when script-code is constructed from Java code.

Extended JavaScript Support

When dealing with JavaScript that's not directly embedded inside an HTML page, IDEA usually just treats it as plain text. Consider the following example that creates an HTML page from an XSLT script. Without the JavaScript language being injected into the "script" tag with the XHTML namespace as shown in the screenshot below, this would be treated as plain text, with no further code assistance.

Support for JSP Custom Tags

With IntelliLang it's also possible to make the content and attributes of custom JSP tags being treated as another language. This can be useful e.g. for server-side scripting using JavaScript or any other Language implementation available for IntelliJ IDEA.

One thing that's important to know is that the taglib's URI which supplies a custom tag should be used as the namespace URI of the XML tag to inject a language into. The namespace-textfields contain a list of all known taglib URIs in the project.

Unfortunately, at the moment the support for refactoring and navigation inside JSP custom tags seems to be broken and attempting to use code completion may result in exceptions thrown in IDEA core. See also the known issues below.

Pattern Validation

Here's an obvious example right from IntelliJ IDEA's OpenAPI:

 * @return descriptive name to be used in "suppress" comments and annotations,
 *         must consist of [a-zA-Z_0-9]+
@NonNls @NotNull public String getID() {
  return getShortName();

The contract of the method getID() is that it should only return strings that match the pattern "[a-zA-Z_0-9]+". The short note in the JavaDoc can be easily overlooked though because the contract isn't specified in an automatically verifiable way.

However, if this method were annotated as @Pattern("[a-zA-Z_0-9]+"), any attempt to return a string that doesn't match that pattern would be flagged in the editor:

Pattern Completion

If a regular expression pattern represents an enumeration of different literal values, the plugin offers completion for those values:

Regular Expression Editing

Here are some examples of the enhanced coding support for regular expression patterns:

Backref Validation

Surround With

Character Category Validation

Character Category Completion


The plugin is available for IntelliJ IDEA 6.0 via the built-in plugin manager and at the IntelliJ Plugin Repository.

Known Issues

Unfortunately, there's a number of issues that can cause problems, have a negative impact on the plugin's stability or just reduce the possible usefulness of the plugin:

You can vote for and watch the open issues to get notified about their progress.


Version 0.8 (2006-10-03)

Version 0.9 (2006-10-09)

Version 1.0 (2006-10-18)

Version 1.1 (2006-10-26)

Version 1.2 (2006-10-31)

Version 1.2.1 (2006-11-12)

Version 1.2.2 (2006-12-13)

Version 1.2.3 (2007-01-23)

Version 2.0 (2007-01-23)

Version 2.0.2 (2007-02-12)

Version 2.0.3 (2007-05-10)

Version 2.1 (2007-05-25)

Version 2.1.1 (2007-06-08)

Version 2.1.3 (2007-08-15)

Version 2.1.4 (2007-08-31)

Version 2.1.5 (2007-09-19)


I'm curious to hear if people find the plugin and the idea behind it useful and will be happy about any comments, critics and suggestions. Just leave a comment here, post in the plugin newsgroup/forum or just send me an email.