From 032610490a7b2ba9ec681b8f6d114009208f41df Mon Sep 17 00:00:00 2001 From: Cyril Vrousos <135030683+cyrilvrousos-tas@users.noreply.github.com> Date: Mon, 24 Jul 2023 09:47:39 +0200 Subject: [PATCH] Language server protocol / VS Code extension (#31) * Add VS code extension for XSMP modeler * Removing qualified version for ls.jar * Update CI Signed-off-by: Cyril Vrousos <135030683+cyrilvrousos-tas@users.noreply.github.com> * Add content assist * Add hover services on keywords * Implemented unit tests --------- Signed-off-by: Cyril Vrousos <135030683+cyrilvrousos-tas@users.noreply.github.com> Co-authored-by: cyrilvrousos-tas --- .github/workflows/github-release.yml | 109 ++-- README.md | 4 +- org.eclipse.xsmp.forms/META-INF/MANIFEST.MF | 4 +- .../forms/service/XsmpReferenceService.java | 2 +- org.eclipse.xsmp.ide.tests/.classpath | 11 + org.eclipse.xsmp.ide.tests/.project | 40 ++ .../org.eclipse.core.resources.prefs | 2 + .../.settings/org.eclipse.jdt.core.prefs | 15 + .../org.eclipse.xtend.core.Xtend.prefs | 7 + .../org.sonarlint.eclipse.core.prefs | 2 +- .../META-INF/MANIFEST.MF | 23 + .../services/org.eclipse.xtext.ISetup | 1 + org.eclipse.xsmp.ide.tests/build.properties | 3 + org.eclipse.xsmp.ide.tests/pom.xml | 25 + .../AbstractXsmpcatLanguageServerTest.java | 22 + .../xsmp/ide/tests/CompletionTest.java | 192 ++++++ .../xsmp/ide/tests/FormattingTest.java | 82 +++ .../org/eclipse/xsmp/ide/tests/HoverTest.java | 113 ++++ .../org/eclipse/xsmp/ide/tests/TestUtils.java | 39 ++ .../eclipse/xsmp/ide/tests/ValidatorTest.java | 111 ++++ org.eclipse.xsmp.ide/.classpath | 7 +- org.eclipse.xsmp.ide/META-INF/MANIFEST.MF | 12 +- org.eclipse.xsmp.ide/build.properties | 3 +- org.eclipse.xsmp.ide/pom.xml | 181 +++++- org.eclipse.xsmp.ide/src/log4j.properties | 16 + .../eclipse/xsmp/ide/XsmpcatIdeModule.java | 42 +- .../org/eclipse/xsmp/ide/XsmpcatIdeSetup.java | 2 +- .../AbstractIdeContentProposalProvider.java | 122 ++++ .../ide}/contentassist/IReferenceFilter.java | 4 +- .../XsmpcatIdeContentProposalProvider.xtend | 238 ++++++++ .../contentassist/XsmpcatReferenceFilter.java | 12 +- .../xsmp/ide/hover/XsmpcatHoverService.java | 53 ++ .../hover/XsmpcatKeywordAtOffsetHelper.java | 13 +- .../xsmp/ide/hover/XsmpcatKeywordHovers.xtend | 302 ++++++++++ .../quickfix/XsmpcatIdeQuickfixProvider.java | 59 ++ .../ide/server/XsmpcatProjectManager.java | 65 ++ .../ide/server/XsmpcatServerLauncher.java | 22 + .../xsmp/ide/server/XsmpcatServerModule.java | 25 + .../org.eclipse.xsmp.target.target | 1 + .../org/eclipse/xsmp/tests/testValid.xsmpcat | 12 +- .../XsmpcatReferenceProposalCreator.java | 1 + .../XsmpcatDispatchingEObjectTextHover.java | 15 +- .../ui/hover/XsmpcatEObjectHoverProvider.java | 7 +- .../xsmp/ui/hover/XsmpcatKeywordHovers.xtend | 557 +++++++++--------- ...rossReferenceTemplateVariableResolver.java | 2 +- org.eclipse.xsmp.vscode_extension/.classpath | 11 + org.eclipse.xsmp.vscode_extension/.gitignore | 4 + org.eclipse.xsmp.vscode_extension/.project | 34 ++ .../org.eclipse.core.resources.prefs | 2 + .../.settings/org.eclipse.jdt.core.prefs | 15 + .../org.eclipse.xtend.core.Xtend.prefs | 5 + .../.vscodeignore | 9 + .../META-INF/MANIFEST.MF | 9 + .../build.properties | 3 + .../images/xsmp.png | Bin 0 -> 7063 bytes .../package.json | 63 ++ org.eclipse.xsmp.vscode_extension/pom.xml | 45 ++ .../src/extension.ts | 53 ++ .../src/tsconfig.json | 13 + .../syntaxes/xsmp.tmLanguage.json | 57 ++ .../xsmp.configuration.json | 27 + org.eclipse.xsmp/.classpath | 1 - org.eclipse.xsmp/build.properties | 1 - .../xsmp/XsmpcatExtensionRuntimeModule.java | 6 + .../xsmp/formatting2/XsmpcatFormatter.java | 10 + .../src/org/eclipse/xsmp/util/XsmpUtil.java | 41 +- pom.xml | 2 + 67 files changed, 2603 insertions(+), 388 deletions(-) create mode 100644 org.eclipse.xsmp.ide.tests/.classpath create mode 100644 org.eclipse.xsmp.ide.tests/.project create mode 100644 org.eclipse.xsmp.ide.tests/.settings/org.eclipse.core.resources.prefs create mode 100644 org.eclipse.xsmp.ide.tests/.settings/org.eclipse.jdt.core.prefs create mode 100644 org.eclipse.xsmp.ide.tests/.settings/org.eclipse.xtend.core.Xtend.prefs rename {org.eclipse.xsmp.ide => org.eclipse.xsmp.ide.tests}/.settings/org.sonarlint.eclipse.core.prefs (81%) create mode 100644 org.eclipse.xsmp.ide.tests/META-INF/MANIFEST.MF create mode 100644 org.eclipse.xsmp.ide.tests/META-INF/services/org.eclipse.xtext.ISetup create mode 100644 org.eclipse.xsmp.ide.tests/build.properties create mode 100644 org.eclipse.xsmp.ide.tests/pom.xml create mode 100644 org.eclipse.xsmp.ide.tests/src/org/eclipse/xsmp/ide/tests/AbstractXsmpcatLanguageServerTest.java create mode 100644 org.eclipse.xsmp.ide.tests/src/org/eclipse/xsmp/ide/tests/CompletionTest.java create mode 100644 org.eclipse.xsmp.ide.tests/src/org/eclipse/xsmp/ide/tests/FormattingTest.java create mode 100644 org.eclipse.xsmp.ide.tests/src/org/eclipse/xsmp/ide/tests/HoverTest.java create mode 100644 org.eclipse.xsmp.ide.tests/src/org/eclipse/xsmp/ide/tests/TestUtils.java create mode 100644 org.eclipse.xsmp.ide.tests/src/org/eclipse/xsmp/ide/tests/ValidatorTest.java create mode 100644 org.eclipse.xsmp.ide/src/log4j.properties create mode 100644 org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/contentassist/AbstractIdeContentProposalProvider.java rename {org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui => org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide}/contentassist/IReferenceFilter.java (89%) create mode 100644 org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/contentassist/XsmpcatIdeContentProposalProvider.xtend rename {org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui => org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide}/contentassist/XsmpcatReferenceFilter.java (95%) create mode 100644 org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/hover/XsmpcatHoverService.java rename {org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui => org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide}/hover/XsmpcatKeywordAtOffsetHelper.java (76%) create mode 100644 org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/hover/XsmpcatKeywordHovers.xtend create mode 100644 org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/quickfix/XsmpcatIdeQuickfixProvider.java create mode 100644 org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/server/XsmpcatProjectManager.java create mode 100644 org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/server/XsmpcatServerLauncher.java create mode 100644 org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/server/XsmpcatServerModule.java create mode 100644 org.eclipse.xsmp.vscode_extension/.classpath create mode 100644 org.eclipse.xsmp.vscode_extension/.gitignore create mode 100644 org.eclipse.xsmp.vscode_extension/.project create mode 100644 org.eclipse.xsmp.vscode_extension/.settings/org.eclipse.core.resources.prefs create mode 100644 org.eclipse.xsmp.vscode_extension/.settings/org.eclipse.jdt.core.prefs create mode 100644 org.eclipse.xsmp.vscode_extension/.settings/org.eclipse.xtend.core.Xtend.prefs create mode 100644 org.eclipse.xsmp.vscode_extension/.vscodeignore create mode 100644 org.eclipse.xsmp.vscode_extension/META-INF/MANIFEST.MF create mode 100644 org.eclipse.xsmp.vscode_extension/build.properties create mode 100644 org.eclipse.xsmp.vscode_extension/images/xsmp.png create mode 100644 org.eclipse.xsmp.vscode_extension/package.json create mode 100644 org.eclipse.xsmp.vscode_extension/pom.xml create mode 100644 org.eclipse.xsmp.vscode_extension/src/extension.ts create mode 100644 org.eclipse.xsmp.vscode_extension/src/tsconfig.json create mode 100644 org.eclipse.xsmp.vscode_extension/syntaxes/xsmp.tmLanguage.json create mode 100644 org.eclipse.xsmp.vscode_extension/xsmp.configuration.json diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml index d12ab29e..c3540d51 100644 --- a/.github/workflows/github-release.yml +++ b/.github/workflows/github-release.yml @@ -1,6 +1,6 @@ -# This workflow will release the Eclipse repository on github when a new tag is pushed +# This workflow will release the Eclipse repository on GitHub when a new tag is pushed -name: Release on github +name: Release on GitHub on: push: @@ -9,48 +9,73 @@ on: jobs: build: - runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - name: Set up JDK 17 - uses: actions/setup-java@v3 - with: - java-version: '17' - distribution: 'temurin' - cache: maven - - name: Build with Maven - run: mvn -B package --file pom.xml - - name: Create release - id: create_release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token - with: - tag_name: ${{ github.ref }} - release_name: Release ${{ github.ref }} - body: | - This release contains XSMP modeler ${{ github.ref_name }} + - uses: actions/checkout@v3 + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'temurin' + cache: maven + + - name: Build with Maven + run: mvn -B package --file pom.xml + + - name: Install npm dependencies + working-directory: org.eclipse.xsmp.vscode_extension + run: | + npm install + npm install -g @vscode/vsce + + - name: Package VS Code Extension + working-directory: org.eclipse.xsmp.vscode_extension + run: | + vsce package --out "target/xsmp-modeler.vsix" + ls -l target + + - name: Create release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token + with: + tag_name: ${{ github.ref }} + release_name: Release ${{ github.ref }} + body: | + This release contains XSMP modeler ${{ github.ref_name }} + + To install XSMP Modeler in Eclipse, add or update the XSMP [software site](https://help.eclipse.org/latest/index.jsp?topic=/org.eclipse.platform.doc.user/tasks/tasks-127.htm) with URL: + `jar:https://github.com/ThalesGroup/xsmp-modeler-core/releases/download/${{ github.ref_name }}/org.eclipse.xsmp.repository-${{ github.ref_name }}.zip!/` + + To use XSMP Modeler in Visual Studio Code, please install this [extension](https://github.com/ThalesGroup/xsmp-modeler-core/releases/download/${{ github.ref_name }}/xsmp-modeler-${{ github.ref_name }}.vsix). + draft: true + prerelease: false + - name: Upload release asset + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ${{ github.workspace }}/org.eclipse.xsmp.repository/target/org.eclipse.xsmp.repository.zip + asset_name: org.eclipse.xsmp.repository-${{ github.ref_name }}.zip + asset_content_type: application/zip + + - name: Upload extension + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ${{ github.workspace }}/org.eclipse.xsmp.vscode_extension/target/xsmp-modeler.vsix + asset_name: xsmp-modeler-${{ github.ref_name }}.vsix + asset_content_type: application/octet-stream - To install, add or update the XSMP [software site](https://help.eclipse.org/latest/index.jsp?topic=/org.eclipse.platform.doc.user/tasks/tasks-127.htm) with URL: - `jar:https://github.com/ThalesGroup/xsmp-modeler-core/releases/download/${{ github.ref_name }}/org.eclipse.xsmp.repository-${{ github.ref_name }}.zip!/` - draft: true - prerelease: false - - name: Upload release asset - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ${{ github.workspace }}/org.eclipse.xsmp.repository/target/org.eclipse.xsmp.repository.zip - asset_name: org.eclipse.xsmp.repository-${{ github.ref_name }}.zip - asset_content_type: application/zip - - name: Publish release - uses: StuYarrow/publish-release@v1.1.2 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - id: ${{ steps.create_release.outputs.id }} - \ No newline at end of file + - name: Publish release + uses: StuYarrow/publish-release@v1.1.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + id: ${{ steps.create_release.outputs.id }} diff --git a/README.md b/README.md index 7538ff0e..595c459a 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,9 @@ ## Get started -XSMP Modeler is an Eclipse framework for development of SMDL (Simulation Model Definition Language) as defined in the [ECSS SMP standard](https://ecss.nl/standard/ecss-e-st-40-07c-simulation-modelling-platform-2-march-2020/). +XSMP Modeler is a framework for development of SMDL (Simulation Model Definition Language) as defined in the [ECSS SMP standard](https://ecss.nl/standard/ecss-e-st-40-07c-simulation-modelling-platform-2-march-2020/). + +The primary supported IDE is Eclipse. LSP extension for Visual Studio Code is also provided (preview). It comes with: - an integrated Text Editor with coloring, error checking, auto-completion, formatting, hover information, outline, quick fix, ... diff --git a/org.eclipse.xsmp.forms/META-INF/MANIFEST.MF b/org.eclipse.xsmp.forms/META-INF/MANIFEST.MF index 195c6c6a..8c9bebb5 100644 --- a/org.eclipse.xsmp.forms/META-INF/MANIFEST.MF +++ b/org.eclipse.xsmp.forms/META-INF/MANIFEST.MF @@ -30,10 +30,10 @@ Require-Bundle: org.eclipse.xsmp, org.eclipse.emfforms.editor, org.eclipse.emfforms.swt.core.di, org.eclipse.xtext.ui, - org.eclipse.xsmp.ui, org.eclipse.e4.core.contexts, org.eclipse.emf.ecp.edit.swt, - org.eclipse.emf.ecp.common.ui + org.eclipse.emf.ecp.common.ui, + org.eclipse.xsmp.ide;bundle-version="1.1.0" Bundle-RequiredExecutionEnvironment: JavaSE-17 Service-Component: OSGI-INF/uuidRendererService.xml, OSGI-INF/expressionRendererService.xml diff --git a/org.eclipse.xsmp.forms/src/org/eclipse/xsmp/forms/service/XsmpReferenceService.java b/org.eclipse.xsmp.forms/src/org/eclipse/xsmp/forms/service/XsmpReferenceService.java index 5474cc93..853afbb2 100644 --- a/org.eclipse.xsmp.forms/src/org/eclipse/xsmp/forms/service/XsmpReferenceService.java +++ b/org.eclipse.xsmp.forms/src/org/eclipse/xsmp/forms/service/XsmpReferenceService.java @@ -28,7 +28,7 @@ import org.eclipse.emfforms.common.Optional; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.swt.widgets.Display; -import org.eclipse.xsmp.ui.contentassist.IReferenceFilter; +import org.eclipse.xsmp.ide.contentassist.IReferenceFilter; import org.eclipse.xtext.resource.XtextResource; import org.eclipse.xtext.scoping.IScopeProvider; diff --git a/org.eclipse.xsmp.ide.tests/.classpath b/org.eclipse.xsmp.ide.tests/.classpath new file mode 100644 index 00000000..7f87f1ff --- /dev/null +++ b/org.eclipse.xsmp.ide.tests/.classpath @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/org.eclipse.xsmp.ide.tests/.project b/org.eclipse.xsmp.ide.tests/.project new file mode 100644 index 00000000..f7829f9c --- /dev/null +++ b/org.eclipse.xsmp.ide.tests/.project @@ -0,0 +1,40 @@ + + + org.eclipse.xsmp.ide.tests + + + + + + org.eclipse.xtext.ui.shared.xtextBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.m2e.core.maven2Nature + org.eclipse.xtext.ui.shared.xtextNature + org.eclipse.jdt.core.javanature + org.eclipse.pde.PluginNature + + diff --git a/org.eclipse.xsmp.ide.tests/.settings/org.eclipse.core.resources.prefs b/org.eclipse.xsmp.ide.tests/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 00000000..99f26c02 --- /dev/null +++ b/org.eclipse.xsmp.ide.tests/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/org.eclipse.xsmp.ide.tests/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.xsmp.ide.tests/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..9478cb16 --- /dev/null +++ b/org.eclipse.xsmp.ide.tests/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,15 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=17 diff --git a/org.eclipse.xsmp.ide.tests/.settings/org.eclipse.xtend.core.Xtend.prefs b/org.eclipse.xsmp.ide.tests/.settings/org.eclipse.xtend.core.Xtend.prefs new file mode 100644 index 00000000..fdf3191a --- /dev/null +++ b/org.eclipse.xsmp.ide.tests/.settings/org.eclipse.xtend.core.Xtend.prefs @@ -0,0 +1,7 @@ +//outlet.DEFAULT_OUTPUT.sourceFolder.src/main/java.directory=xtend-gen +//outlet.DEFAULT_OUTPUT.sourceFolder.src/test/java.directory=xtend-gen +BuilderConfiguration.is_project_specific=true +eclipse.preferences.version=1 +outlet.DEFAULT_OUTPUT.hideLocalSyntheticVariables=true +outlet.DEFAULT_OUTPUT.installDslAsPrimarySource=false +outlet.DEFAULT_OUTPUT.userOutputPerSourceFolder=true diff --git a/org.eclipse.xsmp.ide/.settings/org.sonarlint.eclipse.core.prefs b/org.eclipse.xsmp.ide.tests/.settings/org.sonarlint.eclipse.core.prefs similarity index 81% rename from org.eclipse.xsmp.ide/.settings/org.sonarlint.eclipse.core.prefs rename to org.eclipse.xsmp.ide.tests/.settings/org.sonarlint.eclipse.core.prefs index d232e045..1f0292f3 100644 --- a/org.eclipse.xsmp.ide/.settings/org.sonarlint.eclipse.core.prefs +++ b/org.eclipse.xsmp.ide.tests/.settings/org.sonarlint.eclipse.core.prefs @@ -4,4 +4,4 @@ eclipse.preferences.version=1 idePrefixKey= projectKey=ThalesGroup_xsmp-modeler-core serverId=SonarCloud/thalesgroup -sqPrefixKey=org.eclipse.xsmp.ide +sqPrefixKey=org.eclipse.xsmp.ide.tests diff --git a/org.eclipse.xsmp.ide.tests/META-INF/MANIFEST.MF b/org.eclipse.xsmp.ide.tests/META-INF/MANIFEST.MF new file mode 100644 index 00000000..5eacbc79 --- /dev/null +++ b/org.eclipse.xsmp.ide.tests/META-INF/MANIFEST.MF @@ -0,0 +1,23 @@ +Manifest-Version: 1.0 +Automatic-Module-Name: org.eclipse.xsmp.ide.tests +Bundle-ManifestVersion: 2 +Bundle-Name: org.eclipse.xsmp.ide.tests +Bundle-Vendor: Thales Alenia Space +Bundle-Version: 1.1.0.qualifier +Bundle-SymbolicName: org.eclipse.xsmp.ide.tests;singleton:=true +Bundle-ActivationPolicy: lazy +Require-Bundle: org.eclipse.xtext.testing, + org.eclipse.xtext.ide, + org.junit;bundle-version="4.13.2", + org.eclipse.xsmp;bundle-version="1.1.0", + org.eclipse.xsmp.ide;bundle-version="1.1.0", + org.eclipse.xsmp.lib;bundle-version="1.1.0", + org.antlr.runtime;bundle-version="[3.2.0,3.2.1)", + org.apache.commons.commons-io;bundle-version="2.11.0", + org.eclipse.xtend.lib;bundle-version="2.30.0", + org.eclipse.lsp4j;bundle-version="0.20.1", + org.eclipse.lsp4j.jsonrpc;bundle-version="0.20.1" +Import-Package: org.junit.jupiter.api;version="[5.1.0,6.0.0)", + org.junit.jupiter.api.extension;version="[5.1.0,6.0.0)" +Bundle-RequiredExecutionEnvironment: JavaSE-17 +Export-Package: org.eclipse.xsmp.ide.tests diff --git a/org.eclipse.xsmp.ide.tests/META-INF/services/org.eclipse.xtext.ISetup b/org.eclipse.xsmp.ide.tests/META-INF/services/org.eclipse.xtext.ISetup new file mode 100644 index 00000000..97361e44 --- /dev/null +++ b/org.eclipse.xsmp.ide.tests/META-INF/services/org.eclipse.xtext.ISetup @@ -0,0 +1 @@ +org.eclipse.xsmp.ide.XsmpcatIdeSetup diff --git a/org.eclipse.xsmp.ide.tests/build.properties b/org.eclipse.xsmp.ide.tests/build.properties new file mode 100644 index 00000000..268afdf2 --- /dev/null +++ b/org.eclipse.xsmp.ide.tests/build.properties @@ -0,0 +1,3 @@ +source.. = src/ +bin.includes = .,\ + META-INF/ diff --git a/org.eclipse.xsmp.ide.tests/pom.xml b/org.eclipse.xsmp.ide.tests/pom.xml new file mode 100644 index 00000000..8fc6aab2 --- /dev/null +++ b/org.eclipse.xsmp.ide.tests/pom.xml @@ -0,0 +1,25 @@ + + 4.0.0 + + org.eclipse.xsmp + org.eclipse.xsmp.parent + 1.1.0-SNAPSHOT + + org.eclipse.xsmp.ide.tests + eclipse-test-plugin + + + + src + + + + + + org.eclipse.xtend + xtend-maven-plugin + + + + + diff --git a/org.eclipse.xsmp.ide.tests/src/org/eclipse/xsmp/ide/tests/AbstractXsmpcatLanguageServerTest.java b/org.eclipse.xsmp.ide.tests/src/org/eclipse/xsmp/ide/tests/AbstractXsmpcatLanguageServerTest.java new file mode 100644 index 00000000..7d208559 --- /dev/null +++ b/org.eclipse.xsmp.ide.tests/src/org/eclipse/xsmp/ide/tests/AbstractXsmpcatLanguageServerTest.java @@ -0,0 +1,22 @@ +/******************************************************************************* +* Copyright (C) 2023 THALES ALENIA SPACE FRANCE. +* +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License 2.0 +* which accompanies this distribution, and is available at +* https://www.eclipse.org/legal/epl-2.0/ +* +* SPDX-License-Identifier: EPL-2.0 +******************************************************************************/ +package org.eclipse.xsmp.ide.tests; + +import org.eclipse.xtext.testing.AbstractLanguageServerTest; + +public abstract class AbstractXsmpcatLanguageServerTest extends AbstractLanguageServerTest +{ + + public AbstractXsmpcatLanguageServerTest() + { + super("xsmpcat"); + } +} diff --git a/org.eclipse.xsmp.ide.tests/src/org/eclipse/xsmp/ide/tests/CompletionTest.java b/org.eclipse.xsmp.ide.tests/src/org/eclipse/xsmp/ide/tests/CompletionTest.java new file mode 100644 index 00000000..1b07c386 --- /dev/null +++ b/org.eclipse.xsmp.ide.tests/src/org/eclipse/xsmp/ide/tests/CompletionTest.java @@ -0,0 +1,192 @@ +/******************************************************************************* +* Copyright (C) 2023 THALES ALENIA SPACE FRANCE. +* +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License 2.0 +* which accompanies this distribution, and is available at +* https://www.eclipse.org/legal/epl-2.0/ +* +* SPDX-License-Identifier: EPL-2.0 +******************************************************************************/ +package org.eclipse.xsmp.ide.tests; + +import org.eclipse.xtext.testing.TestCompletionConfiguration; +import org.junit.jupiter.api.Test; + +class CompletionTest extends AbstractXsmpcatLanguageServerTest +{ + @Test + void testCompletion_01() + { + testCompletion((TestCompletionConfiguration it) -> { + it.setModel(""" + catalogue TestCatalogue + + + """); + it.setLine(2); + + final var expected = """ + Create a Namespace -> namespace ${1:name} + { + $0 + } // namespace ${1:name} + [[2, 0] .. [2, 0]] + documentation (ML_DOCUMENTATION) -> documentation [[2, 0] .. [2, 0]] + import -> import [[2, 0] .. [2, 0]] + namespace -> namespace [[2, 0] .. [2, 0]] + @ -> @ [[2, 0] .. [2, 0]] + """; + + it.setExpectedCompletionItems(expected); + }); + } + + @Test + void testCompletion_02() + { + testCompletion((TestCompletionConfiguration it) -> { + it.setModel(""" + catalogue TestCatalogue + + namespace TestNamespace + { + /** @uuid 563ca54c-6d21-46d2-83a3-029eb18f66ed */ + model TestModel + { + + } + } + """); + it.setLine(7); + + final var expected = """ + Create a Constant -> constant ${1|None|} ${2:name} = $0 + [[7, 0] .. [7, 0]] + Create a Container -> container ${1|TestModel,TestNamespace.TestModel|}[*] ${2:name} + [[7, 0] .. [7, 0]] + Create a Field -> field ${1|None|} ${2:name} + [[7, 0] .. [7, 0]] + Create a Property -> property ${1|None|} ${2:name} + [[7, 0] .. [7, 0]] + Create a Reference -> reference ${1|None|}[*] ${2:name} + [[7, 0] .. [7, 0]] + Create an Association -> association ${1|TestModel,TestNamespace.TestModel|} ${2:name} + [[7, 0] .. [7, 0]] + Create an EntryPoint -> entrypoint ${1:name} + [[7, 0] .. [7, 0]] + Create an Event Sink -> eventsink ${1|None|} ${2:name} + [[7, 0] .. [7, 0]] + Create an Event Source -> eventsource ${1|None|} ${2:name} + [[7, 0] .. [7, 0]] + Create an Operation -> def void ${1:name} ($0) + [[7, 0] .. [7, 0]] + documentation (ML_DOCUMENTATION) -> documentation [[7, 0] .. [7, 0]] + association -> association [[7, 0] .. [7, 0]] + constant -> constant [[7, 0] .. [7, 0]] + container -> container [[7, 0] .. [7, 0]] + def -> def [[7, 0] .. [7, 0]] + entrypoint -> entrypoint [[7, 0] .. [7, 0]] + eventsink -> eventsink [[7, 0] .. [7, 0]] + eventsource -> eventsource [[7, 0] .. [7, 0]] + field -> field [[7, 0] .. [7, 0]] + property -> property [[7, 0] .. [7, 0]] + reference -> reference [[7, 0] .. [7, 0]] + @ -> @ [[7, 0] .. [7, 0]] + } -> } [[7, 0] .. [7, 0]] + """; + + it.setExpectedCompletionItems(expected); + }); + } + + @Test + void testCompletion_03() + { + testCompletion((TestCompletionConfiguration it) -> { + TestUtils.loadEcssSmpLibrary(it); + + it.setModel(""" + catalogue TestCatalogue + + namespace TestNamespace + { + /** @uuid 563ca54c-6d21-46d2-83a3-029eb18f66ed */ + model TestModel + { + def B + } + } + """); + it.setLine(7); + it.setColumn(9); + + final var expected = """ + Bool (PrimitiveType) -> Bool [[7, 8] .. [7, 9]] + Smp.Bool (PrimitiveType) -> Smp.Bool [[7, 8] .. [7, 9]] + """; + + it.setExpectedCompletionItems(expected); + }); + } + + @Test + void testCompletion_04() + { + testCompletion((TestCompletionConfiguration it) -> { + TestUtils.loadEcssSmpLibrary(it); + + it.setModel(""" + catalogue TestCatalogue + + namespace TestNamespace + { + /** @uuid 563ca54c-6d21-46d2-83a3-029eb18f66ed */ + model TestModel + { + field B + } + } + """); + it.setLine(7); + it.setColumn(11); + + final var expected = """ + Bool (PrimitiveType) -> Bool [[7, 10] .. [7, 11]] + Smp.Bool (PrimitiveType) -> Smp.Bool [[7, 10] .. [7, 11]] + """; + + it.setExpectedCompletionItems(expected); + }); + } + + @Test + void testCompletion_05() + { + testCompletion((TestCompletionConfiguration it) -> { + TestUtils.loadEcssSmpLibrary(it); + + it.setModel(""" + catalogue TestCatalogue + + namespace TestNamespace + { + /** @uuid 563ca54c-6d21-46d2-83a3-029eb18f66ed */ + struct TestModel + { + field B + } + } + """); + it.setLine(7); + it.setColumn(11); + + final var expected = """ + Bool (PrimitiveType) -> Bool [[7, 10] .. [7, 11]] + Smp.Bool (PrimitiveType) -> Smp.Bool [[7, 10] .. [7, 11]] + """; + + it.setExpectedCompletionItems(expected); + }); + } +} diff --git a/org.eclipse.xsmp.ide.tests/src/org/eclipse/xsmp/ide/tests/FormattingTest.java b/org.eclipse.xsmp.ide.tests/src/org/eclipse/xsmp/ide/tests/FormattingTest.java new file mode 100644 index 00000000..956c24c3 --- /dev/null +++ b/org.eclipse.xsmp.ide.tests/src/org/eclipse/xsmp/ide/tests/FormattingTest.java @@ -0,0 +1,82 @@ +/******************************************************************************* +* Copyright (C) 2023 THALES ALENIA SPACE FRANCE. +* +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License 2.0 +* which accompanies this distribution, and is available at +* https://www.eclipse.org/legal/epl-2.0/ +* +* SPDX-License-Identifier: EPL-2.0 +******************************************************************************/ +package org.eclipse.xsmp.ide.tests; + +import org.eclipse.xtext.testing.FormattingConfiguration; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +class FormattingTest extends AbstractXsmpcatLanguageServerTest +{ + @Test + void testFormatting_1() + { + testFormatting((FormattingConfiguration it) -> { + it.setModel( + "catalogue TestCatalogue namespace TestNamespace { /** @uuid 87b404c9-2a35-4446-a675-64af8b6a1f68 */ model TestModel { field Bool fea_mybool } }"); + + final var expected = """ + + catalogue TestCatalogue + + + namespace TestNamespace + { + /** @uuid 87b404c9-2a35-4446-a675-64af8b6a1f68 */ + model TestModel + { + field Bool fea_mybool + } + } + + """; + it.setExpectedText(expected); + }); + } + + @Test + @Disabled("Remove useless space between description and namespace in Xsmpcat formatting") + void testFormatting_2() + { + testFormatting((FormattingConfiguration it) -> { + final var model = """ + catalogue TestCatalogue + + namespace TestNamespace { + + /** Description of my event + + @uuid 4ce8488e-bf6c-4eda-8f08-85e0ac7ce126 */ + event TestEvent + } + """; + it.setModel(model); + + final var expected = """ + + catalogue TestCatalogue + + + namespace TestNamespace + { + /** + * Description of my event + * + * @uuid 4ce8488e-bf6c-4eda-8f08-85e0ac7ce126 + */ + event TestEvent + } + + """; + it.setExpectedText(expected); + }); + } +} diff --git a/org.eclipse.xsmp.ide.tests/src/org/eclipse/xsmp/ide/tests/HoverTest.java b/org.eclipse.xsmp.ide.tests/src/org/eclipse/xsmp/ide/tests/HoverTest.java new file mode 100644 index 00000000..84d265c6 --- /dev/null +++ b/org.eclipse.xsmp.ide.tests/src/org/eclipse/xsmp/ide/tests/HoverTest.java @@ -0,0 +1,113 @@ +/******************************************************************************* +* Copyright (C) 2023 THALES ALENIA SPACE FRANCE. +* +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License 2.0 +* which accompanies this distribution, and is available at +* https://www.eclipse.org/legal/epl-2.0/ +* +* SPDX-License-Identifier: EPL-2.0 +******************************************************************************/ +package org.eclipse.xsmp.ide.tests; + +import org.eclipse.xtext.testing.HoverTestConfiguration; +import org.junit.jupiter.api.Test; + +class HoverTest extends AbstractXsmpcatLanguageServerTest +{ + @Test + void testHover_1() + { + testHover((HoverTestConfiguration it) -> { + final var model = """ + catalogue Catalogue1 + + namespace Namespace1 { } + """; + it.setModel(model); + it.setLine(2); + + final var expectedHover = """ + [[2, 0] .. [2, 9]] + kind: markdown + value: `namespace { }` + + A **Namespace** is a primary ordering mechanism. + + A **namespace** may contain other namespaces (nested namespaces), and does typically contain types. + In SMDL, namespaces are contained within a **Catalogue** (either directly, or within another namespace in a catalogue). + All sub-elements of a namespace (namespaces and types) must have unique names. + """; + it.setExpectedHover(expectedHover); + }); + } + + @Test + void testHover_2() + { + testHover((HoverTestConfiguration it) -> { + // Include ECSS-SMP library + TestUtils.loadEcssSmpLibrary(it); + + final var model = """ + catalogue TestCatalogue + + namespace TestNamespace + { + /** @uuid 563ca54c-6d21-46d2-83a3-029eb18f66ed */ + model TestModel + { + field Bool fea_bool + } + }"""; + + it.setModel(model); + it.setLine(7); + it.setColumn(15); + + final var expectedHover = """ + [[7, 14] .. [7, 18]] + kind: markdown + value: boolean with true or false
+ """; + it.setExpectedHover(expectedHover); + }); + } + + @Test + void testHover_3() + { + testHover((HoverTestConfiguration it) -> { + final var model = """ + catalogue TestCatalogue + + namespace TestNamespace + { + /** + * Description of my integer + * + * @uuid 6ca8c3ec-d081-49d1-9ea7-7cc791afa2c1 + */ + integer TestInteger + + /** @uuid 563ca54c-6d21-46d2-83a3-029eb18f66ed */ + model TestModel + { + field TestInteger fea_int + } + }"""; + + it.setModel(model); + it.setLine(14); + it.setColumn(16); + + final var expectedHover = """ + [[14, 14] .. [14, 25]] + kind: markdown + value: Description of my integer
+ """; + it.setExpectedHover(expectedHover); + }); + } + +} diff --git a/org.eclipse.xsmp.ide.tests/src/org/eclipse/xsmp/ide/tests/TestUtils.java b/org.eclipse.xsmp.ide.tests/src/org/eclipse/xsmp/ide/tests/TestUtils.java new file mode 100644 index 00000000..f4b7708a --- /dev/null +++ b/org.eclipse.xsmp.ide.tests/src/org/eclipse/xsmp/ide/tests/TestUtils.java @@ -0,0 +1,39 @@ +/******************************************************************************* +* Copyright (C) 2023 THALES ALENIA SPACE FRANCE. +* +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License 2.0 +* which accompanies this distribution, and is available at +* https://www.eclipse.org/legal/epl-2.0/ +* +* SPDX-License-Identifier: EPL-2.0 +******************************************************************************/ +package org.eclipse.xsmp.ide.tests; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import org.apache.commons.io.IOUtils; +import org.eclipse.xtext.testing.TextDocumentPositionConfiguration; + +import com.google.common.collect.ImmutableMap; + +public class TestUtils +{ + public static void loadEcssSmpLibrary(TextDocumentPositionConfiguration it) + { + final var inputStream = TestUtils.class + .getResourceAsStream("/org/eclipse/xsmp/lib/ecss.smp.xsmpcat"); + + try + { + it.setFilesInScope(ImmutableMap. builder() + .put("ecss.smp.xsmpcat", IOUtils.toString(inputStream, StandardCharsets.UTF_8)) + .build()); + } + catch (final IOException e) + { + e.printStackTrace(); + } + } +} diff --git a/org.eclipse.xsmp.ide.tests/src/org/eclipse/xsmp/ide/tests/ValidatorTest.java b/org.eclipse.xsmp.ide.tests/src/org/eclipse/xsmp/ide/tests/ValidatorTest.java new file mode 100644 index 00000000..80468a71 --- /dev/null +++ b/org.eclipse.xsmp.ide.tests/src/org/eclipse/xsmp/ide/tests/ValidatorTest.java @@ -0,0 +1,111 @@ +/******************************************************************************* +* Copyright (C) 2023 THALES ALENIA SPACE FRANCE. +* +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License 2.0 +* which accompanies this distribution, and is available at +* https://www.eclipse.org/legal/epl-2.0/ +* +* SPDX-License-Identifier: EPL-2.0 +******************************************************************************/ +package org.eclipse.xsmp.ide.tests; + +import java.util.List; + +import org.eclipse.lsp4j.Diagnostic; +import org.junit.Assert; +import org.junit.jupiter.api.Test; + +import com.google.common.collect.Iterables; + +class ValidatorTest extends AbstractXsmpcatLanguageServerTest +{ + @Test + void testMissingUuid() + { + final var model = """ + catalogue TestCatalogue + + namespace TestNamespace + { + model TestModel + { + def void ope_test () + } + } + """; + + writeFile("test1.xsmpcat", model); + initialize(); + + final var problems = problems(); + Assert.assertEquals(1, problems.size()); + + final Diagnostic problem = Iterables.getFirst(problems, null); + assertEquals("Missing Type UUID.", problem.getMessage()); + } + + @Test + void testWrongKeyword() + { + final var model = """ + catalogue TestCatalogue + + namespace TestNamespace + { + integger TestWrongInteger + } + """; + + writeFile("test2.xsmpcat", model); + initialize(); + + final var problems = problems(); + Assert.assertEquals(1, problems.size()); + + final Diagnostic problem = Iterables.getFirst(problems, null); + assertEquals("mismatched input 'integger' expecting '}'", problem.getMessage()); + } + + @Test + void testVisibilityProblem() + { + final var model = """ + catalogue TestCatalogue + + namespace TestNamespace1 + { + /** @uuid ab7de841-e453-4e44-ad89-b111125af9cd */ + model MyFirstModel + { + + } + + } + + namespace TestNamespace2 + { + /** @uuid 89c3e6f7-448c-43ab-90bb-e774a49e8df3 */ + model MySndModel extends TestNamespace1.MyFirstModel + { + + } + + } + """; + + writeFile("test3.xsmpcat", model); + initialize(); + + final var problems = problems(); + Assert.assertEquals(1, problems.size()); + + final Diagnostic problem = Iterables.getFirst(problems, null); + assertEquals("The Model TestNamespace1.MyFirstModel is not visible.", problem.getMessage()); + } + + private List problems() + { + return Iterables.getFirst(getDiagnostics().entrySet(), null).getValue(); + } +} diff --git a/org.eclipse.xsmp.ide/.classpath b/org.eclipse.xsmp.ide/.classpath index 5b5030fb..688f53f1 100644 --- a/org.eclipse.xsmp.ide/.classpath +++ b/org.eclipse.xsmp.ide/.classpath @@ -1,8 +1,13 @@ - + + + + + + diff --git a/org.eclipse.xsmp.ide/META-INF/MANIFEST.MF b/org.eclipse.xsmp.ide/META-INF/MANIFEST.MF index 0babb7dc..5ad68144 100644 --- a/org.eclipse.xsmp.ide/META-INF/MANIFEST.MF +++ b/org.eclipse.xsmp.ide/META-INF/MANIFEST.MF @@ -9,7 +9,13 @@ Bundle-ActivationPolicy: lazy Require-Bundle: org.eclipse.xsmp, org.eclipse.xtext.ide, org.eclipse.xtext.xbase.ide, - org.antlr.runtime;bundle-version="[3.2.0,3.2.1)" + org.antlr.runtime;bundle-version="[3.2.0,3.2.1)", + org.apache.log4j;bundle-version="1.2.24", + com.google.gson;bundle-version="2.10.1", + org.eclipse.lsp4j;bundle-version="0.20.1" Bundle-RequiredExecutionEnvironment: JavaSE-17 -Export-Package: org.eclipse.xsmp.ide.contentassist.antlr, - org.eclipse.xsmp.ide.contentassist.antlr.internal +Export-Package: org.eclipse.xsmp.ide, + org.eclipse.xsmp.ide.contentassist, + org.eclipse.xsmp.ide.contentassist.antlr, + org.eclipse.xsmp.ide.contentassist.antlr.internal, + org.eclipse.xsmp.ide.hover diff --git a/org.eclipse.xsmp.ide/build.properties b/org.eclipse.xsmp.ide/build.properties index b33c1857..5c6bbf99 100644 --- a/org.eclipse.xsmp.ide/build.properties +++ b/org.eclipse.xsmp.ide/build.properties @@ -1,5 +1,6 @@ source.. = src/,\ - src-gen/ + src-gen/,\ + xtend-gen/ bin.includes = .,\ META-INF/ bin.excludes = **/*.xtend diff --git a/org.eclipse.xsmp.ide/pom.xml b/org.eclipse.xsmp.ide/pom.xml index 0b9573ff..8b98dbc8 100644 --- a/org.eclipse.xsmp.ide/pom.xml +++ b/org.eclipse.xsmp.ide/pom.xml @@ -1,4 +1,5 @@ - 4.0.0 @@ -8,17 +9,189 @@ org.eclipse.xsmp.ide eclipse-plugin - + - src + true - + + + + ch.qos.reload4j + reload4j + + + org.eclipse.lsp4j + org.eclipse.lsp4j + + + org.ow2.asm + asm + + + org.eclipse.xsmp + org.eclipse.xsmp.lib + ${project.version} + + org.eclipse.xtend xtend-maven-plugin + + org.eclipse.tycho + target-platform-configuration + + consider + + + + org.apache.maven.plugins + maven-dependency-plugin + 3.5.0 + + + copy-dependencies + package + + copy-dependencies + + + p2.eclipse-feature + ${project.build.directory}/libs + false + false + true + true + + com.ibm.icu, + org.apache.ant, + org.apache.commons.lang, + org.apache.commons.logging, + org.eclipse.core.commands, + org.eclipse.core.contenttype, + org.eclipse.core.expressions, + org.eclipse.core.filesystem, + org.eclipse.core.jobs, + org.eclipse.core.resources, + org.eclipse.core.runtime, + org.eclipse.core.variables, + org.eclipse.debug.core, + org.eclipse.emf.codegen.ecore, + org.eclipse.emf.codegen, + org.eclipse.emf.mwe.core, + org.eclipse.emf.mwe.utils, + org.eclipse.emf.mwe2.lib, + org.eclipse.emf.mwe2.runtime, + org.eclipse.equinox.app, + org.eclipse.equinox.preferences, + org.eclipse.equinox.registry, + org.eclipse.jdt.core, + org.eclipse.jdt.debug, + org.eclipse.jdt.launching, + org.eclipse.text, + + + + + + + com.googlecode.addjars-maven-plugin + addjars-maven-plugin + 1.0.5 + + + package + + add-jars + + + + + ${project.build.directory}/libs + + + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.4.1 + + + + + org.eclipse.xsmp.ide.server.XsmpcatServerLauncher + + + plugin.properties + + + + + + + + *:org.xtext.example.mydsl1.ide-org.eclipse.lsp4j* + + *:org.xtext.example.mydsl1.ide-org.eclipse.xtext.xbase.lib* + + *:org.xtext.example.mydsl1.ide-org.eclipse.xtend.lib* + + *:org.xtext.example.mydsl1.ide-com.google.guava* + *:org.xtext.example.mydsl1.ide-asm* + *:org.xtext.example.mydsl1.ide-log4j* + *:org.xtext.example.mydsl1.ide-reload4j* + + *:org.xtext.example.mydsl1.ide-org.objectweb.asm* + + *:org.xtext.example.mydsl1.ide-org.apache.log4j* + + + + + *:* + + META-INF/INDEX.LIST + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + .options + .api_description + *.profile + *.html + about.* + about_files/* + plugin.xml + systembundle.properties + profile.list + **/*._trace + **/*.g + **/*.mwe2 + **/*.xtext + + + + false + ${project.artifactId}-ls + true + + + + package + + shade + + + + diff --git a/org.eclipse.xsmp.ide/src/log4j.properties b/org.eclipse.xsmp.ide/src/log4j.properties new file mode 100644 index 00000000..570fc664 --- /dev/null +++ b/org.eclipse.xsmp.ide/src/log4j.properties @@ -0,0 +1,16 @@ +# Log configuration for Xsmp logging. +# This log configuration will be used for the non-UI parts of Xsmp. +# +# For your convenience: valid log levels are (from least to most significant): +# TRACE, DEBUG, INFO, WARN, ERROR and FATAL +# Log4J manual: http://logging.apache.org/log4j/1.2/manual.html + +# Root logger configuration. Don't change this. +log4j.rootLogger=INFO, default + +# This appender will write to the stdout console +log4j.appender.default=org.apache.log4j.ConsoleAppender +log4j.appender.default.layout=org.apache.log4j.PatternLayout +log4j.appender.default.layout.ConversionPattern=%-4r %-5p - %m%n + +# Configure your log categories below: diff --git a/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/XsmpcatIdeModule.java b/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/XsmpcatIdeModule.java index c1288b93..7b54ac61 100644 --- a/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/XsmpcatIdeModule.java +++ b/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/XsmpcatIdeModule.java @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2020-2022 THALES ALENIA SPACE FRANCE. +* Copyright (C) 2020-2023 THALES ALENIA SPACE FRANCE. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -10,9 +10,47 @@ ******************************************************************************/ package org.eclipse.xsmp.ide; +import org.eclipse.xsmp.ide.contentassist.XsmpcatIdeContentProposalProvider; +import org.eclipse.xsmp.ide.hover.XsmpcatHoverService; +import org.eclipse.xsmp.ide.quickfix.XsmpcatIdeQuickfixProvider; +import org.eclipse.xtext.ide.editor.contentassist.IdeContentProposalProvider; +import org.eclipse.xtext.ide.editor.quickfix.IQuickFixProvider; +import org.eclipse.xtext.ide.server.codeActions.ICodeActionService2; +import org.eclipse.xtext.ide.server.codeActions.QuickFixCodeActionService; +import org.eclipse.xtext.ide.server.hover.HoverService; + /** * Use this class to register ide components. */ public class XsmpcatIdeModule extends AbstractXsmpcatIdeModule { -} + static + { + @SuppressWarnings("unused") + final Class< ? >[] classes = { + org.apache.log4j.ConsoleAppender.class, + org.apache.log4j.DailyRollingFileAppender.class, + org.apache.log4j.PatternLayout.class }; + } + + public Class< ? extends IQuickFixProvider> bindIQuickFixProvider() + { + return XsmpcatIdeQuickfixProvider.class; + } + + public Class< ? extends ICodeActionService2> bindICodeActionService2() + { + return QuickFixCodeActionService.class; + } + + public Class< ? extends IdeContentProposalProvider> bindIdeContentProposalProvider() + { + return XsmpcatIdeContentProposalProvider.class; + } + + public Class< ? extends HoverService> bindHoverService() + { + return XsmpcatHoverService.class; + } + +} \ No newline at end of file diff --git a/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/XsmpcatIdeSetup.java b/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/XsmpcatIdeSetup.java index 8e8ef6f6..143268d5 100644 --- a/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/XsmpcatIdeSetup.java +++ b/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/XsmpcatIdeSetup.java @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2020-2022 THALES ALENIA SPACE FRANCE. +* Copyright (C) 2020-2023 THALES ALENIA SPACE FRANCE. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 diff --git a/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/contentassist/AbstractIdeContentProposalProvider.java b/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/contentassist/AbstractIdeContentProposalProvider.java new file mode 100644 index 00000000..11bbb7bb --- /dev/null +++ b/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/contentassist/AbstractIdeContentProposalProvider.java @@ -0,0 +1,122 @@ +/******************************************************************************* +* Copyright (C) 2023 THALES ALENIA SPACE FRANCE. +* +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License 2.0 +* which accompanies this distribution, and is available at +* https://www.eclipse.org/legal/epl-2.0/ +* +* SPDX-License-Identifier: EPL-2.0 +******************************************************************************/ +package org.eclipse.xsmp.ide.contentassist; + +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.xtext.CrossReference; +import org.eclipse.xtext.GrammarUtil; +import org.eclipse.xtext.Keyword; +import org.eclipse.xtext.ide.editor.contentassist.ContentAssistContext; +import org.eclipse.xtext.ide.editor.contentassist.IIdeContentProposalAcceptor; +import org.eclipse.xtext.ide.editor.contentassist.IdeContentProposalProvider; +import org.eclipse.xtext.util.PolymorphicDispatcher; +import org.eclipse.xtext.util.PolymorphicDispatcher.ErrorHandler; +import org.eclipse.xtext.util.PolymorphicDispatcher.WarningErrorHandler; + +import com.google.inject.Inject; + +public class AbstractIdeContentProposalProvider extends IdeContentProposalProvider +{ + @Inject + protected XsmpcatReferenceFilter filter; + + private final Map> dispatchers; + + private final static Logger log = Logger.getLogger(AbstractIdeContentProposalProvider.class); + + protected AbstractIdeContentProposalProvider() + { + dispatchers = new HashMap<>(); + } + + @Override + protected void _createProposals(Keyword keyword, ContentAssistContext context, + IIdeContentProposalAcceptor acceptor) + { + final var method = "complete_" + keyword.getValue(); + if (methodExists(getClass(), method)) + { + invokeMethod(method, acceptor, context); + } + + super._createProposals(keyword, context, acceptor); + } + + protected void invokeMethod(String methodName, IIdeContentProposalAcceptor acceptor, + ContentAssistContext context) + { + var dispatcher = dispatchers.get(methodName); + if (dispatcher == null) + { + final ErrorHandler errorHandler = WarningErrorHandler.get(log); + dispatcher = new PolymorphicDispatcher<>(methodName, 2, 2, Collections.singletonList(this), + errorHandler) { + @Override + public Class< ? > getDefaultClass(int paramIndex) + { + if (paramIndex == 0) + { + return EObject.class; + } + return super.getDefaultClass(paramIndex); + } + }; + dispatchers.put(methodName, dispatcher); + } + dispatcher.invoke(context, acceptor); + } + + @Override + protected void _createProposals(CrossReference reference, ContentAssistContext context, + IIdeContentProposalAcceptor acceptor) + { + final var containingParserRule = GrammarUtil.containingParserRule(reference); + if (!GrammarUtil.isDatatypeRule(containingParserRule)) + { + EReference ref; + if (containingParserRule.isWildcard()) + { + ref = GrammarUtil.getReference(reference, context.getCurrentModel().eClass()); + } + else + { + ref = GrammarUtil.getReference(reference); + } + final var currentModel = context.getCurrentModel(); + if (ref != null && currentModel != null) + { + final var scope = getScopeProvider().getScope(currentModel, ref); + getCrossrefProposalProvider().lookupCrossReference(scope, reference, context, acceptor, + filter.getFilter(currentModel, ref)); + } + } + } + + protected static boolean methodExists(Class< ? > clazz, String methodName) + { + final var methods = clazz.getDeclaredMethods(); + for (final Method method : methods) + { + if (method.getName().equals(methodName)) + { + return true; + } + } + return false; + } +} diff --git a/org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/contentassist/IReferenceFilter.java b/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/contentassist/IReferenceFilter.java similarity index 89% rename from org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/contentassist/IReferenceFilter.java rename to org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/contentassist/IReferenceFilter.java index 3dc28e77..c84e1044 100644 --- a/org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/contentassist/IReferenceFilter.java +++ b/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/contentassist/IReferenceFilter.java @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2020-2022 THALES ALENIA SPACE FRANCE. +* Copyright (C) 2020-2023 THALES ALENIA SPACE FRANCE. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -8,7 +8,7 @@ * * SPDX-License-Identifier: EPL-2.0 ******************************************************************************/ -package org.eclipse.xsmp.ui.contentassist; +package org.eclipse.xsmp.ide.contentassist; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; diff --git a/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/contentassist/XsmpcatIdeContentProposalProvider.xtend b/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/contentassist/XsmpcatIdeContentProposalProvider.xtend new file mode 100644 index 00000000..cf8a99b9 --- /dev/null +++ b/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/contentassist/XsmpcatIdeContentProposalProvider.xtend @@ -0,0 +1,238 @@ +/******************************************************************************* +* Copyright (C) 2023 THALES ALENIA SPACE FRANCE. +* +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License 2.0 +* which accompanies this distribution, and is available at +* https://www.eclipse.org/legal/epl-2.0/ +* +* SPDX-License-Identifier: EPL-2.0 +******************************************************************************/ +package org.eclipse.xsmp.ide.contentassist + +import com.google.common.base.Joiner +import com.google.common.collect.Iterables +import java.time.Instant +import java.time.temporal.ChronoUnit +import java.util.UUID +import org.eclipse.emf.ecore.EObject +import org.eclipse.emf.ecore.EReference +import org.eclipse.xsmp.xcatalogue.XcataloguePackage +import org.eclipse.xtext.ide.editor.contentassist.ContentAssistContext +import org.eclipse.xtext.ide.editor.contentassist.IIdeContentProposalAcceptor + +class XsmpcatIdeContentProposalProvider extends AbstractIdeContentProposalProvider { + + int snippetPriority = 400; + + def protected complete_association(ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { + acceptor.accept(getProposalCreator().createSnippet(''' + association ${1|«getCrossReferences(context.currentModel, XcataloguePackage.Literals.ASSOCIATION__TYPE)»|} ${2:name} + ''', "Create an Association", context), snippetPriority); + } + + def protected complete_catalogue(ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { + acceptor.accept(getProposalCreator().createSnippet(''' + /** + * Specifies the SMP Component Model as Catalogue. + * + * @date «Instant.now.truncatedTo(ChronoUnit.SECONDS).toString» + * @author «System.getProperty("user.name")» + * @title Catalogue + * @version 1.0 + */ + catalogue ${1:name} + ''', "Create a Catalogue", context), snippetPriority); + } + + def protected complete_class(ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { + acceptor.accept(getProposalCreator().createSnippet(''' + /** @uuid «generateUuid» */ + class ${1:name} + { + $0 + } + ''', "Create a Class", context), snippetPriority); + + } + + def protected complete_constant(ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { + acceptor.accept(getProposalCreator().createSnippet(''' + constant ${1|«getCrossReferences(context.currentModel, XcataloguePackage.Literals.CONSTANT__TYPE)»|} ${2:name} = $0 + ''', "Create a Constant", context), snippetPriority); + } + + def protected complete_container(ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { + acceptor.accept(getProposalCreator().createSnippet(''' + container ${1|«getCrossReferences(context.currentModel, XcataloguePackage.Literals.CONTAINER__TYPE)»|}[*] ${2:name} + ''', "Create a Container", context), snippetPriority); + } + + def protected complete_def(ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { + acceptor.accept(getProposalCreator().createSnippet(''' + def void ${1:name} ($0) + ''', "Create an Operation", context), snippetPriority); + } + + def protected complete_entrypoint(ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { + acceptor.accept(getProposalCreator().createSnippet(''' + entrypoint ${1:name} + ''', "Create an EntryPoint", context), snippetPriority); + } + + def protected complete_enum(ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { + acceptor.accept(getProposalCreator().createSnippet(''' + /** @uuid «generateUuid» */ + enum ${1:name} + { + $0 = 0 + } + ''', "Create an Enumeration", context), snippetPriority); + } + + def protected complete_event(ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { + acceptor.accept(getProposalCreator().createSnippet(''' + /** @uuid «generateUuid» */ + event ${1:name} + ''', "Create an Event Type", context), snippetPriority); + } + + def protected complete_eventsink(ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { + acceptor.accept(getProposalCreator().createSnippet(''' + eventsink ${1|«getCrossReferences(context.currentModel, XcataloguePackage.Literals.EVENT_SINK__TYPE)»|} ${2:name} + ''', "Create an Event Sink", context), snippetPriority); + } + + def protected complete_eventsource(ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { + acceptor.accept(getProposalCreator().createSnippet(''' + eventsource ${1|«getCrossReferences(context.currentModel, XcataloguePackage.Literals.EVENT_SOURCE__TYPE)»|} ${2:name} + ''', "Create an Event Source", context), snippetPriority); + } + + def protected complete_exception(ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { + acceptor.accept(getProposalCreator().createSnippet(''' + /** @uuid «generateUuid» */ + exception ${1:name} + { + $0 + } + ''', "Create an Exception", context), snippetPriority); + } + + def protected complete_field(ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { + acceptor.accept(getProposalCreator().createSnippet(''' + field ${1|«getCrossReferences(context.currentModel, XcataloguePackage.Literals.FIELD__TYPE)»|} ${2:name} + ''', "Create a Field", context), snippetPriority); + } + + def protected complete_integer(ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { + acceptor.accept(getProposalCreator().createSnippet(''' + /** @uuid «generateUuid» */ + integer ${1:name} + ''', "Create an Integer type", context), snippetPriority); + } + + def protected complete_float(ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { + acceptor.accept(getProposalCreator().createSnippet(''' + /** @uuid «generateUuid» */ + float ${1:name} + ''', "Create a Float", context), snippetPriority); + } + + def protected complete_interface(ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { + acceptor.accept(getProposalCreator().createSnippet(''' + /** @uuid «generateUuid» */ + interface ${1:name} + { + $0 + } + ''', "Create an Interface", context), snippetPriority); + } + + def protected complete_model(ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { + acceptor.accept(getProposalCreator().createSnippet(''' + /** @uuid «generateUuid» */ + model ${1:name} + { + $0 + } + ''', "Create a Model", context), snippetPriority); + } + + def protected complete_namespace(ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { + acceptor.accept(getProposalCreator().createSnippet(''' + namespace ${1:name} + { + $0 + } // namespace ${1:name} + ''', "Create a Namespace", context), snippetPriority); + } + + def protected complete_property(ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { + acceptor.accept(getProposalCreator().createSnippet(''' + property ${1|«getCrossReferences(context.currentModel, XcataloguePackage.Literals.PROPERTY__TYPE)»|} ${2:name} + ''', "Create a Property", context), snippetPriority); + } + + def protected complete_reference(ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { + acceptor.accept(getProposalCreator().createSnippet(''' + reference ${1|«getCrossReferences(context.currentModel, XcataloguePackage.Literals.REFERENCE__INTERFACE)»|}[*] ${2:name} + ''', "Create a Reference", context), snippetPriority); + } + + def protected complete_service(ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { + acceptor.accept(getProposalCreator().createSnippet(''' + /** @uuid «generateUuid» */ + service ${1:name} + { + $0 + } + ''', "Create a Service", context), snippetPriority); + } + + def protected complete_string(ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { + acceptor.accept(getProposalCreator().createSnippet(''' + /** @uuid «generateUuid» */ + string ${1:name}[$0] + ''', "Create a String Type", context), snippetPriority); + } + + def protected complete_structure(ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { + acceptor.accept(getProposalCreator().createSnippet(''' + /** @uuid «generateUuid» */ + struct ${1:name} + { + $0 + } + ''', "Create a Structure", context), snippetPriority); + } + + def protected complete_valueReference(ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { + acceptor.accept(getProposalCreator().createSnippet(''' + /** @uuid «generateUuid» */ + using ${1:name} = ${2|«getCrossReferences(context.currentModel, XcataloguePackage.Literals.VALUE_REFERENCE__TYPE)»|} + ''', "Create a Value Reference", context), snippetPriority); + } + + def protected complete_array(ContentAssistContext context, IIdeContentProposalAcceptor acceptor) { + acceptor.accept(getProposalCreator().createSnippet(''' + /** @uuid «generateUuid» */ + array ${1:name} = ${2|«getCrossReferences(context.currentModel, XcataloguePackage.Literals.ARRAY__ITEM_TYPE)»|}[$0] + ''', "Create an Array Type", context), snippetPriority); + } + + def private String getCrossReferences(EObject eObject, EReference eReference) { + val scope = scopeProvider.getScope(eObject, eReference) + val filteredCandidates = Iterables.filter(scope.allElements, filter.getFilter(eObject, eReference)) + + if (filteredCandidates.empty) { + return "None" + } + + return Joiner.on(",").join(filteredCandidates.map[it|it.name]) + } + + def private String generateUuid() { + UUID.randomUUID.toString + } +} diff --git a/org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/contentassist/XsmpcatReferenceFilter.java b/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/contentassist/XsmpcatReferenceFilter.java similarity index 95% rename from org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/contentassist/XsmpcatReferenceFilter.java rename to org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/contentassist/XsmpcatReferenceFilter.java index a4aeedae..0621f2ab 100644 --- a/org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/contentassist/XsmpcatReferenceFilter.java +++ b/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/contentassist/XsmpcatReferenceFilter.java @@ -1,4 +1,14 @@ -package org.eclipse.xsmp.ui.contentassist; +/******************************************************************************* +* Copyright (C) 2020-2023 THALES ALENIA SPACE FRANCE. +* +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License 2.0 +* which accompanies this distribution, and is available at +* https://www.eclipse.org/legal/epl-2.0/ +* +* SPDX-License-Identifier: EPL-2.0 +******************************************************************************/ +package org.eclipse.xsmp.ide.contentassist; import java.util.Arrays; import java.util.List; diff --git a/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/hover/XsmpcatHoverService.java b/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/hover/XsmpcatHoverService.java new file mode 100644 index 00000000..47a4eb26 --- /dev/null +++ b/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/hover/XsmpcatHoverService.java @@ -0,0 +1,53 @@ +/******************************************************************************* +* Copyright (C) 2023 THALES ALENIA SPACE FRANCE. +* +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License 2.0 +* which accompanies this distribution, and is available at +* https://www.eclipse.org/legal/epl-2.0/ +* +* SPDX-License-Identifier: EPL-2.0 +******************************************************************************/ +package org.eclipse.xsmp.ide.hover; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtext.Keyword; +import org.eclipse.xtext.ide.server.Document; +import org.eclipse.xtext.ide.server.hover.HoverContext; +import org.eclipse.xtext.ide.server.hover.HoverService; +import org.eclipse.xtext.resource.XtextResource; + +import com.google.inject.Inject; + +public class XsmpcatHoverService extends HoverService +{ + @Inject + private XsmpcatKeywordHovers keywordHovers; + + @Inject + private XsmpcatKeywordAtOffsetHelper keywordHelper; + + @Override + public String getContents(EObject element) + { + if (element instanceof Keyword) + { + return keywordHovers.hoverText((Keyword) element); + } + return super.getContents(element); + } + + @Override + protected HoverContext createContext(Document document, XtextResource resource, int offset) + { + // Looking for a keyword + final var result = keywordHelper.resolveKeywordAt(resource, offset); + if (result != null) + { + return new HoverContext(document, resource, offset, result.getSecond(), result.getFirst()); + } + + return super.createContext(document, resource, offset); + } + +} diff --git a/org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/hover/XsmpcatKeywordAtOffsetHelper.java b/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/hover/XsmpcatKeywordAtOffsetHelper.java similarity index 76% rename from org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/hover/XsmpcatKeywordAtOffsetHelper.java rename to org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/hover/XsmpcatKeywordAtOffsetHelper.java index 9a534489..cec26faa 100644 --- a/org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/hover/XsmpcatKeywordAtOffsetHelper.java +++ b/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/hover/XsmpcatKeywordAtOffsetHelper.java @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2020-2022 THALES ALENIA SPACE FRANCE. +* Copyright (C) 2023 THALES ALENIA SPACE FRANCE. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -8,21 +8,20 @@ * * SPDX-License-Identifier: EPL-2.0 ******************************************************************************/ -package org.eclipse.xsmp.ui.hover; +package org.eclipse.xsmp.ide.hover; import org.eclipse.emf.ecore.EObject; -import org.eclipse.jface.text.IRegion; -import org.eclipse.jface.text.Region; import org.eclipse.xtext.Keyword; import org.eclipse.xtext.nodemodel.util.NodeModelUtils; import org.eclipse.xtext.resource.XtextResource; +import org.eclipse.xtext.util.ITextRegion; import org.eclipse.xtext.util.Pair; +import org.eclipse.xtext.util.TextRegion; import org.eclipse.xtext.util.Tuples; -/** Inspired by {@link org.eclipse.xtext.resource.EObjectAtOffsetHelper} */ public class XsmpcatKeywordAtOffsetHelper { - public Pair resolveKeywordAt(XtextResource resource, int offset) + public Pair resolveKeywordAt(XtextResource resource, int offset) { final var parseResult = resource.getParseResult(); if (parseResult != null) @@ -36,7 +35,7 @@ public Pair resolveKeywordAt(XtextResource resource, int offse { final var keyword = (Keyword) leaf.getGrammarElement(); return Tuples.create((EObject) keyword, - (IRegion) new Region(leaf.getOffset(), leaf.getLength())); + (ITextRegion) new TextRegion(leaf.getOffset(), leaf.getLength())); } } return null; diff --git a/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/hover/XsmpcatKeywordHovers.xtend b/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/hover/XsmpcatKeywordHovers.xtend new file mode 100644 index 00000000..c94b8a7b --- /dev/null +++ b/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/hover/XsmpcatKeywordHovers.xtend @@ -0,0 +1,302 @@ +/******************************************************************************* +* Copyright (C) 2023 THALES ALENIA SPACE FRANCE. +* +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License 2.0 +* which accompanies this distribution, and is available at +* https://www.eclipse.org/legal/epl-2.0/ +* +* SPDX-License-Identifier: EPL-2.0 +******************************************************************************/ +package org.eclipse.xsmp.ide.hover + +import org.eclipse.xsmp.services.XsmpcatGrammarAccess +import javax.inject.Inject +import org.eclipse.xtext.Keyword + +class XsmpcatKeywordHovers { + + @Inject XsmpcatGrammarAccess ga; + + def multiplicity() { + ''' + multiplicity: + - empty : 1 element + - ? : 0 or 1 element + - [] | [*] : 0 to infinitite + - [ expr ] : expr elements + - [ expr ... * ] : expr to infinitite + - [ expr1 ... expr2 ] : expr1 to expr2 + ''' + } + + def hoverText(Keyword k) { + val result = switch (k) { + case ga.catalogueAccess.catalogueKeyword_1: ''' + `catalogue ` + + A **Catalogue** is a document that defines types. + + It contains namespaces as a primary ordering mechanism. + The names of these namespaces need to be unique within the catalogue. + ''' + case ga.namespaceMemberAccess.namespaceKeyword_3_0_1, + case ga.namespaceAccess.namespaceKeyword_4: ''' + `namespace { }` + + A **Namespace** is a primary ordering mechanism. + + A **namespace** may contain other namespaces (nested namespaces), and does typically contain types. + In SMDL, namespaces are contained within a **Catalogue** (either directly, or within another namespace in a catalogue). + All sub-elements of a namespace (namespaces and types) must have unique names. + ''' + case ga.namespaceMemberAccess.structKeyword_3_1_2: ''' + `struct { }` + + A **Structure** type collects an arbitrary number of **Fields** representing the state of the structure. + + Within a structure, each field needs to be given a unique name. + In order to arrive at semantically correct (data) type definitions, a structure type may not be recursive, i.e. a structure may not have a field that is typed by the structure itself. + A structure can also serve as a namespace to define an arbitrary number of **Constants**. + ''' + case ga.namespaceMemberAccess.classKeyword_3_2_2: ''' + `[abstract] class [extends ] { }` + + The **Class** metaclass is derived from **Structure**. + + A **class** may be abstract (attribute **Abstract**), and it may **extend** from a single base class (implementation inheritance), which is represented by the Base link. + As the Class metaclass is derived from Structure it can contain constants and fields. + Further, it can have arbitrary numbers of properties (Property elements), operations (**Operation** elements), and associations (**Association** elements). + ''' + case ga.namespaceMemberAccess.exceptionKeyword_3_3_2: ''' + `[abstract] exception [extends ] { }` + + An **Exception** represents a non-recoverable error that can occur when calling into an **Operation** or **Property** getter/setter (within an **Operation** this is represented by the **RaisedException** links and within a **Property** this is represented by the **GetRaises** and **SetRaises** links, respectively). + + An Exception can contain constants and fields (from **Structure**) as well as operations, properties and associations (from **Class**). The fields represent the state variables of the exception which carry additional information when the exception is raised. + Furthermore, an **Exception** may be **Abstract** (from **Class**), and it may inherit from a single base exception (implementation inheritance), which is represented by the Base link (from **Class**). + ''' + case ga.namespaceMemberAccess.interfaceKeyword_3_4_2: ''' + `interface [extends , ..., ] { }` + + An **Interface** is a reference type that serves as a contract in a loosely coupled architecture. It has the ability to contain constants, properties and operations (from ReferenceType). + + An **Interface** may inherit from other interfaces (interface inheritance), which is represented via the Base links. + + **Remark**: It is strongly recommended to only use value types, references and other interfaces in the properties and operations of an interface (i.e. not to use models). Otherwise, a dependency between a model implementing the interface, and other models referenced by this interface is introduced, which is against the idea of interface-based or component-based design. + ''' + case ga.namespaceMemberAccess.modelKeyword_3_5_2: ''' + `[abstract] model [extends ] [implements , ..., ] { }` + + The **Model** metaclass is a component and hence inherits all component mechanisms. + + These mechanisms allow using various different modelling approaches. + + For a class-based design, a **Model** may provide a collection of **Field** elements to define its internal state. + For scheduling and global events, a **Model** may provide a collection of **EntryPoint** elements that can be registered with the **Scheduler** or **EventManager** services of a Simulation Environment. + For an interface-based design, a **Model** may provide (i.e. implement) an arbitrary number of interfaces, which is represented via the **Interface** links. + For a component-based design, a **Model** may provide **Container** elements to contain other models (composition), and **Reference** elements to reference other components (aggregation). + These components can either be models or services. + For an event-based design, a **Model** may support inter-model events via the **EventSink** and **EventSource** elements. + For a dataflow-based design, the fields of a **Model** can be tagged as Input or Output fields. + In addition, a **Model** may have **Association** elements to express associations to other models or fields of other models. + ''' + case ga.namespaceMemberAccess.serviceKeyword_3_6_2: ''' + `[abstract] service [extends ] [implements , ..., ] { }` + + The Service metaclass is a component and hence inherits all component mechanisms. + A Service can reference one or more interfaces via the **Interface** links (inherited from Component), where at least one of them must be derived from Smp::IService, which qualifies it as a service interface. + ''' + // Array + case ga.namespaceMemberAccess.arrayKeyword_3_7_2_0_0, + case ga.namespaceMemberAccess.usingKeyword_3_7_2_0_1: ''' + `array = []` + + An **Array** type defines a fixed-size array of identically typed elements, where ItemType defines the type of the array items, and Size defines the number of array items. + + Multi-dimensional arrays are defined when ItemType is an **Array** type as well. + Dynamic arrays are not supported by SMDL, as they are not supported by some potential target platforms, and introduce various difficulties in memory management. + + **Remarks**: Nevertheless, specific mechanisms are available to allow dynamic collections of components, either for containment (composition) or references (aggregation). + ''' + // ValueReference + case ga.namespaceMemberAccess.usingKeyword_3_8_2: ''' + `using = ` + + A **ValueReference** is a type that references a specific value type. It is the "missing link" between value types and reference types. + ''' + case ga.namespaceMemberAccess.integerKeyword_3_9_2: ''' + `integer [extends <(Int8|Int16|Int32|Int64|UInt8|UInt16|UInt32|UInt64)>] [in <(*|integralExpression) ... (*|integralExpression)>]` + + An **Integer** type represents integer values with a given range of valid values (via the Minimum and Maximum attributes). + + The Unit element can hold a physical unit that can be used by applications to ensure physical unit integrity across models. + Optionally, the **PrimitiveType** used to encode the integer value may be specified (one of **Int8**, **Int16**, **Int32**, **Int64**, **UIn8**, **UInt16**, **UInt32**, **UInt64**, where the default is **Int32**). + ''' + case ga.namespaceMemberAccess.floatKeyword_3_10_2: ''' + `float [extends <(Float32|Float64)>] [in <(*|decimalExpression) ... (*|decimalExpression)>]` + + A **Float** type represents floating-point values with a given range of valid values (via the Minimum and Maximum attributes). + + The MinInclusive and MaxInclusive attributes determine whether the boundaries are included in the range or not. + The Unit element can hold a physical unit that can be used by applications to ensure physical unit integrity across models. + + Optionally, the **PrimitiveType** used to encode the floating-point value may be specified (one of **Float32** or **Float64**, where the default is **Float64**). + ''' + case ga.namespaceMemberAccess.eventKeyword_3_11_2: ''' + `event [extends ]` + + An **Event** Type is used to specify the type of an event. + This can be used not only to give a meaningful name to an event type, but also to link it to an existing simple type (via the EventArgs attribute) that is passed as an argument with every invocation of the event. + ''' + case ga.namespaceMemberAccess.stringKeyword_3_12_2: ''' + `string []` + + A **String** type represents fixed Length string values base on **Char8**. + + The **String** language element defines an **Array** of **Char8** values, but allows a more natural handling of it, e.g. by storing a string value as one string, not as an array of individual characters. + As with arrays, SMDL does not allow defining variable-sized strings, as these have the same problems as dynamic arrays (e.g. their size is not know up-front, and their use requires memory allocation). + ''' + case ga.namespaceMemberAccess.primitiveKeyword_3_13_2: ''' + A number of pre-defined types are needed in order to bootstrap the type system. + + These pre-defined value types are represented by instances of the metaclass **PrimitiveType**. + This mechanism is only used in order to bootstrap the type system and may not be used to define new types for modelling. + This is an important restriction, as all values of primitive types may be held in a **SimpleValue**. + The metaclasses derived from **SimpleValue**, however, are pre-defined and cannot be extended. + ''' + case ga.namespaceMemberAccess.nativeKeyword_3_14_2: ''' + A **Native** Type specifies a type with any number of platform mappings. It is used to anchor existing or user-defined types into different target platforms. + + This mechanism is used within the specification to define the SMDL primitive types with respect to the Metamodel, but it can also be used to define native types within an arbitrary SMDL catalogue for use by models. + In the latter case, native types are typically used to bind a model to some external library or existing Application Programming **Interface** (API). + ''' + case ga.namespaceMemberAccess.attributeKeyword_3_15_2, + case ga.namespaceMemberAccess.attributeKeyword_3_17_2: ''' + An **Attribute** Type defines a new type available for adding attributes to elements. + + The AllowMultiple attribute specifies if a corresponding Attribute may be attached more than once to a language element, while the Usage element defines to which language elements attributes of this type can be attached. + An attribute type always references a value type, and specifies a Default value. + ''' + case ga.namespaceMemberAccess.enumKeyword_3_16_2: ''' + `enum { }` + + An **Enumeration** type represents one of a number of pre-defined enumeration literals. + + The Enumeration language element can be used to create user-defined enumeration types. + An enumeration must always contain at least one EnumerationLiteral, each having a name and an integer Value attached to it. + All enumeration literals of an enumeration type must have unique names and values, respectively. + ''' + case ga.fieldDeclarationAccess.fieldKeyword_1: ''' + `[input] [output] [transient] field [ = defaultValueExpression]` + + A **Field** is a feature that is typed by any value type but String8, and that may have a Default value. + + The transient attribute defines how the field is published to the simulation environment. + Only non transient fields are stored using external persistence. + The visibility to the user within the simulation environment can be controlled via the standard SMP attribute "View". + By default, a field is not transient and the View attribute defaults to "None" when not applied. + The Input and Output attributes define whether the field value is an input for internal calculations (i.e. needed in order to perform these calculations), or an output of internal calculations (i.e. modified when performing these calculations). + These flags default to false, but can be changed from their default value to support dataflow-based design. + ''' + case ga.constantDeclarationAccess.constantKeyword_1: ''' + `constant = valueExpression` + + A **Constant** is a feature that is typed by a simple type and that must have a Value. + ''' + case ga.associationDeclarationAccess.associationKeyword_1: ''' + `association ` + + An **Association** is a feature that is typed by a language type (Type link). An association always expresses a reference to an instance of the referenced language type. + + This reference is either another model (if the Type link refers to a **Model** or **Interface**), or it is a field contained in another model (if the Type link refers to a ValueType). + ''' + case ga.propertyDeclarationAccess.propertyKeyword_1: ''' + `[(readOnly|writeOnly|readWrite)] property [get throws ] [set throws ] [ -> ]` + + A **Property** has a similar syntax as a Field: It is a feature that references a language type. + + However, the semantics is different in that a property does not represent a state and that it can be assigned an Access attribute to specify how the property can be accessed (either readWrite, readOnly, or writeOnly, see **AccessKind**). + Furthermore, a property can be assigned a **Category** attribute to help grouping the properties within its owning type, and a property may specify an arbitrary number of exceptions that it can raise in its getter (**GetRaises**) and/or setter (**SetRaises**). + + **Remark**: The category can be used in applications as ordering or filtering criterion, for example in a property grid. The term "property" used here closely corresponds in its semantics to the same term in the Java Beans specification and in the Microsoft .NET framework. That is, a property formally represents a "getter" or a "setter" operation or both which allow accessing state or configuration information (or derived information thereof) in a controlled way and which can also be exposed via interfaces (in contrast to fields). + ''' + case ga.containerDeclarationAccess.containerKeyword_0: ''' + `container [ = defaultComponent]` + «multiplicity()» + + A **Container** defines the rules of composition (containment of children) for a Component. + + The type of components that can be contained is specified via the Type link. + The Lower and Upper attributes specify the multiplicity, i.e. the number of possibly stored components. + Therein the upper bound may be unlimited, which is represented by Upper=-1. + Furthermore, a container may specify a default implementation of the container type via the DefaultComponentl link. Remark : SMDL support tools may use this during instantiation (i.e. during model integration) to select an initial implementation for newly created contained components. + ''' + case ga.referenceDeclarationAccess.referenceKeyword_0: ''' + `reference ` + «multiplicity()» + + A **Reference** defines the rules of aggregation (links to components) for a **Component**. + + The type of components (models or services) that can be referenced is specified by the **Interface** link. + Thereby, a service reference is characterized by an interface that is derived from `Smp::IService`. + The Lower and Upper attributes specify the multiplicity, i.e. the number of possibly held references to components implementing this interface. + Therein the upper bound may be unlimited, which is represented by Upper=-1. + ''' + case ga.entryPointDeclarationAccess.entrypointKeyword_0: ''' + `entrypoint ` + + An **EntryPoint** is a named element of a **Component** (**Model** or **Service**). + + It corresponds to a void operation taking no parameters that can be called from an external client (e.g. the Scheduler or Event Manager services). + An Entry Point can reference both Input fields (which must have their Input attribute set to true) and Output fields (which must have their Output attribute set to true). + These links can be used to ensure that all component output fields are updated before the entry point is called, or that all input fields can be used after the entry point has been called. + ''' + case ga.eventSinkDeclarationAccess.eventsinkKeyword_0: ''' + `eventsink ` + + An **EventSink** is used to specify that a **Component** can receive a specific event using a given name. An **EventSink** can be connected to any number of **EventSource** instances. + ''' + case ga.eventSourceDeclarationAccess.eventsourceKeyword_0: ''' + `eventsource ` + + An **EventSource** is used to specify that a **Component** publishes a specific event under a given name. + + The Multicast attribute can be used to specify whether any number of sinks can connect to the source (the default), or only a single sink can connect (**Multicast=false**). + + **Remark**: A tool for model integration can use the **Multicast** attribute to configure the user interface accordingly to ease the specification of event links. + ''' + case ga.operationDeclarationAccess.defKeyword_1: ''' + `def (|void) (, ..., ) [throws , ..., ]` + + `p*: [(in|out|inout)] [ = defaultValueExpression]` + + An **Operation** may have an arbitrary number of parameters, where at most one of the parameters may be of **Direction = ParameterDirectionKind.return**. + + If such a parameter is absent, the operation is a void function (procedure) without return value. + An **RaisedException** may specify an arbitrary number of exceptions that it can raise (**RaisedException**). + ''' + case ga.visibilityModifiersAccess.privateKeyword_0: ''' + The element is visible only within its containing classifier. + ''' + case ga.visibilityModifiersAccess.protectedKeyword_1: ''' + The element is visible within its containing classifier and derived classifiers thereof. + ''' + case ga.visibilityModifiersAccess.publicKeyword_2: ''' + The element is globally visible. + ''' + case ga.parameterDirectionKindAccess.inInKeyword_0_0: ''' + The parameter is read-only to the operation, i.e. its value must be specified on call, and cannot be changed inside the operation. + ''' + case ga.parameterDirectionKindAccess.outOutKeyword_1_0: ''' + The parameter is write-only to the operation, i.e. its value is unspecified on call, and must be set by the operation. + ''' + case ga.parameterDirectionKindAccess.inoutInoutKeyword_2_0: ''' + The parameter must be specified on call, and may be changed by the operation. + ''' + default: + '''''' + } + result.toString; + } +} diff --git a/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/quickfix/XsmpcatIdeQuickfixProvider.java b/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/quickfix/XsmpcatIdeQuickfixProvider.java new file mode 100644 index 00000000..eb3b8795 --- /dev/null +++ b/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/quickfix/XsmpcatIdeQuickfixProvider.java @@ -0,0 +1,59 @@ +/******************************************************************************* +* Copyright (C) 2023 THALES ALENIA SPACE FRANCE. +* +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License 2.0 +* which accompanies this distribution, and is available at +* https://www.eclipse.org/legal/epl-2.0/ +* +* SPDX-License-Identifier: EPL-2.0 +******************************************************************************/ +package org.eclipse.xsmp.ide.quickfix; + +import java.util.UUID; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.xsmp.validation.XsmpcatIssueCodesProvider; +import org.eclipse.xsmp.xcatalogue.Type; +import org.eclipse.xsmp.xcatalogue.VisibilityElement; +import org.eclipse.xsmp.xcatalogue.VisibilityKind; +import org.eclipse.xtext.ide.editor.quickfix.AbstractDeclarativeIdeQuickfixProvider; +import org.eclipse.xtext.ide.editor.quickfix.DiagnosticResolutionAcceptor; +import org.eclipse.xtext.ide.editor.quickfix.QuickFix; + +import com.google.gson.JsonArray; + +public class XsmpcatIdeQuickfixProvider extends AbstractDeclarativeIdeQuickfixProvider +{ + + @QuickFix(XsmpcatIssueCodesProvider.INVALID_UUID) + public void generateUUID(DiagnosticResolutionAcceptor acceptor) + { + acceptor.accept("Generate UUID", e -> { + + if (e instanceof Type) + { + ((Type) e).setUuid(UUID.randomUUID().toString()); + } + }); + + } + + @QuickFix(XsmpcatIssueCodesProvider.HIDDEN_ELEMENT) + public void changeVisibility(DiagnosticResolutionAcceptor acceptor) + { + acceptor.accept("Change Type visibility", (issue, e) -> e2 -> { + final var data = (JsonArray) issue.getData(); + + final var feature = e.eClass().getEStructuralFeature(data.get(1).getAsString()); + final var elem = (EObject) e.eGet(feature); + + if (elem instanceof final VisibilityElement elemcast && !elem.eIsProxy()) + { + elemcast.setVisibility(VisibilityKind.getByName(data.get(2).getAsString())); + // FIXME not working + } + }); + } + +} diff --git a/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/server/XsmpcatProjectManager.java b/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/server/XsmpcatProjectManager.java new file mode 100644 index 00000000..7ed6ae39 --- /dev/null +++ b/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/server/XsmpcatProjectManager.java @@ -0,0 +1,65 @@ +/******************************************************************************* +* Copyright (C) 2023 THALES ALENIA SPACE FRANCE. +* +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License 2.0 +* which accompanies this distribution, and is available at +* https://www.eclipse.org/legal/epl-2.0/ +* +* SPDX-License-Identifier: EPL-2.0 +******************************************************************************/ +package org.eclipse.xsmp.ide.server; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.xtext.build.IncrementalBuilder.Result; +import org.eclipse.xtext.ide.server.ProjectManager; +import org.eclipse.xtext.resource.IExternalContentSupport.IExternalContentProvider; +import org.eclipse.xtext.resource.impl.ProjectDescription; +import org.eclipse.xtext.resource.impl.ResourceDescriptionsData; +import org.eclipse.xtext.util.CancelIndicator; +import org.eclipse.xtext.validation.Issue; +import org.eclipse.xtext.workspace.IProjectConfig; +import org.eclipse.xtext.workspace.ISourceFolder; +import org.eclipse.xtext.xbase.lib.Procedures.Procedure2; + +import com.google.inject.Provider; + +public class XsmpcatProjectManager extends ProjectManager +{ + + IProjectConfig projectConfig; + + @Override + public void initialize(ProjectDescription description, IProjectConfig projectConfig, + Procedure2< ? super URI, ? super Iterable> acceptor, + IExternalContentProvider openedDocumentsContentProvider, + Provider> indexProvider, + CancelIndicator cancelIndicator) + { + super.initialize(description, projectConfig, acceptor, openedDocumentsContentProvider, + indexProvider, cancelIndicator); + this.projectConfig = projectConfig; + } + + @Override + public Result doInitialBuild(CancelIndicator cancelIndicator) + { + final List allUris = new ArrayList<>(); + for (final ISourceFolder srcFolder : super.getProjectConfig().getSourceFolders()) + { + allUris.addAll(srcFolder.getAllResources(fileSystemScanner)); + } + + // Include ECSS-SMP library + final var url = getClass().getResource("/org/eclipse/xsmp/lib/ecss.smp.xsmpcat"); + allUris.add(URI.createURI(url.toString())); + + return super.doBuild(allUris, Collections.emptyList(), Collections.emptyList(), + cancelIndicator); + } +} diff --git a/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/server/XsmpcatServerLauncher.java b/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/server/XsmpcatServerLauncher.java new file mode 100644 index 00000000..902c260a --- /dev/null +++ b/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/server/XsmpcatServerLauncher.java @@ -0,0 +1,22 @@ +/******************************************************************************* +* Copyright (C) 2023 THALES ALENIA SPACE FRANCE. +* +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License 2.0 +* which accompanies this distribution, and is available at +* https://www.eclipse.org/legal/epl-2.0/ +* +* SPDX-License-Identifier: EPL-2.0 +******************************************************************************/ +package org.eclipse.xsmp.ide.server; + +import org.eclipse.xtext.ide.server.ServerLauncher; + +public class XsmpcatServerLauncher extends ServerLauncher +{ + + public static void main(String[] args) + { + ServerLauncher.launch(XsmpcatServerLauncher.class.getName(), args, new XsmpcatServerModule()); + } +} diff --git a/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/server/XsmpcatServerModule.java b/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/server/XsmpcatServerModule.java new file mode 100644 index 00000000..a5223441 --- /dev/null +++ b/org.eclipse.xsmp.ide/src/org/eclipse/xsmp/ide/server/XsmpcatServerModule.java @@ -0,0 +1,25 @@ +/******************************************************************************* +* Copyright (C) 2023 THALES ALENIA SPACE FRANCE. +* +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License 2.0 +* which accompanies this distribution, and is available at +* https://www.eclipse.org/legal/epl-2.0/ +* +* SPDX-License-Identifier: EPL-2.0 +******************************************************************************/ +package org.eclipse.xsmp.ide.server; + +import org.eclipse.xtext.ide.server.ProjectManager; +import org.eclipse.xtext.ide.server.ServerModule; + +public class XsmpcatServerModule extends ServerModule +{ + + @Override + protected void configure() + { + super.configure(); + bind(ProjectManager.class).to(XsmpcatProjectManager.class); + } +} diff --git a/org.eclipse.xsmp.target/org.eclipse.xsmp.target.target b/org.eclipse.xsmp.target/org.eclipse.xsmp.target.target index a1039e12..c77750d4 100644 --- a/org.eclipse.xsmp.target/org.eclipse.xsmp.target.target +++ b/org.eclipse.xsmp.target/org.eclipse.xsmp.target.target @@ -14,6 +14,7 @@ + diff --git a/org.eclipse.xsmp.tests/resources/org/eclipse/xsmp/tests/testValid.xsmpcat b/org.eclipse.xsmp.tests/resources/org/eclipse/xsmp/tests/testValid.xsmpcat index 19c82ea9..3f965a68 100644 --- a/org.eclipse.xsmp.tests/resources/org/eclipse/xsmp/tests/testValid.xsmpcat +++ b/org.eclipse.xsmp.tests/resources/org/eclipse/xsmp/tests/testValid.xsmpcat @@ -294,12 +294,12 @@ namespace ns field AStruct aStruct = {true, 10} - container IComposite container = AModel - container IComposite? optional_container = AnAbstractModel - container IComposite[*] list_container = AnAbstractModel - container IComposite[+] non_empty_list_container = AnAbstractModel - container IComposite[4] list_container_4 = AnAbstractModel - container IComposite[4 ... *] list_container_4_or_more = AnAbstractModel + container IComponent container = AModel + container IComponent? optional_container = AnAbstractModel + container IComponent[*] list_container = AnAbstractModel + container IComponent[+] non_empty_list_container = AnAbstractModel + container IComponent[4] list_container_4 = AnAbstractModel + container IComponent[4 ... *] list_container_4_or_more = AnAbstractModel container IComposite[4 ... 10] list_container_betwwen_4_and_10 reference IComposite reference diff --git a/org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/contentassist/XsmpcatReferenceProposalCreator.java b/org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/contentassist/XsmpcatReferenceProposalCreator.java index d740baf8..31640856 100644 --- a/org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/contentassist/XsmpcatReferenceProposalCreator.java +++ b/org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/contentassist/XsmpcatReferenceProposalCreator.java @@ -16,6 +16,7 @@ import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.eclipse.xsmp.ide.contentassist.IReferenceFilter; import org.eclipse.xtext.resource.IEObjectDescription; import org.eclipse.xtext.scoping.IScope; import org.eclipse.xtext.ui.editor.contentassist.AbstractJavaBasedContentProposalProvider.ReferenceProposalCreator; diff --git a/org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/hover/XsmpcatDispatchingEObjectTextHover.java b/org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/hover/XsmpcatDispatchingEObjectTextHover.java index 57c691cc..a049822e 100644 --- a/org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/hover/XsmpcatDispatchingEObjectTextHover.java +++ b/org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/hover/XsmpcatDispatchingEObjectTextHover.java @@ -14,12 +14,15 @@ import org.eclipse.jface.text.IInformationControlCreator; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.Region; +import org.eclipse.xsmp.ide.hover.XsmpcatKeywordAtOffsetHelper; import org.eclipse.xsmp.xcatalogue.BuiltInExpression; import org.eclipse.xtext.Keyword; import org.eclipse.xtext.resource.XtextResource; import org.eclipse.xtext.ui.editor.hover.DispatchingEObjectTextHover; import org.eclipse.xtext.ui.editor.hover.IEObjectHoverProvider; import org.eclipse.xtext.util.Pair; +import org.eclipse.xtext.util.Tuples; import com.google.inject.Inject; @@ -63,10 +66,18 @@ public Object getHoverInfo(EObject first, ITextViewer textViewer, IRegion hoverR @Override protected Pair getXtextElementAt(XtextResource resource, final int offset) { - var result = super.getXtextElementAt(resource, offset); + final var result = super.getXtextElementAt(resource, offset); if (result == null) { - result = keywordAtOffsetHelper.resolveKeywordAt(resource, offset); + final var tmp = keywordAtOffsetHelper.resolveKeywordAt(resource, offset); + if (tmp == null) + { + return null; + } + + final var textRegion = tmp.getSecond(); + return Tuples.create(tmp.getFirst(), + (IRegion) new Region(textRegion.getOffset(), textRegion.getLength())); } return result; } diff --git a/org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/hover/XsmpcatEObjectHoverProvider.java b/org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/hover/XsmpcatEObjectHoverProvider.java index 13f11e5d..7c0c336a 100644 --- a/org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/hover/XsmpcatEObjectHoverProvider.java +++ b/org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/hover/XsmpcatEObjectHoverProvider.java @@ -37,12 +37,7 @@ protected String getHoverInfoAsHtml(EObject o) { if (o instanceof Keyword) { - final var hover = keywordHovers.hoverText((Keyword) o); - - if (hover != null) - { - return hover; - } + return keywordHovers.hoverText((Keyword) o); } final var hover = super.getHoverInfoAsHtml(o); diff --git a/org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/hover/XsmpcatKeywordHovers.xtend b/org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/hover/XsmpcatKeywordHovers.xtend index 947b5d3d..78dc982e 100644 --- a/org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/hover/XsmpcatKeywordHovers.xtend +++ b/org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/hover/XsmpcatKeywordHovers.xtend @@ -16,285 +16,284 @@ import org.eclipse.xtext.Keyword class XsmpcatKeywordHovers { - @Inject XsmpcatGrammarAccess ga; + @Inject XsmpcatGrammarAccess ga; - def multiplicity() { - ''' - multiplicity: - - empty : 1 element - - ? : 0 or 1 element - - [] | [*] : 0 to infinitite - - [ expr ] : expr elements - - [ expr ... * ] : expr to infinitite - - [ expr1 ... expr2 ] : expr1 to expr2 - ''' - } + def multiplicity() { + ''' + multiplicity: + - empty : 1 element + - ? : 0 or 1 element + - [] | [*] : 0 to infinitite + - [ expr ] : expr elements + - [ expr ... * ] : expr to infinitite + - [ expr1 ... expr2 ] : expr1 to expr2 + ''' + } - def hoverText(Keyword k) { - val result = switch (k) { - case ga.catalogueAccess.catalogueKeyword_1: ''' -

catalogue name

-
- A Catalogue is a document that defines types. -

It contains namespaces as a primary ordering mechanism. -
The names of these namespaces need to be unique within the catalogue.

- ''' - case ga.namespaceMemberAccess.namespaceKeyword_3_0_1, - case ga.namespaceAccess.namespaceKeyword_4: ''' -

namespace name { }

-
- A Namespace is a primary ordering mechanism.
-

A namespace may contain other namespaces (nested namespaces), and does typically contain types. -
In SMDL, namespaces are contained within a Catalogue (either directly, or within another namespace in a catalogue). -
All sub-elements of a namespace (namespaces and types) must have unique names.

- ''' - case ga.namespaceMemberAccess.structKeyword_3_1_2: ''' -

struct name { }

-
- A Structure type collects an arbitrary number of Fields representing the state of the structure. -

Within a structure, each field needs to be given a unique name. -
In order to arrive at semantically correct (data) type definitions, a structure type may not be recursive, i.e. a structure may not have a field that is typed by the structure itself. -
A structure can also serve as a namespace to define an arbitrary number of Constants.

- ''' - case ga.namespaceMemberAccess.classKeyword_3_2_2: ''' -

[abstract] class name [extends base] { }

-
-

The Class metaclass is derived from Structure. -
A class may be abstract (attribute Abstract), and it may extend from a single base class (implementation inheritance), which is represented by the Base link. -
As the Class metaclass is derived from Structure it can contain constants and fields. -
Further, it can have arbitrary numbers of properties (Property elements), operations (Operation elements), and associations (Association elements).

- ''' - case ga.namespaceMemberAccess.exceptionKeyword_3_3_2: ''' -

[abstract] exception name [extends base] { }

-
-

An Exception represents a non-recoverable error that can occur when calling into an Operation or Property getter/setter (within an Operation this is represented by the RaisedException links and within a Property this is represented by the GetRaises and SetRaises links, respectively). -
An Exception can contain constants and fields (from Structure) as well as operations, properties and associations (from Class). The fields represent the state variables of the exception which carry additional information when the exception is raised. -
Furthermore, an Exception may be Abstract (from Class), and it may inherit from a single base exception (implementation inheritance), which is represented by the Base link (from Class).

- ''' - case ga.namespaceMemberAccess.interfaceKeyword_3_4_2: ''' -

interface name [extends interface1, ..., interfaceN] { }

-
-

An Interface is a reference type that serves as a contract in a loosely coupled architecture. It has the ability to contain constants, properties and operations (from ReferenceType). -
An Interface may inherit from other interfaces (interface inheritance), which is represented via the Base links. - - - Remark - - : It is strongly recommended to only use value types, references and other interfaces in the properties and operations of an interface (i.e. not to use models). Otherwise, a dependency between a model implementing the interface, and other models referenced by this interface is introduced, which is against the idea of interface-based or component-based design. -

- ''' - case ga.namespaceMemberAccess.modelKeyword_3_5_2: ''' -

[abstract] model name [extends base] [implements interface1, ..., interfaceN] { }

-
-

The Model metaclass is a component and hence inherits all component mechanisms. -
These mechanisms allow using various different modelling approaches. -
For a class-based design, a Model may provide a collection of Field elements to define its internal state. -
For scheduling and global events, a Model may provide a collection of EntryPoint elements that can be registered with the Scheduler or EventManager services of a Simulation Environment. -
For an interface-based design, a Model may provide (i.e. implement) an arbitrary number of interfaces, which is represented via the Interface links. -
For a component-based design, a Model may provide Container elements to contain other models (composition), and Reference elements to reference other components (aggregation). -
These components can either be models or services. -
For an event-based design, a Model may support inter-model events via the EventSink and EventSource elements. -
For a dataflow-based design, the fields of a Model can be tagged as Input or Output fields. -
In addition, a Model may have Association elements to express associations to other models or fields of other models.

- ''' - case ga.namespaceMemberAccess.serviceKeyword_3_6_2: ''' -

[abstract] service name [extends base] [implements interface1, ..., interfaceN] { }

-
-

The Service metaclass is a component and hence inherits all component mechanisms. -
A Service can reference one or more interfaces via the Interface links (inherited from Component), where at least one of them must be derived from Smp::IService, which qualifies it as a service interface.

- ''' - // Array - case ga.namespaceMemberAccess.arrayKeyword_3_7_2_0_0, - case ga.namespaceMemberAccess.usingKeyword_3_7_2_0_1: ''' -

array name = type [integerExpression]

-
-

An Array type defines a fixed-size array of identically typed elements, where ItemType defines the type of the array items, and Size defines the number of array items. -
Multi-dimensional arrays are defined when ItemType is an Array type as well. -
Dynamic arrays are not supported by SMDL, as they are not supported by some potential target platforms, and introduce various difficulties in memory management. - - - Remarks - - : Nevertheless, specific mechanisms are available to allow dynamic collections of components, either for containment (composition) or references (aggregation). -

- ''' - // ValueReference - case ga.namespaceMemberAccess.usingKeyword_3_8_2: ''' -

using name = type *

-
-

A ValueReference is a type that references a specific value type. It is the "missing link" between value types and reference types.

- ''' - case ga.namespaceMemberAccess.integerKeyword_3_9_2: ''' -

integer name [extends (Int8|Int16|Int32|Int64|UInt8|UInt16|UInt32|UInt64)] [in (*|integralExpression) ... (*|integralExpression)]

-
-

An Integer type represents integer values with a given range of valid values (via the Minimum and Maximum attributes). -
The Unit element can hold a physical unit that can be used by applications to ensure physical unit integrity across models. -
Optionally, the PrimitiveType used to encode the integer value may be specified (one of Int8, Int16, Int32, Int64, UIn8, UInt16, UInt32, UInt64, where the default is Int32).

- ''' - case ga.namespaceMemberAccess.floatKeyword_3_10_2: ''' -

float name [extends (Float32|Float64)] [in (*|decimalExpression) ... (*|decimalExpression)]

-
-

A Float type represents floating-point values with a given range of valid values (via the Minimum and Maximum attributes). -
The MinInclusive and MaxInclusive attributes determine whether the boundaries are included in the range or not. -
The Unit element can hold a physical unit that can be used by applications to ensure physical unit integrity across models. -
Optionally, the PrimitiveType used to encode the floating-point value may be specified (one of Float32 or Float64, where the default is Float64).

- ''' - case ga.namespaceMemberAccess.eventKeyword_3_11_2: ''' -

event name [extends simpleType]

-
-

An Event Type is used to specify the type of an event. -
This can be used not only to give a meaningful name to an event type, but also to link it to an existing simple type (via the EventArgs attribute) that is passed as an argument with every invocation of the event.

- ''' - case ga.namespaceMemberAccess.stringKeyword_3_12_2: ''' -

string name [integerExpression]

-
-

A String type represents fixed Length string values base on Char8. -
The String language element defines an Array of Char8 values, but allows a more natural handling of it, e.g. by storing a string value as one string, not as an array of individual characters. -
As with arrays, SMDL does not allow defining variable-sized strings, as these have the same problems as dynamic arrays (e.g. their size is not know up-front, and their use requires memory allocation).

- ''' - case ga.namespaceMemberAccess.primitiveKeyword_3_13_2: ''' - A number of pre-defined types are needed in order to bootstrap the type system. -
-

These pre-defined value types are represented by instances of the metaclass PrimitiveType. -
This mechanism is only used in order to bootstrap the type system and may not be used to define new types for modelling. -
This is an important restriction, as all values of primitive types may be held in a SimpleValue. -
The metaclasses derived from SimpleValue, however, are pre-defined and cannot be extended.

- ''' - case ga.namespaceMemberAccess.nativeKeyword_3_14_2: ''' - A Native Type specifies a type with any number of platform mappings. It is used to anchor existing or user-defined types into different target platforms. -

This mechanism is used within the specification to define the SMDL primitive types with respect to the Metamodel, but it can also be used to define native types within an arbitrary SMDL catalogue for use by models. -
In the latter case, native types are typically used to bind a model to some external library or existing Application Programming Interface (API).

- ''' - case ga.namespaceMemberAccess.attributeKeyword_3_15_2, - case ga.namespaceMemberAccess.attributeKeyword_3_17_2: ''' - An Attribute Type defines a new type available for adding attributes to elements. -


The AllowMultiple attribute specifies if a corresponding Attribute may be attached more than once to a language element, while the Usage element defines to which language elements attributes of this type can be attached. -
An attribute type always references a value type, and specifies a Default value.

- ''' - case ga.namespaceMemberAccess.enumKeyword_3_16_2: ''' -

enum name { }

-
- An Enumeration type represents one of a number of pre-defined enumeration literals. -

The Enumeration language element can be used to create user-defined enumeration types. -
An enumeration must always contain at least one EnumerationLiteral, each having a name and an integer Value attached to it. -
All enumeration literals of an enumeration type must have unique names and values, respectively.

- ''' - case ga.fieldDeclarationAccess.fieldKeyword_1: ''' -

[input] [output] [transient] field type name [ = defaultValueExpression]

-
- A Field is a feature that is typed by any value type but String8, and that may have a Default value. -

The transient attribute defines how the field is published to the simulation environment. -
Only non transient fields are stored using external persistence. -
The visibility to the user within the simulation environment can be controlled via the standard SMP attribute "View". -
By default, a field is not transient and the View attribute defaults to "None" when not applied. -
The Input and Output attributes define whether the field value is an input for internal calculations (i.e. needed in order to perform these calculations), or an output of internal calculations (i.e. modified when performing these calculations). -
These flags default to false, but can be changed from their default value to support dataflow-based design.

- ''' - case ga.constantDeclarationAccess.constantKeyword_1: ''' -

constant type name = valueExpression

-
- A Constant is a feature that is typed by a simple type and that must have a Value. - ''' - case ga.associationDeclarationAccess.associationKeyword_1: ''' -

association type name

-
- An Association is a feature that is typed by a language type (Type link). An association always expresses a reference to an instance of the referenced language type. -


This reference is either another model (if the Type link refers to a Model or Interface), or it is a field contained in another model (if the Type link refers to a ValueType).

- ''' - case ga.propertyDeclarationAccess.propertyKeyword_1: ''' -

[(readOnly|writeOnly|readWrite)]property type name [get throws exception1, ..., exceptionN] [set throws exception1, ..., exceptionN] [ -> attachedField]

-
- A Property has a similar syntax as a Field: It is a feature that references a language type. -

However, the semantics is different in that a property does not represent a state and that it can be assigned an Access attribute to specify how the property can be accessed (either readWrite, readOnly, or writeOnly, see AccessKind). -
Furthermore, a property can be assigned a Category attribute to help grouping the properties within its owning type, and a property may specify an arbitrary number of exceptions that it can raise in its getter (GetRaises) and/or setter (SetRaises). - - - Remark - - : The category can be used in applications as ordering or filtering criterion, for example in a property grid. The term "property" used here closely corresponds in its semantics to the same term in the Java Beans specification and in the Microsoft .NET framework. - That is, a property formally represents a "getter" or a "setter" operation or both which allow accessing state or configuration information (or derived information thereof) in a controlled way and which can also be exposed via interfaces (in contrast to fields). -

- ''' - case ga.containerDeclarationAccess.containerKeyword_0: ''' -

container type multiplicity? name [ = defaultComponent]

- «multiplicity()» -
- A Container defines the rules of composition (containment of children) for a Component. -

The type of components that can be contained is specified via the Type link. -
The Lower and Upper attributes specify the multiplicity, i.e. the number of possibly stored components. -
Therein the upper bound may be unlimited, which is represented by Upper=-1. -
Furthermore, a container may specify a default implementation of the container type via the DefaultComponentl link. - - - Remark - - : SMDL support tools may use this during instantiation (i.e. during model integration) to select an initial implementation for newly created contained components. -

- ''' - case ga.referenceDeclarationAccess.referenceKeyword_0: ''' -

reference interface multiplicity? name

- «multiplicity()» -
- A Reference defines the rules of aggregation (links to components) for a Component. -

The type of components (models or services) that can be referenced is specified by the Interface link. -
Thereby, a service reference is characterized by an interface that is derived from Smp::IService. -
The Lower and Upper attributes specify the multiplicity, i.e. the number of possibly held references to components implementing this interface. -
Therein the upper bound may be unlimited, which is represented by Upper=-1.

- ''' - case ga.entryPointDeclarationAccess.entrypointKeyword_0: ''' -

entrypoint name

-
- An EntryPoint is a named element of a Component (Model or Service). -

It corresponds to a void operation taking no parameters that can be called from an external client (e.g. the Scheduler or Event Manager services). -
An Entry Point can reference both Input fields (which must have their Input attribute set to true) and Output fields (which must have their Output attribute set to true). -
These links can be used to ensure that all component output fields are updated before the entry point is called, or that all input fields can be used after the entry point has been called.

- ''' - case ga.eventSinkDeclarationAccess.eventsinkKeyword_0: ''' -

eventsink type name

-
- An EventSink is used to specify that a Component can receive a specific event using a given name. An EventSink can be connected to any number of EventSource instances. - ''' - case ga.eventSourceDeclarationAccess.eventsourceKeyword_0: ''' -

eventsource type name

-
- An EventSource is used to specify that a Component publishes a specific event under a given name. -

The Multicast attribute can be used to specify whether any number of sinks can connect to the source (the default), or only a single sink can connect (Multicast=false). - - - Remark - - : A tool for model integration can use the Multicast attribute to configure the user interface accordingly to ease the specification of event links. -

- ''' - case ga.operationDeclarationAccess.defKeyword_1: ''' -

def (returnType|void) name (p1, ..., pN) [throws exception1, ..., exceptionN]

-

p*: [(in|out|inout)] type name [ = defaultValueExpression]

-
- An Operation may have an arbitrary number of parameters, where at most one of the parameters may be of Direction = ParameterDirectionKind.return. -

If such a parameter is absent, the operation is a void function (procedure) without return value. -
An RaisedException may specify an arbitrary number of exceptions that it can raise (RaisedException).

- ''' - case ga.visibilityModifiersAccess.privateKeyword_0: ''' - The element is visible only within its containing classifier. - ''' - case ga.visibilityModifiersAccess.protectedKeyword_1: ''' - The element is visible within its containing classifier and derived classifiers thereof. - ''' - case ga.visibilityModifiersAccess.publicKeyword_2: ''' - The element is globally visible. - ''' - case ga.parameterDirectionKindAccess.inInKeyword_0_0: ''' - The parameter is read-only to the operation, i.e. its value must be specified on call, and cannot be changed inside the operation. - ''' - case ga.parameterDirectionKindAccess.outOutKeyword_1_0: ''' - The parameter is write-only to the operation, i.e. its value is unspecified on call, and must be set by the operation. - ''' - case ga.parameterDirectionKindAccess.inoutInoutKeyword_2_0: ''' - The parameter must be specified on call, and may be changed by the operation. - ''' - default: - return null - } - result.toString; - } + def hoverText(Keyword k) { + val result = switch (k) { + case ga.catalogueAccess.catalogueKeyword_1: ''' +

catalogue name

+
+ A Catalogue is a document that defines types. +

It contains namespaces as a primary ordering mechanism. +
The names of these namespaces need to be unique within the catalogue.

+ ''' + case ga.namespaceMemberAccess.namespaceKeyword_3_0_1, + case ga.namespaceAccess.namespaceKeyword_4: ''' +

namespace name { }

+
+ A Namespace is a primary ordering mechanism.
+

A namespace may contain other namespaces (nested namespaces), and does typically contain types. +
In SMDL, namespaces are contained within a Catalogue (either directly, or within another namespace in a catalogue). +
All sub-elements of a namespace (namespaces and types) must have unique names.

+ ''' + case ga.namespaceMemberAccess.structKeyword_3_1_2: ''' +

struct name { }

+
+ A Structure type collects an arbitrary number of Fields representing the state of the structure. +

Within a structure, each field needs to be given a unique name. +
In order to arrive at semantically correct (data) type definitions, a structure type may not be recursive, i.e. a structure may not have a field that is typed by the structure itself. +
A structure can also serve as a namespace to define an arbitrary number of Constants.

+ ''' + case ga.namespaceMemberAccess.classKeyword_3_2_2: ''' +

[abstract] class name [extends base] { }

+
+

The Class metaclass is derived from Structure. +
A class may be abstract (attribute Abstract), and it may extend from a single base class (implementation inheritance), which is represented by the Base link. +
As the Class metaclass is derived from Structure it can contain constants and fields. +
Further, it can have arbitrary numbers of properties (Property elements), operations (Operation elements), and associations (Association elements).

+ ''' + case ga.namespaceMemberAccess.exceptionKeyword_3_3_2: ''' +

[abstract] exception name [extends base] { }

+
+

An Exception represents a non-recoverable error that can occur when calling into an Operation or Property getter/setter (within an Operation this is represented by the RaisedException links and within a Property this is represented by the GetRaises and SetRaises links, respectively). +
An Exception can contain constants and fields (from Structure) as well as operations, properties and associations (from Class). The fields represent the state variables of the exception which carry additional information when the exception is raised. +
Furthermore, an Exception may be Abstract (from Class), and it may inherit from a single base exception (implementation inheritance), which is represented by the Base link (from Class).

+ ''' + case ga.namespaceMemberAccess.interfaceKeyword_3_4_2: ''' +

interface name [extends interface1, ..., interfaceN] { }

+
+

An Interface is a reference type that serves as a contract in a loosely coupled architecture. It has the ability to contain constants, properties and operations (from ReferenceType). +
An Interface may inherit from other interfaces (interface inheritance), which is represented via the Base links. + + + Remark + + : It is strongly recommended to only use value types, references and other interfaces in the properties and operations of an interface (i.e. not to use models). Otherwise, a dependency between a model implementing the interface, and other models referenced by this interface is introduced, which is against the idea of interface-based or component-based design. +

+ ''' + case ga.namespaceMemberAccess.modelKeyword_3_5_2: ''' +

[abstract] model name [extends base] [implements interface1, ..., interfaceN] { }

+
+

The Model metaclass is a component and hence inherits all component mechanisms. +
These mechanisms allow using various different modelling approaches. +
For a class-based design, a Model may provide a collection of Field elements to define its internal state. +
For scheduling and global events, a Model may provide a collection of EntryPoint elements that can be registered with the Scheduler or EventManager services of a Simulation Environment. +
For an interface-based design, a Model may provide (i.e. implement) an arbitrary number of interfaces, which is represented via the Interface links. +
For a component-based design, a Model may provide Container elements to contain other models (composition), and Reference elements to reference other components (aggregation). +
These components can either be models or services. +
For an event-based design, a Model may support inter-model events via the EventSink and EventSource elements. +
For a dataflow-based design, the fields of a Model can be tagged as Input or Output fields. +
In addition, a Model may have Association elements to express associations to other models or fields of other models.

+ ''' + case ga.namespaceMemberAccess.serviceKeyword_3_6_2: ''' +

[abstract] service name [extends base] [implements interface1, ..., interfaceN] { }

+
+

The Service metaclass is a component and hence inherits all component mechanisms. +
A Service can reference one or more interfaces via the Interface links (inherited from Component), where at least one of them must be derived from Smp::IService, which qualifies it as a service interface.

+ ''' + // Array + case ga.namespaceMemberAccess.arrayKeyword_3_7_2_0_0, + case ga.namespaceMemberAccess.usingKeyword_3_7_2_0_1: ''' +

array name = type [integerExpression]

+
+

An Array type defines a fixed-size array of identically typed elements, where ItemType defines the type of the array items, and Size defines the number of array items. +
Multi-dimensional arrays are defined when ItemType is an Array type as well. +
Dynamic arrays are not supported by SMDL, as they are not supported by some potential target platforms, and introduce various difficulties in memory management. + + + Remarks + + : Nevertheless, specific mechanisms are available to allow dynamic collections of components, either for containment (composition) or references (aggregation). +

+ ''' + // ValueReference + case ga.namespaceMemberAccess.usingKeyword_3_8_2: ''' +

using name = type *

+
+

A ValueReference is a type that references a specific value type. It is the "missing link" between value types and reference types.

+ ''' + case ga.namespaceMemberAccess.integerKeyword_3_9_2: ''' +

integer name [extends (Int8|Int16|Int32|Int64|UInt8|UInt16|UInt32|UInt64)] [in (*|integralExpression) ... (*|integralExpression)]

+
+

An Integer type represents integer values with a given range of valid values (via the Minimum and Maximum attributes). +
The Unit element can hold a physical unit that can be used by applications to ensure physical unit integrity across models. +
Optionally, the PrimitiveType used to encode the integer value may be specified (one of Int8, Int16, Int32, Int64, UIn8, UInt16, UInt32, UInt64, where the default is Int32).

+ ''' + case ga.namespaceMemberAccess.floatKeyword_3_10_2: ''' +

float name [extends (Float32|Float64)] [in (*|decimalExpression) ... (*|decimalExpression)]

+
+

A Float type represents floating-point values with a given range of valid values (via the Minimum and Maximum attributes). +
The MinInclusive and MaxInclusive attributes determine whether the boundaries are included in the range or not. +
The Unit element can hold a physical unit that can be used by applications to ensure physical unit integrity across models. +
Optionally, the PrimitiveType used to encode the floating-point value may be specified (one of Float32 or Float64, where the default is Float64).

+ ''' + case ga.namespaceMemberAccess.eventKeyword_3_11_2: ''' +

event name [extends simpleType]

+
+

An Event Type is used to specify the type of an event. +
This can be used not only to give a meaningful name to an event type, but also to link it to an existing simple type (via the EventArgs attribute) that is passed as an argument with every invocation of the event.

+ ''' + case ga.namespaceMemberAccess.stringKeyword_3_12_2: ''' +

string name [integerExpression]

+
+

A String type represents fixed Length string values base on Char8. +
The String language element defines an Array of Char8 values, but allows a more natural handling of it, e.g. by storing a string value as one string, not as an array of individual characters. +
As with arrays, SMDL does not allow defining variable-sized strings, as these have the same problems as dynamic arrays (e.g. their size is not know up-front, and their use requires memory allocation).

+ ''' + case ga.namespaceMemberAccess.primitiveKeyword_3_13_2: ''' + A number of pre-defined types are needed in order to bootstrap the type system. +
+

These pre-defined value types are represented by instances of the metaclass PrimitiveType. +
This mechanism is only used in order to bootstrap the type system and may not be used to define new types for modelling. +
This is an important restriction, as all values of primitive types may be held in a SimpleValue. +
The metaclasses derived from SimpleValue, however, are pre-defined and cannot be extended.

+ ''' + case ga.namespaceMemberAccess.nativeKeyword_3_14_2: ''' + A Native Type specifies a type with any number of platform mappings. It is used to anchor existing or user-defined types into different target platforms. +

This mechanism is used within the specification to define the SMDL primitive types with respect to the Metamodel, but it can also be used to define native types within an arbitrary SMDL catalogue for use by models. +
In the latter case, native types are typically used to bind a model to some external library or existing Application Programming Interface (API).

+ ''' + case ga.namespaceMemberAccess.attributeKeyword_3_15_2, + case ga.namespaceMemberAccess.attributeKeyword_3_17_2: ''' + An Attribute Type defines a new type available for adding attributes to elements. +


The AllowMultiple attribute specifies if a corresponding Attribute may be attached more than once to a language element, while the Usage element defines to which language elements attributes of this type can be attached. +
An attribute type always references a value type, and specifies a Default value.

+ ''' + case ga.namespaceMemberAccess.enumKeyword_3_16_2: ''' +

enum name { }

+
+ An Enumeration type represents one of a number of pre-defined enumeration literals. +

The Enumeration language element can be used to create user-defined enumeration types. +
An enumeration must always contain at least one EnumerationLiteral, each having a name and an integer Value attached to it. +
All enumeration literals of an enumeration type must have unique names and values, respectively.

+ ''' + case ga.fieldDeclarationAccess.fieldKeyword_1: ''' +

[input] [output] [transient] field type name [ = defaultValueExpression]

+
+ A Field is a feature that is typed by any value type but String8, and that may have a Default value. +

The transient attribute defines how the field is published to the simulation environment. +
Only non transient fields are stored using external persistence. +
The visibility to the user within the simulation environment can be controlled via the standard SMP attribute "View". +
By default, a field is not transient and the View attribute defaults to "None" when not applied. +
The Input and Output attributes define whether the field value is an input for internal calculations (i.e. needed in order to perform these calculations), or an output of internal calculations (i.e. modified when performing these calculations). +
These flags default to false, but can be changed from their default value to support dataflow-based design.

+ ''' + case ga.constantDeclarationAccess.constantKeyword_1: ''' +

constant type name = valueExpression

+
+ A Constant is a feature that is typed by a simple type and that must have a Value. + ''' + case ga.associationDeclarationAccess.associationKeyword_1: ''' +

association type name

+
+ An Association is a feature that is typed by a language type (Type link). An association always expresses a reference to an instance of the referenced language type. +


This reference is either another model (if the Type link refers to a Model or Interface), or it is a field contained in another model (if the Type link refers to a ValueType).

+ ''' + case ga.propertyDeclarationAccess.propertyKeyword_1: ''' +

[(readOnly|writeOnly|readWrite)]property type name [get throws exception1, ..., exceptionN] [set throws exception1, ..., exceptionN] [ -> attachedField]

+
+ A Property has a similar syntax as a Field: It is a feature that references a language type. +

However, the semantics is different in that a property does not represent a state and that it can be assigned an Access attribute to specify how the property can be accessed (either readWrite, readOnly, or writeOnly, see AccessKind). +
Furthermore, a property can be assigned a Category attribute to help grouping the properties within its owning type, and a property may specify an arbitrary number of exceptions that it can raise in its getter (GetRaises) and/or setter (SetRaises). + + + Remark + + : The category can be used in applications as ordering or filtering criterion, for example in a property grid. The term "property" used here closely corresponds in its semantics to the same term in the Java Beans specification and in the Microsoft .NET framework. + That is, a property formally represents a "getter" or a "setter" operation or both which allow accessing state or configuration information (or derived information thereof) in a controlled way and which can also be exposed via interfaces (in contrast to fields). +

+ ''' + case ga.containerDeclarationAccess.containerKeyword_0: ''' +

container type multiplicity? name [ = defaultComponent]

+ «multiplicity()» +
+ A Container defines the rules of composition (containment of children) for a Component. +

The type of components that can be contained is specified via the Type link. +
The Lower and Upper attributes specify the multiplicity, i.e. the number of possibly stored components. +
Therein the upper bound may be unlimited, which is represented by Upper=-1. +
Furthermore, a container may specify a default implementation of the container type via the DefaultComponentl link. + + + Remark + + : SMDL support tools may use this during instantiation (i.e. during model integration) to select an initial implementation for newly created contained components. +

+ ''' + case ga.referenceDeclarationAccess.referenceKeyword_0: ''' +

reference interface multiplicity? name

+ «multiplicity()» +
+ A Reference defines the rules of aggregation (links to components) for a Component. +

The type of components (models or services) that can be referenced is specified by the Interface link. +
Thereby, a service reference is characterized by an interface that is derived from Smp::IService. +
The Lower and Upper attributes specify the multiplicity, i.e. the number of possibly held references to components implementing this interface. +
Therein the upper bound may be unlimited, which is represented by Upper=-1.

+ ''' + case ga.entryPointDeclarationAccess.entrypointKeyword_0: ''' +

entrypoint name

+
+ An EntryPoint is a named element of a Component (Model or Service). +

It corresponds to a void operation taking no parameters that can be called from an external client (e.g. the Scheduler or Event Manager services). +
An Entry Point can reference both Input fields (which must have their Input attribute set to true) and Output fields (which must have their Output attribute set to true). +
These links can be used to ensure that all component output fields are updated before the entry point is called, or that all input fields can be used after the entry point has been called.

+ ''' + case ga.eventSinkDeclarationAccess.eventsinkKeyword_0: ''' +

eventsink type name

+
+ An EventSink is used to specify that a Component can receive a specific event using a given name. An EventSink can be connected to any number of EventSource instances. + ''' + case ga.eventSourceDeclarationAccess.eventsourceKeyword_0: ''' +

eventsource type name

+
+ An EventSource is used to specify that a Component publishes a specific event under a given name. +

The Multicast attribute can be used to specify whether any number of sinks can connect to the source (the default), or only a single sink can connect (Multicast=false). + + + Remark + + : A tool for model integration can use the Multicast attribute to configure the user interface accordingly to ease the specification of event links. +

+ ''' + case ga.operationDeclarationAccess.defKeyword_1: ''' +

def (returnType|void) name (p1, ..., pN) [throws exception1, ..., exceptionN]

+

p*: [(in|out|inout)] type name [ = defaultValueExpression]

+
+ An Operation may have an arbitrary number of parameters, where at most one of the parameters may be of Direction = ParameterDirectionKind.return. +

If such a parameter is absent, the operation is a void function (procedure) without return value. +
An RaisedException may specify an arbitrary number of exceptions that it can raise (RaisedException).

+ ''' + case ga.visibilityModifiersAccess.privateKeyword_0: ''' + The element is visible only within its containing classifier. + ''' + case ga.visibilityModifiersAccess.protectedKeyword_1: ''' + The element is visible within its containing classifier and derived classifiers thereof. + ''' + case ga.visibilityModifiersAccess.publicKeyword_2: ''' + The element is globally visible. + ''' + case ga.parameterDirectionKindAccess.inInKeyword_0_0: ''' + The parameter is read-only to the operation, i.e. its value must be specified on call, and cannot be changed inside the operation. + ''' + case ga.parameterDirectionKindAccess.outOutKeyword_1_0: ''' + The parameter is write-only to the operation, i.e. its value is unspecified on call, and must be set by the operation. + ''' + case ga.parameterDirectionKindAccess.inoutInoutKeyword_2_0: ''' + The parameter must be specified on call, and may be changed by the operation. + ''' + default: '''''' + } + result.toString; + } } diff --git a/org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/template/XsmpcatCrossReferenceTemplateVariableResolver.java b/org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/template/XsmpcatCrossReferenceTemplateVariableResolver.java index b75e7632..eb5abbf4 100644 --- a/org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/template/XsmpcatCrossReferenceTemplateVariableResolver.java +++ b/org.eclipse.xsmp.ui/src/org/eclipse/xsmp/ui/template/XsmpcatCrossReferenceTemplateVariableResolver.java @@ -19,7 +19,7 @@ import org.apache.log4j.Logger; import org.eclipse.emf.ecore.EObject; import org.eclipse.jface.text.templates.TemplateVariable; -import org.eclipse.xsmp.ui.contentassist.IReferenceFilter; +import org.eclipse.xsmp.ide.contentassist.IReferenceFilter; import org.eclipse.xsmp.util.QualifiedNames; import org.eclipse.xsmp.xcatalogue.PrimitiveType; import org.eclipse.xtext.naming.IQualifiedNameConverter; diff --git a/org.eclipse.xsmp.vscode_extension/.classpath b/org.eclipse.xsmp.vscode_extension/.classpath new file mode 100644 index 00000000..fe1a2053 --- /dev/null +++ b/org.eclipse.xsmp.vscode_extension/.classpath @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/org.eclipse.xsmp.vscode_extension/.gitignore b/org.eclipse.xsmp.vscode_extension/.gitignore new file mode 100644 index 00000000..a88ef41e --- /dev/null +++ b/org.eclipse.xsmp.vscode_extension/.gitignore @@ -0,0 +1,4 @@ +package-lock.json +*.vsix + +node_modules/ \ No newline at end of file diff --git a/org.eclipse.xsmp.vscode_extension/.project b/org.eclipse.xsmp.vscode_extension/.project new file mode 100644 index 00000000..ce8fcbcd --- /dev/null +++ b/org.eclipse.xsmp.vscode_extension/.project @@ -0,0 +1,34 @@ + + + org.eclipse.xsmp.vscode_extension + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.m2e.core.maven2Nature + org.eclipse.jdt.core.javanature + org.eclipse.pde.PluginNature + + diff --git a/org.eclipse.xsmp.vscode_extension/.settings/org.eclipse.core.resources.prefs b/org.eclipse.xsmp.vscode_extension/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 00000000..99f26c02 --- /dev/null +++ b/org.eclipse.xsmp.vscode_extension/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/org.eclipse.xsmp.vscode_extension/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.xsmp.vscode_extension/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..9478cb16 --- /dev/null +++ b/org.eclipse.xsmp.vscode_extension/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,15 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=17 diff --git a/org.eclipse.xsmp.vscode_extension/.settings/org.eclipse.xtend.core.Xtend.prefs b/org.eclipse.xsmp.vscode_extension/.settings/org.eclipse.xtend.core.Xtend.prefs new file mode 100644 index 00000000..680a0f30 --- /dev/null +++ b/org.eclipse.xsmp.vscode_extension/.settings/org.eclipse.xtend.core.Xtend.prefs @@ -0,0 +1,5 @@ +BuilderConfiguration.is_project_specific=true +eclipse.preferences.version=1 +outlet.DEFAULT_OUTPUT.hideLocalSyntheticVariables=true +outlet.DEFAULT_OUTPUT.installDslAsPrimarySource=false +outlet.DEFAULT_OUTPUT.userOutputPerSourceFolder=true \ No newline at end of file diff --git a/org.eclipse.xsmp.vscode_extension/.vscodeignore b/org.eclipse.xsmp.vscode_extension/.vscodeignore new file mode 100644 index 00000000..3c8969c9 --- /dev/null +++ b/org.eclipse.xsmp.vscode_extension/.vscodeignore @@ -0,0 +1,9 @@ +.classpath +.project +.gitignore +package.json +package-lock.json +build.properties + +.settings/ +META-INF/ \ No newline at end of file diff --git a/org.eclipse.xsmp.vscode_extension/META-INF/MANIFEST.MF b/org.eclipse.xsmp.vscode_extension/META-INF/MANIFEST.MF new file mode 100644 index 00000000..5a86285f --- /dev/null +++ b/org.eclipse.xsmp.vscode_extension/META-INF/MANIFEST.MF @@ -0,0 +1,9 @@ +Manifest-Version: 1.0 +Automatic-Module-Name: org.eclipse.xsmp.vscode_extension +Bundle-ManifestVersion: 2 +Bundle-Name: org.eclipse.xsmp.vscode_extension +Bundle-Vendor: Thales Alenia Space +Bundle-Version: 1.1.0.qualifier +Bundle-SymbolicName: org.eclipse.xsmp.vscode_extension;singleton:=true +Bundle-ActivationPolicy: lazy +Bundle-RequiredExecutionEnvironment: JavaSE-17 diff --git a/org.eclipse.xsmp.vscode_extension/build.properties b/org.eclipse.xsmp.vscode_extension/build.properties new file mode 100644 index 00000000..ecaa4534 --- /dev/null +++ b/org.eclipse.xsmp.vscode_extension/build.properties @@ -0,0 +1,3 @@ +bin.includes = .,\ + META-INF/ +source.. = src/ \ No newline at end of file diff --git a/org.eclipse.xsmp.vscode_extension/images/xsmp.png b/org.eclipse.xsmp.vscode_extension/images/xsmp.png new file mode 100644 index 0000000000000000000000000000000000000000..036455397882b249f18a807a375905964a4059ec GIT binary patch literal 7063 zcmd6M_d6S2^nXz^Mypn0v^834?@f!?v?zkm*t3YeHPuopsz%J9sz!pK)Lzk`W~*Ya z#wgmNsy3gzKi|LL`_uP(e!0(cpZlEGx#yhMIrls_@sX(>69b6h%9Sfj2KqYYSFTV( zu3VuIqq|DpX_TYpB`=gtMtV9|E)&v*yRKZ}eq^BY;BnaOuLbvKY~WtPo+j{d@4W~2 zUr>S9RvDA8QoUzqXQ#Ho1CiRF`~#lR{(0+eia}G{z$zDagRbxXl`4MjKCQa<`m81? zB8d+0>McKRht|y@qz7Gt-h8Y+R;y7jYi}=qE;VUkPtE`Tqrk_}Gwt4w-Rdo{UJl86 zOx_m~{gtKQH!BKNj6)W6RfjJL2WXS0!43K{a!%=cWlNe0jTcPbOxx|q(Jhzs)gPa9 z@yVCmdHpU*NAd6hhc}rTWAG5dWq=&NYE2hKdwY+ifnIc+lzCwkA*1) z*XaNG`@szY$^V#&56)4s63q3LMj{5&iTkXih)%G0Fh<`z;UyrY6b5r?{5hN{HJ5q==51m16x1M!*J84_{d_ zStY8;P4pD!{g%joOuE8?@69gxRv~dI!~6yC4Z(lBrb`M7Q^-7lx{`%x3+GtL5A&&fi<^Z^Jv_>K7%Z zHwKp+SD>T{C3T!F8z^?dPFpoNPya%OB{_?N3BVoJj0&kyF&6Bycjw_8qYXG?C6T(Y zqpV+WyPAY_c>Io@Vyv-;d|O3>j!P`r%ED;%delJ+4W?A*>as0qI_LW~{L(FI9`((D zzurcjWxsgz@2?74P_1-VQqz{;b%VLFFbKrJ`w4RT)hEL3W7^=?uO5e{!lT-M4DAs> zH~sQd^mLl|I7X$BuNwk1Z2c5~EVOeKfjTbU>nyjd*SYxTEUr5#CF%3$O76+Xmy_nX z|Lj`muqun4Nxk4+(c@yFwLS@od!obYd6VSm*kr*3+P8TjyA2jJtC2%yY}#~Oo)dO1 zwY2P-n>1YbV=9NbQUzRJZ-nkRpDl_~Imk&dKHbFA{f6=T;a=BPxbSjUI#F#yMy!XO zIV{3oVU$s&Gli`uM~Ptvs^su`rQv(;MDfKPe0)xPwg~O<#wut`1=);IIxMT4(0*VH z5~Ts5O0|3&?bW{h!eP_u)g#xTA*H6)+--PC8z`iDPq&wcBbz&PRJmq{ICj+0 zS@sfKEtlC?Vo$jlVC;d~UMN}cU&?9jo;|bQR>%`E?5+Q}hZ}#Yn9qAW+nkYH?O9Y9 zCjA%3pop`25hQRNkakcngsZA>%0Fmh}fP%RSk1w!4m886<^2u7uhm4};{t%L#O( zd-L54F$%;Gn_-6rXFU}i{jnT`nT#T_46d!18;{_tI=|n z(+1IzX{5@xQu^v2eLV%e{=dHmvn*-jnXtv~&V^av!k>)Tdqj(O_vsxtNfhIuKW#}_ z)ey(|-1BOW@6#_j@WsE(N9lT+l)*V?|C|o8P07ymEk#8iHF9)>dtma< z$f&#Hu^rWG&A>s;To)7A(~#GD%l{Idaj?7rNysCMtShOF*9XR7o5{vFqr%X;I2;D`d)THv=J&8 zqUi5J*En5xsw9W&RuTR-15w@Wz<)tg8c_j2G7HNVnx=5p`1H=p;nN)XjSEhc>@kLV zW0?ao`tX2SntMA9DZl9qhdmHjl*#$?6#{2%pKT|3L(iw)ep0;1-81HZ)FEC(!t6P| z`-qhfodCS-cp>9SuJnry-S;B7SO6xU;lzSaXB0hCh;d{vi`Yh1~Vo|Q3>KI+no|)-=_@pVam1Vn}h8LrCHL_cdYDBDx&|CA8e^65>36g_q+L53T{VZ@7+Q9a;nqP3Eo5-l$8733+5o*CGJU`E5u z34zKo4-k_Bdz=oM?#}EjH5j)@*vd)JfE3sOA~C33!}sB5imYEGQSJePy6pBaA#eF; z+a{y$DslIPSb63v#}zEk)Ds`48DQ<_BSFDL2CM^OjNtYCh&THAmrz?(N=)34hzz>#+L$uEfjF)q$=AFKf~txC=m3Og|9 zBZwx#F&n(vd63AOK!LgUx2w9h_y&BiZb+6fO*bwd1!`hqV#F*yK%KW}J5-{Ki2fyq zYJ)J5QIvkuW(@gY0jWD1g12#|p)GvOmMJe3d7wFy@8Si-)t6XN`>jd{M6l<}g%$reu=p7XGN0Tx3S*!k$%#GlT$f{e6lQar|}IdQd}f5^}v zuTgUl_c&jS*;S5tQW$!1XGWdWEHclW$cPoa@j<7#vB^1+1(WK#dLJ-$4#YQ{rtkek zz3$#xKbjIy=Zm}>6B1Ug7jv-llm%;Bqi8y6U2t{B^yc@fq)9DJ>m z-~GH&W0=s2hrcm8y-GtwN9~*#D48Kxv5UYd`LP+mLhKYFPTmz8#xLPiz0tpEfGVQ;yLRbnsKNBF^Z`8XGXX z<{n63^IBVXKqnBU!o5wMFcph(WT-1dG)fi$|Nf1by=VSBC}+>#pMH*_k@pZh(*$*O zjQqBD9^)_q92f8eV!CHF%V!|ske%JF1ex~Fo!wRaPk1--W;#-F!T6qsDG6~2?;IKu zNLo+lF8uaYMeST45xcnZGK+HAx@A!_G#pWxcptG1uobg`F-#sNRRsF?tLoW>>YL2S zRLKTaOvjcv$@)CG)vC#ec9Bl1zN+H8`Uyc0r@Jb}y)Dr1M-se++X@s6ZBbi?HbCF$ z(|^6rmk?(cZ?XdnU2!EgjaKR&iUk0w9i-{RHXIA*$XF|@PnfBTiy3I-juE%zVqvV81kslx!|*t{e}tH!->!(-r@Vqb;t24hw)&50&xLZ zgt8}V=|PP}ZyCU)Brq$mSy#SJz3H=JE%l3m1VqeuSINUZM6kIPncL+$!~T`ttW@6B z{r$Opr2-8+%e4f~y&8@H<=Q*&=KmGgplN%7ep!N@e;$!2t>bnCRDg`FUt!p8k*le0% zVhgKo3NR4DWUkBc7`J^rvUj_?9^&$}RXTnuWoIQ9mFsiU2KI{-u0R|`Ci7`5+fKPq z6ZL+Q9|~6K4~_Vy_WeWMA-%IW4RtPp&b_E8=KURIW6D8soc~V)a>Pq{(t=?Q)I|KO zFaOcX^4EfdIL}iRiAVLnEP@MJXVE6gDc99Tp`<2%i8LJ!2wrWJ5HOn*oc_Q*gB7x` zWK3?qv{69j_x9V40~Vqy;&ZQm7mS?`k2p&A1@bds*U@gy!DF6_@X+&&_#ZLy5{8rACL14a_ck=no0I9qp^e z^YiHu`XxcTq!CeLeNC?rNKy(5xK|5igPf+U2>+(#k>ajl>cg4Z@zJBevK??v^NkUtBp z3^|&g@IIwymT7Y-vp>r8DFOXV*s3uCh!mEIW)RyOs-s|{odAKv#)>53{wf3~EiC-Rwa?A;{+z|;QaRAsmWA1X=@K*%6=+E=+xk1lC-WU zu1_+JMuiNxa3n0b9v-XqJrZzy1G1Y!?rNv-S+$R;ltyQ8Xg9v+gRYo@##dnYf`G}< zY+1CGE*qrZo&1=6C9g4``xs_GSXqvxy2<>W*Xc}n*U)zDxKQjP$E^CB?kW;j*~Bwh zo;3d|vaY=_VSJC=zDYfLWZS`WS;=H#PSCiE3gA0JX1irVEavZrJQSr7PvNz%{!&j> zNzv~xN%J&ri`v`nlWJ1i{Mu2&=V)PCplLeb1&BK6&^1N*IygmHqQ=URNszAbE; z@)~~(!sj)UWtxVu1C*F<66JU)8{|zJuYIh_VXTse%KVIZr(1vfuM%shm3`7ZT=B3r z^l5P;rBT44iy+xOr>SWdVT=F9Er4^bjxP|CQ`#_-!>C0Du^EB^Uwqsgt$);h86`$Z z;^C?A{+7#4JuXOa%EoWkMITFqkZy=m?w4Hi;dbLgyb2en3Iz3$H#e^q)xpW za2r%P?I^4Rzt;glc5BSK*ze&4r&g8~(^+UIhHthx7?RqzEB$1f1{SW<5~*oA6cjQ0 zRxktk3}qQnbP6mN((AT8ZP$Ia^;rU5RSA`IwE75TGt~_Pd<1N1dvD zw(7tkTd=n^>Mp(J;X%NN1kS4=lL=@TOP#&?R>_T=B9aZg5ebW4Uwl+FM$3fIuO7gt z!3d%I0MwJhw_MEc3w?OXj6B!^7Wmd^@?J&_M?(+cJlJk?n9!VT9bZ`PWk`7B)n8VF zKdv1fE-VI@|146|tDrPOxMo>6tML52IQJ9i;HN*S1%flKA+7tDyRrv0p42diQCnd@ zr0n^RN4}FNcGOuiwhnCA_+;L`D4h=*r|cKTu|W*}VcEOzxl{Fmy(NFg)CdnKcrnU; zTm{j}jcgDG?5fJbn_N@!;MguaPjP+eG{4_}3B~c#ui0bhOXvSV@X6`#zQdf{T+^k9 zB&Ib$n)=56o5a0Aal*T6!Y_>#)%F!Bo1yGvZPQ_kRi3#PDc+IxtBA%H?1pRnSE230 z+WspJ3L4vuLFO(~XkO3a?zC|aeA2+O$`kDmzZJv!Z44{*4J z!jP}e4p43Qnn&(rGX%~Zo~=*9xF+K^$iT#W?<3Q<+-+a7DM4SK5q|2>w!+0W0!1y3 zdiQ_FSQ^v)2(Tn0IrT(63x1g5rM}Qiv?fU5o{L@%+%EoKJ5`6i249=4pT#Y1Z{{f? z4)|18{W<<~=Wy;4Q_>ij%eXyPDBlr&aE}fvqO1XWM~>B}`D80*ayrH;a%a#YLHGTmq}tZ zcTU*u{D+oe(hxx=N!6ZB3S+xOq`!QiHZx{wbH(obf2{;%zP9|TiX-l-5x*#Bg3jYt z+Iu7sdXsl9M$I~jP()dGQe_jFtqJ{SPzjmNKKHdKyIH6#jTBOd;^m}uX4pJTi+rd) z=lH`=q;sr9V@kH&pj(lK=7$X*!rpc6=%lKa`TJ>N*+?_8yL3|I*Zt%7uif0$=8(1= z}U^eMzPDvte`i%kfrI@TYUTYzSm@N8COHtXXtlUg% zQ9y;1uu-L)*t+V@8SD&Q1e}CFNZrq~Ar)XgetH4=6%?7OfL&}tee*aRQJ20oDcfP8 zJ}ERAC~l!{V|UXl(UyuqxR{D}CRvL?`8hwbG{FRx{X4{Gt8xe62+V2chA5k;$PUiw+IV1CcP%gUT?Z%;y|qk+S&*^or7XUl?8K zHq4Es`_1~UvzZS#1iho8W*fiH>7?PQPto=@Q7gh+M>9zo1ptm%X8KDWTId36rQ#Gt z$_s=Z?+Rr-K4}`PNHYBGDvh}3NkPD(3r+1KUEpD$q!9Fzhr}v0X;bgIy2v|$ zU&6&Dl(+csmCQd)B$01(0=WpTm43<(&9gyA!{yJ}v0wD;g?5HOR_{8uM_g!J)pAcl z6yqHk-{+M67+m}?g;PNJfqzXW;DO!BDXY2!=|tO+v;)An9L z0-Q=fIe~(Qpz&eiW8(;DBI`zTj(2m~M(!v6&IwvQuu%M(Du;CPMoSvz_{QDwEW+`1 zbMYTTlWN+^qJO0ynbkF8iwoSF^E%}oxEvR=H|iWOnL|d8^+#!EFd_#_J5o_qQ~EyUV`?L<4)-=fOZfnIgkz#>bDHAXYL( zin+t~(4KG}BTmq!wf3`ca0{T@;LfQ`RGV-)HIxJFCbZJyU+X%bw*kp72Phc8KQQ zaT3G&E`@B4DKPEP=Mm_bhs1ZW6APW&g`OFb7Hr>Zn5jR!7dRbHQu5_NLaLEgJ<{y}s$up5kTKgpf z^`q7thI>bX2aun(_A!ZQ+m;rTX328~j&co(28*IsB9#vZ;xc8BtcK0czoaqnA|$jD`$>BFC?QXj?R%G429ecg-}vuDTO{Y5l@PSV>2 znGuK(C0FxCAxku-Zu&D81gINUv~71CGQ8pY$ww&3Bz~u99v8CjT`++KZJhcvX6HOE zO(hULx`r@~KPx~_V?wI#p1hA(zrrBm()GBu(dghUpWXHUSCZIwNnw%;fc`WX;3WUF OT`>Tg>eOh#p8pTWG)XJ~ literal 0 HcmV?d00001 diff --git a/org.eclipse.xsmp.vscode_extension/package.json b/org.eclipse.xsmp.vscode_extension/package.json new file mode 100644 index 00000000..c9f11b10 --- /dev/null +++ b/org.eclipse.xsmp.vscode_extension/package.json @@ -0,0 +1,63 @@ +{ + "name": "xsmp-modeler", + "displayName": "XSMP Modeler", + "description": "VSCode extension for XSMP Modeler", + "version": "1.1.0", + "publisher": "Thales Alenia Space", + "author": "Thales Alenia Space", + "icon": "images/xsmp.png", + "license": "EPL-2.0", + "repository": { + "type": "git", + "url": "https://github.com/ThalesGroup/xsmp-modeler-core.git" + }, + "bugs": { + "url": "https://github.com/ThalesGroup/xsmp-modeler-core/issues" + }, + "engines": { + "vscode": "^1.75.0" + }, + "categories": [ + "Programming Languages" + ], + "activationEvents": [ + "onLanguage:xsmpcat" + ], + "main": "target/extension", + "contributes": { + "languages": [ + { + "id": "xsmpcat", + "aliases": [ + "xsmpcat" + ], + "extensions": [ + ".xsmpcat" + ], + "configuration": "./xsmp.configuration.json" + } + ], + "grammars": [ + { + "language": "xsmpcat", + "scopeName": "source.xsmpcat", + "path": "./syntaxes/xsmp.tmLanguage.json" + } + ] + }, + "devDependencies": { + "@types/node": "^17.0.34", + "@types/vscode": "^1.67.0", + "typescript": "^4.6.4", + "@vscode/test-electron": "^2.1.3" + }, + "dependencies": { + "vscode-languageclient": "^8.0.1" + }, + "scripts": { + "prepublish": "tsc -p ./src", + "compile": "tsc -p ./src", + "watch": "tsc -w -p ./src", + "update-vscode": "node ./node_modules/vscode/bin/install" + } +} \ No newline at end of file diff --git a/org.eclipse.xsmp.vscode_extension/pom.xml b/org.eclipse.xsmp.vscode_extension/pom.xml new file mode 100644 index 00000000..00f59c0f --- /dev/null +++ b/org.eclipse.xsmp.vscode_extension/pom.xml @@ -0,0 +1,45 @@ + + 4.0.0 + + org.eclipse.xsmp + org.eclipse.xsmp.parent + 1.1.0-SNAPSHOT + + org.eclipse.xsmp.vscode_extension + eclipse-plugin + + + + + org.apache.maven.plugins + maven-resources-plugin + 3.2.0 + + + copy-jar + prepare-package + + copy-resources + + + + ${project.build.directory}/language-server + + + + ${project.basedir}/../org.eclipse.xsmp.ide/target + + + org.eclipse.xsmp.ide-ls.jar + + + + + + + + + + diff --git a/org.eclipse.xsmp.vscode_extension/src/extension.ts b/org.eclipse.xsmp.vscode_extension/src/extension.ts new file mode 100644 index 00000000..7bebf309 --- /dev/null +++ b/org.eclipse.xsmp.vscode_extension/src/extension.ts @@ -0,0 +1,53 @@ +/******************************************************************************* +* Copyright (C) 2023 THALES ALENIA SPACE FRANCE. +* +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License 2.0 +* which accompanies this distribution, and is available at +* https://www.eclipse.org/legal/epl-2.0/ +* +* SPDX-License-Identifier: EPL-2.0 +******************************************************************************/ +'use strict'; + +import * as path from 'path'; + +import { Trace } from 'vscode-jsonrpc'; +import { workspace, ExtensionContext } from 'vscode'; +import { LanguageClient, LanguageClientOptions, ServerOptions } from 'vscode-languageclient/node'; + +let lc: LanguageClient; + +export function activate(context: ExtensionContext) { + let launcher = 'org.eclipse.xsmp.ide-ls.jar'; + let script = context.asAbsolutePath(path.join('target', 'language-server', launcher)); + + let serverOptions: ServerOptions = { + run: { command: 'java', args: ['-jar', script] }, + debug: { command: 'java', args: ['-jar', script], options: { env: createDebugEnv() } } + }; + + let clientOptions: LanguageClientOptions = { + documentSelector: ['xsmpcat'], + synchronize: { + fileEvents: workspace.createFileSystemWatcher('**/*.*') + } + }; + + // Create the language client and start the client. + lc = new LanguageClient('Xtext Server', serverOptions, clientOptions); + + // enable tracing (.Off, .Messages, Verbose) + lc.setTrace(Trace.Verbose); + lc.start(); +} + +export function deactivate() { + return lc.stop(); +} + +function createDebugEnv() { + return Object.assign({ + JAVA_OPTS: "-Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n,quiet=y" + }, process.env) +} \ No newline at end of file diff --git a/org.eclipse.xsmp.vscode_extension/src/tsconfig.json b/org.eclipse.xsmp.vscode_extension/src/tsconfig.json new file mode 100644 index 00000000..f3e002e3 --- /dev/null +++ b/org.eclipse.xsmp.vscode_extension/src/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "es6", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": false, + "inlineSources": false, + "declaration": true, + "stripInternal": true, + "lib": [ "es6" ], + "outDir": "../target" + } +} \ No newline at end of file diff --git a/org.eclipse.xsmp.vscode_extension/syntaxes/xsmp.tmLanguage.json b/org.eclipse.xsmp.vscode_extension/syntaxes/xsmp.tmLanguage.json new file mode 100644 index 00000000..6ec063ba --- /dev/null +++ b/org.eclipse.xsmp.vscode_extension/syntaxes/xsmp.tmLanguage.json @@ -0,0 +1,57 @@ +{ + "name": "Xsmpcat", + "scopeName": "source.xsmpcat", + "fileTypes": [ + "xsmpcat" + ], + "repository": { + "general": { + "patterns": [ + { + "include": "#linecomment" + }, + { + "include": "#blockcomment" + }, + { + "include": "#blockcommentdocumentation" + }, + { + "include": "#keyword" + }, + { + "include": "#keyword_operators" + } + ] + }, + "linecomment": { + "name": "comment.line.double-dash.xsmpcat", + "begin": "(^[ \\t]+)?(?=//)", + "end": "(?=$)" + }, + "blockcomment": { + "name": "comment.block.xsmpcat", + "begin": "/\\*(?!\\*)", + "end": "\\*/" + }, + "blockcommentdocumentation": { + "name": "comment.block.documentation.xsmpcat", + "begin": "/\\*\\*", + "end": "\\*/" + }, + "keyword": { + "name": "keyword.control.xsmpcat", + "match": "\\b(catalogue|model|struct|exception|container|writeOnly|constant|def|integer|float|eventsink|eventsource|reference|output|protected|entrypoint|property|using|void|readOnly|throws|enum|input|extends|field|transient|true|false|abstract|inout|service|namespace|array|native|get|readWrite|attribute|event|class|set|string|primitive|association|interface|out|public|private|import)\\b" + }, + "keyword_operators": { + "name": "keyword.operator.xsmpcat", + "match": "\\b(\\|\\||<<|<=|>=|==|!=|<|>|&&|->|\\[|\\]|\\{|\\}|\\.|~|\\$|%|\\(|\\)|\\*|\\+|,|-|/|@|\\?|\\^)\\b" + } + }, + "patterns": [ + { + "include": "#general" + } + ], + "uuid": "8383e49a-fa0d-4bb5-827b-10e8abb294ca" +} \ No newline at end of file diff --git a/org.eclipse.xsmp.vscode_extension/xsmp.configuration.json b/org.eclipse.xsmp.vscode_extension/xsmp.configuration.json new file mode 100644 index 00000000..b284b965 --- /dev/null +++ b/org.eclipse.xsmp.vscode_extension/xsmp.configuration.json @@ -0,0 +1,27 @@ +{ + "comments": { + "lineComment": "//", + "blockComment": [ "/*", "*/" ], + "blockCommentDocumentation": [ "/**", "*/" ] + }, + "brackets": [ + ["{", "}"], + ["[", "]"], + ["(", ")"] + ], + "autoClosingPairs": [ + ["{", "}"], + ["[", "]"], + ["(", ")"], + ["\"", "\""], + ["'", "'"], + ["/*", "*/"] + ], + "surroundingPairs": [ + ["{", "}"], + ["[", "]"], + ["(", ")"], + ["\"", "\""], + ["'", "'"] + ] +} \ No newline at end of file diff --git a/org.eclipse.xsmp/.classpath b/org.eclipse.xsmp/.classpath index 8c10dd05..494814cc 100644 --- a/org.eclipse.xsmp/.classpath +++ b/org.eclipse.xsmp/.classpath @@ -14,7 +14,6 @@ - diff --git a/org.eclipse.xsmp/build.properties b/org.eclipse.xsmp/build.properties index b7115e2d..18a5646e 100644 --- a/org.eclipse.xsmp/build.properties +++ b/org.eclipse.xsmp/build.properties @@ -9,7 +9,6 @@ jars.compile.order = . source.. = emf-gen/,\ src/,\ src-gen/,\ - xtend-gen/,\ target/generated-sources/java-templates/ additional.bundles = org.eclipse.xtext.common.types,\ org.eclipse.xtext.xtext.generator,\ diff --git a/org.eclipse.xsmp/src/org/eclipse/xsmp/XsmpcatExtensionRuntimeModule.java b/org.eclipse.xsmp/src/org/eclipse/xsmp/XsmpcatExtensionRuntimeModule.java index a84769a0..0494ab12 100644 --- a/org.eclipse.xsmp/src/org/eclipse/xsmp/XsmpcatExtensionRuntimeModule.java +++ b/org.eclipse.xsmp/src/org/eclipse/xsmp/XsmpcatExtensionRuntimeModule.java @@ -21,6 +21,7 @@ import org.eclipse.xsmp.validation.XsmpcatIssueCodesProvider; import org.eclipse.xtext.conversion.IValueConverterService; import org.eclipse.xtext.documentation.IEObjectDocumentationProvider; +import org.eclipse.xtext.formatting.IIndentationInformation; import org.eclipse.xtext.generator.IOutputConfigurationProvider; import org.eclipse.xtext.naming.IQualifiedNameProvider; import org.eclipse.xtext.resource.IDefaultResourceDescriptionStrategy; @@ -53,6 +54,11 @@ public void configureIScopeProviderDelegate(Binder binder) return XsmpcatValueConverterService.class; } + public Class< ? extends IIndentationInformation> bindIIndentationInformation() + { + return org.eclipse.xsmp.formatting2.XsmpcatFormatter.IndentationInformation.class; + } + /** * @return the IEObjectDocumentationProvider class */ diff --git a/org.eclipse.xsmp/src/org/eclipse/xsmp/formatting2/XsmpcatFormatter.java b/org.eclipse.xsmp/src/org/eclipse/xsmp/formatting2/XsmpcatFormatter.java index 8b4d8033..20a92446 100644 --- a/org.eclipse.xsmp/src/org/eclipse/xsmp/formatting2/XsmpcatFormatter.java +++ b/org.eclipse.xsmp/src/org/eclipse/xsmp/formatting2/XsmpcatFormatter.java @@ -88,6 +88,7 @@ import org.eclipse.xsmp.xcatalogue.UnaryOperation; import org.eclipse.xsmp.xcatalogue.ValueReference; import org.eclipse.xtext.Keyword; +import org.eclipse.xtext.formatting.IIndentationInformation; import org.eclipse.xtext.formatting2.AbstractJavaFormatter; import org.eclipse.xtext.formatting2.IFormattableDocument; import org.eclipse.xtext.formatting2.ITextReplacer; @@ -108,6 +109,15 @@ @SuppressWarnings("restriction") public class XsmpcatFormatter extends AbstractJavaFormatter { + public static class IndentationInformation implements IIndentationInformation + { + @Override + public java.lang.String getIndentString() + { + return " "; + } + } + @Inject private XsmpcatGrammarAccess ga; diff --git a/org.eclipse.xsmp/src/org/eclipse/xsmp/util/XsmpUtil.java b/org.eclipse.xsmp/src/org/eclipse/xsmp/util/XsmpUtil.java index ee6e8ce8..375101dc 100644 --- a/org.eclipse.xsmp/src/org/eclipse/xsmp/util/XsmpUtil.java +++ b/org.eclipse.xsmp/src/org/eclipse/xsmp/util/XsmpUtil.java @@ -318,30 +318,24 @@ protected boolean isBaseOf(EObject base, Interface derived) protected boolean isBaseOf(EObject base, Model derived) { - final var baseFqn = fqn(base); - - return QualifiedNames.Smp_IModel.equals(baseFqn) || isBaseOf(base, (Component) derived); + return QualifiedNames.Smp_IModel.equals(fqn(base)) || isBaseOf(base, (Component) derived); } protected boolean isBaseOf(EObject base, Service derived) { - final var baseFqn = fqn(base); - - return QualifiedNames.Smp_IService.equals(baseFqn) || isBaseOf(base, (Component) derived); + return QualifiedNames.Smp_IService.equals(fqn(base)) || isBaseOf(base, (Component) derived); } protected boolean isBaseOf(EObject base, Component derived) { - final var baseFqn = fqn(base); - - return base == derived || QualifiedNames.Smp_IComponent.equals(baseFqn) - || isBaseOf(base, derived.getBase()) + return base == derived || QualifiedNames.Smp_IComponent.equals(fqn(base)) + || derived.getBase() != null && isBaseOf(base, derived.getBase()) || derived.getInterface().stream().anyMatch(b -> isBaseOf(base, b)); } protected boolean isBaseOf(EObject base, Class derived) { - return base == derived || isBaseOf(base, derived.getBase()); + return base == derived || derived.getBase() != null && isBaseOf(base, derived.getBase()); } public VisibilityKind getMinVisibility(Type type, EObject from) @@ -776,14 +770,13 @@ public boolean isSimpleArray(Array o) public boolean isConst(Parameter o) { final var id = QualifiedNames.Attributes_Const; - return cache.get(Tuples.pair(o, id), o.eResource(), () -> attributeBoolValue(o, id, () -> { - return switch (o.getDirection()) - { - case IN -> !(o.getType() instanceof ValueType); - case RETURN, OUT, INOUT -> false; - default -> false; - }; - })); + return cache.get(Tuples.pair(o, id), o.eResource(), + () -> attributeBoolValue(o, id, () -> switch (o.getDirection()) + { + case IN -> !(o.getType() instanceof ValueType); + case RETURN, OUT, INOUT -> false; + default -> false; + })); } @@ -823,7 +816,7 @@ public List getAssignableFields(Structure structure) .map(Field.class::cast) .filter(it -> getVisibility(it) == VisibilityKind.PUBLIC && !isStatic(it)) .collect(Collectors.toList()); - if (structure instanceof org.eclipse.xsmp.xcatalogue.Class clazz) + if (structure instanceof final org.eclipse.xsmp.xcatalogue.Class clazz) { final var base = clazz.getBase(); if (base instanceof Structure && !isBaseOf(base, clazz)) @@ -843,7 +836,7 @@ public Iterable getFields(Structure structure) final var fields = Iterables.filter(Iterables.filter(structure.getMember(), Field.class), it -> !isStatic(it)); - if (structure instanceof org.eclipse.xsmp.xcatalogue.Class clazz) + if (structure instanceof final org.eclipse.xsmp.xcatalogue.Class clazz) { final var base = clazz.getBase(); if (base instanceof Structure && !isBaseOf(base, clazz)) @@ -943,7 +936,8 @@ private Type findType(EObject parent) case XcataloguePackage.CONSTANT -> ((Constant) parent).getType(); case XcataloguePackage.ASSOCIATION -> ((Association) parent).getType(); case XcataloguePackage.PARAMETER -> ((Parameter) parent).getType(); - case XcataloguePackage.STRING, XcataloguePackage.ARRAY, XcataloguePackage.MULTIPLICITY -> findPrimitiveType(parent, QualifiedNames.Smp_Int64); + case XcataloguePackage.STRING, XcataloguePackage.ARRAY, XcataloguePackage.MULTIPLICITY -> findPrimitiveType( + parent, QualifiedNames.Smp_Int64); case XcataloguePackage.FLOAT -> { final var type = ((Float) parent).getPrimitiveType(); @@ -954,7 +948,8 @@ private Type findType(EObject parent) final var type = ((org.eclipse.xsmp.xcatalogue.Integer) parent).getPrimitiveType(); yield type != null ? type : findPrimitiveType(parent, QualifiedNames.Smp_Int32); } - case XcataloguePackage.ENUMERATION_LITERAL -> findPrimitiveType(parent, QualifiedNames.Smp_Int32); + case XcataloguePackage.ENUMERATION_LITERAL -> findPrimitiveType(parent, + QualifiedNames.Smp_Int32); case XcataloguePackage.ENUMERATION -> (Type) parent; case XcataloguePackage.ATTRIBUTE -> { diff --git a/pom.xml b/pom.xml index ad9df366..7d91852c 100644 --- a/pom.xml +++ b/pom.xml @@ -32,6 +32,7 @@ org.eclipse.xsmp.lib org.eclipse.xsmp.forms org.eclipse.xsmp.ide + org.eclipse.xsmp.ide.tests org.eclipse.xsmp.design org.eclipse.xsmp.ui org.eclipse.xsmp.ui.tests @@ -48,6 +49,7 @@ org.eclipse.xsmp.profile.simsat.cli org.eclipse.xsmp.profile.simsat.feature org.eclipse.xsmp.profile.simsat.ui + org.eclipse.xsmp.vscode_extension