diff --git a/server/xtext-diagram/src/main/java/io/typefox/sprotty/server/xtext/DiagramLanguageServerExtension.xtend b/server/xtext-diagram/src/main/java/io/typefox/sprotty/server/xtext/DiagramLanguageServerExtension.xtend index 5d9ebe0..76e5c3d 100644 --- a/server/xtext-diagram/src/main/java/io/typefox/sprotty/server/xtext/DiagramLanguageServerExtension.xtend +++ b/server/xtext-diagram/src/main/java/io/typefox/sprotty/server/xtext/DiagramLanguageServerExtension.xtend @@ -56,6 +56,10 @@ class DiagramLanguageServerExtension implements DiagramServerEndpoint, ILanguage updateDiagrams(deltas.map[uri].toSet) ] } + + def ILanguageServerAccess getLanguageServerAccess() { + languageServerAccess + } protected def DiagramEndpoint getClient() { if (_client === null) { @@ -95,7 +99,7 @@ class DiagramLanguageServerExtension implements DiagramServerEndpoint, ILanguage server.languageServerExtension = this } - protected def List findDiagramServersByUri(String uri) { + def List findDiagramServersByUri(String uri) { synchronized (diagramServers) { diagramServers.values.filter(LanguageAwareDiagramServer).filter[sourceUri == uri].toList } diff --git a/server/xtext-diagram/src/main/java/io/typefox/sprotty/server/xtext/ide/IdeDiagramClient.xtend b/server/xtext-diagram/src/main/java/io/typefox/sprotty/server/xtext/ide/IdeDiagramClient.xtend new file mode 100644 index 0000000..63f6d7b --- /dev/null +++ b/server/xtext-diagram/src/main/java/io/typefox/sprotty/server/xtext/ide/IdeDiagramClient.xtend @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2017 TypeFox and others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ +package io.typefox.sprotty.server.xtext.ide + +import io.typefox.sprotty.server.xtext.DiagramEndpoint +import org.eclipse.lsp4j.Location +import org.eclipse.lsp4j.jsonrpc.services.JsonNotification +import org.eclipse.lsp4j.jsonrpc.services.JsonSegment + +@JsonSegment('diagram') +interface IdeDiagramClient extends DiagramEndpoint { + + @JsonNotification + def void openInTextEditor(Location location) + +} diff --git a/server/xtext-diagram/src/main/java/io/typefox/sprotty/server/xtext/ide/IdeDiagramModule.xtend b/server/xtext-diagram/src/main/java/io/typefox/sprotty/server/xtext/ide/IdeDiagramModule.xtend new file mode 100644 index 0000000..4abacf0 --- /dev/null +++ b/server/xtext-diagram/src/main/java/io/typefox/sprotty/server/xtext/ide/IdeDiagramModule.xtend @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2017 TypeFox and others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ +package io.typefox.sprotty.server.xtext.ide + +import io.typefox.sprotty.server.xtext.DefaultDiagramModule +import org.eclipse.xtext.ide.server.occurrences.IDocumentHighlightService +import io.typefox.sprotty.server.xtext.DiagramLanguageServerExtension + +class IdeDiagramModule extends DefaultDiagramModule { + + def Class bindDiagramLanguageServerExtension() { + IdeLanguageServerExtension + } + + override bindIDiagramServerProvider() { + IdeLanguageServerExtension + } + + def Class bindIDocumentHighlightService() { + IdeHighlightService + } + + override bindIDiagramSelectionListener() { + IdeDiagramSelectionListener + } +} diff --git a/server/xtext-diagram/src/main/java/io/typefox/sprotty/server/xtext/ide/IdeDiagramSelectionListener.xtend b/server/xtext-diagram/src/main/java/io/typefox/sprotty/server/xtext/ide/IdeDiagramSelectionListener.xtend new file mode 100644 index 0000000..81b19f0 --- /dev/null +++ b/server/xtext-diagram/src/main/java/io/typefox/sprotty/server/xtext/ide/IdeDiagramSelectionListener.xtend @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2017 TypeFox and others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ +package io.typefox.sprotty.server.xtext.ide + +import com.google.inject.Inject +import io.typefox.sprotty.api.IDiagramSelectionListener +import io.typefox.sprotty.api.IDiagramServer +import io.typefox.sprotty.api.SModelIndex +import io.typefox.sprotty.api.SelectAction +import io.typefox.sprotty.server.xtext.DiagramLanguageServerExtension +import io.typefox.sprotty.server.xtext.LanguageAwareDiagramServer +import org.eclipse.emf.common.util.URI +import org.eclipse.lsp4j.Location +import org.eclipse.lsp4j.Range +import org.eclipse.xtext.ide.server.UriExtensions + +class IdeDiagramSelectionListener implements IDiagramSelectionListener { + + @Inject extension DiagramLanguageServerExtension + + @Inject extension UriExtensions + + override selectionChanged(SelectAction action, IDiagramServer server) { + if(server instanceof LanguageAwareDiagramServer) { + val languageServerExtension = server.languageServerExtension + if(languageServerExtension instanceof IdeLanguageServerExtension) { + if(!action.deselectAll && action.selectedElementsIDs !== null && action.selectedElementsIDs.size === 1) { + val id = action.selectedElementsIDs.head + val selectedElement = new SModelIndex(server.model).get(id) + if (selectedElement instanceof io.typefox.sprotty.server.xtext.tracing.Traceable) { + val traceRegion = selectedElement.significantRegion + if(traceRegion !== null) { + val uri = server.sourceUri + if(uri !== null) { + uri.findDiagramServersByUri.forEach[ + languageServerExtension.languageServerAccess.doRead( + URI.createURI(uri).toPath, [ context | + val start = context.document.getPosition(traceRegion.offset) + val end = context.document.getPosition(traceRegion.offset + traceRegion.length) + languageServerExtension.client.openInTextEditor(new Location(uri, new Range(start, end))) + return null + ]) + ] + } + } + } + } + } + } + } +} + \ No newline at end of file diff --git a/server/xtext-diagram/src/main/java/io/typefox/sprotty/server/xtext/ide/IdeHighlightService.xtend b/server/xtext-diagram/src/main/java/io/typefox/sprotty/server/xtext/ide/IdeHighlightService.xtend new file mode 100644 index 0000000..96e56d3 --- /dev/null +++ b/server/xtext-diagram/src/main/java/io/typefox/sprotty/server/xtext/ide/IdeHighlightService.xtend @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2017 TypeFox and others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ +package io.typefox.sprotty.server.xtext.ide + +import com.google.inject.Inject +import io.typefox.sprotty.api.FitToScreenAction +import io.typefox.sprotty.api.SModelElement +import io.typefox.sprotty.api.SelectAction +import io.typefox.sprotty.server.xtext.DiagramLanguageServerExtension +import java.util.function.Consumer +import org.eclipse.xtext.ide.server.occurrences.DefaultDocumentHighlightService +import org.eclipse.xtext.resource.EObjectAtOffsetHelper +import org.eclipse.xtext.resource.XtextResource + +class IdeHighlightService extends DefaultDocumentHighlightService { + + @Inject extension DiagramLanguageServerExtension + + @Inject extension EObjectAtOffsetHelper + + override getDocumentHighlights(XtextResource resource, int offset) { + val result = super.getDocumentHighlights(resource, offset) + val element = resolveElementAt(resource, offset) + if (element !== null) { + findDiagramServersByUri(resource.getURI.toString).forEach [ server | + val traceables = newArrayList() + server.model.findTraceablesAtOffset(offset, [ + traceables += it + ]) + if(!traceables.empty) { + val smallest = traceables.minBy[ traceRegion.length ] + server.dispatch(new SelectAction [ + selectedElementsIDs = #[(smallest as SModelElement).id] + deselectAll = true + ]) + server.dispatch(new FitToScreenAction [ + maxZoom = 1.0 + elementIds = #[(smallest as SModelElement).id] + ]) + } + ] + } + return result + } + + protected def void findTraceablesAtOffset(SModelElement root, int offset, Consumer consumer) { + if (root instanceof io.typefox.sprotty.server.xtext.tracing.Traceable) { + val traceRegion = root.traceRegion + if(traceRegion !== null && traceRegion.offset <= offset && traceRegion.offset + traceRegion.length > offset) + consumer.accept(root) + } + root.children?.forEach[ + findTraceablesAtOffset(offset, consumer) + ] + } +} diff --git a/server/xtext-diagram/src/main/java/io/typefox/sprotty/server/xtext/ide/IdeLanguageServerExtension.xtend b/server/xtext-diagram/src/main/java/io/typefox/sprotty/server/xtext/ide/IdeLanguageServerExtension.xtend new file mode 100644 index 0000000..8accd91 --- /dev/null +++ b/server/xtext-diagram/src/main/java/io/typefox/sprotty/server/xtext/ide/IdeLanguageServerExtension.xtend @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2017 TypeFox and others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ +package io.typefox.sprotty.server.xtext.ide + +import io.typefox.sprotty.server.xtext.DiagramLanguageServerExtension +import org.eclipse.lsp4j.jsonrpc.Endpoint +import org.eclipse.lsp4j.jsonrpc.services.ServiceEndpoints + +class IdeLanguageServerExtension extends DiagramLanguageServerExtension { + + IdeDiagramClient _client + + override protected IdeDiagramClient getClient() { + if (_client === null) { + val client = languageServerAccess.languageClient + if (client instanceof Endpoint) { + _client = ServiceEndpoints.toServiceObject(client, IdeDiagramClient) + } + } + return _client + } +} diff --git a/server/xtext-diagram/src/main/java/io/typefox/sprotty/server/xtext/tracing/TraceRegionProvider.xtend b/server/xtext-diagram/src/main/java/io/typefox/sprotty/server/xtext/tracing/TraceRegionProvider.xtend new file mode 100644 index 0000000..c6ef0b0 --- /dev/null +++ b/server/xtext-diagram/src/main/java/io/typefox/sprotty/server/xtext/tracing/TraceRegionProvider.xtend @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2017 TypeFox and others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ +package io.typefox.sprotty.server.xtext.tracing + +import io.typefox.sprotty.server.xtext.tracing.TextRegion +import org.eclipse.emf.ecore.EObject +import org.eclipse.emf.ecore.EStructuralFeature +import org.eclipse.emf.ecore.EcorePackage +import org.eclipse.xtext.nodemodel.INode +import org.eclipse.xtext.nodemodel.util.NodeModelUtils + +class TraceRegionProvider { + + def TextRegion getTraceRegion(EObject element) { + val node = NodeModelUtils.findActualNodeFor(element) + if (node !== null) { + val document = node.rootNode.text + val leafNodes = node.leafNodes.filter[!hidden] + if(!leafNodes.empty) { + var start = leafNodes.head.offset + while (start > 0 && document.charAt(start - 1) === 32) + start-- + var end = leafNodes.last.endOffset + while(end < document.length && document.charAt(end) === 32) + end++ + return new TextRegion(start, end - start) + } + } + return null + } + + def TextRegion getSignificantRegion(EObject element) { + val feature = element.relevantFeature + if (feature !== null) + return NodeModelUtils.findNodesForFeature(element, feature).head.toTextRegion + else + return NodeModelUtils.findActualNodeFor(element).toTextRegion + } + + protected def toTextRegion(INode node) { + val leafNodes = node.leafNodes.filter[!hidden] + if(!leafNodes.empty) { + var start = leafNodes.head.offset + var end = leafNodes.last.endOffset + return new TextRegion(start, end - start) + } + } + + protected def EStructuralFeature getRelevantFeature(EObject element) { + element.eClass.getEAllAttributes.findFirst[name == 'name'] + ?: element.eClass.getEAllAttributes.findFirst[getEAttributeType === EcorePackage.Literals.ESTRING] + ?: element.eClass.getEAllReferences.findFirst[isContainment && upperBound === 1] + } +} diff --git a/server/xtext-diagram/src/main/java/io/typefox/sprotty/server/xtext/tracing/Traceable.xtend b/server/xtext-diagram/src/main/java/io/typefox/sprotty/server/xtext/tracing/Traceable.xtend new file mode 100644 index 0000000..26f8446 --- /dev/null +++ b/server/xtext-diagram/src/main/java/io/typefox/sprotty/server/xtext/tracing/Traceable.xtend @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2017 TypeFox and others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ +package io.typefox.sprotty.server.xtext.tracing + +import org.eclipse.xtend.lib.annotations.Data + +interface Traceable { + def TextRegion getTraceRegion() + def void setTraceRegion(TextRegion traceRegion) + def TextRegion getSignificantRegion() + def void setSignificantRegion(TextRegion traceRegion) +} + +@Data +class TextRegion { + int offset + int length +} \ No newline at end of file