This is a fairly rare use case but it comes up at times: how do you implement UI that behaves like a reference but without using a reference?

For example:

  • you might want to refer to something that is not a node, such as a model or a module,
  • you want to refer to a node in another model but without introducing a dependency on that model (creating a “weak” reference).

In these cases you cannot use built-in references but you can still create something that comes pretty close, what I would call a pseudoreference.

There are four main “ingredients” to a reference:

  1. Structure: a concept that keeps information about the target of the pseudoreference. It can be a model or node reference, serialized to a string.
  2. Completion menu: showing all the available targets for the user to choose.
  3. Navigation: jumping to the target on Ctrl+Click or Ctrl/Cmd+B.
  4. Checking for broken references (i.e. when the target is gone).

With pseudoreferences we can make most of these work, though some things might work differently from the normal references.

There are several implementations of pseudoreferences in MPS and I will use them as examples rather than building a separate sample.

Model references

The first example is a model reference represented by ModelIdentity interface concept and ModelPointer concept implementing it (MPS link).

ModelPointer defines a few properties and children to contain the information about the target model. It defines a named substitute menu (AllRepositoryModels_SM, MPS link) that simply returns all available models. The concept is designed to be reusable so the menu isn’t engaged by default (in case you want to reuse the ModelPointer concept in your language but have the user choose from a different set of models).

Unfortunately, the MPS editor language doesn’t provide any means to set up navigation to a model on Ctrl+Click, so navigating to the target model is not supported.

Broken model references are not highlighted in any way, probably left for the reusing language to implement.

“Reflection” node references

The jetbrains.mps.lang.migration language implements a “dynamic” node reference concept, named ReflectionNodeReference (MPS link). This concept contains properties to store the ID of the target node and its model. The editor looks up the node if it exists and shows its presentation. If the target node exists, the editor enables navigation to it via navigatable-node style function:

The concept does not mark missing targets as an error (as it is not an error in this case). Rather, it highlights them with a yellow background: