Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Langium and apply new langium-sprotty features #104

Merged
merged 2 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
24 changes: 17 additions & 7 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,32 @@ 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
}
]
};
this.traceProvider.trace(edge, transition);
this.markerProvider.addDiagnosticMarker(edge, transition, ctx);
return edge;
}

}
Loading
Loading