Langium Meets Sprotty: Combining Text and Diagrams in VS Code
The combination of text and diagrams offers several advantages, especially if the diagram is laid out automatically. So far, Sprotty could be used for the visualization in combination with an Xtext-based language server. However, this means that both Java and TypeScript are used as programming languages, which complicates the development and maintenance. The recently released language engineering tool Langium solves this problem by enabling to implement the language server in TypeScript as well. In this post I want to show the combination of Langium and Sprotty on the basis of a concrete DSL.
A Domain-Specific Language
System-Theoretic Process Analysis (STPA) is a relatively new hazard analysis technique. Usually, it is executed manually on paper. However, the time needed to apply STPA can be reduced by providing tools for it. There already exist several tools supporting STPA, but only one of them offers a visualization. However, that tool works exclusively on the visualization. In order to provide textual as well as graphical support for STPA, I developed a DSL for STPA with an automatic visualization using Langium and Sprotty.
In the DSL, components for nine different aspects can be defined, whereby one of them is a control structure. The control structure is already a graph containing system components as nodes and control actions and feedback as edges. For the other aspects, each component consists of an ID, a description, and a list of references to components of other aspects. In the visualization each of those components is represented by a node with the same ID and edges going to the components that are referenced. Thereby, components of different aspects should be in different layers to provide a better overview.
The user can change the color-style of the visualization to colorful, which colors components based on the aspect they belong to, or print-style, which is black and white. Additionally, an option is provided to give every component a different form based on their aspect. Another option regards the visualization of hierarchy. It can be toggled to visualize sub-components in their own layer with an edge going to their parent instead of being contained in the parent.
The overall structure of the implementation consists of three folders: extension, language-server, and webview. The first one is the entry point for the extension. It provides the methods for activating the language client as well as creating the webview by extending
SprottyLspEditVscodeExtension. The language-server contains the implementation of the DSL while the webview contains the implementation of the visualization.
The grammar for the DSL is defined in a Langium file in the language-server folder using Langium's EBNF syntax. In order to provide the correct scope for the references, I implemented a scope provider that extends the default one. For each component the available components that can be referenced are determined in it. Additionally, a custom validator checks that all IDs are unique and that every aspect of STPA is defined. These two services, validator and scope provider, must be declared in the module of the language server to override the default ones. Furthermore, I added a new service to the module. It contains options the user can change. So far, it only contains an option that determines the way sub-components are visualized. This option can be toggled by sending a notification to the language server. The reaction to the notification is defined in a main file, where also the connection to the client is created and the language server is started.
For the visualization of a STPA file, a webview is created using Sprotty. Each node type, control structure node and STPA node, has its own view class with a render method creating the desired virtual DOM node. These views are configured in the module of the diagram. However, a connection is needed between the language server and Sprotty so that the Sprotty frontend receives a graph model to be visualized.
This is done by extending the
LangiumDiagramGenerator in the language server. It contains a
generateRoot method that must be implemented. This method specifies the translation of, in my case, a STPA model to a SGraph. In order to use the custom diagram generator, it must be registered by overriding the default one in the language server module. Furthermore, an elk layout engine can be registered to layout the graph. Langium provides a
layout service that contains a
LayoutConfigurator, which can be overridden as well. Using a custom configurator provides the possibility to set options for specific graph elements. For the STPA-DSL, this includes setting strategy options of elk to interactive. This way the layer of a node can be set based on the STPA aspect it belongs to.
Overall, the goal of a DSL with an automatic visualization was achieved without too much effort. Langium provides several services that can be quite easily customized for the specific DSL, and the ability to add new services is also very useful. With the services for the diagram generation and layout configuration, the generated diagram can also be easily adjusted. I can greatly recommend using the combination of Langium and Sprotty when developing a DSL.