Eclipse GLSP VSCode Integration
This package contains the glue code for integrating GLSP diagrams in VS Code.
This library enables the implementation of GLSP Diagram editors for VS Code base on the Custom Editor API.
Where to find the sources?
In addition to this repository, the related source code can be found here:
Getting started
This section will show you how to get your first GLSP extension up and running using the GLSP VSCode Integration.
Example Extension
You can find a complete example extension that uses this package here.
It makes heavy use of default implementations like the default GLSP server, the default GLSP client and the default GLSP Sprotty client.
Example Code
There are a few steps that are absolutely necessary for the GLSP VSCode Integration to work. They are outlined in this section.
Extension
First you need to set up your extension starter code. This is done by setting the "main"
field of your package.json
to the entry point of your extension and exporting an activate()
function from that file.
For more information on how to set up your VSCode extension please visit https://code.visualstudio.com/api.
Code Example
import * as vscode from 'vscode';
export async function activate(context: vscode.ExtensionContext): Promise<void> {
}
Server
Next we will start a GLSP server from within the activate function. If you have already have the server running through some other process you can skip this step.
If you are using the default GLSP server implementation provided at https://github.com/eclipse-glsp/glsp-server, you can use the GlspServerLauncher
quickstart component to start the server with very little code:
Code Example
import { GlspServerLauncher } from '@eclipse-glsp/vscode-integration/lib/quickstart-components';
export async function activate(context: vscode.ExtensionContext): Promise<void> {
const serverProcess = new GlspServerLauncher({
jarPath: '/your/path/to/server.jar',
serverPort: 5007
});
context.subscriptions.push(serverProcess);
await serverProcess.start();
}
Server Interface and GLSP VSCode Connector
A connector class is needed to provide an interface for the _GLSP VSCode integration_to communicate with the server.
If you are using the default GLSP server which communicates over JSON-RPC, you can make use of the SocketGlspVscodeServer
quickstart component to implement the needed interface with very little boilerplate code.
If we have a server component providing the needed interface we can create an instance of the GlspVscodeConnector
and pass the server component. The GlspVscodeConnector
lies at the core of this package and provides all the needed functionality.
Code Example
import { GlspVscodeConnector } from '@eclipse-glsp/vscode-integration';
import { SocketGlspVscodeServer } from '@eclipse-glsp/vscode-integration/lib/quickstart-components';
export async function activate(context: vscode.ExtensionContext): Promise<void> {
const workflowServer = new SocketGlspVscodeServer({
clientId: 'some.client.id',
clientName: 'SomeClientName',
serverPort: 5007
});
const glspVscodeConnector = new GlspVscodeConnector({ server: workflowServer });
context.subscriptions.push(workflowServer, glspVscodeConnector);
}
Custom Editor Provider
In order to have a custom editor in VSCode a component implementing the vscode.CustomEditorProvider
needs to be registered from within the extension (more information on custom editors here).
The GLSP VSCode integration package gives you free reign over how you implement your CustomEditorProvider
, however a few function calls at certain places are needed for the integration to work properly:
- The
onDidChangeCustomDocument
of your CustomEditorProvider
should always fire
at least when GlspVscodeConnector.onDidChangeCustomDocument
fires.
GlspVscodeConnector.saveDocument(document)
should be called when CustomEditorProvider.saveCustomDocument
is called.
GlspVscodeConnector.saveDocument(document, destination)
should be called when
CustomEditorProvider.saveCustomDocumentAs
is called.
GlspVscodeConnector.revertDocument()
should be called when CustomEditorProvider.revertCustomDocument
is called.
You can use the GlspEditorProvider
quickstart component to set up such an editor provider without much boilerplate code.
If you chose to create a CustomEditorProvider
yourself, the resolveCustomEditor
function of the CustomEditorProvider
act as an excellent place to register your GLSP clients.
You can do this with the GlspVscodeConnector.registerClient(client)
function.
You are free to choose on how your clients implement the needed interface,however if you need inspiration on how to do it with the default GLSP components, you can take a look at the example here.
Code Example
import MyCustomEditorProvider from './my-custom-editor-provider.ts';
export async function activate(context: vscode.ExtensionContext): Promise<void> {
const customEditorProvider = vscode.window.registerCustomEditorProvider(
'your.custom.editor',
new MyCustomEditorProvider(glspVscodeConnector),
{
webviewOptions: { retainContextWhenHidden: true },
supportsMultipleEditorsPerDocument: false
}
);
context.subscriptions.push(customEditorProvider);
}
export default class WorkflowEditorProvider implements vscode.CustomEditorProvider {
onDidChangeCustomDocument: vscode.Event<vscode.CustomDocumentContentChangeEvent<vscode.CustomDocument>>;
constructor(private readonly glspVscodeConnector: GlspVscodeConnector) {
this.onDidChangeCustomDocument = glspVscodeConnector.onDidChangeCustomDocument;
}
saveCustomDocument(document: vscode.CustomDocument, cancellation: vscode.CancellationToken): Thenable<void> {
return this.glspVscodeConnector.saveDocument(document);
}
saveCustomDocumentAs(document: vscode.CustomDocument, destination: vscode.Uri, cancellation: vscode.CancellationToken): Thenable<void> {
return this.glspVscodeConnector.saveDocument(document, destination);
}
revertCustomDocument(document: vscode.CustomDocument, cancellation: vscode.CancellationToken): Thenable<void> {
return this.glspVscodeConnector.revertDocument(document, 'your.diagram.type');
}
resolveCustomEditor(
document: vscode.CustomDocument,
webviewPanel: vscode.WebviewPanel,
token: vscode.CancellationToken
): void | Thenable<void> {
const onSendToClientEmitter = new vscode.EventEmitter<unknown>();
const onClientMessage = new vscode.EventEmitter<unknown>();
this.glspVscodeConnector.registerClient({
clientId: 'your.glsp.client.id.here',
document: document,
webviewPanel: webviewPanel,
onClientMessage: onClientSendEmitter.event,
onSendToClientEmitter: onSendToClientEmitter
});
webviewPanel.webview.html = `(Your webview HTML here)`;
}
}
Final touches
All that's left to do is a final call to start the server and the extension should be up and running.
Code Example
export async function activate(context: vscode.ExtensionContext): Promise<void> {
workflowServer.start();
}
API
This package exports a number of members, the most important one being the GlspVscodeConnector
-Class.
GlspVscodeConnector
This is the core of the VSCode integration and provides various functionality.
It primarily intercepts certain GLSP Actions sent from the clients or server to trigger VSCode specific contributions.
This currently includes:
- File dirty state
- File "Save" and "Save as..."
- File reverting
- Diagnostics or "markers" and "validations"
- External target navigation
- Exporting as SVG (with dialog window)
- Providing element selection context to extensions
Options
The GlspVscodeConnector
takes one constructor argument - an object containing its configuration.
export interface GlspVscodeConnectorOptions {
server: GlspVscodeServer;
logging?: boolean;
onBeforeReceiveMessageFromClient?: (message: unknown, callback: InterceptorCallback) => void;
onBeforeReceiveMessageFromServer?(message: unknown, callback: InterceptorCallback): void;
onBeforePropagateMessageToServer?(originalMessage: unknown, processedMessage: unknown, messageChanged: boolean): unknown | undefined;
onBeforePropagateMessageToClient?(originalMessage: unknown, processedMessage: unknown, messageChanged: boolean): unknown | undefined;
}
Methods and Fields
interface GlspVscodeConnector<D extends vscode.CustomDocument = vscode.CustomDocument> extends vscode.Disposable {
onSelectionUpdate: vscode.Event<string[]>;
onDidChangeCustomDocument: vscode.Event<vscode.CustomDocumentEditEvent<D>>;
registerClient(client: GlspVscodeClient<D>): void;
sendActionToActiveClient(action: Action): void;
saveDocument(document: D, destination?: vscode.Uri): Promise<void>;
revertDocument(document: D, diagramType: string): Promise<void>;
}
GlspVscodeServer
export interface GlspVscodeServer {
readonly onSendToServerEmitter: vscode.EventEmitter<unknown>;
readonly onServerMessage: vscode.Event<unknown>;
}
GlspVscodeClient
export interface GlspVscodeClient<D extends vscode.CustomDocument = vscode.CustomDocument> {
readonly clientId: string;
readonly webviewPanel: vscode.WebviewPanel;
readonly document: D;
readonly onSendToClientEmitter: vscode.EventEmitter<unknown>;
readonly onClientMessage: vscode.Event<unknown>;
}
Quickstart Components
This package also exposes components which can be taken advantage of if you are using the default GLSP components.
They can be imported using
import * as QuickstartComponents from '@eclipse-glsp/vscode-integration/lib/quickstart-components';
GlspServerLauncher
A small class used to start a default implementation GLSP server.
interface GlspServerLauncher extends vscode.Disposable {
constructor(options: JavaSocketServerLauncherOptions);
start(): Promise<void>;
stop(): void;
}
interface JavaSocketServerLauncherOptions {
readonly jarPath: string;
readonly serverPort: number;
readonly logging?: boolean;
readonly additionalArgs?: string[];
}
SocketGlspVscodeServer
A can component that provides the right interface for the GLSP VSCode integration to be used as server and which can connect to a default implementation GLSP server.
interface SocketGlspVscodeServerOptions {
readonly serverPort: number;
readonly clientId: string;
readonly clientName: string;
}
interface SocketGlspVscodeServer extends GlspVscodeServer, vscode.Disposable {
constructor(private readonly options: SocketGlspVscodeServerOptions);
start(): Promise<void>;
stop(): Promise<void>;
}
GlspEditorProvider
An extensible base class to create a CustomEditorProvider that takes care of diagram initialization and custom document events.
Webview setup needs to be implemented.
export abstract class GlspEditorProvider implements vscode.CustomEditorProvider {
abstract diagramType: string;
constructor(protected readonly glspVscodeConnector: GlspVscodeConnector);
abstract setUpWebview(
document: vscode.CustomDocument,
webviewPanel: vscode.WebviewPanel,
token: vscode.CancellationToken,
clientId: string
): void;
}
More information
For more information, please visit the Eclipse GLSP Umbrella repository and the Eclipse GLSP Website.
If you have questions, please raise them in the discussions and have a look at our communication and support options.