diff --git a/index.html b/index.html index 235b5c10e..578d72460 100644 --- a/index.html +++ b/index.html @@ -19,7 +19,9 @@

Examples

Please execute npm run start:example:server beforehand:
Web Client for Node.js Language Server

- Web Client & Langium Web Worker Language Server Example + Web Client & Langium LS (Web Worker) +

+ Web Client & Statemachine LS (Web Worker)

Browser Example

diff --git a/packages/client/tsconfig.json b/packages/client/tsconfig.json new file mode 100644 index 000000000..25c9de527 --- /dev/null +++ b/packages/client/tsconfig.json @@ -0,0 +1,12 @@ +// this file is required for VSCode to work properly +{ + "extends": "./tsconfig.src.json", + "compilerOptions": { + "noEmit": true, + "rootDir": "." + }, + "include": [ + "src/**/*", + "test/**/*" + ] +} diff --git a/packages/examples/main/langium_wwls.html b/packages/examples/main/langium_client.html similarity index 86% rename from packages/examples/main/langium_wwls.html rename to packages/examples/main/langium_client.html index f9e466816..fd945577b 100644 --- a/packages/examples/main/langium_wwls.html +++ b/packages/examples/main/langium_client.html @@ -10,7 +10,7 @@

Monaco Language Client & Langium Web Worker Language Server Example

