After discussing the pros and cons of generic and custom empty lines yesterday, let’s have a look at the steps required to implement custom empty lines. I provide them in the form of a checklist, similar to another language design pattern that I described earlier, Inline definitions.
To make the following text less abstract and easier to follow, I will use an example where we have a StatementList
concept that contains a multiple child statements
of concept Statement
, i.e. statements: Statement[0..n]
. Assuming
that Statement
is abstract and we want to add an EmptyStatement
to represent an empty line, here is what we have to
do:
- Create
EmptyStatement
concept.- Structure:
EmptyStatement
extendsStatement
. - Editor:
EmptyStatement_Editor
consists of a single empty<constant>
cell witheditable : true
style. Making the cell editable will let the user convert (substitute) the empty statement with a non-empty one by typing.EmptyStatement_SubstituteMenu
, the default substitution menu forEmptyStatement
, is defined and left empty. This will causeEmptyStatement
to be excluded from completion menus.
- Structure:
StatementList_Editor
: the%statements%
collection is modified to include an element factory that returnsnew node<EmptyStatement>
. This will tell MPS to create a newEmptyStatement
node whenEnter
is pressed, instead of creating the abstractStatement
.- (Optional.) In
StatementList_Behavior
it may be useful to add a behavior method that filters out empty statements:public sequence<node<Statement>> nonEmptyStatements() { this.statements.where({~it => !it.isInstanceOf(EmptyStatement); }); }
And that’s all there is to it.
Some more improvements:
- Empty lines are good places for context assistant menu
placeholders, so if you use context assistant in your language, consider adding a placeholder after the empty constant
cell. This is illustrated in the
robot_Kaja
MPS sample. - If you use mbeddr platform, it provides interface
com.mbeddr.core.base.structure.IEmpty
that can be used as a marker for empty lines. It also defines an empty default substitution menu so you don’t have to create one yourself if you extend the interface.