GLSP Protocol
Following the successful pattern provided by the language server protocol (LSP) for textual languages, GLSP provides a defined protocol for the communication between the GLSP client and the server. In this modular architecture, server and client are well encapsulated and can be developed in an independent way. This allows mixing in the ideal technologies on both sides and reusing existing clients and server.
1. Server-Client Lifecycle
The base communication between the client and server is performed using action messages whereas we assume that each client connection will start their own server instance. Thus each server is only responsible for a single client.
A client implementation must consider the following interface:
Code
interface GLSPClient {
/**
* Unique client Id.
*/
readonly id: string;
/**
* Current client state.
*/
readonly currentState: ClientState;
/**
* Initializes the client and the server connection. During the start procedure the client is in the
* `Starting` state and will transition to either `Running` or `StartFailed`. Calling this method
* if the client is already running has no effect.
*
* @returns A promise that resolves if the startup was successful.
*/
start(): Promise<void>;
/**
* Send an `initialize` request to the server. The server needs to be initialized in order to accept and
* process other requests and notifications. The {@link InitializeResult} ist cached and can be retrieved
* via the {@link GLSPClient.initializeResult} property.
* Only the first method invocation actually sends a request to the server. Subsequent invocations simply
* return the cached result.
*
* @param params Initialize parameters
* @returns A promise of the {@link InitializeResult}.
*/
initializeServer(params: InitializeParameters): Promise<InitializeResult>;
/**
* The cached {@link {InitializeResult}. Is `undefined` if the server has not been initialized yet via
* the {@link GLSPClient.initializeServer} method.
*/
readonly initializeResult: InitializeResult | undefined;
/**
* Event that is fired once the first invocation of {@link GLSPClient.initializeServer} has been completed.
*/
readonly onServerInitialized: Event<InitializeResult>;
/**
* Send an `initializeClientSession` request to the server. One client application may open several session.
* Each individual diagram on the client side counts as one session and has to provide
* a unique clientId.
*
* @param params InitializeClientSession parameters
* @returns A promise that resolves if the initialization was successful
*/
initializeClientSession(params: InitializeClientSessionParameters): Promise<void>;
/**
* Sends a `disposeClientSession` request to the server. This request has to be sent at the end of client session lifecycle
* e.g. when an editor widget is closed.
*
* @param params DisposeClientSession parameters
* @returns A promise that resolves if the disposal was successful
*/
disposeClientSession(params: DisposeClientSessionParameters): Promise<void>;
/**
* Send a `shutdown` notification to the server.
*/
shutdownServer(): void;
/**
* Stops the client and disposes unknown resources. During the stop procedure the client is in the `Stopping` state and will
* transition to either `Stopped` or `ServerError`.
*
* @returns A promise that resolves after the server was stopped and disposed.
*/
stop(): Promise<void>;
/**
* Send an action message to the server.
*
* @param message The message
*/
sendActionMessage(message: ActionMessage): void;
/**
* Sets a handler/listener for action messages received from the server.
* Can be scoped to a particular client session by passing the corresponding `clientId`.
*
* @param handler The action message handler
* @param clientId If passed given action message handler will only be invoked for action messages with this client id.
* @returns A {@link Disposable} that can be used to unregister the handler
*/
onActionMessage(handler: ActionMessageHandler, clientId?: string): Disposable;
}
export enum ClientState {
/**
* The client has been created.
*/
Initial,
/**
* `Start` has been called on the client and the start process is still on-going.
*/
Starting,
/**
* The client failed to complete the start process.
*/
StartFailed,
/**
* The client was successfully started and is now running.
*/
Running,
/**
* `Stop` has been called on the client and the stop process is still on-going.
*/
Stopping,
/**
* The client stopped and disposed the server connection. Thus, action messages can no longer be sent.
*/
Stopped,
/**
* An error was encountered while connecting to the server. No action messages can be sent.
*/
ServerError
}
/**
* A key-value pair structure for custom arguments.
*/
interface Args {
[key: string]: string | number | boolean;
}
type ActionMessageHandler = (message: ActionMessage) => void;
In GLSP we provide a default client implementation based on JSON-RPC messages.
Initialize Request
The initialize
request has to be the first request from the client to the server. Until the server has responded with an InitializeResult
no other request or notification can be handled and is expected to throw an error. A client is uniquely identified by an applicationId
and has to specify on which protocolVersion
it is based on. In addition, custom arguments can be provided in the args
map to allow for custom initialization behavior on the server. The request returns an InitializeResult
that encapsulates server information and capabilities. The InitializeResult
is used inform the client about the action kinds that the server can handle for a specific diagramType
.
Code
interface InitializeParameters {
/**
* Unique identifier for the current client application.
*/
applicationId: string;
/**
* GLSP protocol version that this client is implementing.
*/
protocolVersion: string;
/**
* Additional custom arguments e.g. application specific parameters.
*/
args?: Args;
}
interface InitializeResult {
/**
* GLSP protocol version that the server is implementing.
*/
protocolVersion: string;
/**
* The actions (grouped by `diagramType`) that the server can handle.
*/
serverActions: ServerActions;
}
/**
* A key-value pair structure to map a `diagramType` to its server-handled action kinds.
*/
interface ServerActions {
[key: string]: string[];
}
InitializeClientSession Request
When a new graphical representation (diagram) is created a InitializeClientSession
request has to be sent to the server. Each individual diagram on the client side counts as one session and has to provide a unique clientSessionId
and its diagramType
. In addition, custom arguments can be provided in the args
map to allow for custom initialization behavior on the server.
Code
interface InitializeClientSessionParameters {
/**
* Unique identifier for the new client session.
*/
clientSessionId: string;
/**
* Unique identifier of the diagram type for which the session should be configured.
*/
diagramType: string;
/**
* The set of action kinds that can be handled by the client.
* Used by the server to know which dispatched actions should be forwarded to the client.
*/
clientActionKinds: string[];
/**
* Additional custom arguments.
*/
args?: Args;
}
DisposeClientSession Request
When a graphical representation (diagram) is no longer needed, e.g. the tab containing the diagram widget has been closed, a DisposeClientSession
request has to be sent to the server. The session is identified by its unique clientSessionId
. In addition, custom arguments can be provided in the args
map to allow for custom dispose behavior on the server.
Code
interface DisposeClientSessionParameters {
/**
* Unique identifier of the client session that should be disposed.
*/
clientSessionId: string;
/**
* Additional custom arguments.
*/
args?: Args;
}
Shutdown Notification
If the client disconnects from the server, it may send a shutdown
notification to give the server a chance to clean up any resources dedicated to the client. The shutdown request does not have any parameters as the server is already aware of the client.
Action Messages
Any communication that is performed between initialization and shutdown is handled by sending action messages, either from the client to the server or from the server to the client. This is the core part of the Graphical Language Server Protocol.
2. Graphical Language Server Protocol
The graphical language server protocol defines how the client and the server communicate and which actions are sent between them. It heavily builds on the client-server protocol defined in Sprotty but adds additional actions to enable editing and other capabilities. Additional information regarding the lifecycle of some action messages can be found in the Sprotty documentation.
Please note that there are several actions that are used purely on the client side. Such actions are not part of this protocol.
2.1. Base Protocol
The base protocol describes the structure of the messages that are sent between the server and the client.
2.1.1. ActionMessage
A general message serves as an envelope carrying an action to be transmitted between the client and the server via a DiagramServer.
Code
interface ActionMessage<A extends Action = Action> {
/**
* Used to identify a specific client session.
*/
clientId: string;
/**
* The action to execute.
*/
Action: A;
}
2.1.2. Action
An action is a declarative description of a behavior that shall be invoked by the receiver upon receipt of the action. It is a plain data structure, and as such transferable between server and client. Actions contained in action messages are identified by their kind
attribute. This attribute is required for all actions. Certain actions are meant to be sent from the client to the server or vice versa, while other actions can be sent both ways, by the client or the server. All actions must extend the default action interface.
Code
interface Action {
/**
* Unique identifier specifying the kind of action to process.
*/
kind: string;
}
2.1.2.1. RequestAction
A request action is tied to the expectation of receiving a corresponding response action. The requestId
property is used to match the received response with the original request.
Code
interface RequestAction<Res extends ResponseAction> extends Action {
/**
* Unique id for this request. In order to match a response to this request, the response needs to have the same id.
*/
requestId: string;
}
2.1.2.2. ResponseAction
A response action is sent to respond to a request action. The responseId
must match the requestId
of the preceding request. In case the responseId
is empty or undefined, the action is handled as standalone, i.e. it was fired without a preceding request.
Code
interface ResponseAction extends Action {
/**
* Id corresponding to the request this action responds to.
*/
responseId: string;
}
2.1.2.3. RejectAction
A reject action is a response fired to indicate that a request must be rejected.
Code
interface RejectAction extends ResponseAction {
kind: 'rejectRequest';
/**
* A human-readable description of the reject reason. Typically this is an error message
* that has been thrown when handling the corresponding RequestAction.
*/
message: string;
/**
* Optional additional details.
*/
detail?: JsonAny;
}
2.1.2.4. Operation
Operations are actions that denote requests from the client to modify the model. Model modifications are always performed by the server. After a successful modification, the server sends the updated model back to the client using the UpdateModelAction
.
Code
/**
* Marker interface for operations.
*/
interface Operation extends Action {
/**
* Discriminator property to make operations distinguishable from plain Actions.
*/
isOperation: true;
}
/**
* An operation that executes a list of operations.
*/
interface CompoundOperation extends Operation {
readonly kind = 'compound';
/**
* List of operations that should be executed.
*/
operationList: Operation[];
}
2.2. Model Structure
The basic model structure in GLSP is called a GModel
. Such a model consists of GModelElements
conforming to an GModelElementSchema
.
Sprotty already defines a similar, graph-like model called SGraph
conforming to the SGraphSchema
. This graph consists nodes, edges, compartments, labels, and ports. The GModel
is an extension of the sprotty graph model.
2.2.1. GModelElementSchema
The schema of an GModelElement
describes its serializable form. The actual class-based model is created from its schema in a deserialization step on client and server side. Each model element must have a unique ID and a type that is used to look up its view, i.e., the graphical representation.
Code
interface GModelElementSchema {
/**
* Unique identifier for this element.
*/
id: string;
/**
* Type to look up the graphical representation of this element.
*/
type: string;
/**
* Children of this element.
*/
children?: GModelElementSchema[];
/**
* CSS classes that should be applied on this element.
*/
cssClasses?: string[];
}
2.2.1.1. GModelRootSchema
Serializable schema for the root element of the model tree. Usually actions refer to elements in the graphical model via an elementId
. However, a few actions actually need to transfer the graphical model. In such cases, the graphical model needs to be represented as a serializable GModelRootSchema
.
Code
interface GModelRootSchema extends GModelElementSchema {
/**
* Bounds of this element in the canvas.
*/
canvasBounds?: Bounds;
/**
* Version of this root element.
*/
revision?: number;
}
2.2.2. GModelElement
All elements of the diagram model inherit from base class GModelElement
. Each model element must have a unique ID and a type that is used to look up its view. Additionally, each element provides access to its root element and holds an index to speed up the model element lookup.
Each model element has a set of features. A feature is a symbol identifying some functionality that can be enabled or disabled for a model element, e.g. a resizeFeature
. The set of supported features is determined by the features
property.
Code
class GModelElement {
/**
* Unique identifier for this element.
*/
id: string;
/**
* Type to look up the graphical representation of this element.
*/
type: string;
/**
* CSS classes that should be applied on this element.
*/
cssClasses?: string[];
/**
* A set of features supported by this element, e.g.,
*/
features?: FeatureSet;
/**
* This element's root element.
*/
root: GModelRoot;
/**
* Access to the model's index for faster element lookup.
*/
index: GModelIndex<GModelElement>;
}
2.2.2.1. GParentElement
A parent element may contain child elements, thus the diagram model forms a tree.
Code
class GParentElement extends GModelElement {
/**
* Children of this element.
*/
readonly children: ReadonlyArray<GChildElement>;
/**
* Adds a child element to this element.
*/
add(child: GChildElement, index?: number);
/**
* Removes a child element from this element.
*/
remove(child: GChildElement);
/**
* Removes all child elements from this element.
*/
removeAll(filter?: (e: GChildElement) => boolean);
/**
* Moves a child element to a new index.
*/
move(child: GChildElement, newIndex: number);
}
2.2.2.2. GChildElement
A child element is contained in a parent element. All elements except the model root are child elements. In order to keep the model class hierarchy simple, every child element is also a parent element, although for many elements the array of children is empty (i.e. they are leafs in the model element tree).
Code
class GChildElement extends GParentElement {
/**
* Parent of this element.
*/
readonly parent: GParentElement;
}
2.2.2.3. GModelRoot
Base class for the root element of the diagram model tree.
Code
class GModelRoot extends GParentElement {
/**
* Access to the index which is built up for faster element lookup.
*/
readonly index: GModelIndex<GModelElement>;
/**
* Bounds of this element in the canvas.
*/
canvasBounds?: Bounds;
/**
* Version of this root element.
*/
revision?: number;
}
2.3. Types
2.3.1. Args
Arguments are a key-value map with the key being a string and the value being either a string, a number, or a boolean value.
Code
type Args = { [key: string]: string | number | boolean };
2.3.2. Point
A Point
is composed of the (x,y) coordinates of an object.
Code
interface Point {
/**
* The abscissa of the point.
*/
readonly x: number;
/**
* The ordinate of the point.
*/
readonly y: number;
}
2.3.3. Dimension
The Dimension
of an object is composed of its width and height.
Code
interface Dimension {
/**
* The width of an element.
*/
readonly width: number;
/**
* the height of an element.
*/
readonly height: number;
}
2.3.4. Bounds
The bounds are the position (x, y) and dimension (width, height) of an object. As such the Bounds
type extends both Point
and Dimension
.
Code
interface Bounds extends Point, Dimension {}
2.3.5. ElementAndBounds
The ElementAndBounds
type is used to associate new bounds with a model element, which is referenced via its id.
Code
interface ElementAndBounds {
/**
* The identifier of the element.
*/
elementId: string;
/**
* The new size of the element.
*/
newSize: Dimension;
/**
* The new position of the element.
*/
newPosition?: Point;
}
2.3.6. ElementAndAlignment
The ElementAndAlignment
type is used to associate a new alignment with a model element, which is referenced via its id.
Code
interface ElementAndAlignment {
/**
* The identifier of an element.
*/
elementId: string;
/**
* The new alignment of the element.
*/
newAlignment: Point;
}
2.3.7. ElementAndRoutingPoints
The ElementAndRoutingPoints
type is used to associate an edge with specific routing points.
Code
interface ElementAndRoutingPoints {
/**
* The identifier of an element.
*/
elementId: string;
/**
* The new list of routing points.
*/
newRoutingPoints?: Point[];
}
2.3.8. EditorContext
The EditorContext
may be used to represent the current state of the editor for particular actions. It encompasses the last recorded mouse position, the list of selected elements, and may contain custom arguments to encode additional state information.
Code
interface EditorContext {
/**
* The list of selected element identifiers.
*/
readonly selectedElementIds: string[];
/**
* The last recorded mouse position.
*/
readonly lastMousePosition?: Point;
/**
* Custom arguments.
*/
readonly args?: Args;
}
2.3.9. LabeledAction
Labeled actions are used to denote a group of actions in a user-interface context, e.g., to define an entry in the command palette or in the context menu.
Code
interface LabeledAction {
/**
* Group label.
*/
label: string;
/**
* Actions in the group.
*/
actions: Action[];
/**
* Optional group icon.
*/
icon?: string;
}
2.4 Model Data
2.4.1. RequestModelAction
Sent from the client to the server in order to request a graphical model. Usually this is the first message that is sent from the client to the server, so it is also used to initiate the communication. The response is a SetModelAction
or an UpdateModelAction
.
Code
interface RequestModelAction extends RequestAction<SetModelAction> {
/**
* The kind of the action.
*/
kind = "requestModel";
/**
* Additional options used to compute the graphical model.
*/
options?: { [key: string]: string });
}
2.4.2. SetModelAction
Sent from the server to the client in order to set the model. If a model is already present, it is replaced.
Code
interface SetModelAction extends ResponseAction {
/**
* The kind of the action.
*/
kind = 'setModel';
/**
* The new graphical model elements.
*/
newRoot: GModelRootSchema;
}
2.4.3. UpdateModelAction
Sent from the server to the client in order to update the model. If no model is present yet, this behaves the same as a SetModelAction
. The transition from the old model to the new one can be animated.
Code
interface UpdateModelAction extends Action {
/**
* The kind of the action.
*/
kind = 'updateModel';
/**
* The new root element of the graphical model.
*/
newRoot?: GModelRootSchema;
/**
* Boolean flag to indicate wether updated/changed elements should be animated in the diagram.
*/
animate?: boolean;
}
2.4.4. SourceModelChangedAction
Sent from the server to the client in order to indicate that the source model has changed. The source model denotes the data source from which the diagram has been originally derived (such as a file, a database, etc.). Typically clients would react to such an action by asking the user whether she wants to reload the diagram or ignore the changes and continue editing. If the editor has no changes (i.e. is not dirty), clients may also choose to directly refresh the editor by sending a RequestModelAction.
Code
interface SourceModelChangedAction extends Action {
/**
* The kind of the action.
*/
kind = 'sourceModelChanged';
/**
* A human readable name of the source model (e.g. the file name).
*/
sourceModelName: string;
}
2.5. Model Saving
2.5.1. SaveModelAction
Sent from the client to the server in order to persist the current model state back to the source model.
A new fileUri
can be defined to save the model to a new destination different from its original source model.
Code
interface SaveModelAction extends Action {
/**
* The kind of the action.
*/
kind = 'saveModel';
/**
* The optional destination file uri.
*/
fileUri?: string;
}
2.5.2. SetDirtyStateAction
The server sends a SetDirtyStateAction
to indicate to the client that the current model state on the server does not correspond to the persisted model state of the source model. A client may ignore such an action or use it to indicate to the user the dirty state.
Code
interface SetDirtyStateAction extends Action {
/**
* The kind of the action.
*/
kind = 'setDirtyState';
/**
* True if the current model state is dirty
*/
isDirty: boolean;
/**
* A string indicating the reason for the dirty state change e.g 'operation', 'undo' ...
*/
reason?: string;
}
2.5.3. RequestExportSvgAction
A RequestExportSvgAction
is sent by the client (or the server) to initiate the SVG export of the current diagram.
The handler of this action is expected to retrieve the diagram SVG and should send an ExportSvgAction
as response.
Typically the ExportSvgAction
is handled directly on client side.
Code
interface ExportSvgAction extends ResponseAction {
/**
* The kind of the action.
*/
kind = 'exportSvg';
/**
* The diagram GModel as serializable SVG.
*/
svg: string;
/**
* Id corresponding to the request this action responds to.
*/
responseId: string;
}
2.5.4. ExportSvgAction
The client sends an ExportSvgAction
to indicate that the diagram, which represents the current model state, should be exported in SVG format.
The action only provides the diagram SVG as plain string.
The expected result of executing an ExportSvgAction
is a new file in SVG-format on the underlying filesystem.
However, other details like the target destination, concrete file name, file extension etc. are not specified in the protocol.
So it is the responsibility of the action handler to process this information accordingly and export the result to the underlying filesystem.
Code
interface ExportSvgAction extends ResponseAction {
/**
* The kind of the action.
*/
kind = 'exportSvg';
/**
* The diagram GModel as serializable SVG.
*/
svg: string;
/**
* Id corresponding to the request this action responds to.
*/
responseId: string;
}
2.6. Model Layout
In GLSP the server usually controls the model’s layout by applying bounds to all elements and sending an updated model to the client (SetModelAction, UpdateModelAction). However, calculating the correct bounds of each element may not be straight-forward as it may depend on certain client-side rendering properties, such as label size.
On the client-side GLSP calculates the layout on two levels: The Micro Layout
is responsible to layout a single element with all its labels, icons, compartments in a horizontal box, vertical box, or other layout containers. The Macro Layout
is responsible for layouting the network of nodes and edges on the canvas. If a server needs information from the micro layout, it can send a RequestBoundsAction
to the client who will respond with a ComputedBoundsAction
containing all elements and their bounds.
2.6.1. RequestBoundsAction
Sent from the server to the client to request bounds for the given model. The model is rendered invisibly so the bounds can derived from the DOM. The response is a ComputedBoundsAction
. This hidden rendering round-trip is necessary if the client is responsible for parts of the layout.
Code
interface RequestBoundsAction extends RequestAction {
/**
* The kind of the action.
*/
kind = 'requestBounds';
/**
* The model elements to consider to compute the new bounds.
*/
newRoot: GModelRootSchema;
}
2.6.2. ComputedBoundsAction
Sent from the client to the server to transmit the result of bounds computation as a response to a RequestBoundsAction
. If the server is responsible for parts of the layout, it can do so after applying the computed bounds received with this action. Otherwise there is no need to send the computed bounds to the server, so they can be processed locally by the client.
Code
interface ComputedBoundsAction extends ResponseAction {
/**
* The kind of the action.
*/
kind = 'computedBounds';
/**
* The new bounds of the model elements.
*/
bounds: ElementAndBounds[];
/*
* The revision number.
*/
revision?: number;
/**
* The new alignment of the model elements.
*/
alignments?: ElementAndAlignment[];
/**
* The route of the model elements.
*/
routes?: ElementAndRoutingPoints[];
}
2.6.3. LayoutOperation
Request a layout of the diagram or selected elements from the server.
Code
interface LayoutOperation extends Operation {
/**
* The kind of the action.
*/
kind = 'layout';
/**
* The identifiers of the elements that should be layouted, will default to the root element if not defined.
*/
elementIds?: string[];
}
2.7. Model Edit Mode
GLSP supports setting the model into different edit modes. We pre-define two such modes: readonly
and editable
. However these modes can be customized as need be.
2.7.1. SetEditModeAction
Sent from the client to the server to set the model into a specific editor mode, allowing the server to react to certain requests differently depending on the mode. A client may also listen to this action to prevent certain user interactions preemptively.
Code
interface SetEditModeAction extends Action {
/**
* The kind of the action.
*/
kind = 'setEditMode';
/**
* The new edit mode of the diagram.
*/
editMode: string;
}
2.8. Client-Side Actions
There are several actions that are issued and processed on the client to manipulate the view port, select elements, etc. Those actions may also be sent by the server to trigger the respective client behavior. Please note that we only list actions here that are actually used by the current default implementation of the GLSP server.
2.8.1. View Port
View port actions manipulate the viewport on the client-side and may be sent from the server to highlight changes or improve general usability.
2.8.1.1. CenterAction
Centers the viewport on the elements with the given identifiers. It changes the scroll setting of the viewport accordingly and resets the zoom to its default. This action can also be created on the client but it can also be sent by the server in order to perform such a viewport change remotely.
Code
interface CenterAction extends Action {
/**
* The kind of the action.
*/
kind = 'center';
/**
* The identifier of the elements on which the viewport should be centered.
*/
elementIds: string[];
/**
* Indicate if the modification of the viewport should be realized with or without support of animations.
*/
animate: boolean = true;
/**
* Indicates whether the zoom level should be kept.
*/
retainZoom: boolean = false;
}
2.8.1.2. FitToScreenAction
Triggers to fit all or a list of elements into the available drawing area. The resulting fit-to-screen command changes the zoom and scroll settings of the viewport so the model can be shown completely. This action can also be sent from the server to the client in order to perform such a viewport change programmatically.
Code
interface FitToScreenAction extends Action {
/**
* The kind of the action.
*/
kind = 'fit';
/**
* The identifier of the elements to fit on screen.
*/
elementIds: string[];
/**
* The padding that should be visible on the viewport.
*/
padding?: number;
/**
* The max zoom level authorized.
*/
maxZoom?: number;
/**
* Indicate if the action should be performed with animation support or not.
*/
animate: boolean = true;
}
2.8.2. Client Notification
To notify the client about user-facing events or long running operations, the server can send a server status notification, a server message notification or progress notifications.
Status and message notifications are used to inform the user about one-time events. Status notifications are typically shown directly on the diagram as an overlay for a certain time. Status messages, on the other hand, are persistent notifications and are typically shown in a dedicated notification area until the user discards them.
Progress notifications only appear while the long running operation is running and indicate the progress of this operation with messages and optionally a progress bar.
2.8.2.1. StatusAction
This action is typically sent by the server (or the client) to signal a state change. If a timeout is given the respective status should disappear after the timeout is reached.
Code
interface StatusAction extends Action {
/**
* The kind of the action.
*/
kind = 'status';
/**
* The severity of the status.
*/
severity: SeverityLeel;
/**
* The message describing the status.
*/
message: string;
/**
* Timeout after which a displayed status disappears.
*/
timeout?: number;
}
2.8.2.2. MessageAction
This action is typically sent by the server (or the client) to notify the user about something of interest.
Code
interface MessageAction extends Action {
/**
* The kind of the action.
*/
kind = 'message';
/**
* The severity of the message.
*/
severity: SeverityLevel;
/**
* The message text.
*/
message: string;
/**
* Further details on the message.
*/
details: string;
}
2.8.2.3. SeverityLevel
The severity of a status or message.
Code
/**
* The possible server status severity levels.
*/
type SeverityLevel = 'NONE' | 'INFO' | 'WARNING' | 'ERROR' | 'FATAL' | 'OK';
2.8.2.4. StartProgressAction
This action is sent by the server to the client to request presenting the progress of a long running process in the UI.
Code
export interface StartProgressAction extends Action {
/**
* The kind of the action.
*/
kind = 'startProgress';
/**
* An ID that can be used in subsequent `updateProgress` and `endProgress` events to make them refer to the same progress reporting.
*/
progressId: string;
/**
* Short title of the progress reporting. Shown in the UI to describe the long running process.
*/
title: string;
/**
* Optional additional progress message. Shown in the UI to describe the long running process.
*/
message?: string;
/**
* Progress percentage to display (value range: 0 to 100). If omitted no percentage is shown.
*/
percentage?: number;
}
2.8.2.5. UpdateProgressAction
This action is sent by the server to the client to presenting an update of the progress of a long running process in the UI.
Code
export interface UpdateProgressAction extends Action {
/**
* The kind of the action.
*/
kind = 'updateProgress';
/**
* The ID of the progress reporting to update.
*/
progressId: string;
/**
* The message to show in the progress reporting.
*/
message?: string;
/**
* The percentage (value range: 0 to 100) to show in the progress reporting.
*/
percentage?: number;
}
2.8.2.6. EndProgressAction
This action is sent by the server to the client to end the reporting of a progress.
Code
export interface EndProgressAction extends Action {
/**
* The kind of the action.
*/
kind = 'endProgress';
/**
* The ID of the progress reporting to update.
*/
progressId: string;
/**
* The message to show in the progress reporting.
*/
message?: string;
}
2.8.3. Element Selection
2.8.3.1. SelectAction
Triggered when the user changes the selection, e.g. by clicking on a selectable element. The action should trigger a change in the selected
state accordingly, so the elements can be rendered differently. The server can send such an action to the client in order to change the selection remotely.
Code
interface SelectAction extends Action {
/**
* The kind of the action.
*/
kind = 'elementSelected';
/**
* The identifier of the elements to mark as selected.
*/
selectedElementsIDs: string[];
/**
* The identifier of the elements to mark as not selected.
*/
deselectedElementsIDs: string[];
/**
* Whether all currently selected elements should be deselected.
*/
deselectAll?: boolean;
}
2.8.3.2. SelectAllAction
Used for selecting or deselecting all elements.
Code
interface SelectAllAction extends Action {
/**
* The kind of the action.
*/
kind = 'allSelected';
/**
* If `select` is true, all elements are selected, otherwise they are deselected.
*/
select: boolean;
}
2.9. Element Hover
2.9.1. RequestPopupModelAction
Triggered when the user hovers the mouse pointer over an element to get a popup with details on that element. This action is sent from the client to the server. The response is a SetPopupModelAction
.
Code
interface RequestPopupModelAction extends Action {
/**
* The kind of the action.
*/
kind = 'requestPopupModel';
/**
* The identifier of the elements for which a popup is requested.
*/
elementId: string;
/**
* The bounds.
*/
bounds: Bounds;
}
2.9.2. SetPopupModelAction
Sent from the server to the client to display a popup in response to a RequestPopupModelAction
. This action can also be used to remove any existing popup by choosing EMPTY_ROOT
as root element.
Code
interface SetPopupModelAction extends Action {
/**
* The kind of the action.
*/
kind = 'setPopupModel';
/**
* The model elements composing the popup to display.
*/
newRoot: GModelRootSchema;
}
2.10. Element Validation
Validation in GLSP is performed by using validation markers. A marker represents the validation result for a single model element:
Code
interface Marker {
/**
* Short label describing this marker message, e.g., short validation message
*/
readonly label: string;
/**
* Full description of this marker, e.g., full validation message
*/
readonly description: string;
/**
* Id of the model element this marker refers to
*/
readonly elementId: string;
/**
* Marker kind, e.g., info, warning, error or custom kind
*/
readonly kind: string;
}
2.10.1. RequestMarkersAction
Action to retrieve markers for the specified model elements. Sent from the client to the server.
Code
interface RequestMarkersAction extends RequestAction {
/**
* The kind of the action.
*/
kind = 'requestMarkers';
/**
* The elements for which markers are requested, may be just the root element.
*/
elementsIDs: string[];
/**
* The reason for this request, e.g. a `batch` validation or a `live` validation.
*/
reason?: string;
}
2.10.2. SetMarkersAction
Response to the RequestMarkersAction
containing all validation markers. Sent from the server to the client.
This action always sends the entire list of markers.
Thus, clients can replace all markers for a specific reason
with the new ones that have been sent with the same reason
.
Code
interface SetMarkersAction extends ResponseAction {
/**
* The kind of the action.
*/
kind = 'setMarkers';
/**
* The list of markers to be set in the diagram editor.
*/
markers: Marker[];
/**
* The reason for this response, e.g. a `batch` validation or a `live` validation.
*/
reason?: string;
}
2.10.3. DeleteMarkersAction
To remove markers for elements a client or server may send a DeleteMarkersAction
with all markers that should be removed.
Code
interface DeleteMarkersAction extends Action {
/**
* The kind of the action.
*/
kind = 'deleteMarkers';
/**
* The list of markers that should be deleted.
*/
markers: Marker[];
}
2.11. Element Navigation
GLSP makes no assumption about the type of navigation a user may want to perform. Thus a generic infrastructure is provided that the client and server can use to implement specific navigation types, e.g., navigation to documentation, implementation, etc. The type of navigation is identified by the targetTypeId
.
A client may request the targets for a specific type of navigation by querying the server to which the server will respond with a set of navigation targets. A NavigationTarget
identifies the object we want to navigate to via its uri and may further provide a label to display for the client. Additionally, generic arguments may be used to to encode any domain- or navigation type-specific information.
Code
interface NavigationTarget {
/**
* URI to identify the object we want to navigate to.
*/
uri: string;
/**
* Optional label to display to the user.
*/
label?: string;
/**
* Domain-specific arguments that may be interpreted directly or resolved further.
*/
args?: Args;
}
2.11.1. RequestNavigationTargetsAction
Action that is usually sent from the client to the server to request navigation targets for a specific navigation type such as documentation
or implementation
in the given editor context.
Code
interface RequestNavigationTargetsAction extends RequestAction<SetNavigationTargetsAction> {
/**
* The kind of the action.
*/
kind = 'requestNavigationTargets';
/**
* Identifier of the type of navigation targets we want to retrieve, e.g., 'documentation', 'implementation', etc.
*/
targetTypeId: string;
/**
* The current editor context.
*/
editorContext: EditorContext;
}
2.11.2. SetNavigationTargetsAction
Response action from the server following a RequestNavigationTargetsAction
. It contains all available navigation targets for the queried target type in the provided editor context. The server may also provide additional information using the arguments, e.g., warnings, that can be interpreted by the client.
Code
interface SetNavigationTargetsAction extends ResponseAction {
/**
* The kind of the action.
*/
kind = 'setNavigationTargets';
/**
* A list of navigation targets.
*/
targets: NavigationTarget[];
/**
* Custom arguments that may be interpreted by the client.
*/
args?: Args;
}
2.11.3. NavigateToTargetAction
Action that triggers the navigation to a particular navigation target. This may be used by the client internally or may be sent from the server.
Code
interface NavigateToTargetAction extends Action {
/**
* The kind of the action.
*/
kind = 'navigateToTarget';
/**
* The target to which we navigate.
*/
target: NavigationTarget;
}
2.11.4. ResolveNavigationTargetAction
If a client cannot navigate to a target directly, a ResolveNavigationTargetAction
may be sent to the server to resolve the navigation target to one or more model elements. This may be useful in cases where the resolution of each target is expensive or the client architecture requires an indirection.
Code
interface ResolveNavigationTargetAction extends RequestAction<SetResolvedNavigationTargetAction> {
/**
* The kind of the action.
*/
kind = 'resolveNavigationTarget';
/**
* The navigation target to resolve.
*/
navigationTarget: NavigationTarget;
}
2.11.4. SetResolvedNavigationTargetAction
An action sent from the server in response to a ResolveNavigationTargetAction
. The response contains the resolved element ids for the given target and may contain additional information in the args
property.
Code
interface SetResolvedNavigationTargetAction extends ResponseAction {
/**
* The kind of the action.
*/
kind = 'setResolvedNavigationTarget';
/**
* The element ids of the resolved navigation target.
*/
elementIds: string[];
/**
* Custom arguments that may be interpreted by the client.
*/
args?: Args;
}
2.11.5. NavigateToExternalTargetAction
If a navigation target cannot be resolved or the resolved target is something that is not part of our source model, e.g., a separate documentation file, a NavigateToExternalTargetAction
may be sent. Since the target it outside of the model scope such an action would be typically handled by an integration layer (such as the surrounding IDE).
Code
interface NavigateToExternalTargetAction extends Action {
/**
* The kind of the action.
*/
kind = 'navigateToExternalTarget';
/**
* The target to which we navigate.
*/
target: NavigationTarget;
}
2.12. Element Type Hints
Type hints are used to define what modifications are supported on the different element types. Conceptually type hints are similar to features
of a model elements but define the functionality on a type level. The rationale is to avoid a client-server round-trip for user feedback of each synchronous user interaction.
In GLSP we distinguish between ShapeTypeHints
and EdgeTypeHints
. These hints specify whether an element can be resized, relocated and/or deleted. Optionally, they specify a list of element types that can be contained/connected by this element.
Code
interface TypeHint {
/**
* The identifier of an element.
*/
readonly elementTypeId: string;
/**
* Specifies whether the element can be relocated.
*/
readonly repositionable: boolean;
/**
* Specifies whether the element can be deleted
*/
readonly deletable: boolean;
}
interface ShapeTypeHint extends TypeHint {
/**
* Specifies whether the element can be resized.
*/
readonly resizable: boolean;
/**
* Specifies whether the element can be moved to another parent
*/
readonly reparentable: boolean;
/**
* The types of elements that can be contained by this element (if any)
*/
readonly containableElementTypeIds?: string[];
}
interface EdgeTypeHint extends TypeHint {
/**
* Specifies whether the routing points of the edge can be changed
* i.e. edited by the user.
*/
readonly routable: boolean;
/**
* Allowed source element types for this edge type
* If not defined unknown element can be used as source element for this edge.
*/
readonly sourceElementTypeIds?: string[];
/**
* Allowed targe element types for this edge type
* If not defined unknown element can be used as target element for this edge.
*/
readonly targetElementTypeIds?: string[];
/**
* Indicates whether this type hint is dynamic or not. Dynamic edge type hints
* require an additional runtime check before creating an edge, when checking
* source and target element types is not sufficient.
*/
readonly dynamic?: boolean;
}
2.12.1. RequestTypeHintsAction
Sent from the client to the server in order to request hints on whether certain modifications are allowed for a specific element type. The RequestTypeHintsAction
is optional, but should usually be among the first messages sent from the client to the server after receiving the model via RequestModelAction
. The response is a SetTypeHintsAction
.
Code
interface RequestTypeHintsAction extends RequestAction<SetTypeHintsAction> {
/**
* The kind of the action.
*/
kind = 'requestTypeHints';
}
2.12.2. SetTypeHintsAction
Sent from the server to the client in order to provide hints certain modifications are allowed for a specific element type.
Code
interface SetTypeHintsAction extends ResponseAction {
/**
* The kind of the action.
*/
kind = 'setTypeHints';
/**
* The hints for shape types.
*/
shapeHints: ShapeTypeHint[];
/**
* The hints for edge types.
*/
edgeHints: EdgeTypeHint[];
}
2.12.3. RequestCheckEdgeAction
Sent from the client to the server to check wether the provided edge context information is valid i.e. creation of an edge with the given edge type and source/target element is allowed by the server.
Typically this action is dispatched by edge creation tools in the creation phase of an edge that’s associated with a dynamic EdgeTypeHint
.
Code
interface RequestCheckEdgeAction extends RequestAction<CheckEdgeResultAction> {
kind: 'requestCheckEdge';
/**
* The element type of the edge being created.
*/
edgeType: string;
/**
* The ID of the edge source element.
*/
sourceElementId: string;
/**
* The ID of the edge target element to check.
*/
targetElementId?: string;
}
2.12.4. CheckEdgeResultAction
Sent from the server to the client as a response for a {@link RequestCheckEdgeAction}. It provides a boolean indicating whether the edge context information provided by the corresponding request action is valid i.e. creation of an edge with the given edge type and source/target element is allowed.
Code
interface CheckEdgeResultAction extends ResponseAction {
kind: 'checkEdgeTargetResult';
/**
* true if the selected element is a valid target for this edge,
* false otherwise.
*/
isValid: boolean;
/**
* The element type of the edge that has been checked.
*/
edgeType: string;
/**
* The ID of the source element of the edge that has been checked.
*/
sourceElementId: string;
/**
* The ID of the target element of the edge that has been checked.
*/
targetElementId?: string;
}
2.13. Element Creation and Deletion
2.13.1. CreateNodeOperation
Code
In order to create a node in the model the client can send a CreateNodeOperation
with the necessary information to create that node.
interface CreateNodeOperation extends CreateOperation {
/**
* The kind of the action.
*/
kind = 'createNode';
/*
* The location at which the operation shall be executed.
*/
location?: Point;
/*
* The container in which the operation shall be executed.
*/
containerId?: string;
}
2.13.2. CreateEdgeOperation
In order to create an edge in the model the client can send a CreateEdgeOperation
with the necessary information to create that edge.
Code
interface CreateEdgeOperation extends CreateOperation {
/**
* The kind of the action.
*/
kind = 'createEdge';
/*
* The source element.
*/
sourceElementId: string;
/*
* The target element.
*/
targetElementId: string;
}
2.13.3. DeleteElementOperation
The client sends a DeleteElementOperation
to the server to request the deletion of an element from the model.
Code
interface DeleteElementOperation extends Operation {
/**
* The kind of the action.
*/
kind = 'deleteElement';
/**
* The elements to be deleted.
*/
elementIds: string[];
}
2.14. Node Modification
2.14.1. ChangeBoundsOperation
Triggers the position or size change of elements. This action concerns only the element’s graphical size and position. Whether an element can be resized or repositioned may be specified by the server with a TypeHint
to allow for immediate user feedback before resizing or repositioning.
Code
interface ChangeBoundsOperation extends Operation {
/**
* The kind of the action.
*/
kind = 'changeBounds';
/**
* The new bounds of the respective elements.
*/
newBounds: ElementAndBounds[];
}
2.14.2. ChangeContainerOperation
The client sends a ChangeContainerOperation
to the server to request the execution of a changeContainer
operation.
Code
interface ChangeContainerOperation implements Operation {
/**
* The kind of the action.
*/
kind = 'changeContainer';
/**
* The element to be changed.
*/
elementId: string;
/**
* The element container of the changeContainer operation.
*/
targetContainerId: string;
/**
* The graphical location.
*/
location?: string;
}
2.15. Edge Modification
2.15.1. ReconnectEdgeOperation
If the source and/or target element of an edge should be adapted, the client can send a ReconnectEdgeOperation
to the server.
Code
interface ReconnectEdgeOperation extends Operation {
/**
* The kind of the action.
*/
kind = 'reconnectEdge';
/**
* The edge element that should be reconnected.
*/
edgeElementId: string;
/**
* The (new) source element of the edge.
*/
sourceElementId: string;
/**
* The (new) target element of the edge.
*/
targetElementId: string;
/*
* Additional arguments for custom behavior.
*/
args?: Args;
}
2.15.2. ChangeRoutingPointsOperation
An edge may have zero or more routing points that “re-direct” the edge between the source and the target element. In order to set these routing points the client may send a ChangeRoutingPointsOperation
.
Code
interface ChangeRoutingPointsOperation extends Operation {
/**
* The kind of the action.
*/
kind = 'changeRoutingPoints';
/**
* The routing points of the edge (may be empty).
*/
newRoutingPoints: ElementAndRoutingPoints[];
}
2.16. Element Text Editing
A common use case in diagrams is to query the user for textual input to perform a certain action, e.g., when editing the text on a label.
To support the validation of user input in the context of such an action before actually applying that user input, GLSP defines two actions: RequestEditValidationAction
and SetEditValidationResultAction
.
Code
interface ValidationStatus {
/**
* The severity of the validation returned by the server.
*/
readonly severity: ValidationStatus.Severity;
/**
* The validation status message which may be rendered in the view.
*/
readonly message?: string;
/**
* A potential error that encodes more details.
*/
readonly error?: ResponseError;
}
interface ResponseError {
/**
* Code identifying the error kind.
*/
readonly code: number;
/**
* Error message.
*/
readonly message: string;
/**
* Additional custom data, e.g., a serialized stacktrace.
*/
readonly data: Object;
}
namespace ValidationStatus {
enum Severity {
FATAL,
ERROR,
WARNING,
INFO,
OK,
NONE
}
}
2.16.1. RequestEditValidationAction
Requests the validation of the given text in the context of the provided model element. Typically sent from the client to the server.
Code
interface RequestEditValidationAction extends RequestAction<SetEditValidationResultAction> {
/**
* The kind of the action.
*/
kind = 'requestEditValidation';
/**
* Context in which the text is validated, e.g., 'label-edit'.
*/
contextId: string;
/**
* Model element that is being edited.
*/
modelElementId: string;
/**
* Text that should be considered for the model element.
*/
text: string;
}
2.16.2. SetEditValidationResultAction
Response to a RequestEditValidationAction
containing the validation result for applying a text on a certain model element.
Code
interface SetEditValidationResultAction extends ResponseAction {
/**
* The kind of the action.
*/
kind = 'setEditValidationResult';
/**
* Validation status.
*/
status: ValidationStatus;
/*
* Additional arguments for custom behavior.
*/
args?: Args;
}
2.16.3. ApplyLabelEditOperation
A very common use case in domain models is the support of labels that display textual information to the user. For instance, the GGraph
model has support for labels that can be attached to a node, edge, or port, and that contain some text that is rendered in the view. To apply new text to such a label element the client may send an ApplyLabelEditOperation
to the server.
Code
interface ApplyLabelEditOperation extends Operation {
/**
* The kind of the action.
*/
kind = 'applyLabelEdit';
/**
* Identifier of the label model element.
*/
labelId: string;
/**
* Text that should be applied on the label.
*/
text: string;
}
2.17. Clipboard
In GLSP the clipboard needs to be managed by the client but the conversion from the selection to be copied into a clipboard-compatible format is handled by the server. By default, GLSP use application/json
as exchange format.
Code
type ClipboardData = { [format: string]: string };
2.17.1. RequestClipboardDataAction
Requests the clipboard data for the current editor context, i.e., the selected elements, in a clipboard-compatible format.
Code
interface RequestClipboardDataAction extends RequestAction<SetClipboardDataAction> {
/**
* The kind of the action.
*/
kind = 'requestClipboardData';
/**
* The current editor context.
*/
editorContext: EditorContext;
}
2.17.2. SetClipboardDataAction
Server response to a RequestClipboardDataAction
containing the selected elements as clipboard-compatible format.
Code
interface SetClipboardDataAction extends ResponseAction {
/**
* The kind of the action.
*/
kind = 'setClipboardData';
/**
* The selected elements from the editor context as clipboard data.
*/
clipboardData: ClipboardData;
}
2.17.3. CutOperation
Requests a cut operation from the server, i.e., deleting the selected elements from the model. Before submitting a CutOperation
a client should ensure that the cut elements are put into the clipboard.
Code
interface CutOperation extends Operation {
/**
* The kind of the action.
*/
kind = 'cut';
/**
* The current editor context.
*/
editorContext: EditorContext;
}
2.17.4. PasteOperation
Requests a paste operation from the server by providing the current clipboard data. Typically this means that elements should be created based on the data in the clipboard.
Code
interface PasteOperation extends Operation {
/**
* The kind of the action.
*/
kind = 'paste';
/**
* The current editor context.
*/
editorContext: EditorContext;
/**
* The clipboard data that should be pasted to the editor's last recorded mouse position (see `editorContext`).
*/
clipboardData: ClipboardData;
}
2.18. Undo / Redo
A server usually keeps a command stack of all commands executed on the model. To navigate the command stack the following actions can be used.
2.18.1. UndoAction
Trigger an undo of the latest executed command.
Code
interface UndoAction {
/**
* The kind of the action.
*/
kind = 'glspUndo';
}
2.18.2. RedoAction
Trigger a redo of the latest undone command.
Code
interface RedoAction {
/**
* The kind of the action.
*/
kind = 'glspRedo';
}
2.19. Contexts
A context is a dedicated space in the client that is identified via a unique id. Context actions are a specific set of actions that are available in that context id. At the moment we support three such contexts:
- The Context Menu with the context id
context-menu
- The Command Palette with the context id
command-palette
- The Tool Palette with the context id
tool-palette
2.19.1. RequestContextActions
Code
The RequestContextActions is sent from the client to the server to request the available actions for the context with id contextId
.
interface RequestContextActions extends RequestAction<SetContextActions> {
/**
* The kind of the action.
*/
kind = 'requestContextActions';
/**
* The identifier for the context.
*/
contextId: string;
/**
* The current editor context.
*/
editorContext: EditorContext;
}
2.19.2. SetContextActions
The SetContextActions
is the response to a RequestContextActions
containing all actions for the queried context.
Code
interface SetContextActions extends ResponseAction {
/**
* The kind of the action.
*/
kind = 'setContextActions';
/**
* The actions available in the queried context.
*/
readonly actions: LabeledAction[];
/**
* Custom arguments.
*/
args: ?Args;
}
2.19.3. Context Menu
The context menu is an overlay that is triggered by a right click from the user. The menu may be filled with actions from the client but may also be filled with actions from the server. If server actions are to be used, the client needs to send a RequestContextActions
action with context id context-menu
and handle the returned actions from the SetContextActions
response accordingly, e.g., rendering them in a context menu.
2.19.4. Command Palette
The command palette is an “auto-complete” widget that is triggered when the user hits Ctrl+Space
. The menu may be filled with actions from the client but may also be filled with actions from the server. If server actions are to be used, the client needs to send a RequestContextActions
action with context id command-palette
and handle the returned actions from the SetContextActions
response accordingly, i.e., rendering them in a auto-complete widget.
2.19.5. Tool Palette
The tool palette is a widget on the graph’s canvas that displays a set of tools and actions that the user can use to interact with the model. As such the tool palette consists of two parts: tools and labeled actions.
A tool is a uniquely identified functionality that can be either enabled or disabled. Tools can be activated and de-activated from the user by clicking their rendered representation in the platte or may be activated using dedicated actions.
Code
interface Tool {
/**
* Unique tool id.
*/
readonly id: string;
/**
* Notifies the tool to become active.
*/
enable(): void;
/**
* Notifies the tool to become inactive.
*/
disable(): void;
}
By default, the tool palette in GLSP includes the following tools in the palette:
- Default Tool (Selection Tool)
- Mouse Delete Tool
- Validation Tool
The supported actions of the tool palette come from the server. If server actions are to be used, the client needs to send a RequestContextActions
action with context id tool-palette
and handle the returned actions from the SetContextActions
response accordingly, e.g., rendering them in the tool palette. A user may click on any of the entries in the tool palette to trigger the corresponding action.
For creating new elements we provide two dedicated trigger actions that can be sent from the server to activate and configure the Node Creation Tool
or the Edge Creation Tool
respectively. This indirection is necessary as the user, after clicking on the respective action, still needs to provide additional information, i.e., the location of the new node or which elements should be connected through an edge. After all information is available, the actual creation operation is triggered.
2.19.5.1. TriggerNodeCreationAction
Triggers the enablement of the tool that is responsible for creating nodes and initializes it with the creation of nodes of the given elementTypeId
.
Code
interface TriggerNodeCreationAction extends Action {
/**
* The kind of the action.
*/
kind = 'triggerNodeCreation';
/**
* The type of node that should be created by the node creation tool.
*/
elementTypeId: string;
/**
* Custom arguments.
*/
args?: Args;
}
2.19.5.2. TriggerEdgeCreationAction
Triggers the enablement of the tool that is responsible for creating edges and initializes it with the creation of edges of the given elementTypeId
.
Code
interface TriggerEdgeCreationAction extends Action {
/**
* The kind of the action.
*/
kind = 'triggerEdgeCreation';
/**
* The type of edge that should be created by the edge creation tool.
*/
elementTypeId: string;
/**
* Custom arguments.
*/
args?: Args;
}