Skip to content

Commit

Permalink
Update Langium and apply new langium-sprotty features
Browse files Browse the repository at this point in the history
  • Loading branch information
spoenemann committed May 14, 2024
1 parent 24a1a1c commit b259ddb
Show file tree
Hide file tree
Showing 18 changed files with 1,187 additions and 1,082 deletions.
29 changes: 21 additions & 8 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
"--extensionDevelopmentPath=${workspaceFolder}/examples/states-langium/extension"
],
"outFiles": [
"${workspaceFolder}/examples/states-langium/extension/pack/*.js",
"${workspaceFolder}/sprotty-vscode-extension/lib/**/*.js"
"${workspaceFolder}/examples/states-langium/extension/pack/extension/src/*.cjs",
"${workspaceFolder}/packages/sprotty-vscode/lib/**/*.js"
],
"sourceMaps": true
},
Expand All @@ -36,8 +36,8 @@
"--extensionDevelopmentPath=${workspaceFolder}/examples/states-langium/extension"
],
"outFiles": [
"${workspaceFolder}/examples/states-langium/extension/pack/*.js",
"${workspaceFolder}/sprotty-vscode-extension/lib/**/*.js"
"${workspaceFolder}/examples/states-langium/extension/pack/extension/src/*.cjs",
"${workspaceFolder}/packages/sprotty-vscode/lib/**/*.js"
],
"sourceMaps": true
},
Expand All @@ -54,8 +54,8 @@
"--extensionDevelopmentPath=${workspaceFolder}/examples/states-langium/extension"
],
"outFiles": [
"${workspaceFolder}/examples/states-langium/extension/pack/*.js",
"${workspaceFolder}/sprotty-vscode-extension/lib/**/*.js"
"${workspaceFolder}/examples/states-langium/extension/pack/extension/src/*.cjs",
"${workspaceFolder}/packages/sprotty-vscode/lib/**/*.js"
],
"sourceMaps": true
},
Expand All @@ -70,9 +70,22 @@
],
"outFiles": [
"${workspaceFolder}/examples/states-xtext/extension/pack/*.js",
"${workspaceFolder}/sprotty-vscode-extension/lib/**/*.js"
"${workspaceFolder}/packages/sprotty-vscode/lib/**/*.js"
],
"sourceMaps": true
}
},
{
"name": "Attach to Language Server",
"type": "node",
"port": 6009,
"request": "attach",
"skipFiles": [
"<node_internals>/**"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/examples/states-langium/extension/pack/language-server/src/*.cjs"
]
},
]
}
85 changes: 85 additions & 0 deletions examples/states-langium/extension/esbuild.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//@ts-check
import * as esbuild from 'esbuild';

const options = {
watch: process.argv.includes('--watch'),
minify: process.argv.includes('--minify'),
};

const successMessage = options.watch
? 'Watch build succeeded'
: 'Build succeeded';

/** @type {import('esbuild').Plugin[]} */
const plugins = [
{
name: 'watch-plugin',
setup(build) {
build.onEnd((result) => {
if (result.errors.length === 0) {
console.log(getTime() + successMessage);
}
});
},
},
];

const nodeContext = await esbuild.context({
entryPoints: [
'src/states-extension.ts',
'../language-server/src/main.ts'
],
outdir: 'pack',
bundle: true,
target: 'es6',
format: 'cjs',
loader: { '.ts': 'ts' },
outExtension: {
'.js': '.cjs',
},
external: ['vscode'],
platform: 'node',
sourcemap: !options.minify,
minify: options.minify,
plugins,
});

const browserContext = await esbuild.context({
entryPoints: ['../../states-webview/src/main.ts'],
outdir: 'pack/diagram',
bundle: true,
target: 'es6',
loader: { '.ts': 'ts', '.css': 'css' },
platform: 'browser',
sourcemap: !options.minify,
minify: options.minify,
plugins,
});

if (options.watch) {
await Promise.all([
nodeContext.watch(),
browserContext.watch()
]);
} else {
await Promise.all([
nodeContext.rebuild(),
browserContext.rebuild()
]);
nodeContext.dispose();
browserContext.dispose();
}

function getTime() {
const date = new Date();
return `[${`${padZeroes(date.getHours())}:${padZeroes(
date.getMinutes()
)}:${padZeroes(date.getSeconds())}`}] `;
}

/**
* @param {number} i
*/
function padZeroes(i) {
return i.toString().padStart(2, '0');
}
25 changes: 7 additions & 18 deletions examples/states-langium/extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,7 @@
]
},
"activationEvents": [
"onLanguage:states",
"onWebviewPanel:states",
"onCustomEditor:states",
"onView:states",
"onCommand:states.diagram.open"
"onWebviewPanel:states"
],
"files": [
"lib",
Expand All @@ -184,25 +180,18 @@
"syntaxes",
"webview"
],
"main": "./pack/states-extension",
"main": "./pack/extension/src/states-extension.cjs",
"devDependencies": {
"@types/node": "^14.17.3",
"@types/vscode": "1.50.0",
"source-map-loader": "^4.0.1",
"esbuild": "^0.21.2",
"sprotty-vscode": "^1.0.0",
"states-language-server": "^0.6.0",
"states-sprotty-webview": "^0.6.0",
"ts-loader": "^9.5.1",
"vscode-languageclient": "^9.0.1",
"webpack": "^5.89.0",
"webpack-cli": "^5.1.4"
"vscode-languageclient": "^9.0.1"
},
"scripts": {
"prepare": "yarn run clean && yarn run build && yarn run copy-language-server && yarn run copy-webview",
"prepare": "yarn run clean && yarn run build",
"clean": "shx rm -fr pack",
"build": "webpack --mode=development",
"watch": "webpack --mode=development --watch",
"copy-language-server": "shx cp ../language-server/out/* pack/",
"copy-webview": "shx cp ../../states-webview/out/* pack/"
"build": "node esbuild.mjs",
"watch": "node esbuild.mjs --watch"
}
}
25 changes: 20 additions & 5 deletions examples/states-langium/extension/src/states-extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
********************************************************************************/

