JetBrains MPS 2018.3: Generator Plans, refined Build Language, UI/UX improvements, and Stronger Editor
This year’s third and last major release is here! MPS 2018.3 comes with a range of features to help you develop your projects more effectively. Generator plans are available, the Build Language comes with new constructions, and the editor is stronger than ever. That, plus the latest improvements in the user interface and user experience, should definitely make your life easier.
Concept overridden/implemented icons
MPS marks concepts with an overridden/implemented icon, helping you to easily navigate to the superconcept or subconcept of the current concept.
Custom packages for BaseLanguage Classes
For a long time now, the only way to manage Java packages of generated classes was through the name of a containing model. However, with the new Classifier property ‘packageName’, you can manage the Java package of a generated class. This property is available for root classifiers too.
New generation facilities for BaseLanguage extensions
The BaseLanguage was always intended to be customized with lots of extensions. However, for some extensions, it can be tricky to implement a proper generator. Now, the BaseLanguage provides several new generation-time concepts to help make it easier to write the extensions’ generators.
Generating of Lvalue-expressions
Lvalue-expressions are evaluated to variables which can be read or written with a value. For some cases, generating an Lvalue-expression is difficult since it can depend on the kind of context the expression is used in. Now, the new `generic lvalue-expression` generation-time concept can be utilized to make a generator simpler and context-unaware.
Transform Lvalues to references.
Some expressions aggregate other Lvalue-expressions to make compound operations with a variable that is produced from an aggregated expression (e.g., plus assignment or increment and get expressions). Introducing new expressions with such semantics did not use to be feasible because it was difficult to write a proper generator for such constructions.
Fortunately, in the new release, you can wrap an arbitrary lvalue-expression with the `@byRef` expression, so that the baseLanguage generator will then transform the wrapped expression into an expression of type `Reference<T>`, which will provide you with the get and set operations over the wrapped variable.
Both of these newly introduced generation-time concepts are described in more detail in this article.
Default methods support in BaseLanguage
In this new version, MPS can create the ‘default’ methods in BaseLanguage interfaces. The ‘default’ keyword is implemented by the DefaultModifier concept, which extends the Modifier concept in the BaseLanguage. The DefaultModifier is located in the jetbrains.mps.baseLanguage.jdk8 language. This means that in order to create a ‘default’ method in the interface, you need to import the jdk8 language.
The Generator language
The $INCLUDE$ macro has been deprecated, and there’s a migration to replace its instances with $CALL$. The former did not support templates with arguments, and we didn’t see any reason to keep both mechanisms to invoke a template.
The $WEAVE$ macro and weaving rules can now invoke templates with arguments. When an interpreted template weaves an external template from a ‘compiled’ generator, it is no longer interpreted, but the compiled template code is still executed. ‘Compiled’ templates may now weave interpreted templates.
Java reflection is not used to access the collection of queries from a template model, which is also known as QueriesGenerated.
The default context includes controls for running, building, and debugging the application, with the ability to quickly select or create a new run/debug configuration. There is now a new Touch Bar page to customize the actions under Preferences | Appearance & Behavior | Menus and Toolbars.
And yes, it’s extensible! Just add any required actions to a special MPS `InterfaceGroup`.
High-contrast UI Theme
We’ve added support for a new High-contrast Theme, which can be accessed using the drop-down list from the theme options under Preferences -> Appearance & Behavior.
New actions to find deprecated code
The action Find Usages of Deprecated can find all usages of deprecated elements. Now, the report of the found usages, groups the entries by the expected version of code removal, so it’s easier to recognize their severity and prioritize which to eliminate first.
A new icon for overridden or implemented behavior methods
The behavior methods have been equipped with a new icon. The following screenshot shows a list of getPresentation() methods that override or implement the one selected, and it will allow you to navigate to them from there.
Overridden/implemented icons further enhancements
The popups with the overridden/implemented concepts/classes/methods have become asynchronous, which means that in the background MPS will fill the popup with the search results. Also, you can now filter using the name of search objects.
The finders distributed by MPS have been updated and optimized. To execute a finder asynchronously, you’ll need to use the special OnEachNodeFoundByExpression, which represents a simple finder invocation with a callback which is executed for each found node.
Consequently, the find usages options for a concept have been changed. The options have been extended with Derived Concepts and Concept Ancestors, which yield the list of subconcepts and superconcepts, respectively. Also, the find usages options for the behavior methods have been extended with “Overridden Methods” and “Overriding Methods”.
Suppressing specific errors
Error suppressing used to be a rough tool to prevent MPS from showing an error improperly found by the typesystem checker. If a node was annotated with the attribute ‘SuppressErrorAnnotation’ using the intention ‘Suppress error for node …’, no error message was shown for that node or any of its descendants.
Now, there is the possibility to suppress only specific error messages. The error message will be suppressed for the node and all its descendants but any other messages will still remain present. For more information, please see the documentation.
Tips & Tricks
The default tips & tricks for MPS can now be customized. This can be done with the new tips & tricks concept in the build script. Tips can be reused from the general MPS distribution, or they can be imported from a directory or solution.
Tips & Tricks language
To import tips & tricks from a solution, create a solution with a model and add the languages jetbrains.mps.build.tips and jetbrains.mps.core.xml to model the used languages. Then you can create an instance of the MPSTipsAndTricks concept, where multiple tips can be created. Each tip is HTML-formatted text and may include up to one image.
Build packaging options
The custom packaging option in the BuildMps_IdeaPlugin has been deprecated and should not be used from now on. Now it’s possible to choose the packaging directly in the layout BuildMpsLayout_Plugin construction.
With Auto packaging, all the provided languages and solutions are put into the ‘languages’ folder under the plugin root directory and Manual packaging implies that the developer has to provide the whole plugin layout on his own.
New construction in the Build Language
The test module configuration in the build language has been extended to specify additional IntelliJ IDEA plugins which must be loaded when MPS ant tests are executed.
There are scenarios when the test needs a particular plugin in its environment, which the MPS build language engine could not deduce from the modules containing the tests. Now you can ensure that the plugin you need is present during the MPS Ant test execution.
Reusable cell action maps
Cell action map items from an existing action map can be reused in a new one via imports.
Fully compiled datatypes
Moving forward to fully compiled languages, we’ve made datatypes completely generated. All generated information regarding datatypes is now available from SModel API.
Saving migration data as annotations
Now MPS supports a new mechanism of transferring migration data which is highly recommended for newly created migrations. The produced node containing data should be now attached to any node that is close enough to the place to which the data is related.
The migration script producing nodes with data should declare the concept of such nodes and use a putData() construction to insert each such annotation into the model:
Retrieving nodes containing data performs quite the similar way as it used to be:
Improved conflict resolution
Previously, it was impossible to apply changes from both the local and remote sides, as applying from one side simply rejected the changes from the other.
For children in multiple roles, it is not practical if both changes are applied. This is why now, after you apply changes from one side of the conflict, the other conflicting changes are converted into an addition at the end of the changed group. It is necessary to apply or ignore them separately.