Intentions are a very good example of how MPS enables language authors to smoothen the user experience of people using their language. Intentions provide fast access to the most used operations with syntactical constructions of a language, such as "negate boolean", "invert if condition," etc. If you've ever used IntelliJ IDEA's intentions or similar features of any modern IDEs, you will find MPS intentions very familiar.
Using intentions
Like in IDEA, if there are avaliable intentions applicable to the code at the current position, a light bulb is shown. To view the list of avaliable intentions, press Alt+Enter or click the light bulb. To apply an intention, either click it or select it and press Enter. This will trigger the intention and alter the code accordingly.
Example: list of applicable intentions
Intention types
All intentions are "shortcuts" of a sort, bringing some operations on node structure closer to the user. Three kinds of intentions can be distinguished: regular intentions, "surround with" intentions and "generate" intentions.
Generally speaking, there is no technical difference between these types of intentions. They only differ in how they are typically used by the user.
regular intentions are listed on the intentions list (the light bulb) and they directly perform transformations on a node without asking the user for parameters customizing the operations.
"surround with" intentions are used to implement a special kind of transformation - surrounding some node(s) with another construct (e.g. "surround with parenthesis"). These intentions are not offered to the users unless they press ctrl-alt-T (the surround with command) on a node. Neither they are shown in general intentions pop-up menu.
"generate" intentions are used to produce some new nodes using user-specified parameters. In contrast with regular intentions, intentions of this type can show some interactive UI. This type of intentions has its own shortcut - alt-insert (ctrl-n on Macs)
Common Intention Structure
Regular Intentions
is error intention - This flag is responsible for an intention's presentation. It distinguishes two types of intentions - "error" intentions which correct some errors in the code (e.g. a missing 'cast') and "regular" intentions, which are intended to help the user perform some genuine code transformations. To visually distinguish the two types, error intentions are shown with a red bulb, instead of an orange one, and are placed above regular intentions in the applicable intentions list.
Parameterized regular intentions
Intentions can sometimes be very close to one another. They may all need to perform the same transformation with a node, just slightly differently. E.g. all "Add ... macro" intentions in the generator ultimately add a macro, but the added macro itself is different for different intentions. This is the case when parameterized intention is needed. Instead of creating separate intentions, you create a single intention and allow for its parametrization. The intention has a parameter function, which returns a list of parameter values. Based on the list, a number of intentions are created , each with a diferent parameter value. The parameter values can then be accessed in almost every intention's method.
| Note You don't have an access to the parameter in the isApplicable function. This is because of performance reasons. As isApplicable is executed very often and delays would quickly become noticeable by the user, you should perform only base checks in isApplicable. All parameter-dependent checks should be performed in the parameter function, and if a check was not passed, this parameter should not be returned |
Surround With - Intentions
This type of intentions is very similar to regular intentions and all the mentioned details apply to these intentions as well.
Generate - Intentions
The main difference from the general intentions is the executeUI function, which is executed before regular execute and is supposed to present some UI to the user. If the UI returns false, no further processing is done - the execute function is not performed
| Note It is not a good idea to show UI in the execute function - such a code will mostly likely throw an exception at runtime |
Where to store my intentions?
You can create intentions in any model by importing the intentions language. However, MPS collects intentions only from the Intentions language aspects. If you want your intentions to be used by the MPS intentions subsystem, they must be stored in the Intentions aspect of your language.
Examples
You can find some intentions examples in jetbrains.mps.baseLanguage.intentions.
You can also see all intentions by going to the IntentionDeclaration concept (press Ctrl+N, type "IntentionDeclaration", press ENTER) and finding all instances of this concept (pres Alt+F7, check instances, check Global Scope).