import * as path from 'path';
import { registerDefaultCommands, registerTextEditorSync } from 'sprotty-vscode';
import {
SprottyDiagramIdentifier, WebviewContainer, createFileUri, createWebviewHtml as doCreateWebviewHtml,
registerDefaultCommands, registerTextEditorSync
} from 'sprotty-vscode';
import { LspSprottyEditorProvider, LspSprottyViewProvider, LspWebviewPanelManager } from 'sprotty-vscode/lib/lsp';
import * as vscode from 'vscode';
import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind } from 'vscode-languageclient/node';
Expand All @@ -30,14 +33,22 @@ export function activate(context: vscode.ExtensionContext) {
}

languageClient = createLanguageClient(context);
const extensionPath = context.extensionUri.fsPath;
const localResourceRoots = [createFileUri(extensionPath, 'pack', 'diagram')];
const createWebviewHtml = (identifier: SprottyDiagramIdentifier, container: WebviewContainer) => doCreateWebviewHtml(identifier, container, {
scriptUri: createFileUri(extensionPath, 'pack', 'diagram', 'main.js'),
cssUri: createFileUri(extensionPath, 'pack', 'diagram', 'main.css')
});

if (diagramMode === 'panel') {
// Set up webview panel manager for freestyle webviews
const webviewPanelManager = new LspWebviewPanelManager({
extensionUri: context.extensionUri,
defaultDiagramType: 'states',
languageClient,
supportedFileExtensions: ['.sm']
supportedFileExtensions: ['.sm'],
localResourceRoots,
createWebviewHtml
});
registerDefaultCommands(webviewPanelManager, context, { extensionPrefix: 'states' });
}
Expand All @@ -48,7 +59,9 @@ export function activate(context: vscode.ExtensionContext) {
extensionUri: context.extensionUri,
viewType: 'states',
languageClient,
supportedFileExtensions: ['.sm']
supportedFileExtensions: ['.sm'],
localResourceRoots,
createWebviewHtml
});
context.subscriptions.push(
vscode.window.registerCustomEditorProvider('states', webviewEditorProvider, {
Expand All @@ -66,7 +79,9 @@ export function activate(context: vscode.ExtensionContext) {
languageClient,
supportedFileExtensions: ['.sm'],
openActiveEditor: true,
messenger: new Messenger({ignoreHiddenViews: false})
messenger: new Messenger({ignoreHiddenViews: false}),
localResourceRoots,
createWebviewHtml
});
context.subscriptions.push(
vscode.window.registerWebviewViewProvider('states', webviewViewProvider, {
Expand All @@ -79,7 +94,7 @@ export function activate(context: vscode.ExtensionContext) {
}

function createLanguageClient(context: vscode.ExtensionContext): LanguageClient {
const serverModule = context.asAbsolutePath(path.join('pack', 'language-server'));
const serverModule = context.asAbsolutePath(path.join('pack', 'language-server', 'src', 'main.cjs'));
// The debug options for the server
// --inspect=6009: runs the server in Node's Inspector mode so VS Code can attach to the server for debugging.
// By setting `process.env.DEBUG_BREAK` to a truthy value, the language server will wait until a debugger is attached.
Expand Down
15 changes: 6 additions & 9 deletions examples/states-langium/language-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,20 @@
},
"type": "module",
"dependencies": {
"langium": "^2.1.2",
"langium-sprotty": "^2.1.0",
"sprotty-elk": "^1.0.0",
"langium": "^3.0.0",
"langium-sprotty": "^3.0.0",
"sprotty-elk": "^1.2.0",
"vscode-languageserver": "^9.0.1"
},
"devDependencies": {
"@types/node": "^14.17.3",
"langium-cli": "^2.1.0",
"ts-loader": "^9.5.1",
"webpack": "^5.89.0",
"webpack-cli": "^5.1.4"
"langium-cli": "^3.0.3"
},
"scripts": {
"prepare": "yarn run clean && yarn run langium:generate && yarn run build",
"clean": "shx rm -fr out",
"build": "webpack --mode=development",
"watch": "webpack --mode=development --watch",
"build": "tsc --noEmit",
"watch": "tsc --noEmit --watch",
"langium:generate": "langium generate",
"langium:watch": "langium generate --watch"
}
Expand Down
32 changes: 24 additions & 8 deletions examples/states-langium/language-server/src/diagram-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,30 @@
********************************************************************************/

import { GeneratorContext, LangiumDiagramGenerator } from 'langium-sprotty';
import { SEdge, SLabel, SModelRoot, SNode, SPort } from 'sprotty-protocol';
import { SEdge, SLabel, SModelRoot, SNode, SPort, EdgeLayoutable } from 'sprotty-protocol';
import { State, StateMachine, Transition } from './generated/ast.js';

export class StatesDiagramGenerator extends LangiumDiagramGenerator {

protected generateRoot(args: GeneratorContext<StateMachine>): SModelRoot {
const { document } = args;
const sm = document.parseResult.value;
return {
const graph = {
type: 'graph',
id: sm.name ?? 'root',
children: [
...sm.states.map(s => this.generateNode(s, args)),
...sm.states.flatMap(s => s.transitions).map(t => this.generateEdge(t, args))
]
};
this.traceProvider.trace(graph, sm);
return graph;
}

protected generateNode(state: State, { idCache }: GeneratorContext<StateMachine>): SNode {
protected generateNode(state: State, ctx: GeneratorContext<StateMachine>): SNode {
const { idCache } = ctx;
const nodeId = idCache.uniqueId(state.name, state);
return {
const node = {
type: 'node',
id: nodeId,
children: [
Expand All @@ -57,25 +60,38 @@ export class StatesDiagramGenerator extends LangiumDiagramGenerator {
paddingRight: 10.0
}
};
this.traceProvider.trace(node, state);
this.markerProvider.addDiagnosticMarker(node, state, ctx);
return node;
}

protected generateEdge(transition: Transition, { idCache }: GeneratorContext<StateMachine>): SEdge {
protected generateEdge(transition: Transition, ctx: GeneratorContext<StateMachine>): SEdge {
const { idCache } = ctx;
const sourceId = idCache.getId(transition.$container);
const targetId = idCache.getId(transition.state?.ref);
const edgeId = idCache.uniqueId(`${sourceId}:${transition.event?.ref?.name}:${targetId}`, transition);
return {
const edge = {
type: 'edge',
id: edgeId,
sourceId: sourceId!,
targetId: targetId!,
children: [
<SLabel>{
<SLabel & EdgeLayoutable>{
type: 'label:xref',
id: idCache.uniqueId(edgeId + '.label'),
text: transition.event?.ref?.name
text: transition.event?.ref?.name,
edgePlacement: {
position: 0.5,
offset: 4,
side: 'left',
rotate: true
}
}
]
};
this.traceProvider.trace(edge, transition);
this.markerProvider.addDiagnosticMarker(edge, transition, ctx);
return edge;
}

}
Loading

0 comments on commit b259ddb

Please sign in to comment.