- +
diff --git a/packages/examples/main/package.json b/packages/examples/main/package.json index 5d41d9fe7..b5d2ad656 100644 --- a/packages/examples/main/package.json +++ b/packages/examples/main/package.json @@ -52,11 +52,11 @@ "clean": "shx rm -fr dist *.tsbuildinfo", "compile": "tsc --build tsconfig.src.json", "build:msg": "echo Building main examples:", - "build:worker:vite": "vite --config vite.langium-worker.ts build", - "build:worker": "esbuild ../../../node_modules/langium-statemachine-dsl/out/language-server/main-browser.js --bundle --tree-shaking=true --minify --format=iife --outfile=./dist/worker/statemachineServerWorker.js", - "build": "npm run build:msg && npm run clean && npm run compile && npm run build:worker", + "build:worker:vite": "vite --config vite.statemachine-worker.ts build", + "build:worker:statemachine": "esbuild ../../../node_modules/langium-statemachine-dsl/out/language-server/main-browser.js --bundle --tree-shaking=true --minify --format=iife --outfile=./dist/worker/statemachineServerWorker.js", + "build:worker:langium": "esbuild ./src/langium/langiumServerWorker.js --bundle --tree-shaking=true --minify --format=iife --outfile=./dist/worker/langiumServerWorker.js", + "build": "npm run build:msg && npm run clean && npm run compile && npm run build:worker:statemachine && npm run build:worker:langium", "start": "node --loader ts-node/esm src/server/main.ts", - "start:ext": "node --loader ts-node/esm src/server/main.ts --external", - "fetch:themes": "node resources/fetchThemes.mjs" + "start:ext": "node --loader ts-node/esm src/server/main.ts --external" } } \ No newline at end of file diff --git a/packages/examples/main/src/langium/example.langium b/packages/examples/main/src/langium/example.langium new file mode 100644 index 000000000..fb187aae5 --- /dev/null +++ b/packages/examples/main/src/langium/example.langium @@ -0,0 +1,215 @@ +/****************************************************************************** + * Copyright 2021 TypeFox GmbH + * This program and the accompanying materials are made available under the + * terms of the MIT License, which is available in the project root. + ******************************************************************************/ +grammar LangiumGrammar + +entry Grammar: + ( + isDeclared?='grammar' name=ID ('with' usedGrammars+=[Grammar:ID] (',' usedGrammars+=[Grammar:ID])*)? + (definesHiddenTokens?='hidden' '(' (hiddenTokens+=[AbstractRule:ID] (',' hiddenTokens+=[AbstractRule:ID])*)? ')')? + )? + imports+=GrammarImport* + (rules+=AbstractRule | interfaces+=Interface | types+=Type)+; + +Interface: + 'interface' name=ID + ('extends' superTypes+=[AbstractType:ID] (',' superTypes+=[AbstractType:ID])*)? + SchemaType; + +fragment SchemaType: + '{' attributes+=TypeAttribute* '}' ';'?; + +TypeAttribute: + name=FeatureName (isOptional?='?')? ':' type=TypeDefinition ';'?; + +TypeDefinition: UnionType; + +UnionType infers TypeDefinition: + ArrayType ({infer UnionType.types+=current} ('|' types+=ArrayType)+)?; + +ArrayType infers TypeDefinition: + ReferenceType ({infer ArrayType.elementType=current} '[' ']')? ; + +ReferenceType infers TypeDefinition: + SimpleType | + {infer ReferenceType} '@' referenceType=SimpleType; + +SimpleType infers TypeDefinition: + '(' TypeDefinition ')' | + {infer SimpleType} (typeRef=[AbstractType:ID] | primitiveType=PrimitiveType | stringType=STRING); + +PrimitiveType returns string: + 'string' | 'number' | 'boolean' | 'Date' | 'bigint'; + +type AbstractType = Interface | Type | Action | ParserRule; + +Type: + 'type' name=ID '=' type=TypeDefinition ';'?; + +AbstractRule: + ParserRule | TerminalRule; + +GrammarImport: + 'import' path=STRING ';'?; + +ParserRule: + (entry?='entry' | fragment?='fragment')? + RuleNameAndParams + (wildcard?='*' | ('returns' (returnType=[AbstractType:ID] | dataType=PrimitiveType)) | inferredType=InferredType)? + (definesHiddenTokens?='hidden' '(' (hiddenTokens+=[AbstractRule:ID] (',' hiddenTokens+=[AbstractRule:ID])*)? ')')? ':' + definition=Alternatives ';'; + +InferredType: + ( 'infer' | 'infers') name=ID; + +fragment RuleNameAndParams: + name=ID ('<' (parameters+=Parameter (',' parameters+=Parameter)*)? '>')?; + +Parameter: + name=ID; + +Alternatives infers AbstractElement: + ConditionalBranch ({infer Alternatives.elements+=current} ('|' elements+=ConditionalBranch)+)?; + +ConditionalBranch infers AbstractElement: + UnorderedGroup + | {infer Group} '<' guardCondition=Disjunction '>' (elements+=AbstractToken)+; + +UnorderedGroup infers AbstractElement: + Group ({infer UnorderedGroup.elements+=current} ('&' elements+=Group)+)?; + +Group infers AbstractElement: + AbstractToken ({infer Group.elements+=current} elements+=AbstractToken+)?; + +AbstractToken infers AbstractElement: + AbstractTokenWithCardinality | + Action; + +AbstractTokenWithCardinality infers AbstractElement: + (Assignment | AbstractTerminal) cardinality=('?'|'*'|'+')?; + +Action infers AbstractElement: + {infer Action} '{' (type=[AbstractType:ID] | inferredType=InferredType) ('.' feature=FeatureName operator=('='|'+=') 'current')? '}'; + +AbstractTerminal infers AbstractElement: + Keyword | + RuleCall | + ParenthesizedElement | + PredicatedKeyword | + PredicatedRuleCall | + PredicatedGroup; + +Keyword: + value=STRING; + +RuleCall: + rule=[AbstractRule:ID] ('<' arguments+=NamedArgument (',' arguments+=NamedArgument)* '>')?; + +NamedArgument: + ( parameter=[Parameter:ID] calledByName?='=')? + ( value=Disjunction ); + +LiteralCondition: + true?='true' | 'false'; + +Disjunction infers Condition: + Conjunction ({infer Disjunction.left=current} '|' right=Conjunction)*; + +Conjunction infers Condition: + Negation ({infer Conjunction.left=current} '&' right=Negation)*; + +Negation infers Condition: + Atom | {infer Negation} '!' value=Negation; + +Atom infers Condition: + ParameterReference | ParenthesizedCondition | LiteralCondition; + +ParenthesizedCondition infers Condition: + '(' Disjunction ')'; + +ParameterReference: + parameter=[Parameter:ID]; + +PredicatedKeyword infers Keyword: + ('=>' | '->') value=STRING; + +PredicatedRuleCall infers RuleCall: + ('=>' | '->') rule=[AbstractRule:ID] ('<' arguments+=NamedArgument (',' arguments+=NamedArgument)* '>')?; + +Assignment infers AbstractElement: + {infer Assignment} ('=>' | '->')? feature=FeatureName operator=('+='|'='|'?=') terminal=AssignableTerminal; + +AssignableTerminal infers AbstractElement: + Keyword | RuleCall | ParenthesizedAssignableElement | CrossReference; + +ParenthesizedAssignableElement infers AbstractElement: + '(' AssignableAlternatives ')'; + +AssignableAlternatives infers AbstractElement: + AssignableTerminal ({infer Alternatives.elements+=current} ('|' elements+=AssignableTerminal)+)?; + +CrossReference infers AbstractElement: + {infer CrossReference} '[' type=[AbstractType] ((deprecatedSyntax?='|' | ':') terminal=CrossReferenceableTerminal )? ']'; + +CrossReferenceableTerminal infers AbstractElement: + Keyword | RuleCall; + +ParenthesizedElement infers AbstractElement: + '(' Alternatives ')'; + +PredicatedGroup infers Group: + ('=>' | '->') '(' elements+=Alternatives ')'; + +ReturnType: + name=(PrimitiveType | ID); + +TerminalRule: + hidden?='hidden'? 'terminal' (fragment?='fragment' name=ID | name=ID ('returns' type=ReturnType)?) ':' + definition=TerminalAlternatives + ';'; + +TerminalAlternatives infers AbstractElement: + TerminalGroup ({infer TerminalAlternatives.elements+=current} '|' elements+=TerminalGroup)*; + +TerminalGroup infers AbstractElement: + TerminalToken ({infer TerminalGroup.elements+=current} elements+=TerminalToken+)?; + +TerminalToken infers AbstractElement: + TerminalTokenElement cardinality=('?'|'*'|'+')?; + +TerminalTokenElement infers AbstractElement: + CharacterRange | TerminalRuleCall | ParenthesizedTerminalElement | NegatedToken | UntilToken | RegexToken | Wildcard; + +ParenthesizedTerminalElement infers AbstractElement: + '(' (lookahead=('?='|'?!'))? TerminalAlternatives ')'; + +TerminalRuleCall infers AbstractElement: + {infer TerminalRuleCall} rule=[TerminalRule:ID]; + +NegatedToken infers AbstractElement: + {infer NegatedToken} '!' terminal=TerminalTokenElement; + +UntilToken infers AbstractElement: + {infer UntilToken} '->' terminal=TerminalTokenElement; + +RegexToken infers AbstractElement: + {infer RegexToken} regex=RegexLiteral; + +Wildcard infers AbstractElement: + {infer Wildcard} '.'; + +CharacterRange infers AbstractElement: + {infer CharacterRange} left=Keyword ('..' right=Keyword)?; + +FeatureName returns string: + 'current' | 'entry' | 'extends' | 'false' | 'fragment' | 'grammar' | 'hidden' | 'import' | 'interface' | 'returns' | 'terminal' | 'true' | 'type' | 'infer' | 'infers' | 'with' | PrimitiveType | ID; + +terminal ID: /\^?[_a-zA-Z][\w_]*/; +terminal STRING: /"(\\.|[^"\\])*"|'(\\.|[^'\\])*'/; +terminal RegexLiteral returns string: /\/(?![*+?])(?:[^\r\n\[/\\]|\\.|\[(?:[^\r\n\]\\]|\\.)*\])+\//; + +hidden terminal WS: /\s+/; +hidden terminal ML_COMMENT: /\/\*[\s\S]*?\*\//; +hidden terminal SL_COMMENT: /\/\/[^\n\r]*/; diff --git a/packages/examples/main/src/langium/langium.configuration.json b/packages/examples/main/src/langium/langium.configuration.json new file mode 100644 index 000000000..5b4cc263e --- /dev/null +++ b/packages/examples/main/src/langium/langium.configuration.json @@ -0,0 +1,164 @@ +{ + "comments": { + "lineComment": "//", + "blockComment": [ + "/*", + "*/" + ] + }, + "brackets": [ + [ + "{", + "}" + ], + [ + "[", + "]" + ], + [ + "(", + ")" + ] + ], + "autoClosingPairs": [ + { + "open": "{", + "close": "}" + }, + { + "open": "[", + "close": "]" + }, + { + "open": "(", + "close": ")" + }, + { + "open": "'", + "close": "'", + "notIn": [ + "string", + "comment" + ] + }, + { + "open": "\"", + "close": "\"", + "notIn": [ + "string" + ] + }, + { + "open": "/**", + "close": " */", + "notIn": [ + "string" + ] + } + ], + "autoCloseBefore": "}])`\n\t", + "surroundingPairs": [ + [ + "{", + "}" + ], + [ + "[", + "]" + ], + [ + "(", + ")" + ] + ], + "colorizedBracketPairs": [ + [ + "(", + ")" + ], + [ + "[", + "]" + ], + [ + "{", + "}" + ], + [ + "<", + ">" + ], + [ + "'", + "'" + ], + [ + "\"", + "\"" + ], + [ + "<", + ">" + ] + ], + "onEnterRules": [ + { + "": "// e.g. /** | */", + "beforeText": { + "pattern": "^\\s*/\\*\\*(?!/)([^\\*]|\\*(?!/))*$" + }, + "afterText": { + "pattern": "^\\s*\\*/$" + }, + "action": { + "indent": "indentOutdent", + "appendText": " * " + } + }, + { + "": "// e.g. /** ...|", + "beforeText": { + "pattern": "^\\s*/\\*\\*(?!/)([^\\*]|\\*(?!/))*$" + }, + "action": { + "indent": "none", + "appendText": " * " + } + }, + { + "": "// e.g. * ...|", + "beforeText": { + "pattern": "^(\\t|[ ])*[ ]\\*([ ]([^\\*]|\\*(?!/))*)?$" + }, + "previousLineText": { + "pattern": "(?=^(\\s*(/\\*\\*|\\*)).*)(?=(?!(\\s*\\*/)))" + }, + "action": { + "indent": "none", + "appendText": "* " + } + }, + { + "": "// e.g. */|", + "beforeText": { + "pattern": "^(\\t|[ ])*[ ]\\*/\\s*$" + }, + "action": { + "indent": "none", + "removeText": 1 + } + }, + { + "beforeText": ":\\s*$", + "action": { + "indent": "indent" + } + }, + { + "beforeText": ";\\s*$", + "action": { + "indent": "outdent" + } + } + ] +} \ No newline at end of file diff --git a/packages/examples/main/src/langium/langium.tmLanguage.json b/packages/examples/main/src/langium/langium.tmLanguage.json new file mode 100644 index 000000000..468c9f90e --- /dev/null +++ b/packages/examples/main/src/langium/langium.tmLanguage.json @@ -0,0 +1,251 @@ +{ + "name": "Langium", + "scopeName": "source.langium", + "fileTypes": [ + "langium" + ], + "patterns": [ + { + "include": "#regex" + }, + { + "include": "#comments" + }, + { + "name": "keyword.control.langium", + "match": "\\b(current|entry|extends|fragment|grammar|hidden|import|infer|infers|interface|returns|terminal|type|with)\\b" + }, + { + "name": "constant.language.langium", + "match": "\\b(?i:true|false)\\b" + }, + { + "name": "keyword.symbol.langium", + "match": "(\\{|\\}|\\:|\\]|\\[|\\(|\\)|(\\??|\\+?)\\=|->|\\=>|<|>|\\,|\\*|\\+|\\@|\\||\\&|\\?|\\!|\\;)" + }, + { + "name": "string.quoted.double.langium", + "begin": "\"", + "end": "\"", + "patterns": [ + { + "include": "#string-character-escape" + } + ] + }, + { + "name": "string.quoted.single.langium", + "begin": "'", + "end": "'", + "patterns": [ + { + "include": "#string-character-escape" + } + ] + } + ], + "repository": { + "comments": { + "patterns": [ + { + "name": "comment.block.langium", + "begin": "/\\*", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.langium" + } + }, + "end": "\\*/", + "endCaptures": { + "0": { + "name": "punctuation.definition.comment.langium" + } + } + }, + { + "begin": "(^\\s+)?(?=//)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.cs" + } + }, + "end": "(?=$)", + "name": "comment.line.langium" + } + ] + }, + "string-character-escape": { + "name": "constant.character.escape.langium", + "match": "\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|u\\{[0-9A-Fa-f]+\\}|[0-2][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.|$)" + }, + "regex": { + "patterns": [ + { + "name": "string.regex.langium", + "begin": "/(?![/*])(?=(?:[^/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+/(?![/*]))", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.langium" + } + }, + "end": "/", + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.langium" + }, + "2": { + "name": "keyword.other.langium" + } + }, + "patterns": [ + { + "include": "#regexp" + } + ] + } + ] + }, + "regexp": { + "patterns": [ + { + "name": "keyword.control.anchor.regexp", + "match": "\\\\[bB]|\\^|\\$" + }, + { + "name": "keyword.other.back-reference.regexp", + "match": "\\\\[1-9]\\d*" + }, + { + "name": "keyword.operator.quantifier.regexp", + "match": "[?+*]|\\{(\\d+,\\d+|\\d+,|,\\d+|\\d+)\\}\\??" + }, + { + "name": "keyword.operator.or.regexp", + "match": "\\|" + }, + { + "name": "meta.group.assertion.regexp", + "begin": "(\\()((\\?=)|(\\?!))", + "beginCaptures": { + "1": { + "name": "punctuation.definition.group.regexp" + }, + "2": { + "name": "punctuation.definition.group.assertion.regexp" + }, + "3": { + "name": "meta.assertion.look-ahead.regexp" + }, + "4": { + "name": "meta.assertion.negative-look-ahead.regexp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.definition.group.regexp" + } + }, + "patterns": [ + { + "include": "#regexp" + } + ] + }, + { + "name": "meta.group.regexp", + "begin": "\\((\\?:)?", + "beginCaptures": { + "0": { + "name": "punctuation.definition.group.regexp" + }, + "1": { + "name": "punctuation.definition.group.capture.regexp" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.group.regexp" + } + }, + "patterns": [ + { + "include": "#regexp" + } + ] + }, + { + "name": "constant.other.character-class.set.regexp", + "begin": "(\\[)(\\^)?", + "beginCaptures": { + "1": { + "name": "punctuation.definition.character-class.regexp" + }, + "2": { + "name": "keyword.operator.negation.regexp" + } + }, + "end": "(\\])", + "endCaptures": { + "1": { + "name": "punctuation.definition.character-class.regexp" + } + }, + "patterns": [ + { + "name": "constant.other.character-class.range.regexp", + "match": "(?:.|(\\\\(?:[0-7]{3}|x\\h\\h|u\\h\\h\\h\\h))|(\\\\c[A-Z])|(\\\\.))\\-(?:[^\\]\\\\]|(\\\\(?:[0-7]{3}|x\\h\\h|u\\h\\h\\h\\h))|(\\\\c[A-Z])|(\\\\.))", + "captures": { + "1": { + "name": "constant.character.numeric.regexp" + }, + "2": { + "name": "constant.character.control.regexp" + }, + "3": { + "name": "constant.character.escape.backslash.regexp" + }, + "4": { + "name": "constant.character.numeric.regexp" + }, + "5": { + "name": "constant.character.control.regexp" + }, + "6": { + "name": "constant.character.escape.backslash.regexp" + } + } + }, + { + "include": "#regex-character-class" + } + ] + }, + { + "include": "#regex-character-class" + } + ] + }, + "regex-character-class": { + "patterns": [ + { + "name": "constant.other.character-class.regexp", + "match": "\\\\[wWsSdDtrnvf]|\\." + }, + { + "name": "constant.character.numeric.regexp", + "match": "\\\\([0-7]{3}|x\\h\\h|u\\h\\h\\h\\h)" + }, + { + "name": "constant.character.control.regexp", + "match": "\\\\c[A-Z]" + }, + { + "name": "constant.character.escape.backslash.regexp", + "match": "\\\\." + } + ] + } + } +} diff --git a/packages/examples/main/src/langium/langiumClient.ts b/packages/examples/main/src/langium/langiumClient.ts new file mode 100644 index 000000000..dd47211fb --- /dev/null +++ b/packages/examples/main/src/langium/langiumClient.ts @@ -0,0 +1,151 @@ +/* -------------------------------------------------------------------------------------------- + * Copyright (c) 2018-2022 TypeFox GmbH (http://www.typefox.io). All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ + +import 'monaco-editor/esm/vs/editor/editor.all.js'; +import 'monaco-editor/esm/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.js'; +import 'monaco-editor/esm/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.js'; +import { editor, Uri } from 'monaco-editor/esm/vs/editor/editor.api.js'; + +import { MonacoLanguageClient, initServices } from 'monaco-languageclient'; +import { BrowserMessageReader, BrowserMessageWriter } from 'vscode-languageserver-protocol/browser.js'; +import { CloseAction, ErrorAction, MessageTransports } from 'vscode-languageclient'; + +import { createConfiguredEditor } from 'vscode/monaco'; +import { registerExtension } from 'vscode/extensions'; +import { updateUserConfiguration } from 'vscode/service-override/configuration'; +import 'vscode/default-extensions/theme-defaults'; + +import { buildWorkerDefinition } from 'monaco-editor-workers'; +buildWorkerDefinition('../../../node_modules/monaco-editor-workers/dist/workers/', new URL('', window.location.href).href, false); + +const languageId = 'langium'; + +const setup = async () => { + console.log('Setting up Langium configuration ...'); + const extension = { + name: 'langium-example', + publisher: 'monaco-languageclient-project', + version: '1.0.0', + engines: { + vscode: '*' + }, + contributes: { + languages: [{ + id: languageId, + extensions: [ + `.${languageId}` + ], + aliases: [ + languageId + ], + configuration: './langium-configuration.json' + }], + grammars: [{ + language: languageId, + scopeName: 'source.langium', + path: './langium-grammar.json' + }], + keybindings: [{ + key: 'ctrl+p', + command: 'editor.action.quickCommand', + when: 'editorTextFocus' + }, { + key: 'ctrl+shift+c', + command: 'editor.action.commentLine', + when: 'editorTextFocus' + }] + } + }; + const { registerFile: registerExtensionFile } = registerExtension(extension); + + registerExtensionFile('/langium-configuration.json', async () => { + const langiumLanguageConfig = new URL('./src/langium/langium.configuration.json', window.location.href).href; + return (await fetch(langiumLanguageConfig)).text(); + }); + + registerExtensionFile('/langium-grammar.json', async () => { + const langiumTmUrl = new URL('./src/langium/langium.tmLanguage.json', window.location.href).href; + return (await fetch(langiumTmUrl)).text(); + }); + + updateUserConfiguration(`{ + "workbench.colorTheme": "Default Dark Modern" +}`); +}; + +const run = async () => { + const exampleLangiumUrl = new URL('./src/langium/example.langium', window.location.href).href; + const responseLangium = await fetch(exampleLangiumUrl); + const editorText = await responseLangium.text(); + + const editorOptions = { + model: editor.createModel(editorText, languageId, Uri.parse('inmemory://example.langium')), + automaticLayout: true + }; + createConfiguredEditor(document.getElementById('container')!, editorOptions); + + function createLanguageClient(transports: MessageTransports): MonacoLanguageClient { + return new MonacoLanguageClient({ + name: 'Langium Client', + clientOptions: { + // use a language id as a document selector + documentSelector: [{ language: languageId }], + // disable the default error handler + errorHandler: { + error: () => ({ action: ErrorAction.Continue }), + closed: () => ({ action: CloseAction.DoNotRestart }) + } + }, + // create a language client connection to the server running in the web worker + connectionProvider: { + get: () => { + return Promise.resolve(transports); + } + } + }); + } + + const langiumWorkerUrl = new URL('./src/langium/langiumServerWorker.ts', window.location.href).href; + const worker = new Worker(langiumWorkerUrl, { + type: 'module', + name: 'Langium LS' + }); + const reader = new BrowserMessageReader(worker); + const writer = new BrowserMessageWriter(worker); + const languageClient = createLanguageClient({ reader, writer }); + languageClient.start(); + reader.onClose(() => languageClient.stop()); + + languageClient.onTelemetry((t) => { + console.log(t); + }); + + languageClient.sendNotification('tester', { test: 'test' }); + + // any further language client / server interaction can't be defined as needed +}; + +try { + await initServices({ + enableFilesService: true, + enableThemeService: true, + enableTextmateService: true, + enableModelService: true, + configureEditorOrViewsServiceConfig: { + enableViewsService: false, + useDefaultOpenEditorFunction: true + }, + configureConfigurationServiceConfig: { + defaultWorkspaceUri: '/tmp' + }, + enableKeybindingsService: true, + enableLanguagesService: true, + debugLogging: true + }); + await setup(); + await run(); +} catch (e) { + console.log(e); +} diff --git a/packages/examples/main/src/langium/langiumServerWorker.ts b/packages/examples/main/src/langium/langiumServerWorker.ts new file mode 100644 index 000000000..96aeefdce --- /dev/null +++ b/packages/examples/main/src/langium/langiumServerWorker.ts @@ -0,0 +1,21 @@ +/* -------------------------------------------------------------------------------------------- + * Copyright (c) 2018-2022 TypeFox GmbH (http://www.typefox.io). All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ + +import { createLangiumGrammarServices, startLanguageServer, EmptyFileSystem, DefaultSharedModuleContext } from 'langium'; +import { BrowserMessageReader, BrowserMessageWriter, createConnection } from 'vscode-languageserver/browser.js'; + +/* browser specific setup code */ +const messageReader = new BrowserMessageReader(self as DedicatedWorkerGlobalScope); +const messageWriter = new BrowserMessageWriter(self as DedicatedWorkerGlobalScope); + +// Inject the shared services and language-specific services +const context = { + connection: createConnection(messageReader, messageWriter), + ...EmptyFileSystem +} as unknown as DefaultSharedModuleContext; +const { shared } = createLangiumGrammarServices(context); + +// Start the language server with the shared services +startLanguageServer(shared); diff --git a/packages/examples/main/src/langium/main.ts b/packages/examples/main/src/langium/statemachineClient.ts similarity index 100% rename from packages/examples/main/src/langium/main.ts rename to packages/examples/main/src/langium/statemachineClient.ts diff --git a/packages/examples/main/statemachine_client.html b/packages/examples/main/statemachine_client.html new file mode 100644 index 000000000..36dea61fd --- /dev/null +++ b/packages/examples/main/statemachine_client.html @@ -0,0 +1,17 @@ + + + + + Monaco Language Client & Langium Web Worker Language Server Example + + + + + +

