diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/ElkGraphConstraintSerializer.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/ElkGraphConstraintSerializer.xtend index 301d96c89..7c22d0c31 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/ElkGraphConstraintSerializer.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/ElkGraphConstraintSerializer.xtend @@ -1,6 +1,6 @@ /* * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient - * + * * http://rtsys.informatik.uni-kiel.de/kieler * * Copyright 2022 by @@ -11,63 +11,42 @@ * This program and the accompanying materials are made available under the * terms of the Eclipse Public License 2.0 which is available at * http://www.eclipse.org/legal/epl-2.0. - * + * * SPDX-License-Identifier: EPL-2.0 */ package de.cau.cs.kieler.klighd.lsp.interactive import de.cau.cs.kieler.klighd.internal.util.KlighdInternalProperties -import de.cau.cs.kieler.klighd.lsp.KGraphLanguageClient -import de.cau.cs.kieler.klighd.lsp.KGraphLanguageServerExtension -import java.io.ByteArrayOutputStream import java.util.List -import java.util.Map import org.eclipse.elk.graph.ElkNode -import org.eclipse.lsp4j.Position -import org.eclipse.lsp4j.Range -import org.eclipse.lsp4j.TextEdit +import org.eclipse.emf.ecore.resource.Resource /** * Serializes constraint for an ELK graph by just adding the corresponding properties. * * @author sdo - * + * */ class ElkGraphConstraintSerializer implements IConstraintSerializer { - + override canHandle(Object graph) { return graph instanceof ElkNode } - - override serializeConstraints(List> changedNodes, + + override serializeConstraints( + List> changedNodes, Object graph, - String uri, - KGraphLanguageServerExtension ls, - KGraphLanguageClient client + Resource resource ) { - // Serialize model into given uri. - val resource = ls.getResource(uri) - - // Get previous file content as String - var outputStream = new ByteArrayOutputStream - resource.save(outputStream, emptyMap) - val codeBefore = outputStream.toString - changedNodes.forEach[c| + val codeBefore = InteractiveUtil.serializeResource(resource) + changedNodes.forEach [ c | val ElkNode elkNode = c.KNode.getProperty(KlighdInternalProperties.MODEL_ELEMENT) as ElkNode elkNode.setProperty(c.property, c.value) ] - val Map> changes = newHashMap - // Get changed file as String - outputStream = new ByteArrayOutputStream - resource.save(outputStream, emptyMap) - val String codeAfter = outputStream.toString().trim - // The range is the length of the previous file. - // Just make sure the range is big enough - val Range range = new Range(new Position(0, 0), new Position(codeBefore.split("\r\n|\r|\n").length * 2, 0)) - val TextEdit textEdit = new TextEdit(range, codeAfter) - changes.put(uri, #[textEdit]); - client.replaceContentInFile(uri, codeAfter, range) + val codeAfter = InteractiveUtil.serializeResource(resource) + + return InteractiveUtil.calculateTextEdit(codeBefore, codeAfter) } - + } diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/IConstraintSerializer.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/IConstraintSerializer.xtend index 019576534..db5002235 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/IConstraintSerializer.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/IConstraintSerializer.xtend @@ -16,9 +16,9 @@ */ package de.cau.cs.kieler.klighd.lsp.interactive -import de.cau.cs.kieler.klighd.lsp.KGraphLanguageClient -import de.cau.cs.kieler.klighd.lsp.KGraphLanguageServerExtension import java.util.List +import org.eclipse.emf.ecore.resource.Resource +import org.eclipse.lsp4j.TextEdit /** * Service interface for implementations that serialize a set constraint in the model. @@ -40,10 +40,8 @@ interface IConstraintSerializer { /** * @param changedNodes The added constraints. * @param graph The model, e.g. SCChart or ElkGraph. - * @param uri The uri of the main source file. - * @param ls The language server. - * @param client The language client. + * @param resource The resource to change + * @return The TextEdit to send to the client consisting of the new text and a range. */ - def void serializeConstraints(List> changedNodes, Object graph, String uri, - KGraphLanguageServerExtension ls, KGraphLanguageClient client); + def TextEdit serializeConstraints(List> changedNodes, Object graph, Resource resource); } \ No newline at end of file diff --git a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend index f450cb878..add8e671d 100644 --- a/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend +++ b/plugins/de.cau.cs.kieler.klighd.lsp/src/de/cau/cs/kieler/klighd/lsp/interactive/InteractiveUtil.xtend @@ -22,12 +22,17 @@ import de.cau.cs.kieler.klighd.kgraph.KIdentifier import de.cau.cs.kieler.klighd.kgraph.KNode import de.cau.cs.kieler.klighd.lsp.KGraphLanguageClient import de.cau.cs.kieler.klighd.lsp.KGraphLanguageServerExtension +import java.io.ByteArrayOutputStream import java.util.ArrayList import java.util.List import java.util.ServiceLoader import org.eclipse.elk.alg.layered.options.LayeredOptions import org.eclipse.elk.graph.ElkNode import org.eclipse.elk.graph.properties.IProperty +import org.eclipse.emf.ecore.resource.Resource +import org.eclipse.lsp4j.Position +import org.eclipse.lsp4j.Range +import org.eclipse.lsp4j.TextEdit /** * Provides utility methods for interactive layout. @@ -186,16 +191,48 @@ class InteractiveUtil { for (IConstraintSerializer cs : ServiceLoader.load(IConstraintSerializer, KlighdDataManager.getClassLoader())) { if (cs.canHandle(sourceModel)) { - cs.serializeConstraints(changedNodes, model, uri, languageServer, client) + val resource = languageServer.getResource(uri) + val textEdit = cs.serializeConstraints(changedNodes, model, resource) + // Send changes to the client. + client.replaceContentInFile(uri, textEdit.newText, textEdit.range) + // If a serializer is registered, we do not need to update the layout since the diagram will update + // since the model changes. serializer = true } } + // If there is no serializer that changes the textual model (which will cause a refresh model action), + // we have to update the layout (not refresh the layout) to update based on the changed via model. if (!serializer) { languageServer.updateLayout(uri) } return } + /** + * Creates a string of a model resource by saving the resource and returning the output string. + * + * @param resource Resource to get the string for. + */ + static def String serializeResource(Resource resource) { + var outputStream = new ByteArrayOutputStream + resource.save(outputStream, emptyMap) + return outputStream.toString + } + + /** + * Creates a TextEdit based on the before and after text. + * + * @param codeBefore The whole text before + * @param codeAfter The new text + * @return A TextEdit that assumes that the whole code before will ne replaced. + */ + static def TextEdit calculateTextEdit(String codeBefore, String codeAfter) { + val lines = codeBefore.split("\r\n|\r|\n") + val lastLineLength = lines.get(lines.size - 1).length + val Range range = new Range(new Position(0, 0), new Position(lines.length, lastLineLength)) + return new TextEdit(range, codeAfter) + } + /** * Returns id of a node. *