mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-16 16:58:56 +00:00
Merge "[storage] store DocumentationAdapter, optionally persist node model (off by default). Fixes broken hover (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=456857)"
This commit is contained in:
commit
70873885e0
4 changed files with 167 additions and 30 deletions
|
@ -0,0 +1,50 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2010 itemis AG (http://www.itemis.eu) and others.
|
||||
* 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.xtext.junit4.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.emf.ecore.resource.impl.ExtensibleURIConverterImpl;
|
||||
import org.eclipse.xtext.util.StringInputStream;
|
||||
|
||||
|
||||
/**
|
||||
* A {@link org.eclipse.emf.ecore.resource.URIConverter} that can create input streams
|
||||
* for synthetic URIs based on previously registered mappings.
|
||||
*
|
||||
* @author Sebastian Zarnekow - Initial contribution and API
|
||||
* @since 2.8
|
||||
*/
|
||||
public class InMemoryURIConverter extends ExtensibleURIConverterImpl {
|
||||
private final Map<URI, InputStream> models = new HashMap<URI, InputStream>();
|
||||
|
||||
public void addModel(String uri, String content) {
|
||||
models.put(URI.createURI(uri), new StringInputStream(content));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(URI uri, Map<?, ?> options) {
|
||||
boolean result = models.containsKey(uri);
|
||||
if (!result) {
|
||||
for(URI knownUri: models.keySet()) {
|
||||
if (uri.toString().endsWith(knownUri.toString()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream createInputStream(URI uri, Map<?, ?> options) throws IOException {
|
||||
return models.get(uri);
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@ import org.eclipse.emf.ecore.resource.impl.ExtensibleURIConverterImpl
|
|||
import org.eclipse.xtext.generator.AbstractFileSystemAccess2
|
||||
import org.eclipse.xtext.generator.IContextualOutputConfigurationProvider
|
||||
import org.eclipse.xtext.generator.IFileSystemAccessExtension3
|
||||
import org.eclipse.xtend.lib.annotations.Accessors
|
||||
|
||||
/**
|
||||
* @author Sven Efftinge - Initial contribution and API
|
||||
|
@ -27,6 +28,7 @@ class ResourceStorageFacade implements IResourceStorageFacade {
|
|||
@Inject IContextualOutputConfigurationProvider outputConfigurationProvider
|
||||
@Inject Provider<AbstractFileSystemAccess2> fileSystemAccessProvider
|
||||
|
||||
@Accessors boolean storeNodeModel = false
|
||||
/**
|
||||
* @return whether the given resource should be loaded from stored resource state
|
||||
*/
|
||||
|
@ -74,11 +76,11 @@ class ResourceStorageFacade implements IResourceStorageFacade {
|
|||
}
|
||||
|
||||
override def ResourceStorageLoadable createResourceStorageLoadable(InputStream in) {
|
||||
return new ResourceStorageLoadable(in)
|
||||
return new ResourceStorageLoadable(in, isStoreNodeModel)
|
||||
}
|
||||
|
||||
override def ResourceStorageWritable createResourceStorageWritable(OutputStream out) {
|
||||
return new ResourceStorageWritable(out)
|
||||
return new ResourceStorageWritable(out, isStoreNodeModel)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,22 +7,31 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.xtext.resource.persistence
|
||||
|
||||
import com.google.common.io.CharStreams
|
||||
import java.io.DataInputStream
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.InputStreamReader
|
||||
import java.io.ObjectInputStream
|
||||
import java.util.zip.ZipInputStream
|
||||
import org.apache.log4j.Logger
|
||||
import org.eclipse.emf.ecore.InternalEObject
|
||||
import org.eclipse.emf.ecore.resource.impl.BinaryResourceImpl
|
||||
import org.eclipse.xtend.lib.annotations.Data
|
||||
import org.eclipse.emf.ecore.resource.impl.BinaryResourceImpl.EObjectInputStream
|
||||
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor
|
||||
import org.eclipse.xtext.nodemodel.impl.SerializableNodeModel
|
||||
import org.eclipse.xtext.nodemodel.serialization.DeserializationConversionContext
|
||||
import org.eclipse.xtext.parser.ParseResult
|
||||
|
||||
/**
|
||||
* @author Sven Efftinge - Initial contribution and API
|
||||
*/
|
||||
@Data class ResourceStorageLoadable {
|
||||
@FinalFieldsConstructor class ResourceStorageLoadable {
|
||||
|
||||
static val LOG = Logger.getLogger(ResourceStorageLoadable)
|
||||
|
||||
InputStream in
|
||||
val InputStream in
|
||||
val boolean storeNodeModel
|
||||
|
||||
protected def void loadIntoResource(StorageAwareResource resource) {
|
||||
try {
|
||||
|
@ -45,21 +54,20 @@ import org.eclipse.xtend.lib.annotations.Data
|
|||
* Overriding methods should first delegate to super before adding their own entries.
|
||||
*/
|
||||
protected def void loadEntries(StorageAwareResource resource, ZipInputStream zipIn) {
|
||||
zipIn.nextEntry
|
||||
readContents(resource, zipIn)
|
||||
|
||||
zipIn.nextEntry
|
||||
readResourceDescription(resource, zipIn)
|
||||
|
||||
if (storeNodeModel) {
|
||||
zipIn.nextEntry
|
||||
readNodeModel(resource, zipIn)
|
||||
}
|
||||
}
|
||||
|
||||
protected def void readResourceDescription(StorageAwareResource resource, ZipInputStream zipIn) {
|
||||
zipIn.nextEntry
|
||||
val objectIn = new ObjectInputStream(zipIn)
|
||||
val description = objectIn.readObject as SerializableResourceDescription
|
||||
description.updateResourceURI(resource.URI)
|
||||
resource.resourceDescription = description
|
||||
}
|
||||
|
||||
protected def void readContents(StorageAwareResource resource, ZipInputStream zipIn) {
|
||||
zipIn.nextEntry
|
||||
val in = new BinaryResourceImpl.EObjectInputStream(zipIn, emptyMap) {
|
||||
protected def void readContents(StorageAwareResource resource, InputStream inputStream) {
|
||||
val in = new BinaryResourceImpl.EObjectInputStream(inputStream, emptyMap) {
|
||||
|
||||
override readCompressedInt() throws IOException {
|
||||
//HACK! null resource set, to avoid usage of resourceSet's package registry
|
||||
|
@ -67,8 +75,45 @@ import org.eclipse.xtend.lib.annotations.Data
|
|||
super.readCompressedInt()
|
||||
}
|
||||
|
||||
override loadEObject() throws IOException {
|
||||
val result = super.loadEObject()
|
||||
handleLoadEObject(result, this)
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
in.loadResource(resource)
|
||||
}
|
||||
|
||||
protected def handleLoadEObject(InternalEObject loaded, EObjectInputStream input) {
|
||||
}
|
||||
|
||||
protected def void readResourceDescription(StorageAwareResource resource, InputStream inputStream) {
|
||||
val objectIn = new ObjectInputStream(inputStream)
|
||||
val description = objectIn.readObject as SerializableResourceDescription
|
||||
description.updateResourceURI(resource.URI)
|
||||
resource.resourceDescription = description
|
||||
}
|
||||
|
||||
protected def void readNodeModel(StorageAwareResource resource, InputStream inputStream) {
|
||||
try {
|
||||
val serializableNodeModel = new SerializableNodeModel(resource)
|
||||
// if this is a synthetic resource (i.e. tests or so, don't load the node model)
|
||||
if (!resource.resourceSet.URIConverter.exists(resource.URI, resource.resourceSet.loadOptions)) {
|
||||
LOG.info("Skipping loading node model for synthetic resource "+resource.URI)
|
||||
return;
|
||||
}
|
||||
val stream = resource.resourceSet.URIConverter.createInputStream(resource.URI)
|
||||
val in = new InputStreamReader(stream, resource.encoding)
|
||||
val completeContent = CharStreams.toString(in)
|
||||
val deserializationContext = new DeserializationConversionContext(resource, completeContent)
|
||||
val dataIn = new DataInputStream(inputStream)
|
||||
serializableNodeModel.readObjectData(dataIn, deserializationContext)
|
||||
resource.parseResult = new ParseResult(resource.contents.head,serializableNodeModel.root, deserializationContext.hasErrors)
|
||||
} catch (IOException e) {
|
||||
LOG.error(e.message, e)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.xtext.resource.persistence
|
||||
|
||||
import java.io.DataOutputStream
|
||||
import java.io.IOException
|
||||
import java.io.ObjectOutputStream
|
||||
import java.io.OutputStream
|
||||
|
@ -14,17 +15,21 @@ import java.util.zip.ZipEntry
|
|||
import java.util.zip.ZipOutputStream
|
||||
import org.apache.log4j.Logger
|
||||
import org.eclipse.emf.common.util.URI
|
||||
import org.eclipse.emf.ecore.InternalEObject
|
||||
import org.eclipse.emf.ecore.resource.impl.BinaryResourceImpl
|
||||
import org.eclipse.xtend.lib.annotations.Data
|
||||
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor
|
||||
import org.eclipse.xtext.nodemodel.impl.SerializableNodeModel
|
||||
import org.eclipse.xtext.nodemodel.serialization.SerializationConversionContext
|
||||
|
||||
/**
|
||||
* @author Sven Efftinge - Initial contribution and API
|
||||
*/
|
||||
@Data class ResourceStorageWritable {
|
||||
@FinalFieldsConstructor class ResourceStorageWritable {
|
||||
|
||||
static val LOG = Logger.getLogger(ResourceStorageWritable)
|
||||
|
||||
OutputStream out
|
||||
val OutputStream out
|
||||
val boolean storeNodeModel
|
||||
|
||||
def void writeResource(StorageAwareResource resource) {
|
||||
if (resource.isLoadedFromStorage) {
|
||||
|
@ -45,41 +50,68 @@ import org.eclipse.xtend.lib.annotations.Data
|
|||
* Overriding methods should first delegate to super before adding their own entries.
|
||||
*/
|
||||
protected def void writeEntries(StorageAwareResource resource, ZipOutputStream zipOut) {
|
||||
writeContents(resource, zipOut)
|
||||
writeResourceDescription(resource, zipOut)
|
||||
zipOut.putNextEntry(new ZipEntry("emf-contents"))
|
||||
try {
|
||||
writeContents(resource, zipOut)
|
||||
} finally {
|
||||
zipOut.closeEntry
|
||||
}
|
||||
|
||||
zipOut.putNextEntry(new ZipEntry("resource-description"))
|
||||
try {
|
||||
writeResourceDescription(resource, zipOut)
|
||||
} finally {
|
||||
zipOut.closeEntry
|
||||
}
|
||||
|
||||
if (storeNodeModel) {
|
||||
zipOut.putNextEntry(new ZipEntry("node-model"))
|
||||
try {
|
||||
writeNodeModel(resource, zipOut)
|
||||
} finally {
|
||||
zipOut.closeEntry
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected def void writeContents(StorageAwareResource storageAwareResource, ZipOutputStream zipOut) {
|
||||
zipOut.putNextEntry(new ZipEntry("emf-contents"))
|
||||
val out = new BinaryResourceImpl.EObjectOutputStream(zipOut, emptyMap) {
|
||||
|
||||
protected def void writeContents(StorageAwareResource storageAwareResource, OutputStream outputStream) {
|
||||
val out = new BinaryResourceImpl.EObjectOutputStream(outputStream, emptyMap) {
|
||||
|
||||
override writeURI(URI uri, String fragment) throws IOException {
|
||||
val fullURI = uri.appendFragment(fragment)
|
||||
val uriToWrite = storageAwareResource.portableURIs.toPortableURI(storageAwareResource, fullURI) ?: fullURI
|
||||
super.writeURI(uriToWrite.trimFragment, uriToWrite.fragment)
|
||||
}
|
||||
|
||||
override saveEObject(InternalEObject internalEObject, Check check) throws IOException {
|
||||
super.saveEObject(internalEObject, check)
|
||||
handleSaveEObject(internalEObject, this)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
try {
|
||||
out.saveResource(storageAwareResource)
|
||||
} finally {
|
||||
out.flush
|
||||
}
|
||||
zipOut.closeEntry
|
||||
}
|
||||
|
||||
protected def void handleSaveEObject(InternalEObject object, BinaryResourceImpl.EObjectOutputStream out) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
|
||||
protected def void writeResourceDescription(StorageAwareResource resource, ZipOutputStream zipOut) {
|
||||
zipOut.putNextEntry(new ZipEntry("resource-description"))
|
||||
protected def void writeResourceDescription(StorageAwareResource resource, OutputStream outputStream) {
|
||||
val description = resource.resourceServiceProvider.resourceDescriptionManager.getResourceDescription(resource);
|
||||
val serializableDescription = SerializableResourceDescription.createCopy(description)
|
||||
convertExternalURIsToPortableURIs(serializableDescription, resource)
|
||||
val out = new ObjectOutputStream(zipOut);
|
||||
val out = new ObjectOutputStream(outputStream);
|
||||
try {
|
||||
out.writeObject(serializableDescription);
|
||||
} finally {
|
||||
out.flush
|
||||
}
|
||||
zipOut.closeEntry
|
||||
}
|
||||
|
||||
def protected void convertExternalURIsToPortableURIs(SerializableResourceDescription description, StorageAwareResource resource) {
|
||||
|
@ -90,4 +122,12 @@ import org.eclipse.xtend.lib.annotations.Data
|
|||
}
|
||||
}
|
||||
|
||||
protected def writeNodeModel(StorageAwareResource resource, OutputStream outputStream) {
|
||||
val out = new DataOutputStream(outputStream);
|
||||
val serializableNodeModel = new SerializableNodeModel(resource)
|
||||
val conversionContext = new SerializationConversionContext(resource)
|
||||
serializableNodeModel.writeObjectData(out, conversionContext)
|
||||
out.flush
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue