From e36d0cb0313ea18c76479e8dbfaf8499fa52db98 Mon Sep 17 00:00:00 2001 From: Tuukka Lehtonen Date: Sat, 26 Aug 2017 00:38:28 +0300 Subject: [PATCH] Support for SCL script database storage, editing and execution * Ontology for defining an SCL script in the database (L0.SCLScript) * A text editor for L0.SCLScripts: ** Basic syntax highlighting (same as in SCL Module editor) ** Script validation ** Easy script execution directly from the editor (CTRL+R) * View scripts in model browser under L0.Library instances * Script execution from Model Browser context menu refs #7450 Change-Id: I57016492589b6a9b693d926a56a3d0fe7b317023 --- .../graph/Layer0SCL.pgraph | 4 + .../graph/Modeling.pgraph | 2 + .../graph/ModelingViewpoint.pgraph | 20 +++ .../org.simantics.modeling.ui/adapters.xml | 3 + bundles/org.simantics.modeling.ui/plugin.xml | 64 ++++++++++ .../simantics/modeling/ui/scl/SCLScripts.java | 94 ++++++++++++++ .../scriptEditor/ReadSCLScriptDefinition.java | 43 +++++++ .../scl/scriptEditor/ReadSCLScriptSource.java | 35 ++++++ .../RunSCLScriptActionFactory.java | 69 +++++++++++ .../scl/scriptEditor/RunSCLScriptHandler.java | 82 +++++++++++++ .../SCLScriptAnnotationModel.java | 116 ++++++++++++++++++ .../ui/scl/scriptEditor/SCLScriptEditor.java | 36 ++++++ .../scriptEditor/SCLScriptEditorAdapter.java | 87 +++++++++++++ .../SCLScriptEditorDocumentProvider.java | 112 +++++++++++++++++ .../scriptEditor/SCLScriptEditorInput.java | 114 +++++++++++++++++ .../SCLScriptEditorInputFactory.java | 29 +++++ .../ui/scl/scriptEditor/SCLScriptSource.java | 55 +++++++++ .../WriteSCLScriptDefinition.java | 46 +++++++ .../scl/Simantics/SCL.scl | 12 +- .../org/simantics/modeling/ModelingUtils.java | 15 +++ bundles/org.simantics.scl.ui/plugin.xml | 9 ++ .../simantics/scl/ui/console/SCLConsole.java | 5 + .../scl/ui/console/SCLConsoleView.java | 12 ++ 23 files changed, 1058 insertions(+), 6 deletions(-) create mode 100644 bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/SCLScripts.java create mode 100644 bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/ReadSCLScriptDefinition.java create mode 100644 bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/ReadSCLScriptSource.java create mode 100644 bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/RunSCLScriptActionFactory.java create mode 100644 bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/RunSCLScriptHandler.java create mode 100644 bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptAnnotationModel.java create mode 100644 bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptEditor.java create mode 100644 bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptEditorAdapter.java create mode 100644 bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptEditorDocumentProvider.java create mode 100644 bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptEditorInput.java create mode 100644 bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptEditorInputFactory.java create mode 100644 bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptSource.java create mode 100644 bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/WriteSCLScriptDefinition.java diff --git a/bundles/org.simantics.layer0/graph/Layer0SCL.pgraph b/bundles/org.simantics.layer0/graph/Layer0SCL.pgraph index 526139c0d..783f4f401 100644 --- a/bundles/org.simantics.layer0/graph/Layer0SCL.pgraph +++ b/bundles/org.simantics.layer0/graph/Layer0SCL.pgraph @@ -57,6 +57,10 @@ L0.SCLModule -- L0.SCLModule.definition --> L0.String -- L0.SCLScript.definition --> L0.String -- L0.Ontology.defaultLocalName --> L0.String + diff --git a/bundles/org.simantics.modeling.ui/plugin.xml b/bundles/org.simantics.modeling.ui/plugin.xml index 7a29cd786..41bf9eccc 100644 --- a/bundles/org.simantics.modeling.ui/plugin.xml +++ b/bundles/org.simantics.modeling.ui/plugin.xml @@ -146,6 +146,20 @@ class="org.simantics.modeling.ui.componentTypeEditor.ComponentTypeScriptEditor" id="org.simantics.modeling.ui.componentTypeScriptEditor"> + + + + + + @@ -184,6 +198,15 @@ + + + + + + @@ -377,6 +400,11 @@ categoryId="org.simantics.modeling.ui.category" id="org.simantics.modeling.typical.sync.toggleRealtime"> + + @@ -962,6 +990,15 @@ commandId="org.simantics.modeling.typical.sync.toggleRealtime" class="org.simantics.modeling.ui.typicals.ToggleTypicalRealtimeSync"> + + + + + + @@ -1001,6 +1038,12 @@ schemeId="org.eclipse.ui.defaultAcceleratorConfiguration" sequence="F1"> + + @@ -1439,6 +1482,17 @@ id="org.simantics.modeling.ui.elementtoolbar"> --> + + + + @@ -1462,6 +1516,11 @@ id="org.simantics.ui.undoContext" parentId="org.eclipse.ui.contexts.window"> + + @@ -1559,6 +1618,11 @@ id="org.simantics.modeling.ui.sclModuleEditor2" priority="10"> + + diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/SCLScripts.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/SCLScripts.java new file mode 100644 index 000000000..350a819fd --- /dev/null +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/SCLScripts.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright (c) 2017 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.modeling.ui.scl; + +import java.io.StringReader; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.PartInitException; +import org.simantics.db.RequestProcessor; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.scl.compiler.commands.CommandSession; +import org.simantics.scl.osgi.SCLOsgi; +import org.simantics.scl.runtime.reporting.SCLReportingHandler; +import org.simantics.utils.datastructures.Pair; +import org.simantics.utils.ui.workbench.WorkbenchUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Tuukka Lehtonen + * @since 1.31.0 + */ +public class SCLScripts { + + private static final Logger LOGGER = LoggerFactory.getLogger(SCLScripts.class); + + private static final String SCL_CONSOLE_ID = "org.simantics.scl.ui.console"; + + /** + * @param processor database handle + * @param script the script to validate + * @return null if ok to run script, otherwise a problem description + * @throws DatabaseException + */ + public static String canRunScript(RequestProcessor processor, final Resource script) throws DatabaseException { + return null; + } + + public static void runScriptWithProgress(String scriptName, String scriptText, CommandSession session, SCLReportingHandler handler) { + Job job = new Job("Run SCL Script") { + @Override + protected IStatus run(IProgressMonitor monitor) { + runScriptWithProgress(monitor, scriptName, scriptText, session, handler); + return Status.OK_STATUS; + } + }; + job.setUser(true); + job.schedule(); + } + + public static void runScriptWithProgress(IProgressMonitor monitor, String scriptName, String scriptText, CommandSession session, SCLReportingHandler handler) { + monitor.beginTask(scriptName, IProgressMonitor.UNKNOWN); + try { + session.execute(new StringReader(scriptText), handler); + } finally { + monitor.done(); + } + } + + public static Pair getOrCreateConsoleCommandSession() { + return getSCLConsoleCommandSession(true); + } + + public static Pair getSCLConsoleCommandSession(boolean createIfNecessary) { + IWorkbenchPart part; + try { + part = createIfNecessary + ? WorkbenchUtils.showView(SCL_CONSOLE_ID, IWorkbenchPage.VIEW_VISIBLE) + : WorkbenchUtils.findView(SCL_CONSOLE_ID); + if (part != null) + return Pair.make(part.getAdapter(CommandSession.class), part.getAdapter(SCLReportingHandler.class)); + } catch (PartInitException e) { + LOGGER.error("Failed to open SCL Console view. Using new CommandSession, reporting to stdout via Logger.", e); + } + SCLReportingHandler handler = SCLReportingHandler.DEFAULT_WITHOUT_ECHO; + return Pair.make(new CommandSession(SCLOsgi.MODULE_REPOSITORY, handler), SCLReportingHandler.DEFAULT); + } + +} diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/ReadSCLScriptDefinition.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/ReadSCLScriptDefinition.java new file mode 100644 index 000000000..8e8ce6ee2 --- /dev/null +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/ReadSCLScriptDefinition.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2017 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.modeling.ui.scl.scriptEditor; + +import org.simantics.databoard.Bindings; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.request.UnaryRead; +import org.simantics.db.exception.DatabaseException; +import org.simantics.layer0.Layer0; +import org.simantics.utils.strings.StringUtils; + +/** + * @author Tuukka Lehtonen + * @since 1.31.0 + */ +public class ReadSCLScriptDefinition extends UnaryRead { + + public ReadSCLScriptDefinition(String scriptURI) { + super(scriptURI); + } + + @Override + public String perform(ReadGraph graph) throws DatabaseException { + Resource scriptResource = graph.getPossibleResource(parameter); + if (scriptResource == null) + return null; + Layer0 L0 = Layer0.getInstance(graph); + if (!graph.isInstanceOf(scriptResource, L0.SCLScript)) + return null; + return StringUtils.safeString( graph.getPossibleRelatedValue(scriptResource, L0.SCLScript_definition, Bindings.STRING) ); + } + +} \ No newline at end of file diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/ReadSCLScriptSource.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/ReadSCLScriptSource.java new file mode 100644 index 000000000..b475c916c --- /dev/null +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/ReadSCLScriptSource.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2017 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.modeling.ui.scl.scriptEditor; + +import org.simantics.db.ReadGraph; +import org.simantics.db.common.request.UnaryRead; +import org.simantics.db.exception.DatabaseException; + +/** + * @author Tuukka Lehtonen + * @since 1.31.0 + */ +class ReadSCLScriptSource extends UnaryRead { + + public ReadSCLScriptSource(String scriptURI) { + super(scriptURI); + } + + @Override + public SCLScriptSource perform(ReadGraph graph) throws DatabaseException { + return new SCLScriptSource( + parameter, + graph.syncRequest(new ReadSCLScriptDefinition(parameter))); + } + +} \ No newline at end of file diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/RunSCLScriptActionFactory.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/RunSCLScriptActionFactory.java new file mode 100644 index 000000000..6171e2185 --- /dev/null +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/RunSCLScriptActionFactory.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2017 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.modeling.ui.scl.scriptEditor; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.action.IStatusLineManager; +import org.eclipse.ui.IWorkbenchPart; +import org.simantics.Simantics; +import org.simantics.databoard.Bindings; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.db.common.primitiverequest.RelatedValue; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.adapter.ActionFactory; +import org.simantics.layer0.Layer0; +import org.simantics.modeling.ui.Activator; +import org.simantics.modeling.ui.scl.SCLScripts; +import org.simantics.scl.compiler.commands.CommandSession; +import org.simantics.scl.runtime.reporting.SCLReportingHandler; +import org.simantics.utils.datastructures.Pair; +import org.simantics.utils.ui.workbench.WorkbenchUtils; + +/** + * @author Tuukka Lehtonen + * @since 1.31.0 + */ +public class RunSCLScriptActionFactory implements ActionFactory { + + @Override + public Runnable create(Object target) { + if(!(target instanceof Resource)) + return null; + return () -> runScript((Resource) target); + } + + public static void runScript(Resource resource) { + try { + Session s = Simantics.getSession(); + Layer0 L0 = Layer0.getInstance(s); + String error = SCLScripts.canRunScript(s, resource); + IWorkbenchPart part = WorkbenchUtils.getActiveWorkbenchPart(); + IStatusLineManager status = part != null ? WorkbenchUtils.getStatusLine(part) : null; + if (error == null) { + String scriptName = s.syncRequest(new RelatedValue(resource, L0.HasName, Bindings.STRING)); + String text = s.syncRequest(new RelatedValue(resource, L0.SCLScript_definition, Bindings.STRING)); + Pair p = SCLScripts.getOrCreateConsoleCommandSession(); + SCLScripts.runScriptWithProgress(scriptName, text, p.first, p.second); + status.setErrorMessage(null); + } else { + if (status != null) + status.setErrorMessage(error); + } + } catch (DatabaseException e) { + Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Failed to run SCL script.", e)); + return; + } + } + +} diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/RunSCLScriptHandler.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/RunSCLScriptHandler.java new file mode 100644 index 000000000..5ba4872ca --- /dev/null +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/RunSCLScriptHandler.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (c) 2017 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.modeling.ui.scl.scriptEditor; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.action.IStatusLineManager; +import org.eclipse.jface.text.IDocument; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.handlers.HandlerUtil; +import org.eclipse.ui.texteditor.ITextEditor; +import org.simantics.Simantics; +import org.simantics.db.RequestProcessor; +import org.simantics.db.Resource; +import org.simantics.db.common.primitiverequest.PossibleResource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.modeling.ui.Activator; +import org.simantics.modeling.ui.scl.SCLScripts; +import org.simantics.scl.compiler.commands.CommandSession; +import org.simantics.scl.runtime.reporting.SCLReportingHandler; +import org.simantics.utils.datastructures.Pair; +import org.simantics.utils.ui.workbench.WorkbenchUtils; + +/** + * @author Tuukka Lehtonen + * @since 1.31.0 + */ +public class RunSCLScriptHandler extends AbstractHandler { + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + IEditorPart editor = HandlerUtil.getActiveEditorChecked(event); + IStatusLineManager status = WorkbenchUtils.getStatusLine(editor); + try { + final Resource script = getInputResource(Simantics.getSession(), editor); + if (script == null) + return null; + String error = SCLScripts.canRunScript(Simantics.getSession(), script); + if (error == null) { + String textSnapshot = getDocumentText(editor); + if (textSnapshot != null) { + Pair p = SCLScripts.getOrCreateConsoleCommandSession(); + SCLScripts.runScriptWithProgress(editor.getTitle(), textSnapshot, p.first, p.second); + status.setErrorMessage(null); + } + } else { + status.setErrorMessage(error); + } + } catch (DatabaseException ex) { + Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Failed to run SCL script.", ex)); + } + return null; + } + + private static Resource getInputResource(RequestProcessor processor, IEditorPart editor) throws DatabaseException { + IEditorInput input = editor.getEditorInput(); + return (input instanceof SCLScriptEditorInput) + ? processor.syncRequest(new PossibleResource(((SCLScriptEditorInput) input).getScriptURI())) + : null; + } + + private static String getDocumentText(IEditorPart editor) { + if (!(editor instanceof ITextEditor)) + return null; + IDocument document = ((ITextEditor) editor).getDocumentProvider().getDocument(editor.getEditorInput()); + return document == null ? null : document.get(); + } + +} diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptAnnotationModel.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptAnnotationModel.java new file mode 100644 index 000000000..fadb4f909 --- /dev/null +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptAnnotationModel.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * Copyright (c) 2017 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.modeling.ui.scl.scriptEditor; + +import java.util.Arrays; +import java.util.List; + +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.source.Annotation; +import org.eclipse.jface.text.source.AnnotationModel; +import org.simantics.Simantics; +import org.simantics.db.procedure.Listener; +import org.simantics.scl.compiler.commands.CommandSession; +import org.simantics.scl.compiler.errors.CompilationError; +import org.simantics.scl.compiler.errors.ErrorSeverity; +import org.simantics.scl.compiler.errors.Locations; +import org.simantics.scl.compiler.module.repository.ModuleRepository; +import org.simantics.scl.runtime.reporting.AbstractSCLReportingHandler; +import org.simantics.scl.runtime.reporting.SCLReportingHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Tuukka Lehtonen + * @since 1.31.0 + */ +public class SCLScriptAnnotationModel extends AnnotationModel { + + private static final Logger LOGGER = LoggerFactory.getLogger(SCLScriptAnnotationModel.class); + + private final SCLScriptEditorInput input; + private final ModuleRepository repository; + private volatile boolean connected = false; + + public SCLScriptAnnotationModel(SCLScriptEditorInput input, ModuleRepository repository) { + this.input = input; + this.repository = repository; + } + + private Listener sourceListener = new Listener() { + @Override + public void execute(String result) { + if (connected && result != null) + updateAnnotations(result); + } + @Override + public void exception(Throwable t) { + LOGGER.error("Failed to read SCL script source from " + input.getScriptURI(), t); + } + @Override + public boolean isDisposed() { + return !connected; + } + }; + + private void listenToSource() { + Simantics.getSession().asyncRequest(new ReadSCLScriptDefinition(input.getScriptURI()), sourceListener); + } + + private static final SCLReportingHandler NOP = new AbstractSCLReportingHandler() { + @Override + public void print(String text) {} + }; + + private void updateAnnotations(String sourceText) { + //LOGGER.debug("updateAnnotations:\n" + sourceText); + CompilationError[] errors = new CommandSession(repository, NOP).validate(sourceText); + setAnnotations(Arrays.asList(errors)); + } + + protected void setAnnotations(List errors) { + synchronized (getLockObject()) { + removeAllAnnotations(); + for (CompilationError error : errors) { + Annotation annotation = new Annotation( + error.severity == ErrorSeverity.ERROR || error.severity == ErrorSeverity.IMPORT_ERROR ? + "org.eclipse.ui.workbench.texteditor.error" : + "org.eclipse.ui.workbench.texteditor.warning", + true, error.description); + int begin = Locations.beginOf(error.location); + int end = Locations.endOf(error.location); + if (begin < 0 || end < begin) { + begin = 0; + end = 1; + } + addAnnotation(annotation, new Position(begin, end - begin)); + } + } + } + + @Override + public void connect(IDocument document) { + //LOGGER.debug("connect(" + document + ")"); + super.connect(document); + connected = true; + listenToSource(); + } + + @Override + public void disconnect(IDocument document) { + //LOGGER.debug("disconnect(" + document + ")"); + connected = false; + super.disconnect(document); + } + +} diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptEditor.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptEditor.java new file mode 100644 index 000000000..253b697b9 --- /dev/null +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptEditor.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2017 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.modeling.ui.scl.scriptEditor; + +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.contexts.IContextService; +import org.simantics.scl.ui.editor.SCLSourceViewerConfigurationNew; +import org.simantics.scl.ui.editor2.SCLModuleEditor2; + +/** + * @author Tuukka Lehtonen + * @since 1.31.0 + */ +public class SCLScriptEditor extends SCLModuleEditor2 { + + public SCLScriptEditor() { + super(); + setDocumentProvider(new SCLScriptEditorDocumentProvider((SCLSourceViewerConfigurationNew) getSourceViewerConfiguration())); + } + + @Override + public void createPartControl(Composite parent) { + super.createPartControl(parent); + getSite().getService(IContextService.class).activateContext("org.simantics.modeling.ui.scl.scriptEditor.context"); + } + +} diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptEditorAdapter.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptEditorAdapter.java new file mode 100644 index 000000000..ceb0e584c --- /dev/null +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptEditorAdapter.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2017 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.modeling.ui.scl.scriptEditor; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; +import org.simantics.Simantics; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.request.ReadRequest; +import org.simantics.db.exception.DatabaseException; +import org.simantics.layer0.Layer0; +import org.simantics.ui.workbench.editor.AbstractResourceEditorAdapter; +import org.simantics.ui.workbench.editor.EditorAdapter; +import org.simantics.utils.ui.workbench.WorkbenchUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Tuukka Lehtonen + * @since 1.31.0 + */ +public class SCLScriptEditorAdapter extends AbstractResourceEditorAdapter implements EditorAdapter { + + private static final Logger LOGGER = LoggerFactory.getLogger(SCLScriptEditorAdapter.class); + + public SCLScriptEditorAdapter() { + super("SCL Script Editor", null, 20); + } + + private Resource toResource(Object input) { + if (input instanceof IStructuredSelection) + input = ((IStructuredSelection)input).getFirstElement(); + if (!(input instanceof Resource)) { + if(input instanceof IAdaptable) { + input = ((IAdaptable)input).getAdapter(Resource.class); + if (input == null) + return null; + } + else + return null; + } + return (Resource) input; + } + + @Override + public boolean canHandle(ReadGraph g, Object input) throws DatabaseException { + Resource resource = toResource(input); + return g.isInstanceOf(resource, Layer0.getInstance(g).SCLScript); + } + + protected void openEditor(Resource input) throws Exception { + IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + if (page == null) + return; + Simantics.getSession().asyncRequest(new ReadRequest() { + @Override + public void run(ReadGraph graph) throws DatabaseException { + String uri = graph.getURI(input); + PlatformUI.getWorkbench().getDisplay().asyncExec(openEditor(uri)); + } + }); + } + + private static Runnable openEditor(String uri) { + return () -> { + try { + WorkbenchUtils.openEditor("org.simantics.modeling.ui.scl.scriptEditor", new SCLScriptEditorInput(uri)); + } catch (PartInitException e) { + LOGGER.error("Could not initialize part", e); + } + }; + } + +} diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptEditorDocumentProvider.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptEditorDocumentProvider.java new file mode 100644 index 000000000..c58e72dce --- /dev/null +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptEditorDocumentProvider.java @@ -0,0 +1,112 @@ +/******************************************************************************* + * Copyright (c) 2017 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.modeling.ui.scl.scriptEditor; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.operation.IRunnableContext; +import org.eclipse.jface.text.Document; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IDocumentPartitioner; +import org.eclipse.jface.text.rules.FastPartitioner; +import org.eclipse.jface.text.source.AnnotationModel; +import org.eclipse.jface.text.source.IAnnotationModel; +import org.eclipse.ui.texteditor.AbstractDocumentProvider; +import org.simantics.scl.osgi.SCLOsgi; +import org.simantics.scl.ui.editor.SCLSourceViewerConfigurationNew; +import org.simantics.scl.ui.editor2.SCLPartitionScanner; + +/** + * @author Tuukka Lehtonen + * @since 1.31.0 + */ +public class SCLScriptEditorDocumentProvider extends AbstractDocumentProvider { + + private SCLSourceViewerConfigurationNew sourceViewer; + protected AnnotationModel annotationModel = new AnnotationModel(); + + private Object currentElement; + private SCLScriptSource currentSource; + + public SCLScriptEditorDocumentProvider(SCLSourceViewerConfigurationNew sourceViewer) { + this.sourceViewer = sourceViewer; + } + + private void updateScriptSource(Object input) { + if (currentElement != null && currentElement.equals(input)) + return; + currentElement = input; + if (!(currentElement instanceof SCLScriptEditorInput)) + return; + + SCLScriptSource source = ((SCLScriptEditorInput) currentElement).getAdapter(SCLScriptSource.class); + if (source != null) + currentSource = source; + } + + @Override + protected IDocument createDocument(Object element) throws CoreException { + updateScriptSource(element); + if (currentSource == null) + throw new CoreException( + new Status(Status.ERROR, "org.simantics.scl.ui", "Source for the SCL module could not be found.")); + Document document = new Document(currentSource.getSourceText()); + IDocumentPartitioner partitioner = new FastPartitioner(new SCLPartitionScanner(), SCLPartitionScanner.PARTITION_TYPES); + partitioner.connect(document); + document.setDocumentPartitioner(partitioner); + sourceViewer.updateCompletionAssistModuleName(currentSource.getScriptURI()); + return document; + } + + @Override + public void changed(Object element) { + updateScriptSource(element); + } + + @Override + public void aboutToChange(Object element) { + super.aboutToChange(element); + } + + @Override + public boolean isModifiable(Object element) { + if (currentSource == null) + return false; + return currentSource.isUpdateable(); + } + + @Override + public boolean isReadOnly(Object element) { + return !isModifiable(element); + } + + @Override + protected IAnnotationModel createAnnotationModel(Object element) throws CoreException { + SCLScriptEditorInput input = (SCLScriptEditorInput) element; + return new SCLScriptAnnotationModel(input, SCLOsgi.MODULE_REPOSITORY); + } + + @Override + protected void doSaveDocument(IProgressMonitor monitor, Object element, + IDocument document, boolean overwrite) throws CoreException + { + if (currentSource != null) + currentSource.update(document.get()); + } + + @Override + protected IRunnableContext getOperationRunner(IProgressMonitor monitor) { + return null; + } + +} diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptEditorInput.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptEditorInput.java new file mode 100644 index 000000000..90a87cba9 --- /dev/null +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptEditorInput.java @@ -0,0 +1,114 @@ +/******************************************************************************* + * Copyright (c) 2017 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.modeling.ui.scl.scriptEditor; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IMemento; +import org.eclipse.ui.IPersistableElement; +import org.simantics.Simantics; +import org.simantics.db.exception.DatabaseException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Tuukka Lehtonen + * @since 1.31.0 + */ +public class SCLScriptEditorInput implements IEditorInput, IPersistableElement { + + private static final Logger LOGGER = LoggerFactory.getLogger(SCLScriptEditorInput.class); + + private final String scriptURI; + + public SCLScriptEditorInput(String scriptURI) { + this.scriptURI = scriptURI; + } + + public String getScriptURI() { + return scriptURI; + } + + @Override + public boolean exists() { + // Not worth it testing this from the database. + return true; + } + + @SuppressWarnings("unchecked") + @Override + public T getAdapter(Class adapter) { + if (adapter.equals(SCLScriptSource.class)) { + try { + return (T) Simantics.getSession().syncRequest(new ReadSCLScriptSource(scriptURI)); + } catch (DatabaseException e) { + LOGGER.error("Failed to read SCL script source", e); + } + } + if (adapter.equals(IPersistableElement.class)) + return (T) this; + return null; + } + + @Override + public String getFactoryId() { + return "org.simantics.modeling.ui.scl.scriptEditor.inputFactory"; + } + + @Override + public String getName() { + int p = scriptURI.lastIndexOf('/'); + if(p >= 0) + return scriptURI.substring(p+1); + else + return scriptURI; + } + + @Override + public String getToolTipText() { + return scriptURI; + } + + @Override + public ImageDescriptor getImageDescriptor() { + return null; + } + + @Override + public IPersistableElement getPersistable() { + return this; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((scriptURI == null) ? 0 : scriptURI.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + SCLScriptEditorInput other = (SCLScriptEditorInput) obj; + return scriptURI.equals(other.scriptURI); + } + + @Override + public void saveState(IMemento memento) { + memento.putTextData(scriptURI); + } + +} diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptEditorInputFactory.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptEditorInputFactory.java new file mode 100644 index 000000000..9087ac798 --- /dev/null +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptEditorInputFactory.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2017 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.modeling.ui.scl.scriptEditor; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.ui.IElementFactory; +import org.eclipse.ui.IMemento; + +/** + * @author Tuukka Lehtonen + * @since 1.31.0 + */ +public class SCLScriptEditorInputFactory implements IElementFactory { + + @Override + public IAdaptable createElement(IMemento memento) { + return new SCLScriptEditorInput(memento.getTextData()); + } + +} diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptSource.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptSource.java new file mode 100644 index 000000000..87c74b7d9 --- /dev/null +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/SCLScriptSource.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2017 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.modeling.ui.scl.scriptEditor; + +import org.simantics.Simantics; +import org.simantics.db.exception.DatabaseException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Tuukka Lehtonen + * @since 1.31.0 + */ +class SCLScriptSource { + + private static final Logger LOGGER = LoggerFactory.getLogger(SCLScriptSource.class); + + private String scriptURI; + private String scriptText; + + public SCLScriptSource(String scriptURI, String scriptText) { + this.scriptURI = scriptURI; + this.scriptText = scriptText; + } + + public void update(String newSourceText) { + try { + Simantics.getSession().syncRequest(new WriteSCLScriptDefinition(scriptURI, newSourceText)); + } catch (DatabaseException e) { + LOGGER.error("Failed to write SCL script source from " + scriptURI, e); + } + } + + public boolean isUpdateable() { + return true; + } + + public String getSourceText() { + return scriptText; + } + + public String getScriptURI() { + return scriptURI; + } + +} \ No newline at end of file diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/WriteSCLScriptDefinition.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/WriteSCLScriptDefinition.java new file mode 100644 index 000000000..67a79df0e --- /dev/null +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/scl/scriptEditor/WriteSCLScriptDefinition.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2017 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.modeling.ui.scl.scriptEditor; + +import org.simantics.databoard.Bindings; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.WriteRequest; +import org.simantics.db.exception.DatabaseException; +import org.simantics.layer0.Layer0; + +/** + * @author Tuukka Lehtonen + * @since 1.31.0 + */ +public class WriteSCLScriptDefinition extends WriteRequest { + + private final String scriptURI; + private final String definition; + + public WriteSCLScriptDefinition(String scriptURI, String sourceText) { + this.scriptURI = scriptURI; + this.definition = sourceText; + } + + @Override + public void perform(WriteGraph graph) throws DatabaseException { + Resource moduleResource = graph.getPossibleResource(scriptURI); + if (moduleResource == null) + return; + Layer0 L0 = Layer0.getInstance(graph); + if (!graph.isInstanceOf(moduleResource, L0.SCLScript)) + return; + graph.claimLiteral(moduleResource, L0.SCLScript_definition, definition, Bindings.STRING); + } + +} \ No newline at end of file diff --git a/bundles/org.simantics.modeling/scl/Simantics/SCL.scl b/bundles/org.simantics.modeling/scl/Simantics/SCL.scl index 32db0f4bc..72c733a59 100644 --- a/bundles/org.simantics.modeling/scl/Simantics/SCL.scl +++ b/bundles/org.simantics.modeling/scl/Simantics/SCL.scl @@ -12,14 +12,13 @@ importJava "org.simantics.scl.ui.editor.TextAndErrors" where createTextAndErrors :: String -> [CompilationError] -> TextAndErrors createSCLModuleAction :: Resource -> () -createSCLModuleAction res = do - syncWrite (\() -> createSCLModuleDefault res) - () +createSCLModuleAction res = ignore $ syncWrite (\() -> createSCLModuleDefault res) + +createSCLScriptAction :: Resource -> () +createSCLScriptAction res = ignore $ syncWrite (\() -> createSCLScriptDefault res) createPGraphAction :: Resource -> () -createPGraphAction res = do - syncWrite (\() -> createPGraphDefault res) - () +createPGraphAction res = ignore $ syncWrite (\() -> createPGraphDefault res) createSCLValueIndependent :: Resource -> String -> Resource createSCLValueIndependent valueType expression = do @@ -41,6 +40,7 @@ setExpression self expression = do importJava "org.simantics.modeling.ModelingUtils" where createSCLModuleDefault :: Resource -> () + createSCLScriptDefault :: Resource -> () createPGraphDefault :: Resource -> () createSCLModule :: Resource -> String -> () diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/ModelingUtils.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/ModelingUtils.java index b4e63a6cc..81505e0bc 100644 --- a/bundles/org.simantics.modeling/src/org/simantics/modeling/ModelingUtils.java +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/ModelingUtils.java @@ -1728,6 +1728,21 @@ public class ModelingUtils { Layer0Utils.addCommentMetadata(graph, "Created SCL Module " + name + " " + sclModule.toString()); } + public static void createSCLScriptDefault(WriteGraph graph, Resource target) throws DatabaseException { + String name = NameUtils.findFreshEscapedName(graph, "SCLScript", target); + createSCLScript(graph, target, name); + } + + public static void createSCLScript(WriteGraph graph, Resource target, String name) throws DatabaseException { + graph.markUndoPoint(); + Layer0 L0 = Layer0.getInstance(graph); + Resource sclModule = GraphUtils.create2(graph, L0.SCLScript, + L0.HasName, name, + L0.PartOf, target, + L0.SCLScript_definition, ""); + Layer0Utils.addCommentMetadata(graph, "Created SCL Script " + name + " " + sclModule.toString()); + } + public static void createPGraphDefault(WriteGraph graph, Resource target) throws DatabaseException { String name = NameUtils.findFreshEscapedName(graph, "Ontology Definition File", target); createPGraph(graph, target, name); diff --git a/bundles/org.simantics.scl.ui/plugin.xml b/bundles/org.simantics.scl.ui/plugin.xml index dd1539c46..ad9e3baf0 100644 --- a/bundles/org.simantics.scl.ui/plugin.xml +++ b/bundles/org.simantics.scl.ui/plugin.xml @@ -21,6 +21,15 @@ id="org.simantics.scl.ui.editor2" name="SCL Module Editor"> + + diff --git a/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/console/SCLConsole.java b/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/console/SCLConsole.java index 5eacaa093..16a946fbe 100644 --- a/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/console/SCLConsole.java +++ b/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/console/SCLConsole.java @@ -173,6 +173,11 @@ public class SCLConsole extends AbstractCommandConsole { public CommandSession getSession() { return session; } + + public SCLReportingHandler getHandler() { + return handler; + } + public void interruptCurrentCommands() { synchronized(currentJobs) { for(Job job : currentJobs) diff --git a/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/console/SCLConsoleView.java b/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/console/SCLConsoleView.java index a7eb43323..63b89a0b5 100644 --- a/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/console/SCLConsoleView.java +++ b/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/console/SCLConsoleView.java @@ -30,11 +30,13 @@ import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.ui.part.ViewPart; import org.eclipse.ui.preferences.ScopedPreferenceStore; +import org.simantics.scl.compiler.commands.CommandSession; import org.simantics.scl.compiler.commands.CommandSessionImportEntry; import org.simantics.scl.compiler.commands.SCLConsoleListener; import org.simantics.scl.compiler.module.repository.UpdateListener; import org.simantics.scl.compiler.testing.TestRunnable; import org.simantics.scl.osgi.internal.TestUtils; +import org.simantics.scl.runtime.reporting.SCLReportingHandler; import org.simantics.scl.ui.Activator; import org.simantics.scl.ui.imports.internal.ManageImportsDialog; import org.simantics.scl.ui.tests.SCLTestsDialog; @@ -335,4 +337,14 @@ public class SCLConsoleView extends ViewPart { console.dispose(); } + @SuppressWarnings("unchecked") + @Override + public T getAdapter(Class adapter) { + if (adapter == CommandSession.class) + return (T) console.getSession(); + if (adapter == SCLReportingHandler.class) + return (T) console.getHandler(); + return super.getAdapter(adapter); + } + } -- 2.43.2