Continuing where we left off last, today we are ready to write some code in our action. We need to choose a file and then invoke the importer logic on the file and the model.
Since MPS builds upon the IDEA Platform which builds upon Swing, we can use the usual Swing components as well as the
platform-provided facilities. I prefer to use classes from the platform when available because they often provide a more
polished look-and-feel. In this case the platform provides a class called
FileChooser for opening a “choose file”
dialog, documented here.
To invoke the
FileChooser we will need to pass to it the current project instance. There are in fact several different
project classes in MPS, one coming from IDEA (
com.intellij.openapi.project.Project) and another one coming from MPS
jetbrains.mps.project.MPSProject). In fact, there are other project classes in MPS but we will not need to concern
ourselves with them in this tutorial.
To obtain an instance of the IDEA project we add a context parameter of type Project to our action. I like to call it
ideaProject to disambiguate it from a MPS project.
Here is what the
FileChooser invocation looks like:
VirtualFile chosenFile = FileChooser.chooseFile( FileChooserDescriptorFactory.createSingleFileDescriptor("json"), this.ideaProject, null);
Virtual file system
The result we get from the dialog is a
VirtualFile object. Virtual files are abstractions provided by the IDEA
platform’s virtual file system (VFS). We are not going to use VFS in our code though, so we will escape the abstraction
immediately by calling
getPath() on it.
Next, we need to make sure that we are not calling the file chooser while holding a model lock.
Model access: reading, writing, and commanding
All model access in MPS takes place under a read-write lock. The rules are documented in the MPS help. In our case, the importer modifies the model so it will need to be invoked from within a command.
By default, an action’s
execute block is wrapped in a command automatically and we don’t have to think of this. On the
other hand, UI calls are disallowed when under a read-write lock to prevent UI freezes and deadlocks. This forces us
to manage model locking explicitly in our code so we need to disable the automatic command by changing
If we now need to execute a piece of code in a command, we do it explicitly by using the
command statement from
jetbrains.mps.lang.access language that was helpfully added to the model for us by the wizard that created the plugin
We need to pass a repository to the command, which we can obtain from the current MPS project, which we get from the context like the IDEA project above.
Show error messages as balloons
Our importer logic can throw exceptions that we should show to the user. If we don’t do anything and simply rethrow the exception, it will cause a flashing exclamation mark to appear in the bottom right corner. If we catch the exception we can use a plain Swing message box to show it, or, even better, a notification. I have written previously about notifications here.
The complete code
Here is what the action looks like after all the modifications:
Next: adding the action to a menu
The action works now but can still only be invoked via the Find Action popup (
Ctrl/Cmd+Shift+A). In the next post we
will add it to a menu.