Monaco Language Client & Langium Web Worker Language Server Example

+
+ +
+ + + diff --git a/packages/examples/main/tsconfig.json b/packages/examples/main/tsconfig.json new file mode 100644 index 000000000..25c9de527 --- /dev/null +++ b/packages/examples/main/tsconfig.json @@ -0,0 +1,12 @@ +// this file is required for VSCode to work properly +{ + "extends": "./tsconfig.src.json", + "compilerOptions": { + "noEmit": true, + "rootDir": "." + }, + "include": [ + "src/**/*", + "test/**/*" + ] +} diff --git a/packages/examples/main/tsconfig.src.json b/packages/examples/main/tsconfig.src.json index 6acbf70a1..ced2f27a3 100644 --- a/packages/examples/main/tsconfig.src.json +++ b/packages/examples/main/tsconfig.src.json @@ -12,7 +12,10 @@ "node" ], "references": [{ - "path": "../../client/tsconfig.src.json" + "path": "../../client/tsconfig.src.json", + }, + { + "path": "../../vscode-ws-jsonrpc/tsconfig.src.json" }], "include": [ "src/**/*.ts", diff --git a/packages/examples/main/vite.langium-worker.ts b/packages/examples/main/vite.statemachine-worker.ts similarity index 100% rename from packages/examples/main/vite.langium-worker.ts rename to packages/examples/main/vite.statemachine-worker.ts diff --git a/packages/vscode-ws-jsonrpc/tsconfig.json b/packages/vscode-ws-jsonrpc/tsconfig.json new file mode 100644 index 000000000..25c9de527 --- /dev/null +++ b/packages/vscode-ws-jsonrpc/tsconfig.json @@ -0,0 +1,12 @@ +// this file is required for VSCode to work properly +{ + "extends": "./tsconfig.src.json", + "compilerOptions": { + "noEmit": true, + "rootDir": "." + }, + "include": [ + "src/**/*", + "test/**/*" + ] +} diff --git a/vite.config.ts b/vite.config.ts index 7176c406c..193a385ad 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -8,7 +8,8 @@ export default defineConfig(() => { rollupOptions: { input: { client: resolve(__dirname, 'packages/examples/main/client.html'), - langiumLsp: resolve(__dirname, 'packages/examples/main/langium_wwls.html'), + langiumClient: resolve(__dirname, 'packages/examples/main/langium_client.html'), + statemachineClient: resolve(__dirname, 'packages/examples/main/statemachine_client.html'), browser: resolve(__dirname, 'packages/examples/main/browser.html'), react: resolve(__dirname, 'packages/examples/main/react.html') }