mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-15 08:18:55 +00:00
[eclipse/xtext#1569] Migrate Xtend code to Java (#1270)
* Migrate Xtend code to Java * Apply auto-formatting and cleanup actions * Add `@since` tags see eclipse/xtext#1569
This commit is contained in:
parent
33a64fb2ee
commit
eea345fba1
51 changed files with 3646 additions and 6063 deletions
|
@ -0,0 +1,250 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2017 TypeFox GmbH (http://www.typefox.io) 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.ide.server;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.xtext.build.IncrementalBuilder;
|
||||
import org.eclipse.xtext.diagnostics.Severity;
|
||||
import org.eclipse.xtext.resource.IResourceDescription;
|
||||
import org.eclipse.xtext.resource.impl.DefaultResourceDescriptionDelta;
|
||||
import org.eclipse.xtext.resource.impl.ProjectDescription;
|
||||
import org.eclipse.xtext.util.CancelIndicator;
|
||||
import org.eclipse.xtext.xbase.lib.IterableExtensions;
|
||||
import org.eclipse.xtext.xbase.lib.util.ToStringBuilder;
|
||||
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
public class BuildManager {
|
||||
/**
|
||||
* The resources that are about to be build.
|
||||
*/
|
||||
protected static class ProjectBuildData {
|
||||
private final List<URI> dirtyFiles;
|
||||
|
||||
private final List<URI> deletedFiles;
|
||||
|
||||
public ProjectBuildData(List<URI> dirtyFiles, List<URI> deletedFiles) {
|
||||
this.dirtyFiles = dirtyFiles;
|
||||
this.deletedFiles = deletedFiles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((deletedFiles == null) ? 0 : deletedFiles.hashCode());
|
||||
result = prime * result + ((dirtyFiles == null) ? 0 : dirtyFiles.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
ProjectBuildData other = (ProjectBuildData) obj;
|
||||
if (deletedFiles == null) {
|
||||
if (other.deletedFiles != null)
|
||||
return false;
|
||||
} else if (!deletedFiles.equals(other.deletedFiles))
|
||||
return false;
|
||||
if (dirtyFiles == null) {
|
||||
if (other.dirtyFiles != null)
|
||||
return false;
|
||||
} else if (!dirtyFiles.equals(other.dirtyFiles))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
ToStringBuilder b = new ToStringBuilder(this);
|
||||
b.add("dirtyFiles", dirtyFiles);
|
||||
b.add("deletedFiles", deletedFiles);
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
public List<URI> getDirtyFiles() {
|
||||
return dirtyFiles;
|
||||
}
|
||||
|
||||
public List<URI> getDeletedFiles() {
|
||||
return deletedFiles;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A handle that can be used to trigger a build.
|
||||
*/
|
||||
public interface Buildable {
|
||||
/**
|
||||
* Run the build
|
||||
*/
|
||||
List<IResourceDescription.Delta> build(CancelIndicator cancelIndicator);
|
||||
|
||||
/**
|
||||
* No build is going to happen.
|
||||
*/
|
||||
Buildable NO_BUILD = (cancelIndicator) -> Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue key for cyclic dependencies
|
||||
*/
|
||||
public static final String CYCLIC_PROJECT_DEPENDENCIES = BuildManager.class.getName()
|
||||
+ ".cyclicProjectDependencies";
|
||||
|
||||
private WorkspaceManager workspaceManager;
|
||||
|
||||
@Inject
|
||||
private Provider<TopologicalSorter> sorterProvider;
|
||||
|
||||
private final LinkedHashSet<URI> dirtyFiles = new LinkedHashSet<>();
|
||||
|
||||
private final LinkedHashSet<URI> deletedFiles = new LinkedHashSet<>();
|
||||
|
||||
private List<IResourceDescription.Delta> unreportedDeltas = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Enqueue the given file collections.
|
||||
*
|
||||
* @return a buildable.
|
||||
*/
|
||||
public Buildable submit(List<URI> dirtyFiles, List<URI> deletedFiles) {
|
||||
queue(this.dirtyFiles, deletedFiles, dirtyFiles);
|
||||
queue(this.deletedFiles, dirtyFiles, deletedFiles);
|
||||
return this::internalBuild;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated this method is no longer used
|
||||
*/
|
||||
@Deprecated
|
||||
public List<IResourceDescription.Delta> doBuild(List<URI> dirtyFiles, List<URI> deletedFiles,
|
||||
CancelIndicator cancelIndicator) {
|
||||
return submit(dirtyFiles, deletedFiles).build(cancelIndicator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the contents of the given set.
|
||||
*/
|
||||
protected void queue(Set<URI> files, Collection<URI> toRemove, Collection<URI> toAdd) {
|
||||
files.removeAll(toRemove);
|
||||
files.addAll(toAdd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run an initial build
|
||||
*
|
||||
* @return the delta.
|
||||
*/
|
||||
public List<IResourceDescription.Delta> doInitialBuild(List<ProjectDescription> projects,
|
||||
CancelIndicator indicator) {
|
||||
List<ProjectDescription> sortedDescriptions = sortByDependencies(projects);
|
||||
List<IResourceDescription.Delta> result = new ArrayList<>();
|
||||
for (ProjectDescription description : sortedDescriptions) {
|
||||
IncrementalBuilder.Result partialresult = workspaceManager.getProjectManager(description.getName())
|
||||
.doInitialBuild(indicator);
|
||||
result.addAll(partialresult.getAffectedResources());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the build on all projects.
|
||||
*/
|
||||
protected List<IResourceDescription.Delta> internalBuild(CancelIndicator cancelIndicator) {
|
||||
List<URI> allDirty = new ArrayList<>(dirtyFiles);
|
||||
Multimap<ProjectDescription, URI> project2dirty = HashMultimap.create();
|
||||
for (URI dirty : allDirty) {
|
||||
project2dirty.put(workspaceManager.getProjectManager(dirty).getProjectDescription(), dirty);
|
||||
}
|
||||
Multimap<ProjectDescription, URI> project2deleted = HashMultimap.create();
|
||||
for (URI deleted : deletedFiles) {
|
||||
ProjectDescription projectManager = workspaceManager.getProjectManager(deleted).getProjectDescription();
|
||||
project2deleted.put(projectManager, deleted);
|
||||
}
|
||||
List<ProjectDescription> sortedDescriptions = sortByDependencies(
|
||||
Sets.union(project2dirty.keySet(), project2deleted.keySet()));
|
||||
for (ProjectDescription it : sortedDescriptions) {
|
||||
ProjectManager projectManager = workspaceManager.getProjectManager(it.getName());
|
||||
List<URI> projectDirty = new ArrayList<>(project2dirty.get(it));
|
||||
List<URI> projectDeleted = new ArrayList<>(project2deleted.get(it));
|
||||
IncrementalBuilder.Result partialResult = projectManager.doBuild(projectDirty, projectDeleted,
|
||||
unreportedDeltas, cancelIndicator);
|
||||
FluentIterable.from(partialResult.getAffectedResources()).transform(IResourceDescription.Delta::getUri)
|
||||
.copyInto(allDirty);
|
||||
dirtyFiles.removeAll(projectDirty);
|
||||
deletedFiles.removeAll(projectDeleted);
|
||||
mergeWithUnreportedDeltas(partialResult.getAffectedResources());
|
||||
}
|
||||
List<IResourceDescription.Delta> result = unreportedDeltas;
|
||||
unreportedDeltas = new ArrayList<>();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.18
|
||||
*/
|
||||
protected void mergeWithUnreportedDeltas(List<IResourceDescription.Delta> newDeltas) {
|
||||
if (unreportedDeltas.isEmpty()) {
|
||||
unreportedDeltas.addAll(newDeltas);
|
||||
} else {
|
||||
Map<URI, IResourceDescription.Delta> unreportedByUri = IterableExtensions.toMap(unreportedDeltas,
|
||||
IResourceDescription.Delta::getUri);
|
||||
for(IResourceDescription.Delta newDelta: newDeltas) {
|
||||
IResourceDescription.Delta unreportedDelta = unreportedByUri.get(newDelta.getUri());
|
||||
if (unreportedDelta == null) {
|
||||
unreportedDeltas.add(newDelta);
|
||||
} else {
|
||||
unreportedDeltas.remove(unreportedDelta);
|
||||
IResourceDescription oldDescription = unreportedDelta.getOld();
|
||||
IResourceDescription newDescription = newDelta.getNew();
|
||||
unreportedDeltas.add(new DefaultResourceDescriptionDelta(oldDescription, newDescription));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a sorted list of projects to be build.
|
||||
*/
|
||||
protected List<ProjectDescription> sortByDependencies(Iterable<ProjectDescription> projectDescriptions) {
|
||||
return sorterProvider.get().sortByDependencies(projectDescriptions, (it) -> {
|
||||
reportDependencyCycle(workspaceManager.getProjectManager(it.getName()));
|
||||
});
|
||||
}
|
||||
|
||||
protected void reportDependencyCycle(ProjectManager manager) {
|
||||
manager.reportProjectIssue("Project has cyclic dependencies", CYCLIC_PROJECT_DEPENDENCIES, Severity.ERROR);
|
||||
}
|
||||
|
||||
public void setWorkspaceManager(WorkspaceManager workspaceManager) {
|
||||
this.workspaceManager = workspaceManager;
|
||||
}
|
||||
}
|
|
@ -1,140 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2017 TypeFox GmbH (http://www.typefox.io) 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.ide.server
|
||||
|
||||
import com.google.common.collect.HashMultimap
|
||||
import com.google.inject.Inject
|
||||
import com.google.inject.Provider
|
||||
import java.util.ArrayList
|
||||
import java.util.Collection
|
||||
import java.util.List
|
||||
import java.util.Set
|
||||
import org.eclipse.emf.common.util.URI
|
||||
import org.eclipse.xtend.lib.annotations.Accessors
|
||||
import org.eclipse.xtend.lib.annotations.Data
|
||||
import org.eclipse.xtext.diagnostics.Severity
|
||||
import org.eclipse.xtext.resource.IResourceDescription
|
||||
import org.eclipse.xtext.resource.impl.ProjectDescription
|
||||
import org.eclipse.xtext.util.CancelIndicator
|
||||
import org.eclipse.xtext.resource.impl.DefaultResourceDescriptionDelta
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
class BuildManager {
|
||||
|
||||
public static val CYCLIC_PROJECT_DEPENDENCIES = BuildManager.canonicalName + '.cyclicProjectDependencies'
|
||||
|
||||
@Accessors(PUBLIC_SETTER)
|
||||
WorkspaceManager workspaceManager
|
||||
@Inject Provider<TopologicalSorter> sorterProvider
|
||||
|
||||
val dirtyFiles = <URI>newLinkedHashSet
|
||||
val deletedFiles = <URI>newLinkedHashSet
|
||||
List<IResourceDescription.Delta> unreportedDeltas = newArrayList
|
||||
|
||||
def Buildable submit(List<URI> dirtyFiles, List<URI> deletedFiles) {
|
||||
queue(this.dirtyFiles, deletedFiles, dirtyFiles)
|
||||
queue(this.deletedFiles, dirtyFiles, deletedFiles)
|
||||
return [cancelIndicator|internalBuild(cancelIndicator)]
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated this method is no longer used
|
||||
*/
|
||||
@Deprecated
|
||||
def List<IResourceDescription.Delta> doBuild(List<URI> dirtyFiles, List<URI> deletedFiles, CancelIndicator cancelIndicator) {
|
||||
return submit(dirtyFiles, deletedFiles).build(cancelIndicator)
|
||||
}
|
||||
|
||||
protected def void queue(Set<URI> files, Collection<URI> toRemove, Collection<URI> toAdd) {
|
||||
files -= toRemove
|
||||
files += toAdd
|
||||
}
|
||||
|
||||
def List<IResourceDescription.Delta> doInitialBuild(List<ProjectDescription> projects, CancelIndicator indicator) {
|
||||
val sortedDescriptions = sortByDependencies(projects)
|
||||
val result = newArrayList
|
||||
for(description : sortedDescriptions) {
|
||||
val partialresult = workspaceManager.getProjectManager(description.name).doInitialBuild(indicator)
|
||||
result.addAll(partialresult.affectedResources)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
protected def List<IResourceDescription.Delta> internalBuild(CancelIndicator cancelIndicator) {
|
||||
val allDirty = new ArrayList(dirtyFiles)
|
||||
val project2dirty = HashMultimap.<ProjectDescription, URI>create
|
||||
for(URI dirty: allDirty) {
|
||||
val projectManager = workspaceManager.getProjectManager(dirty).projectDescription
|
||||
project2dirty.put(projectManager, dirty)
|
||||
}
|
||||
val project2deleted = HashMultimap.<ProjectDescription, URI>create
|
||||
for(URI deleted: deletedFiles) {
|
||||
val projectManager = workspaceManager.getProjectManager(deleted).projectDescription
|
||||
project2deleted.put(projectManager, deleted)
|
||||
}
|
||||
val sortedDescriptions = sortByDependencies(project2dirty.keySet + project2deleted.keySet)
|
||||
for(ProjectDescription it: sortedDescriptions) {
|
||||
val projectManager = workspaceManager.getProjectManager(name)
|
||||
val projectDirty = project2dirty.get(it).toList
|
||||
val projectDeleted = project2deleted.get(it).toList
|
||||
val partialResult = projectManager.doBuild(projectDirty, projectDeleted, unreportedDeltas, cancelIndicator)
|
||||
allDirty.addAll(partialResult.affectedResources.map[uri])
|
||||
this.dirtyFiles -= projectDirty
|
||||
this.deletedFiles -= projectDeleted
|
||||
// prior builds could have been canceled, so their result has not been returned,
|
||||
// but the projectManager already has updated its state
|
||||
mergeWithUnreportedDeltas(partialResult.affectedResources)
|
||||
}
|
||||
val result = unreportedDeltas
|
||||
unreportedDeltas = newArrayList
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.18
|
||||
*/
|
||||
protected def mergeWithUnreportedDeltas(List<IResourceDescription.Delta> newDeltas) {
|
||||
if (unreportedDeltas.empty) {
|
||||
unreportedDeltas += newDeltas
|
||||
} else {
|
||||
val unreportedByUri = unreportedDeltas.toMap[uri]
|
||||
newDeltas.forEach [ newDelta |
|
||||
val unreportedDelta = unreportedByUri.get(newDelta.uri)
|
||||
if (unreportedDelta === null) {
|
||||
unreportedDeltas.add(newDelta)
|
||||
} else {
|
||||
unreportedDeltas -= unreportedDelta
|
||||
unreportedDeltas += new DefaultResourceDescriptionDelta(unreportedDelta.old, newDelta.^new)
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
protected def sortByDependencies(Iterable<ProjectDescription> projectDescriptions) {
|
||||
sorterProvider.get.sortByDependencies(projectDescriptions.toList) [
|
||||
workspaceManager.getProjectManager(name).reportDependencyCycle
|
||||
]
|
||||
}
|
||||
|
||||
protected def reportDependencyCycle(ProjectManager manager) {
|
||||
manager.reportProjectIssue('Project has cyclic dependencies', CYCLIC_PROJECT_DEPENDENCIES, Severity.ERROR)
|
||||
}
|
||||
|
||||
@Data
|
||||
protected static class ProjectBuildData {
|
||||
List<URI> dirtyFiles
|
||||
List<URI> deletedFiles
|
||||
}
|
||||
|
||||
static interface Buildable {
|
||||
def List<IResourceDescription.Delta> build(CancelIndicator cancelIndicator)
|
||||
}
|
||||
}
|
|
@ -5,25 +5,20 @@
|
|||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*******************************************************************************/
|
||||
package org.eclipse.xtext.ide.server
|
||||
package org.eclipse.xtext.ide.server;
|
||||
|
||||
import org.eclipse.xtext.resource.impl.ProjectDescription
|
||||
import org.eclipse.xtext.workspace.IProjectConfig
|
||||
import org.eclipse.xtext.resource.impl.ProjectDescription;
|
||||
import org.eclipse.xtext.workspace.IProjectConfig;
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
interface IProjectDescriptionFactory {
|
||||
def ProjectDescription getProjectDescription(IProjectConfig config)
|
||||
public class DefaultProjectDescriptionFactory implements IProjectDescriptionFactory {
|
||||
@Override
|
||||
public ProjectDescription getProjectDescription(IProjectConfig config) {
|
||||
ProjectDescription result = new ProjectDescription();
|
||||
result.setName(config.getName());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
class DefaultProjectDescriptionFactory implements IProjectDescriptionFactory {
|
||||
|
||||
override getProjectDescription(IProjectConfig config) {
|
||||
new ProjectDescription => [
|
||||
name = config.getName()
|
||||
]
|
||||
}
|
||||
|
||||
}
|
|
@ -21,12 +21,12 @@ public interface ILanguageServerShutdownAndExitHandler {
|
|||
* Callback that is called when Language Servers <code>exit</code> is called.
|
||||
*/
|
||||
void exit();
|
||||
|
||||
|
||||
/**
|
||||
* Callback that is called when Language Servers <code>shutdown</code> is called.
|
||||
*/
|
||||
void shutdown();
|
||||
|
||||
|
||||
/**
|
||||
* Implementation for {@link ILanguageServerShutdownAndExitHandler} that does nothing.
|
||||
*/
|
||||
|
@ -41,14 +41,14 @@ public interface ILanguageServerShutdownAndExitHandler {
|
|||
public void shutdown() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Default Implementation for {@link ILanguageServerShutdownAndExitHandler}. Calls <code>System.exit</code>.
|
||||
*/
|
||||
public static class DefaultImpl implements ILanguageServerShutdownAndExitHandler {
|
||||
|
||||
|
||||
private boolean hasShutdownBeenCalled = false;
|
||||
|
||||
@Override
|
||||
|
@ -64,7 +64,7 @@ public interface ILanguageServerShutdownAndExitHandler {
|
|||
public void shutdown() {
|
||||
hasShutdownBeenCalled = true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/**
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016 TypeFox GmbH (http://www.typefox.io) 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.ide.server;
|
||||
|
||||
import org.eclipse.xtext.resource.impl.ProjectDescription;
|
||||
|
@ -14,7 +14,13 @@ import org.eclipse.xtext.workspace.IProjectConfig;
|
|||
* @author Jan Koehnlein - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public interface IProjectDescriptionFactory {
|
||||
public abstract ProjectDescription getProjectDescription(final IProjectConfig config);
|
||||
/**
|
||||
* Create the description for the given project.
|
||||
*
|
||||
* @param project
|
||||
* the project configuration
|
||||
* @return the description for the project.
|
||||
*/
|
||||
ProjectDescription getProjectDescription(IProjectConfig project);
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
/**
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2017 TypeFox GmbH (http://www.typefox.io) 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.ide.server;
|
||||
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
|
@ -14,7 +14,13 @@ import org.eclipse.xtext.workspace.IWorkspaceConfig;
|
|||
* @author Jan Koehnlein - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public interface IWorkspaceConfigFactory {
|
||||
public abstract IWorkspaceConfig getWorkspaceConfig(final URI workspaceBaseURI);
|
||||
/**
|
||||
* Create a workspace config at the given location.
|
||||
*
|
||||
* @param workspaceBaseURI
|
||||
* the location
|
||||
* @return the workspace configuration.
|
||||
*/
|
||||
IWorkspaceConfig getWorkspaceConfig(URI workspaceBaseURI);
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2017 TypeFox GmbH (http://www.typefox.io) 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.ide.server
|
||||
|
||||
import org.eclipse.emf.common.util.URI
|
||||
import org.eclipse.xtext.workspace.FileProjectConfig
|
||||
import org.eclipse.xtext.workspace.IWorkspaceConfig
|
||||
import org.eclipse.xtext.workspace.WorkspaceConfig
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
interface IWorkspaceConfigFactory {
|
||||
|
||||
def IWorkspaceConfig getWorkspaceConfig(URI workspaceBaseURI)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The workspace itself is a single project
|
||||
*
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
class ProjectWorkspaceConfigFactory implements IWorkspaceConfigFactory {
|
||||
|
||||
override getWorkspaceConfig(URI workspaceBaseURI) {
|
||||
val workspaceConfig = new WorkspaceConfig
|
||||
workspaceConfig.findProjects(workspaceBaseURI)
|
||||
return workspaceConfig
|
||||
}
|
||||
|
||||
def void findProjects(WorkspaceConfig workspaceConfig, URI uri) {
|
||||
if (uri !== null) {
|
||||
val project = new FileProjectConfig(uri, workspaceConfig)
|
||||
project.addSourceFolder('.')
|
||||
workspaceConfig.addProject(project)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -1,873 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2017 TypeFox GmbH (http://www.typefox.io) 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.ide.server
|
||||
|
||||
import com.google.common.collect.ImmutableMap
|
||||
import com.google.common.collect.ImmutableMultimap
|
||||
import com.google.common.collect.LinkedListMultimap
|
||||
import com.google.common.collect.Multimap
|
||||
import com.google.inject.Inject
|
||||
import java.util.List
|
||||
import java.util.Map
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.function.Function
|
||||
import org.eclipse.emf.common.util.URI
|
||||
import org.eclipse.lsp4j.CodeActionParams
|
||||
import org.eclipse.lsp4j.CodeLens
|
||||
import org.eclipse.lsp4j.CodeLensOptions
|
||||
import org.eclipse.lsp4j.CodeLensParams
|
||||
import org.eclipse.lsp4j.ColoringParams
|
||||
import org.eclipse.lsp4j.CompletionItem
|
||||
import org.eclipse.lsp4j.CompletionList
|
||||
import org.eclipse.lsp4j.CompletionOptions
|
||||
import org.eclipse.lsp4j.CompletionParams
|
||||
import org.eclipse.lsp4j.Diagnostic
|
||||
import org.eclipse.lsp4j.DiagnosticSeverity
|
||||
import org.eclipse.lsp4j.DidChangeConfigurationParams
|
||||
import org.eclipse.lsp4j.DidChangeTextDocumentParams
|
||||
import org.eclipse.lsp4j.DidChangeWatchedFilesParams
|
||||
import org.eclipse.lsp4j.DidCloseTextDocumentParams
|
||||
import org.eclipse.lsp4j.DidOpenTextDocumentParams
|
||||
import org.eclipse.lsp4j.DidSaveTextDocumentParams
|
||||
import org.eclipse.lsp4j.DocumentFormattingParams
|
||||
import org.eclipse.lsp4j.DocumentOnTypeFormattingParams
|
||||
import org.eclipse.lsp4j.DocumentRangeFormattingParams
|
||||
import org.eclipse.lsp4j.DocumentSymbol
|
||||
import org.eclipse.lsp4j.DocumentSymbolParams
|
||||
import org.eclipse.lsp4j.ExecuteCommandOptions
|
||||
import org.eclipse.lsp4j.ExecuteCommandParams
|
||||
import org.eclipse.lsp4j.FileChangeType
|
||||
import org.eclipse.lsp4j.InitializeParams
|
||||
import org.eclipse.lsp4j.InitializeResult
|
||||
import org.eclipse.lsp4j.InitializedParams
|
||||
import org.eclipse.lsp4j.Location
|
||||
import org.eclipse.lsp4j.PublishDiagnosticsParams
|
||||
import org.eclipse.lsp4j.Range
|
||||
import org.eclipse.lsp4j.ReferenceParams
|
||||
import org.eclipse.lsp4j.RenameOptions
|
||||
import org.eclipse.lsp4j.RenameParams
|
||||
import org.eclipse.lsp4j.SemanticHighlightingServerCapabilities
|
||||
import org.eclipse.lsp4j.ServerCapabilities
|
||||
import org.eclipse.lsp4j.SignatureHelpOptions
|
||||
import org.eclipse.lsp4j.SymbolInformation
|
||||
import org.eclipse.lsp4j.TextDocumentPositionParams
|
||||
import org.eclipse.lsp4j.TextDocumentSyncKind
|
||||
import org.eclipse.lsp4j.WorkspaceEdit
|
||||
import org.eclipse.lsp4j.WorkspaceSymbolParams
|
||||
import org.eclipse.lsp4j.jsonrpc.Endpoint
|
||||
import org.eclipse.lsp4j.jsonrpc.json.JsonRpcMethod
|
||||
import org.eclipse.lsp4j.jsonrpc.json.JsonRpcMethodProvider
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either
|
||||
import org.eclipse.lsp4j.jsonrpc.services.ServiceEndpoints
|
||||
import org.eclipse.lsp4j.services.LanguageClient
|
||||
import org.eclipse.lsp4j.services.LanguageClientAware
|
||||
import org.eclipse.lsp4j.services.LanguageClientExtensions
|
||||
import org.eclipse.lsp4j.services.LanguageServer
|
||||
import org.eclipse.lsp4j.services.TextDocumentService
|
||||
import org.eclipse.lsp4j.services.WorkspaceService
|
||||
import org.eclipse.xtend.lib.annotations.Accessors
|
||||
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor
|
||||
import org.eclipse.xtext.findReferences.IReferenceFinder.IResourceAccess
|
||||
import org.eclipse.xtext.ide.server.ILanguageServerAccess.IBuildListener
|
||||
import org.eclipse.xtext.ide.server.codeActions.ICodeActionService
|
||||
import org.eclipse.xtext.ide.server.codeActions.ICodeActionService2
|
||||
import org.eclipse.xtext.ide.server.codelens.ICodeLensResolver
|
||||
import org.eclipse.xtext.ide.server.codelens.ICodeLensService
|
||||
import org.eclipse.xtext.ide.server.coloring.IColoringService
|
||||
import org.eclipse.xtext.ide.server.commands.ExecutableCommandRegistry
|
||||
import org.eclipse.xtext.ide.server.concurrent.RequestManager
|
||||
import org.eclipse.xtext.ide.server.contentassist.ContentAssistService
|
||||
import org.eclipse.xtext.ide.server.findReferences.WorkspaceResourceAccess
|
||||
import org.eclipse.xtext.ide.server.formatting.FormattingService
|
||||
import org.eclipse.xtext.ide.server.hover.IHoverService
|
||||
import org.eclipse.xtext.ide.server.occurrences.IDocumentHighlightService
|
||||
import org.eclipse.xtext.ide.server.rename.IRenameService
|
||||
import org.eclipse.xtext.ide.server.rename.IRenameService2
|
||||
import org.eclipse.xtext.ide.server.rename.IRenameService2.PrepareRenameOptions
|
||||
import org.eclipse.xtext.ide.server.semanticHighlight.SemanticHighlightingRegistry
|
||||
import org.eclipse.xtext.ide.server.signatureHelp.ISignatureHelpService
|
||||
import org.eclipse.xtext.ide.server.symbol.DocumentSymbolService
|
||||
import org.eclipse.xtext.ide.server.symbol.HierarchicalDocumentSymbolService
|
||||
import org.eclipse.xtext.ide.server.symbol.IDocumentSymbolService
|
||||
import org.eclipse.xtext.ide.server.symbol.WorkspaceSymbolService
|
||||
import org.eclipse.xtext.resource.IResourceDescription.Delta
|
||||
import org.eclipse.xtext.resource.IResourceServiceProvider
|
||||
import org.eclipse.xtext.resource.XtextResource
|
||||
import org.eclipse.xtext.resource.impl.ResourceDescriptionsProvider
|
||||
import org.eclipse.xtext.util.CancelIndicator
|
||||
import org.eclipse.xtext.util.internal.Log
|
||||
import org.eclipse.xtext.validation.Issue
|
||||
|
||||
import static org.eclipse.xtext.diagnostics.Severity.*
|
||||
|
||||
/**
|
||||
* @author Sven Efftinge - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
@Log class LanguageServerImpl implements LanguageServer, WorkspaceService, TextDocumentService, LanguageClientAware, Endpoint, JsonRpcMethodProvider, IBuildListener {
|
||||
|
||||
@Inject @Accessors(PUBLIC_GETTER) RequestManager requestManager
|
||||
@Inject WorkspaceSymbolService workspaceSymbolService
|
||||
@Inject extension UriExtensions
|
||||
@Inject extension IResourceServiceProvider.Registry languagesRegistry
|
||||
@Inject ExecutableCommandRegistry commandRegistry
|
||||
@Inject SemanticHighlightingRegistry semanticHighlightingRegistry
|
||||
@Inject ILanguageServerShutdownAndExitHandler shutdownAndExitHandler
|
||||
|
||||
// injected below
|
||||
WorkspaceManager workspaceManager
|
||||
InitializeParams params
|
||||
InitializeResult initializeResult
|
||||
CompletableFuture<InitializedParams> initialized = new CompletableFuture
|
||||
|
||||
@Inject
|
||||
def void setWorkspaceManager(WorkspaceManager manager) {
|
||||
this.workspaceManager = manager
|
||||
resourceAccess = new WorkspaceResourceAccess(workspaceManager)
|
||||
}
|
||||
|
||||
private def Iterable<? extends IResourceServiceProvider> getAllLanguages() {
|
||||
this.languagesRegistry.extensionToFactoryMap.keySet.toList.sort.map[ext|
|
||||
val synthUri = URI.createURI("synth:///file."+ext)
|
||||
return synthUri.resourceServiceProvider
|
||||
].toSet
|
||||
}
|
||||
|
||||
override CompletableFuture<InitializeResult> initialize(InitializeParams params) {
|
||||
if (this.params !== null) {
|
||||
throw new IllegalStateException("This language server has already been initialized.")
|
||||
}
|
||||
val baseDir = params.baseDir
|
||||
if (languagesRegistry.extensionToFactoryMap.isEmpty) {
|
||||
throw new IllegalStateException("No Xtext languages have been registered. Please make sure you have added the languages's setup class in '/META-INF/services/org.eclipse.xtext.ISetup'")
|
||||
}
|
||||
this.params = params
|
||||
val result = new InitializeResult
|
||||
var capabilities = new ServerCapabilities => [
|
||||
hoverProvider = true
|
||||
definitionProvider = true
|
||||
referencesProvider = true
|
||||
documentSymbolProvider = true
|
||||
workspaceSymbolProvider = true
|
||||
|
||||
// check if a language with code lens capability exists
|
||||
if (allLanguages.exists[get(ICodeLensService)!==null]) {
|
||||
codeLensProvider = new CodeLensOptions => [
|
||||
resolveProvider = allLanguages.exists[get(ICodeLensResolver)!==null]
|
||||
]
|
||||
}
|
||||
|
||||
// check if a language with code actions capability exists
|
||||
codeActionProvider = allLanguages.exists[get(ICodeActionService) !== null || get(ICodeActionService2) !== null]
|
||||
|
||||
signatureHelpProvider = new SignatureHelpOptions(#['(', ','])
|
||||
textDocumentSync = TextDocumentSyncKind.Incremental
|
||||
completionProvider = new CompletionOptions => [
|
||||
resolveProvider = false
|
||||
triggerCharacters = #["."]
|
||||
]
|
||||
documentFormattingProvider = true
|
||||
documentRangeFormattingProvider = true
|
||||
documentHighlightProvider = true
|
||||
val clientPrepareSupport = Boolean.TRUE == params?.capabilities?.textDocument?.rename?.prepareSupport
|
||||
renameProvider = if (clientPrepareSupport && allLanguages.exists[get(IRenameService2) !== null]) {
|
||||
Either.forRight(new RenameOptions => [
|
||||
prepareProvider = true
|
||||
])
|
||||
} else {
|
||||
Either.forLeft(allLanguages.exists[get(IRenameService) !== null || get(IRenameService2) !== null])
|
||||
}
|
||||
|
||||
val clientCapabilities = params.capabilities;
|
||||
// register execute command capability
|
||||
if (clientCapabilities?.workspace?.executeCommand !== null) {
|
||||
this.commandRegistry.initialize(allLanguages, clientCapabilities, client)
|
||||
executeCommandProvider = new ExecuteCommandOptions => [
|
||||
commands = this.commandRegistry.getCommands()
|
||||
]
|
||||
}
|
||||
|
||||
semanticHighlightingRegistry.initialize(allLanguages, clientCapabilities, client);
|
||||
semanticHighlighting = new SemanticHighlightingServerCapabilities(semanticHighlightingRegistry.allScopes);
|
||||
|
||||
]
|
||||
for (language : allLanguages) {
|
||||
language.get(ICapabilitiesContributor)?.contribute(capabilities, params)
|
||||
}
|
||||
result.capabilities = capabilities
|
||||
|
||||
access.addBuildListener(this);
|
||||
|
||||
return requestManager.runWrite([
|
||||
workspaceManager.initialize(baseDir, [this.publishDiagnostics($0, $1)], CancelIndicator.NullImpl)
|
||||
return null
|
||||
], []).thenApply [
|
||||
this.initializeResult = result
|
||||
return result
|
||||
]
|
||||
}
|
||||
|
||||
override void initialized(InitializedParams params) {
|
||||
initialized.complete(params)
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private def URI deprecatedToBaseDir(InitializeParams params) {
|
||||
if (params.rootPath !== null) {
|
||||
return URI.createFileURI(params.rootPath).toUriString.toUri
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
protected def URI getBaseDir(InitializeParams params) {
|
||||
if (params.rootUri !== null) {
|
||||
return params.rootUri.toUri
|
||||
}
|
||||
return params.deprecatedToBaseDir;
|
||||
}
|
||||
|
||||
override connect(LanguageClient client) {
|
||||
this.client = client
|
||||
}
|
||||
|
||||
override exit() {
|
||||
shutdownAndExitHandler.exit()
|
||||
}
|
||||
|
||||
override CompletableFuture<Object> shutdown() {
|
||||
shutdownAndExitHandler.shutdown()
|
||||
return CompletableFuture.completedFuture(new Object());
|
||||
}
|
||||
|
||||
override TextDocumentService getTextDocumentService() {
|
||||
return this
|
||||
}
|
||||
|
||||
override WorkspaceService getWorkspaceService() {
|
||||
return this
|
||||
}
|
||||
|
||||
// end notification callbacks
|
||||
// file/content change events
|
||||
override didOpen(DidOpenTextDocumentParams params) {
|
||||
requestManager.runWrite([
|
||||
workspaceManager.didOpen(params.textDocument.uri.toUri, params.textDocument.version, params.textDocument.text)
|
||||
], [cancelIndicator , buildable |
|
||||
buildable.build(cancelIndicator)
|
||||
])
|
||||
}
|
||||
|
||||
override didChange(DidChangeTextDocumentParams params) {
|
||||
requestManager.runWrite([
|
||||
workspaceManager.didChangeTextDocumentContent(params.textDocument.uri.toUri, params.textDocument.version, params.contentChanges)
|
||||
], [cancelIndicator , buildable |
|
||||
buildable.build(cancelIndicator)
|
||||
])
|
||||
}
|
||||
|
||||
override didClose(DidCloseTextDocumentParams params) {
|
||||
requestManager.runWrite([
|
||||
workspaceManager.didClose(params.textDocument.uri.toUri)
|
||||
], [cancelIndicator , buildable |
|
||||
buildable.build(cancelIndicator)
|
||||
])
|
||||
}
|
||||
|
||||
override didSave(DidSaveTextDocumentParams params) {
|
||||
// the document's content is in sync with the file system
|
||||
// doesn't matter to us, so do nothing
|
||||
}
|
||||
|
||||
override didChangeWatchedFiles(DidChangeWatchedFilesParams params) {
|
||||
requestManager.runWrite([
|
||||
val dirtyFiles = newArrayList
|
||||
val deletedFiles = newArrayList
|
||||
params.changes.map[fileEvent|toUri(fileEvent.uri) -> fileEvent.type].filter [
|
||||
!workspaceManager.isDocumentOpen(key)
|
||||
].forEach [
|
||||
if (value === FileChangeType.Deleted) {
|
||||
deletedFiles += key
|
||||
} else {
|
||||
dirtyFiles += key
|
||||
}
|
||||
]
|
||||
return workspaceManager.didChangeFiles(dirtyFiles, deletedFiles)
|
||||
], [ cancelIndicator, buildable |
|
||||
buildable.build(cancelIndicator)
|
||||
])
|
||||
}
|
||||
|
||||
override didChangeConfiguration(DidChangeConfigurationParams params) {
|
||||
requestManager.runWrite([
|
||||
workspaceManager.refreshWorkspaceConfig(CancelIndicator.NullImpl)
|
||||
return null
|
||||
], [])
|
||||
}
|
||||
|
||||
// end file/content change events
|
||||
|
||||
WorkspaceResourceAccess resourceAccess
|
||||
|
||||
LanguageClient client
|
||||
|
||||
private def void publishDiagnostics(URI uri, Iterable<? extends Issue> issues) {
|
||||
initialized.thenAccept([
|
||||
val diagnostics = new PublishDiagnosticsParams => [
|
||||
it.uri = toUriString(uri)
|
||||
if (issues.isEmpty) {
|
||||
diagnostics = #[]
|
||||
} else {
|
||||
diagnostics = workspaceManager.doRead(uri) [document, resource|
|
||||
issues.filter[severity !== IGNORE].map[toDiagnostic(document, it)].toList
|
||||
]
|
||||
}
|
||||
]
|
||||
client.publishDiagnostics(diagnostics)
|
||||
])
|
||||
}
|
||||
|
||||
private def Diagnostic toDiagnostic(Document document, Issue issue) {
|
||||
new Diagnostic => [
|
||||
code = issue.code
|
||||
severity = switch issue.severity {
|
||||
case ERROR: DiagnosticSeverity.Error
|
||||
case WARNING: DiagnosticSeverity.Warning
|
||||
case INFO: DiagnosticSeverity.Information
|
||||
default: DiagnosticSeverity.Hint
|
||||
}
|
||||
message = issue.message
|
||||
val start = document.getPosition(issue.offset)
|
||||
val end = document.getPosition(issue.offset+issue.length)
|
||||
range = new Range(
|
||||
start,
|
||||
end
|
||||
)
|
||||
]
|
||||
}
|
||||
// end validation stuff
|
||||
|
||||
@FinalFieldsConstructor
|
||||
static class BufferedCancelIndicator implements CancelIndicator {
|
||||
|
||||
val CancelIndicator delegate;
|
||||
Long canceledSince
|
||||
|
||||
override isCanceled() {
|
||||
if (canceledSince === null && delegate.canceled) {
|
||||
canceledSince = System.currentTimeMillis
|
||||
return false
|
||||
}
|
||||
return canceledSince !== null && System.currentTimeMillis > canceledSince + 1000
|
||||
}
|
||||
|
||||
}
|
||||
// completion stuff
|
||||
override completion(CompletionParams params) {
|
||||
return requestManager.runRead[cancelIndicator | completion(cancelIndicator, params)]
|
||||
}
|
||||
|
||||
protected def Either<List<CompletionItem>, CompletionList> completion(CancelIndicator originalCancelIndicator,
|
||||
CompletionParams params) {
|
||||
val cancelIndicator = new BufferedCancelIndicator(originalCancelIndicator)
|
||||
val uri = params.textDocument.uri.toUri
|
||||
val resourceServiceProvider = uri.resourceServiceProvider
|
||||
val contentAssistService = resourceServiceProvider?.get(ContentAssistService)
|
||||
if (contentAssistService === null) {
|
||||
return Either.forRight(new CompletionList())
|
||||
}
|
||||
|
||||
val completionList = workspaceManager.doRead(uri) [ document, resource |
|
||||
return contentAssistService.createCompletionList(document, resource, params, cancelIndicator)
|
||||
]
|
||||
return Either.forRight(completionList)
|
||||
}
|
||||
|
||||
// end completion stuff
|
||||
// symbols
|
||||
override definition(TextDocumentPositionParams params) {
|
||||
return requestManager.runRead[cancelIndicator|Either.forLeft(definition(cancelIndicator, params))]
|
||||
}
|
||||
|
||||
protected def List<? extends Location> definition(CancelIndicator cancelIndicator, TextDocumentPositionParams params) {
|
||||
val uri = params.textDocument.uri.toUri
|
||||
val resourceServiceProvider = uri.resourceServiceProvider
|
||||
val documentSymbolService = resourceServiceProvider?.get(DocumentSymbolService)
|
||||
if (documentSymbolService === null)
|
||||
return emptyList
|
||||
|
||||
return workspaceManager.doRead(uri) [ document, resource |
|
||||
documentSymbolService.getDefinitions(document, resource, params, resourceAccess, cancelIndicator)
|
||||
]
|
||||
}
|
||||
|
||||
override references(ReferenceParams params) {
|
||||
return requestManager.<List<? extends Location>>runRead[ cancelIndicator |
|
||||
val uri = params.textDocument.uri.toUri
|
||||
val resourceServiceProvider = uri.resourceServiceProvider
|
||||
val documentSymbolService = resourceServiceProvider?.get(DocumentSymbolService)
|
||||
if (documentSymbolService === null)
|
||||
return emptyList
|
||||
|
||||
return workspaceManager.doRead(uri) [ document, resource |
|
||||
documentSymbolService.getReferences(document, resource, params, resourceAccess, workspaceManager.index, cancelIndicator)
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
override documentSymbol(DocumentSymbolParams params) {
|
||||
return requestManager.<List<Either<SymbolInformation, DocumentSymbol>>>runRead[ cancelIndicator |
|
||||
val uri = params.textDocument.uri.toUri
|
||||
val resourceServiceProvider = uri.resourceServiceProvider
|
||||
val documentSymbolService = resourceServiceProvider.IDocumentSymbolService
|
||||
if (documentSymbolService === null) {
|
||||
return emptyList
|
||||
}
|
||||
|
||||
return workspaceManager.doRead(uri) [ document, resource |
|
||||
return documentSymbolService.getSymbols(document, resource, params, cancelIndicator)
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.16
|
||||
*/
|
||||
protected def IDocumentSymbolService getIDocumentSymbolService(IResourceServiceProvider serviceProvider) {
|
||||
if (serviceProvider === null) {
|
||||
return null;
|
||||
}
|
||||
val documentSymbolServiceClass = if(hierarchicalDocumentSymbolSupport) HierarchicalDocumentSymbolService else DocumentSymbolService;
|
||||
return serviceProvider.get(documentSymbolServiceClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code true} if the {@code TextDocumentClientCapabilities} explicitly declares the hierarchical document symbol support
|
||||
* at LS initialization time. Otherwise, false.
|
||||
*/
|
||||
protected def boolean isHierarchicalDocumentSymbolSupport() {
|
||||
return this.params.capabilities?.textDocument?.documentSymbol?.hierarchicalDocumentSymbolSupport ?: false;
|
||||
}
|
||||
|
||||
override symbol(WorkspaceSymbolParams params) {
|
||||
return requestManager.<List<? extends SymbolInformation>>runRead [ cancelIndicator |
|
||||
val indexData = workspaceManager.index
|
||||
return workspaceSymbolService.getSymbols(params.query, resourceAccess, indexData, cancelIndicator)
|
||||
]
|
||||
}
|
||||
|
||||
// end symbols
|
||||
|
||||
// hover
|
||||
|
||||
override hover(TextDocumentPositionParams params) {
|
||||
return requestManager.runRead[ cancelIndicator |
|
||||
val uri = params.textDocument.uri.toUri
|
||||
val resourceServiceProvider = uri.resourceServiceProvider
|
||||
val hoverService = resourceServiceProvider?.get(IHoverService)
|
||||
if (hoverService === null)
|
||||
return IHoverService.EMPTY_HOVER
|
||||
|
||||
return workspaceManager.doRead(uri) [ document, resource |
|
||||
hoverService.hover(document, resource, params, cancelIndicator)
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
// end hover
|
||||
|
||||
override resolveCompletionItem(CompletionItem unresolved) {
|
||||
return CompletableFuture.completedFuture(unresolved)
|
||||
}
|
||||
|
||||
override signatureHelp(TextDocumentPositionParams params) {
|
||||
return requestManager.runRead [ cancelIndicator |
|
||||
val uri = params.textDocument.uri.toUri;
|
||||
val serviceProvider = uri.resourceServiceProvider;
|
||||
val helper = serviceProvider?.get(ISignatureHelpService);
|
||||
if (helper === null)
|
||||
return ISignatureHelpService.EMPTY
|
||||
|
||||
return workspaceManager.doRead(uri) [ doc, resource |
|
||||
helper.getSignatureHelp(doc, resource, params, cancelIndicator)
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
override documentHighlight(TextDocumentPositionParams params) {
|
||||
return requestManager.runRead [ cancelIndicator |
|
||||
val uri = params.textDocument.uri.toUri;
|
||||
val serviceProvider = uri.resourceServiceProvider;
|
||||
val service = serviceProvider?.get(IDocumentHighlightService);
|
||||
if (service === null)
|
||||
return emptyList
|
||||
|
||||
return workspaceManager.doRead(uri) [doc, resource |
|
||||
service.getDocumentHighlights(doc, resource, params, cancelIndicator)
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
override codeAction(CodeActionParams params) {
|
||||
return requestManager.runRead [ cancelIndicator |
|
||||
val uri = params.textDocument.uri.toUri;
|
||||
val serviceProvider = uri.resourceServiceProvider;
|
||||
val service = serviceProvider?.get(ICodeActionService);
|
||||
val service2 = serviceProvider?.get(ICodeActionService2);
|
||||
if (service === null && service2 === null)
|
||||
return emptyList
|
||||
|
||||
return workspaceManager.doRead(uri) [doc, resource |
|
||||
val result = newArrayList
|
||||
result += service?.getCodeActions(doc, resource, params, cancelIndicator) ?: emptyList
|
||||
result += service2?.getCodeActions(new ICodeActionService2.Options() => [ o |
|
||||
o.document = doc
|
||||
o.resource = resource
|
||||
o.languageServerAccess= access
|
||||
o.codeActionParams = params
|
||||
o.cancelIndicator = cancelIndicator
|
||||
]) ?: emptyList
|
||||
return result
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
private def void installURI(List<? extends CodeLens> codeLenses, String uri) {
|
||||
for (lens : codeLenses) {
|
||||
if (lens.data !== null) {
|
||||
lens.data = newArrayList(uri, lens.data)
|
||||
} else {
|
||||
lens.data = uri
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def URI uninstallURI(CodeLens lens) {
|
||||
var URI result = null
|
||||
if (lens.data instanceof String) {
|
||||
result = URI.createURI(lens.data.toString)
|
||||
lens.data = null
|
||||
} else if (lens.data instanceof List<?>) {
|
||||
val l = lens.data as List<?>
|
||||
result = URI.createURI(l.head.toString)
|
||||
lens.data = l.get(1)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
override codeLens(CodeLensParams params) {
|
||||
return requestManager.runRead[ cancelIndicator |
|
||||
val uri = params.textDocument.uri.toUri
|
||||
val resourceServiceProvider = uri.resourceServiceProvider
|
||||
val codeLensService = resourceServiceProvider?.get(ICodeLensService)
|
||||
if (codeLensService === null)
|
||||
return emptyList
|
||||
|
||||
return workspaceManager.doRead(uri) [ document, resource |
|
||||
val result = codeLensService.computeCodeLenses(document, resource, params, cancelIndicator)
|
||||
installURI(result, uri.toString)
|
||||
return result
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
override resolveCodeLens(CodeLens unresolved) {
|
||||
val uri = uninstallURI(unresolved)
|
||||
if (uri === null) {
|
||||
return CompletableFuture.completedFuture(unresolved)
|
||||
}
|
||||
return requestManager.runRead[ cancelIndicator |
|
||||
val resourceServiceProvider = uri.resourceServiceProvider
|
||||
val resolver = resourceServiceProvider?.get(ICodeLensResolver)
|
||||
if (resolver === null)
|
||||
return unresolved
|
||||
|
||||
return workspaceManager.doRead(uri) [ document, resource |
|
||||
val result = resolver.resolveCodeLens(document, resource, unresolved, cancelIndicator)
|
||||
return result
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
override formatting(DocumentFormattingParams params) {
|
||||
return requestManager.runRead[ cancelIndicator |
|
||||
val uri = params.textDocument.uri.toUri
|
||||
val resourceServiceProvider = uri.resourceServiceProvider
|
||||
val formatterService = resourceServiceProvider?.get(FormattingService)
|
||||
if (formatterService === null)
|
||||
return emptyList
|
||||
|
||||
return workspaceManager.doRead(uri) [ document, resource |
|
||||
formatterService.format(document, resource, params, cancelIndicator)
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
override rangeFormatting(DocumentRangeFormattingParams params) {
|
||||
return requestManager.runRead[ cancelIndicator |
|
||||
val uri = params.textDocument.uri.toUri
|
||||
val resourceServiceProvider = uri.resourceServiceProvider
|
||||
val formatterService = resourceServiceProvider?.get(FormattingService)
|
||||
if (formatterService === null)
|
||||
return emptyList
|
||||
|
||||
return workspaceManager.doRead(uri) [ document, resource |
|
||||
formatterService.format(document, resource, params, cancelIndicator)
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
override executeCommand(ExecuteCommandParams params) {
|
||||
return requestManager.runRead[ cancelIndicator |
|
||||
this.commandRegistry.executeCommand(params, this.access, cancelIndicator)
|
||||
]
|
||||
}
|
||||
|
||||
override onTypeFormatting(DocumentOnTypeFormattingParams params) {
|
||||
throw new UnsupportedOperationException("TODO: auto-generated method stub")
|
||||
}
|
||||
|
||||
override rename(RenameParams renameParams) {
|
||||
return requestManager.runRead[ cancelIndicator |
|
||||
val uri = renameParams.textDocument.uri.toUri
|
||||
val resourceServiceProvider = uri.resourceServiceProvider
|
||||
val renameServiceOld = resourceServiceProvider?.get(IRenameService)
|
||||
if (renameServiceOld !== null)
|
||||
return renameServiceOld.rename(workspaceManager, renameParams, cancelIndicator)
|
||||
val renameService2 = resourceServiceProvider?.get(IRenameService2)
|
||||
if (renameService2 !== null)
|
||||
return renameService2.rename(new IRenameService2.Options => [ o |
|
||||
o.languageServerAccess = access
|
||||
o.renameParams = renameParams
|
||||
o.cancelIndicator = cancelIndicator
|
||||
])
|
||||
return new WorkspaceEdit
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.18
|
||||
*/
|
||||
override prepareRename(TextDocumentPositionParams params) {
|
||||
return requestManager.runRead [ cancelIndicator |
|
||||
val uri = params.textDocument.uri.toUri
|
||||
val resourceServiceProvider = uri.resourceServiceProvider
|
||||
val renameService = resourceServiceProvider?.get(IRenameService2)
|
||||
if (renameService === null) {
|
||||
throw new UnsupportedOperationException()
|
||||
}
|
||||
renameService.prepareRename(new PrepareRenameOptions => [
|
||||
it.languageServerAccess = access
|
||||
it.params = params
|
||||
it.cancelIndicator = cancelIndicator
|
||||
])
|
||||
]
|
||||
}
|
||||
|
||||
override notify(String method, Object parameter) {
|
||||
for (endpoint : extensionProviders.get(method)) {
|
||||
try {
|
||||
endpoint.notify(method, parameter)
|
||||
} catch (UnsupportedOperationException e) {
|
||||
if (e !== ILanguageServerExtension.NOT_HANDLED_EXCEPTION) {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override request(String method, Object parameter) {
|
||||
if (!extensionProviders.containsKey(method)) {
|
||||
throw new UnsupportedOperationException("The json request '"+method+"' is unknown.")
|
||||
}
|
||||
for (endpoint : extensionProviders.get(method)) {
|
||||
try {
|
||||
return endpoint.request(method, parameter)
|
||||
} catch (UnsupportedOperationException e) {
|
||||
if (e !== ILanguageServerExtension.NOT_HANDLED_EXCEPTION) {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Map<String, JsonRpcMethod> supportedMethods = null
|
||||
Multimap<String, Endpoint> extensionProviders = LinkedListMultimap.create
|
||||
|
||||
override supportedMethods() {
|
||||
if (this.supportedMethods !== null) {
|
||||
return this.supportedMethods
|
||||
}
|
||||
synchronized (extensionProviders) {
|
||||
val supportedMethods = <String,JsonRpcMethod>newLinkedHashMap()
|
||||
supportedMethods.putAll(ServiceEndpoints.getSupportedMethods(class))
|
||||
val extensions = <String,JsonRpcMethod>newLinkedHashMap()
|
||||
for (resourceServiceProvider : languagesRegistry.extensionToFactoryMap.values.toSet.filter(IResourceServiceProvider)) {
|
||||
val ext = resourceServiceProvider.get(ILanguageServerExtension)
|
||||
if (ext !== null) {
|
||||
ext.initialize(access)
|
||||
val supportedExtensions = if (ext instanceof JsonRpcMethodProvider) {
|
||||
ext.supportedMethods
|
||||
} else {
|
||||
ServiceEndpoints.getSupportedMethods(ext.class)
|
||||
}
|
||||
for (entry : supportedExtensions.entrySet) {
|
||||
if (supportedMethods.containsKey(entry.key)) {
|
||||
LOG.error("The json rpc method '"+entry.key+"' can not be an extension as it is already defined in the LSP standard.")
|
||||
} else {
|
||||
val existing = extensions.put(entry.key, entry.value)
|
||||
if (existing !== null && existing != entry.value) {
|
||||
LOG.error("An incompatible LSP extension '"+entry.key+"' has already been registered. Using 1 ignoring 2. \n1 : "+existing+" \n2 : "+entry.value)
|
||||
extensions.put(entry.key, existing)
|
||||
} else {
|
||||
val endpoint = ServiceEndpoints.toEndpoint(ext)
|
||||
extensionProviders.put(entry.key, endpoint)
|
||||
supportedMethods.put(entry.key, entry.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.supportedMethods = supportedMethods
|
||||
return supportedMethods
|
||||
}
|
||||
}
|
||||
|
||||
ILanguageServerAccess access = new ILanguageServerAccess () {
|
||||
|
||||
override <T> doRead(String uri, Function<Context, T> function) {
|
||||
requestManager.runRead [ cancelIndicator |
|
||||
workspaceManager.doRead(uri.toUri) [ document, resource |
|
||||
val ctx = new Context(resource, document, workspaceManager.isDocumentOpen(resource.URI), cancelIndicator)
|
||||
return function.apply(ctx)
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
override addBuildListener(IBuildListener listener) {
|
||||
workspaceManager.addBuildListener(listener)
|
||||
}
|
||||
|
||||
override getLanguageClient() {
|
||||
client
|
||||
}
|
||||
|
||||
override newLiveScopeResourceSet(URI uri) {
|
||||
val projectManager = workspaceManager.getProjectManager(uri)
|
||||
val resourceSet = projectManager.createNewResourceSet(projectManager.indexState.resourceDescriptions)
|
||||
resourceSet.loadOptions.put(ResourceDescriptionsProvider.LIVE_SCOPE, true)
|
||||
resourceSet
|
||||
}
|
||||
|
||||
override getInitializeParams() {
|
||||
params
|
||||
}
|
||||
|
||||
override <T> doReadIndex(Function<? super IndexContext, ? extends T> function) {
|
||||
requestManager.runRead[ cancelIndicator |
|
||||
val ctx = new IndexContext(workspaceManager.index, cancelIndicator)
|
||||
return function.apply(ctx)
|
||||
]
|
||||
}
|
||||
|
||||
override getInitializeResult() {
|
||||
initializeResult
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override afterBuild(List<Delta> deltas) {
|
||||
deltas.filter[^new !== null].map[uri.toString].forEach [
|
||||
access.<Void>doRead(it) [ ctx |
|
||||
if (ctx.documentOpen) {
|
||||
if (ctx.resource instanceof XtextResource) {
|
||||
// XXX Do the coloring update if the resource has no syntax errors?
|
||||
val resource = ctx.resource as XtextResource;
|
||||
val serviceProvider = resource.URI.resourceServiceProvider;
|
||||
val coloringService = serviceProvider?.get(IColoringService);
|
||||
if (coloringService !== null) {
|
||||
if (client instanceof LanguageClientExtensions) {
|
||||
val doc = ctx.document;
|
||||
val coloringInfos = coloringService.getColoring(resource, doc);
|
||||
if (!coloringInfos.nullOrEmpty) {
|
||||
val uri = resource.URI.toString;
|
||||
client.updateColoring(new ColoringParams(uri, coloringInfos));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
semanticHighlightingRegistry.update(ctx);
|
||||
return /*void*/ null;
|
||||
];
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.16
|
||||
*/
|
||||
protected def ILanguageServerAccess getLanguageServerAccess() {
|
||||
access
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.16
|
||||
*/
|
||||
protected def LanguageClient getLanguageClient() {
|
||||
client
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.16
|
||||
*/
|
||||
protected def ExecutableCommandRegistry getCommandRegistry() {
|
||||
commandRegistry
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.16
|
||||
*/
|
||||
protected def Multimap<String, Endpoint> getExtensionProviders() {
|
||||
ImmutableMultimap.copyOf(extensionProviders)
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.16
|
||||
*/
|
||||
protected def Map<String, JsonRpcMethod> getSupportedMethods() {
|
||||
ImmutableMap.copyOf(supportedMethods)
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.16
|
||||
*/
|
||||
protected def IResourceServiceProvider.Registry getLanguagesRegistry() {
|
||||
languagesRegistry
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.16
|
||||
*/
|
||||
protected def IResourceAccess getWorkspaceResourceAccess() {
|
||||
resourceAccess
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.16
|
||||
*/
|
||||
protected def WorkspaceManager getWorkspaceManager() {
|
||||
workspaceManager
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.16
|
||||
*/
|
||||
protected def WorkspaceSymbolService getWorkspaceSymbolService() {
|
||||
workspaceSymbolService
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2017 TypeFox GmbH (http://www.typefox.io) 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.ide.server;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.xtext.workspace.FileProjectConfig;
|
||||
import org.eclipse.xtext.workspace.WorkspaceConfig;
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
public class MultiProjectWorkspaceConfigFactory extends ProjectWorkspaceConfigFactory {
|
||||
@Override
|
||||
public void findProjects(WorkspaceConfig workspaceConfig, URI uri) {
|
||||
if (uri == null) {
|
||||
return;
|
||||
}
|
||||
File baseFile = new File(uri.toFileString());
|
||||
if (!baseFile.isDirectory()) {
|
||||
return;
|
||||
}
|
||||
for (File dir : baseFile.listFiles(File::isDirectory)) {
|
||||
FileProjectConfig project = new FileProjectConfig(dir, workspaceConfig);
|
||||
project.addSourceFolder(".");
|
||||
workspaceConfig.addProject(project);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2017 TypeFox GmbH (http://www.typefox.io) 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.ide.server
|
||||
|
||||
import java.io.File
|
||||
import org.eclipse.emf.common.util.URI
|
||||
import org.eclipse.xtext.workspace.FileProjectConfig
|
||||
import org.eclipse.xtext.workspace.WorkspaceConfig
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
class MultiProjectWorkspaceConfigFactory extends ProjectWorkspaceConfigFactory {
|
||||
|
||||
override void findProjects(WorkspaceConfig workspaceConfig, URI uri) {
|
||||
if(uri === null) return;
|
||||
|
||||
val baseFile = new File(uri.toFileString)
|
||||
if(!baseFile.isDirectory) return;
|
||||
|
||||
for (file : baseFile.listFiles.filter[directory]) {
|
||||
val project = new FileProjectConfig(file, workspaceConfig)
|
||||
project.addSourceFolder('.')
|
||||
workspaceConfig.addProject(project)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,216 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2017 TypeFox GmbH (http://www.typefox.io) 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.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.emf.ecore.resource.Resource;
|
||||
import org.eclipse.xtext.build.BuildRequest;
|
||||
import org.eclipse.xtext.build.IncrementalBuilder;
|
||||
import org.eclipse.xtext.build.IndexState;
|
||||
import org.eclipse.xtext.diagnostics.Severity;
|
||||
import org.eclipse.xtext.resource.IExternalContentSupport;
|
||||
import org.eclipse.xtext.resource.IResourceDescription;
|
||||
import org.eclipse.xtext.resource.IResourceServiceProvider;
|
||||
import org.eclipse.xtext.resource.XtextResourceSet;
|
||||
import org.eclipse.xtext.resource.impl.ChunkedResourceDescriptions;
|
||||
import org.eclipse.xtext.resource.impl.ProjectDescription;
|
||||
import org.eclipse.xtext.resource.impl.ResourceDescriptionsData;
|
||||
import org.eclipse.xtext.util.CancelIndicator;
|
||||
import org.eclipse.xtext.util.IFileSystemScanner;
|
||||
import org.eclipse.xtext.validation.Issue;
|
||||
import org.eclipse.xtext.workspace.IProjectConfig;
|
||||
import org.eclipse.xtext.workspace.ISourceFolder;
|
||||
import org.eclipse.xtext.workspace.ProjectConfigAdapter;
|
||||
import org.eclipse.xtext.xbase.lib.Procedures.Procedure2;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
/**
|
||||
* @author Sven Efftinge - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
public class ProjectManager {
|
||||
@Inject
|
||||
protected IncrementalBuilder incrementalBuilder;
|
||||
|
||||
@Inject
|
||||
protected Provider<XtextResourceSet> resourceSetProvider;
|
||||
|
||||
@Inject
|
||||
protected IResourceServiceProvider.Registry languagesRegistry;
|
||||
|
||||
@Inject
|
||||
protected IFileSystemScanner fileSystemScanner;
|
||||
|
||||
@Inject
|
||||
protected IExternalContentSupport externalContentSupport;
|
||||
|
||||
private IndexState indexState = new IndexState();
|
||||
|
||||
private URI baseDir;
|
||||
|
||||
private Procedure2<? super URI, ? super Iterable<Issue>> issueAcceptor;
|
||||
|
||||
private Provider<Map<String, ResourceDescriptionsData>> indexProvider;
|
||||
|
||||
private IExternalContentSupport.IExternalContentProvider openedDocumentsContentProvider;
|
||||
|
||||
private XtextResourceSet resourceSet;
|
||||
|
||||
private ProjectDescription projectDescription;
|
||||
|
||||
private IProjectConfig projectConfig;
|
||||
|
||||
public void initialize(ProjectDescription description, IProjectConfig projectConfig,
|
||||
Procedure2<? super URI, ? super Iterable<Issue>> acceptor,
|
||||
IExternalContentSupport.IExternalContentProvider openedDocumentsContentProvider,
|
||||
Provider<Map<String, ResourceDescriptionsData>> indexProvider, CancelIndicator cancelIndicator) {
|
||||
this.projectDescription = description;
|
||||
this.projectConfig = projectConfig;
|
||||
this.baseDir = projectConfig.getPath();
|
||||
this.issueAcceptor = acceptor;
|
||||
this.openedDocumentsContentProvider = openedDocumentsContentProvider;
|
||||
this.indexProvider = indexProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initial build of this project.
|
||||
*/
|
||||
public IncrementalBuilder.Result doInitialBuild(CancelIndicator cancelIndicator) {
|
||||
List<URI> allUris = new ArrayList<>();
|
||||
for (ISourceFolder srcFolder : projectConfig.getSourceFolders()) {
|
||||
allUris.addAll(srcFolder.getAllResources(fileSystemScanner));
|
||||
}
|
||||
return doBuild(allUris, Collections.emptyList(), Collections.emptyList(), cancelIndicator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build this project.
|
||||
*/
|
||||
public IncrementalBuilder.Result doBuild(List<URI> dirtyFiles, List<URI> deletedFiles,
|
||||
List<IResourceDescription.Delta> externalDeltas, CancelIndicator cancelIndicator) {
|
||||
BuildRequest request = newBuildRequest(dirtyFiles, deletedFiles, externalDeltas, cancelIndicator);
|
||||
IncrementalBuilder.Result result = incrementalBuilder.build(request,
|
||||
languagesRegistry::getResourceServiceProvider);
|
||||
indexState = result.getIndexState();
|
||||
resourceSet = request.getResourceSet();
|
||||
indexProvider.get().put(projectDescription.getName(), indexState.getResourceDescriptions());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new build request for this project.
|
||||
*/
|
||||
protected BuildRequest newBuildRequest(List<URI> changedFiles, List<URI> deletedFiles,
|
||||
List<IResourceDescription.Delta> externalDeltas, CancelIndicator cancelIndicator) {
|
||||
BuildRequest result = new BuildRequest();
|
||||
result.setBaseDir(baseDir);
|
||||
result.setState(
|
||||
new IndexState(indexState.getResourceDescriptions().copy(), indexState.getFileMappings().copy()));
|
||||
result.setResourceSet(createFreshResourceSet(result.getState().getResourceDescriptions()));
|
||||
result.setDirtyFiles(changedFiles);
|
||||
result.setDeletedFiles(deletedFiles);
|
||||
result.setExternalDeltas(externalDeltas);
|
||||
result.setAfterValidate((URI uri, Iterable<Issue> issues) -> {
|
||||
issueAcceptor.apply(uri, issues);
|
||||
return true;
|
||||
});
|
||||
result.setCancelIndicator(cancelIndicator);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and configure a new resource set for this project.
|
||||
*/
|
||||
public XtextResourceSet createNewResourceSet(ResourceDescriptionsData newIndex) {
|
||||
XtextResourceSet result = resourceSetProvider.get();
|
||||
projectDescription.attachToEmfObject(result);
|
||||
ProjectConfigAdapter.install(result, projectConfig);
|
||||
ChunkedResourceDescriptions index = new ChunkedResourceDescriptions(indexProvider.get(), result);
|
||||
index.setContainer(projectDescription.getName(), newIndex);
|
||||
externalContentSupport.configureResourceSet(result, openedDocumentsContentProvider);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an empty resource set.
|
||||
*/
|
||||
protected XtextResourceSet createFreshResourceSet(ResourceDescriptionsData newIndex) {
|
||||
if (resourceSet == null) {
|
||||
resourceSet = createNewResourceSet(newIndex);
|
||||
} else {
|
||||
ChunkedResourceDescriptions resDescs = ChunkedResourceDescriptions.findInEmfObject(resourceSet);
|
||||
for (Map.Entry<String, ResourceDescriptionsData> entry : indexProvider.get().entrySet()) {
|
||||
resDescs.setContainer(entry.getKey(), entry.getValue());
|
||||
}
|
||||
resDescs.setContainer(projectDescription.getName(), newIndex);
|
||||
}
|
||||
return resourceSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the resource with the given URI.
|
||||
*/
|
||||
public Resource getResource(URI uri) {
|
||||
Resource resource = resourceSet.getResource(uri, true);
|
||||
resource.getContents();
|
||||
return resource;
|
||||
}
|
||||
|
||||
public void reportProjectIssue(String message, String code, Severity severity) {
|
||||
Issue.IssueImpl result = new Issue.IssueImpl();
|
||||
result.setMessage(message);
|
||||
result.setCode(code);
|
||||
result.setSeverity(severity);
|
||||
result.setUriToProblem(baseDir);
|
||||
issueAcceptor.apply(baseDir, ImmutableList.of(result));
|
||||
}
|
||||
|
||||
public IndexState getIndexState() {
|
||||
return indexState;
|
||||
}
|
||||
|
||||
protected void setIndexState(IndexState indexState) {
|
||||
this.indexState = indexState;
|
||||
}
|
||||
|
||||
public URI getBaseDir() {
|
||||
return baseDir;
|
||||
}
|
||||
|
||||
protected Procedure2<? super URI, ? super Iterable<Issue>> getIssueAcceptor() {
|
||||
return issueAcceptor;
|
||||
}
|
||||
|
||||
protected Provider<Map<String, ResourceDescriptionsData>> getIndexProvider() {
|
||||
return indexProvider;
|
||||
}
|
||||
|
||||
protected IExternalContentSupport.IExternalContentProvider getOpenedDocumentsContentProvider() {
|
||||
return openedDocumentsContentProvider;
|
||||
}
|
||||
|
||||
public XtextResourceSet getResourceSet() {
|
||||
return resourceSet;
|
||||
}
|
||||
|
||||
public ProjectDescription getProjectDescription() {
|
||||
return projectDescription;
|
||||
}
|
||||
|
||||
public IProjectConfig getProjectConfig() {
|
||||
return projectConfig;
|
||||
}
|
||||
}
|
|
@ -1,152 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2017 TypeFox GmbH (http://www.typefox.io) 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.ide.server
|
||||
|
||||
import com.google.inject.Inject
|
||||
import com.google.inject.Provider
|
||||
import java.util.List
|
||||
import java.util.Map
|
||||
import org.eclipse.emf.common.util.URI
|
||||
import org.eclipse.emf.ecore.resource.Resource
|
||||
import org.eclipse.xtend.lib.annotations.Accessors
|
||||
import org.eclipse.xtext.build.BuildRequest
|
||||
import org.eclipse.xtext.build.IncrementalBuilder
|
||||
import org.eclipse.xtext.build.IncrementalBuilder.Result
|
||||
import org.eclipse.xtext.build.IndexState
|
||||
import org.eclipse.xtext.diagnostics.Severity
|
||||
import org.eclipse.xtext.resource.IExternalContentSupport
|
||||
import org.eclipse.xtext.resource.IExternalContentSupport.IExternalContentProvider
|
||||
import org.eclipse.xtext.resource.IResourceServiceProvider
|
||||
import org.eclipse.xtext.resource.XtextResourceSet
|
||||
import org.eclipse.xtext.resource.impl.ChunkedResourceDescriptions
|
||||
import org.eclipse.xtext.resource.impl.ProjectDescription
|
||||
import org.eclipse.xtext.resource.impl.ResourceDescriptionsData
|
||||
import org.eclipse.xtext.util.CancelIndicator
|
||||
import org.eclipse.xtext.util.IFileSystemScanner
|
||||
import org.eclipse.xtext.validation.Issue
|
||||
import org.eclipse.xtext.workspace.IProjectConfig
|
||||
import org.eclipse.xtext.workspace.ProjectConfigAdapter
|
||||
import org.eclipse.xtext.resource.IResourceDescription
|
||||
|
||||
/**
|
||||
* @author Sven Efftinge - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
class ProjectManager {
|
||||
|
||||
@Inject protected IncrementalBuilder incrementalBuilder
|
||||
@Inject protected Provider<XtextResourceSet> resourceSetProvider
|
||||
@Inject protected IResourceServiceProvider.Registry languagesRegistry
|
||||
@Inject protected IFileSystemScanner fileSystemScanner
|
||||
@Inject protected IExternalContentSupport externalContentSupport
|
||||
|
||||
@Accessors(PUBLIC_GETTER, PROTECTED_SETTER)
|
||||
IndexState indexState = new IndexState
|
||||
|
||||
@Accessors(PUBLIC_GETTER)
|
||||
URI baseDir
|
||||
|
||||
@Accessors(PROTECTED_GETTER) (URI, Iterable<Issue>)=>void issueAcceptor
|
||||
@Accessors(PROTECTED_GETTER) Provider<Map<String, ResourceDescriptionsData>> indexProvider
|
||||
@Accessors(PROTECTED_GETTER) IExternalContentProvider openedDocumentsContentProvider
|
||||
|
||||
@Accessors(PUBLIC_GETTER)
|
||||
XtextResourceSet resourceSet
|
||||
|
||||
@Accessors(PUBLIC_GETTER)
|
||||
ProjectDescription projectDescription
|
||||
|
||||
@Accessors(PUBLIC_GETTER)
|
||||
IProjectConfig projectConfig
|
||||
|
||||
def void initialize(ProjectDescription description, IProjectConfig projectConfig, (URI, Iterable<Issue>)=>void acceptor, IExternalContentProvider openedDocumentsContentProvider, Provider<Map<String, ResourceDescriptionsData>> indexProvider, CancelIndicator cancelIndicator) {
|
||||
this.projectDescription = description
|
||||
this.projectConfig = projectConfig
|
||||
this.baseDir = projectConfig.path
|
||||
this.issueAcceptor = acceptor
|
||||
this.openedDocumentsContentProvider = openedDocumentsContentProvider
|
||||
this.indexProvider = indexProvider
|
||||
}
|
||||
|
||||
def Result doInitialBuild(CancelIndicator cancelIndicator) {
|
||||
val uris = newArrayList
|
||||
projectConfig.sourceFolders.forEach [
|
||||
uris += it.getAllResources(fileSystemScanner)
|
||||
]
|
||||
return doBuild(uris, emptyList, emptyList, cancelIndicator)
|
||||
}
|
||||
|
||||
def Result doBuild(List<URI> dirtyFiles, List<URI> deletedFiles, List<IResourceDescription.Delta> externalDeltas, CancelIndicator cancelIndicator) {
|
||||
val request = newBuildRequest(dirtyFiles, deletedFiles, externalDeltas, cancelIndicator)
|
||||
val result = incrementalBuilder.build(request, [
|
||||
languagesRegistry.getResourceServiceProvider(it)
|
||||
])
|
||||
indexState = result.indexState
|
||||
resourceSet = request.resourceSet
|
||||
indexProvider.get.put(projectDescription.name, indexState.resourceDescriptions)
|
||||
return result;
|
||||
}
|
||||
|
||||
protected def BuildRequest newBuildRequest(List<URI> changedFiles, List<URI> deletedFiles, List<IResourceDescription.Delta> externalDeltas, CancelIndicator cancelIndicator) {
|
||||
new BuildRequest => [
|
||||
it.baseDir = baseDir
|
||||
it.state = new IndexState(indexState.resourceDescriptions.copy, indexState.fileMappings.copy)
|
||||
it.resourceSet = createFreshResourceSet(state.resourceDescriptions)
|
||||
it.dirtyFiles = changedFiles
|
||||
it.deletedFiles = deletedFiles
|
||||
it.externalDeltas = externalDeltas
|
||||
afterValidate = [ uri, issues |
|
||||
issueAcceptor.apply(uri, issues)
|
||||
return true
|
||||
]
|
||||
it.cancelIndicator = cancelIndicator
|
||||
]
|
||||
}
|
||||
|
||||
def XtextResourceSet createNewResourceSet(ResourceDescriptionsData newIndex) {
|
||||
resourceSetProvider.get => [
|
||||
projectDescription.attachToEmfObject(it)
|
||||
ProjectConfigAdapter.install(it, projectConfig)
|
||||
val index = new ChunkedResourceDescriptions(indexProvider.get, it)
|
||||
index.setContainer(projectDescription.name, newIndex)
|
||||
externalContentSupport.configureResourceSet(it, openedDocumentsContentProvider)
|
||||
]
|
||||
}
|
||||
|
||||
protected def XtextResourceSet createFreshResourceSet(ResourceDescriptionsData newIndex) {
|
||||
if (this.resourceSet === null) {
|
||||
this.resourceSet = createNewResourceSet(newIndex)
|
||||
} else {
|
||||
val resDescs = ChunkedResourceDescriptions.findInEmfObject(this.resourceSet);
|
||||
// update index with possible upstream changes
|
||||
for (entry : indexProvider.get.entrySet) {
|
||||
resDescs.setContainer(entry.key, entry.value)
|
||||
}
|
||||
resDescs.setContainer(projectDescription.name, newIndex)
|
||||
}
|
||||
return this.resourceSet;
|
||||
}
|
||||
|
||||
def Resource getResource(URI uri) {
|
||||
val resource = resourceSet.getResource(uri, true)
|
||||
// initialize
|
||||
resource.contents
|
||||
return resource
|
||||
}
|
||||
|
||||
def void reportProjectIssue(String message, String code, Severity severity) {
|
||||
issueAcceptor.apply(baseDir, #[
|
||||
new Issue.IssueImpl => [
|
||||
it.message = message
|
||||
it.code = code
|
||||
it.severity = severity
|
||||
it.uriToProblem = baseDir
|
||||
]
|
||||
])
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2017 TypeFox GmbH (http://www.typefox.io) 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.ide.server;
|
||||
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.xtext.workspace.FileProjectConfig;
|
||||
import org.eclipse.xtext.workspace.IWorkspaceConfig;
|
||||
import org.eclipse.xtext.workspace.WorkspaceConfig;
|
||||
|
||||
/**
|
||||
* The workspace itself is a single project
|
||||
*
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
public class ProjectWorkspaceConfigFactory implements IWorkspaceConfigFactory {
|
||||
@Override
|
||||
public IWorkspaceConfig getWorkspaceConfig(URI workspaceBaseURI) {
|
||||
WorkspaceConfig workspaceConfig = new WorkspaceConfig();
|
||||
findProjects(workspaceConfig, workspaceBaseURI);
|
||||
return workspaceConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all projects at the given location. By default, only the a single project at the workspace root is created.
|
||||
*/
|
||||
protected void findProjects(WorkspaceConfig workspaceConfig, URI location) {
|
||||
if (location != null) {
|
||||
FileProjectConfig project = new FileProjectConfig(location, workspaceConfig);
|
||||
project.addSourceFolder(".");
|
||||
workspaceConfig.addProject(project);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,443 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2017 TypeFox GmbH (http://www.typefox.io) 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.ide.server;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.lsp4j.DidChangeTextDocumentParams;
|
||||
import org.eclipse.lsp4j.TextDocumentContentChangeEvent;
|
||||
import org.eclipse.lsp4j.TextEdit;
|
||||
import org.eclipse.lsp4j.jsonrpc.ResponseErrorException;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.ResponseError;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.ResponseErrorCode;
|
||||
import org.eclipse.xtext.ide.server.BuildManager.Buildable;
|
||||
import org.eclipse.xtext.resource.IExternalContentSupport;
|
||||
import org.eclipse.xtext.resource.IResourceDescription;
|
||||
import org.eclipse.xtext.resource.IResourceDescriptions;
|
||||
import org.eclipse.xtext.resource.XtextResource;
|
||||
import org.eclipse.xtext.resource.XtextResourceSet;
|
||||
import org.eclipse.xtext.resource.impl.ChunkedResourceDescriptions;
|
||||
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.IWorkspaceConfig;
|
||||
import org.eclipse.xtext.xbase.lib.Functions.Function2;
|
||||
import org.eclipse.xtext.xbase.lib.Procedures.Procedure2;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
/**
|
||||
* @author Sven Efftinge - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
public class WorkspaceManager {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(WorkspaceManager.class);
|
||||
|
||||
@Inject
|
||||
private Provider<ProjectManager> projectManagerProvider;
|
||||
|
||||
@Inject
|
||||
private IWorkspaceConfigFactory workspaceConfigFactory;
|
||||
|
||||
@Inject
|
||||
private IProjectDescriptionFactory projectDescriptionFactory;
|
||||
|
||||
private BuildManager buildManager;
|
||||
|
||||
private URI baseDir;
|
||||
|
||||
private Procedure2<? super URI, ? super Iterable<Issue>> issueAcceptor;
|
||||
|
||||
private IWorkspaceConfig workspaceConfig;
|
||||
|
||||
private final Map<String, ProjectManager> projectName2ProjectManager = new HashMap<>();
|
||||
|
||||
private final List<ILanguageServerAccess.IBuildListener> buildListeners = new ArrayList<>();
|
||||
|
||||
private final Map<String, ResourceDescriptionsData> fullIndex = new HashMap<>();
|
||||
|
||||
private final Map<URI, Document> openDocuments = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Add the listener to this workspace.
|
||||
*
|
||||
* @param listener
|
||||
* the new listener.
|
||||
*/
|
||||
public void addBuildListener(ILanguageServerAccess.IBuildListener listener) {
|
||||
buildListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a build listener if it was previously registered
|
||||
*
|
||||
* @since 2.18
|
||||
*/
|
||||
public void removeBuildListener(ILanguageServerAccess.IBuildListener listener) {
|
||||
buildListeners.remove(listener);
|
||||
}
|
||||
|
||||
private final IExternalContentSupport.IExternalContentProvider openedDocumentsContentProvider = new IExternalContentSupport.IExternalContentProvider() {
|
||||
@Override
|
||||
public IExternalContentSupport.IExternalContentProvider getActualContentProvider() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContent(URI uri) {
|
||||
Document document = openDocuments.get(uri);
|
||||
if (document != null) {
|
||||
return document.getContents();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasContent(URI uri) {
|
||||
return isDocumentOpen(uri);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Inject the build manager and establish circular dependency.
|
||||
*
|
||||
* @param buildManager
|
||||
* the build manager.
|
||||
*/
|
||||
@Inject
|
||||
public void setBuildManager(BuildManager buildManager) {
|
||||
buildManager.setWorkspaceManager(this);
|
||||
this.buildManager = buildManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a workspace at the given location.
|
||||
*
|
||||
* @param baseDir
|
||||
* the location
|
||||
* @param issueAcceptor
|
||||
* the issue acceptor
|
||||
* @param cancelIndicator
|
||||
* allows to cancel the initialization
|
||||
*/
|
||||
public void initialize(URI baseDir, Procedure2<? super URI, ? super Iterable<Issue>> issueAcceptor,
|
||||
CancelIndicator cancelIndicator) {
|
||||
this.baseDir = baseDir;
|
||||
this.issueAcceptor = issueAcceptor;
|
||||
refreshWorkspaceConfig(cancelIndicator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the workspace.
|
||||
*/
|
||||
protected void refreshWorkspaceConfig(CancelIndicator cancelIndicator) {
|
||||
setWorkspaceConfig(workspaceConfigFactory.getWorkspaceConfig(baseDir));
|
||||
List<ProjectDescription> newProjects = new ArrayList<>();
|
||||
Set<String> projectNames = projectName2ProjectManager.keySet();
|
||||
Set<String> remainingProjectNames = new HashSet<>(projectNames);
|
||||
for (IProjectConfig projectConfig : getWorkspaceConfig().getProjects()) {
|
||||
if (projectName2ProjectManager.containsKey(projectConfig.getName())) {
|
||||
remainingProjectNames.remove(projectConfig.getName());
|
||||
} else {
|
||||
ProjectManager projectManager = projectManagerProvider.get();
|
||||
ProjectDescription projectDescription = projectDescriptionFactory.getProjectDescription(projectConfig);
|
||||
projectManager.initialize(projectDescription, projectConfig, issueAcceptor,
|
||||
openedDocumentsContentProvider, () -> fullIndex, cancelIndicator);
|
||||
projectName2ProjectManager.put(projectDescription.getName(), projectManager);
|
||||
newProjects.add(projectDescription);
|
||||
}
|
||||
}
|
||||
for (String deletedProject : remainingProjectNames) {
|
||||
projectName2ProjectManager.remove(deletedProject);
|
||||
fullIndex.remove(deletedProject);
|
||||
}
|
||||
afterBuild(buildManager.doInitialBuild(newProjects, cancelIndicator));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the workspace configuration
|
||||
* @throws ResponseErrorException
|
||||
* if the workspace is not yet initialized
|
||||
*/
|
||||
protected IWorkspaceConfig getWorkspaceConfig() throws ResponseErrorException {
|
||||
if (workspaceConfig == null) {
|
||||
ResponseError error = new ResponseError(ResponseErrorCode.serverNotInitialized,
|
||||
"Workspace has not been initialized yet.", null);
|
||||
throw new ResponseErrorException(error);
|
||||
}
|
||||
return workspaceConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param workspaceConfig
|
||||
* the new workspace configuration.
|
||||
*/
|
||||
protected void setWorkspaceConfig(IWorkspaceConfig workspaceConfig) {
|
||||
this.workspaceConfig = workspaceConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback after a build was performend
|
||||
*/
|
||||
protected void afterBuild(List<IResourceDescription.Delta> deltas) {
|
||||
for (ILanguageServerAccess.IBuildListener listener : buildListeners) {
|
||||
listener.afterBuild(deltas);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Announce dirty and deleted files and provide means to start a build.
|
||||
*
|
||||
* @param dirtyFiles
|
||||
* the dirty files
|
||||
* @param deletedFiles
|
||||
* the deleted files
|
||||
* @return a build command that can be triggered
|
||||
*/
|
||||
public Buildable didChangeFiles(List<URI> dirtyFiles, List<URI> deletedFiles) {
|
||||
BuildManager.Buildable buildable = buildManager.submit(dirtyFiles, deletedFiles);
|
||||
return (cancelIndicator) -> {
|
||||
List<IResourceDescription.Delta> deltas = buildable.build(cancelIndicator);
|
||||
afterBuild(deltas);
|
||||
return deltas;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Announce dirty and deleted files and perform a build.
|
||||
*
|
||||
* @param dirtyFiles
|
||||
* the dirty files
|
||||
* @param deletedFiles
|
||||
* the deleted files
|
||||
* @param cancelIndicator
|
||||
* cancellation support
|
||||
* @return the delta
|
||||
*/
|
||||
public List<IResourceDescription.Delta> doBuild(List<URI> dirtyFiles, List<URI> deletedFiles,
|
||||
CancelIndicator cancelIndicator) {
|
||||
return didChangeFiles(dirtyFiles, deletedFiles).build(cancelIndicator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current index.
|
||||
*/
|
||||
public IResourceDescriptions getIndex() {
|
||||
return new ChunkedResourceDescriptions(fullIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the project that contains the given URI.
|
||||
*
|
||||
* @param uri
|
||||
* the contained uri
|
||||
* @return the project base uri.
|
||||
*/
|
||||
public URI getProjectBaseDir(URI uri) {
|
||||
IProjectConfig projectConfig = getProjectConfig(uri);
|
||||
if (projectConfig != null) {
|
||||
return projectConfig.getPath();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uri
|
||||
* the contained uri
|
||||
* @return the project manager.
|
||||
*/
|
||||
public ProjectManager getProjectManager(URI uri) {
|
||||
IProjectConfig projectConfig = getProjectConfig(uri);
|
||||
String name = null;
|
||||
if (projectConfig != null) {
|
||||
name = projectConfig.getName();
|
||||
}
|
||||
return getProjectManager(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the project that contains the uri.
|
||||
*/
|
||||
protected IProjectConfig getProjectConfig(URI uri) {
|
||||
return getWorkspaceConfig().findProjectContaining(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the project manager for the project with the given name.
|
||||
*
|
||||
* @param projectName
|
||||
* the project name
|
||||
* @return the project manager
|
||||
*/
|
||||
public ProjectManager getProjectManager(String projectName) {
|
||||
return projectName2ProjectManager.get(projectName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all project managers.
|
||||
*
|
||||
* @return all project managers.
|
||||
*/
|
||||
public List<ProjectManager> getProjectManagers() {
|
||||
return ImmutableList.copyOf(projectName2ProjectManager.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated the server should not apply {@link TextEdit}s but {@link TextDocumentContentChangeEvent}s. Use
|
||||
* {@link #didChangeTextDocumentContent(URI, Integer, Iterable)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public List<IResourceDescription.Delta> didChange(URI uri, Integer version, Iterable<TextEdit> changes,
|
||||
CancelIndicator cancelIndicator) {
|
||||
return didChange(uri, version, changes).build(cancelIndicator);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param version
|
||||
* unused
|
||||
* @deprecated the server should not apply {@link TextEdit}s but {@link TextDocumentContentChangeEvent}s. Use
|
||||
* {@link #didChangeTextDocumentContent(URI, Integer, Iterable)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public BuildManager.Buildable didChange(URI uri, Integer version, Iterable<TextEdit> changes) {
|
||||
Document contents = openDocuments.get(uri);
|
||||
if (contents == null) {
|
||||
LOG.error("The document " + uri + " has not been opened.");
|
||||
return Buildable.NO_BUILD;
|
||||
}
|
||||
openDocuments.put(uri, contents.applyChanges(changes));
|
||||
return didChangeFiles(ImmutableList.of(uri), Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* As opposed to {@link TextEdit}[] the positions in the edits of a {@link DidChangeTextDocumentParams} refer to the
|
||||
* state after applying the preceding edits. See
|
||||
* https://microsoft.github.io/language-server-protocol/specification#textedit-1 and
|
||||
* https://github.com/microsoft/vscode/issues/23173#issuecomment-289378160 for details.
|
||||
*
|
||||
* In particular, this has to be taken into account when undoing the deletion of multiple characters at the end of a
|
||||
* line.
|
||||
*
|
||||
* @since 2.18
|
||||
* @param version
|
||||
* unused
|
||||
*/
|
||||
public BuildManager.Buildable didChangeTextDocumentContent(URI uri, Integer version,
|
||||
Iterable<TextDocumentContentChangeEvent> changes) {
|
||||
Document contents = openDocuments.get(uri);
|
||||
if (contents == null) {
|
||||
LOG.error("The document " + uri + " has not been opened.");
|
||||
return Buildable.NO_BUILD;
|
||||
}
|
||||
openDocuments.put(uri, contents.applyTextDocumentChanges(changes));
|
||||
return didChangeFiles(ImmutableList.of(uri), Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the given document as open and build it.
|
||||
*/
|
||||
public List<IResourceDescription.Delta> didOpen(URI uri, Integer version, String contents,
|
||||
CancelIndicator cancelIndicator) {
|
||||
return didOpen(uri, version, contents).build(cancelIndicator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the given document as open.
|
||||
*/
|
||||
public BuildManager.Buildable didOpen(URI uri, Integer version, String contents) {
|
||||
openDocuments.put(uri, new Document(version, contents));
|
||||
return didChangeFiles(ImmutableList.of(uri), Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated this method is no longer called
|
||||
*/
|
||||
@Deprecated
|
||||
public List<IResourceDescription.Delta> didClose(URI uri, CancelIndicator cancelIndicator) {
|
||||
return didClose(uri).build(cancelIndicator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the given document as cloded.
|
||||
*/
|
||||
public BuildManager.Buildable didClose(URI uri) {
|
||||
openDocuments.remove(uri);
|
||||
if (exists(uri)) {
|
||||
return didChangeFiles(ImmutableList.of(uri), Collections.emptyList());
|
||||
}
|
||||
return didChangeFiles(Collections.emptyList(), ImmutableList.of(uri));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the given resource still exists.
|
||||
*/
|
||||
protected boolean exists(URI uri) {
|
||||
ProjectManager projectManager = getProjectManager(uri);
|
||||
if (projectManager != null) {
|
||||
XtextResourceSet rs = projectManager.getResourceSet();
|
||||
if (rs != null) {
|
||||
return rs.getURIConverter().exists(uri, null);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the resource and the document with the given URI and performa a read operation.
|
||||
*/
|
||||
public <T> T doRead(URI uri, Function2<? super Document, ? super XtextResource, ? extends T> work) {
|
||||
URI resourceURI = uri.trimFragment();
|
||||
ProjectManager projectMnr = getProjectManager(resourceURI);
|
||||
if (projectMnr != null) {
|
||||
XtextResource resource = (XtextResource) projectMnr.getResource(resourceURI);
|
||||
Document doc = getDocument(resource);
|
||||
return work.apply(doc, resource);
|
||||
}
|
||||
return work.apply(null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the document for the given resource.
|
||||
*
|
||||
* @param resource
|
||||
* the resource.
|
||||
* @return the document
|
||||
*/
|
||||
protected Document getDocument(XtextResource resource) {
|
||||
Document doc = openDocuments.get(resource.getURI());
|
||||
if (doc != null) {
|
||||
return doc;
|
||||
}
|
||||
String text = resource.getParseResult().getRootNode().getText();
|
||||
return new Document(1, text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there is a open document with the givne URI.
|
||||
*
|
||||
* @param uri
|
||||
* the URI
|
||||
*/
|
||||
public boolean isDocumentOpen(URI uri) {
|
||||
return openDocuments.containsKey(uri);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,277 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2017 TypeFox GmbH (http://www.typefox.io) 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.ide.server
|
||||
|
||||
import com.google.inject.Inject
|
||||
import com.google.inject.Provider
|
||||
import java.util.ArrayList
|
||||
import java.util.HashSet
|
||||
import java.util.List
|
||||
import java.util.Map
|
||||
import java.util.Set
|
||||
import org.eclipse.emf.common.util.URI
|
||||
import org.eclipse.lsp4j.DidChangeTextDocumentParams
|
||||
import org.eclipse.lsp4j.TextDocumentContentChangeEvent
|
||||
import org.eclipse.lsp4j.TextEdit
|
||||
import org.eclipse.lsp4j.jsonrpc.ResponseErrorException
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.ResponseError
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.ResponseErrorCode
|
||||
import org.eclipse.xtext.ide.server.BuildManager.Buildable
|
||||
import org.eclipse.xtext.ide.server.ILanguageServerAccess.IBuildListener
|
||||
import org.eclipse.xtext.resource.IExternalContentSupport.IExternalContentProvider
|
||||
import org.eclipse.xtext.resource.IResourceDescription
|
||||
import org.eclipse.xtext.resource.IResourceDescription.Delta
|
||||
import org.eclipse.xtext.resource.IResourceDescriptions
|
||||
import org.eclipse.xtext.resource.XtextResource
|
||||
import org.eclipse.xtext.resource.impl.ChunkedResourceDescriptions
|
||||
import org.eclipse.xtext.resource.impl.ResourceDescriptionsData
|
||||
import org.eclipse.xtext.util.CancelIndicator
|
||||
import org.eclipse.xtext.util.internal.Log
|
||||
import org.eclipse.xtext.validation.Issue
|
||||
import org.eclipse.xtext.workspace.IWorkspaceConfig
|
||||
|
||||
/**
|
||||
* @author Sven Efftinge - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
@Log class WorkspaceManager {
|
||||
|
||||
@Inject Provider<ProjectManager> projectManagerProvider
|
||||
@Inject IWorkspaceConfigFactory workspaceConfigFactory
|
||||
@Inject IProjectDescriptionFactory projectDescriptionFactory
|
||||
|
||||
BuildManager buildManager
|
||||
|
||||
Map<String, ProjectManager> projectName2ProjectManager = newHashMap
|
||||
|
||||
URI baseDir
|
||||
(URI, Iterable<Issue>)=>void issueAcceptor
|
||||
IWorkspaceConfig _workspaceConfig
|
||||
|
||||
List<IBuildListener> buildListeners = newArrayList
|
||||
|
||||
def void addBuildListener(IBuildListener listener) {
|
||||
this.buildListeners += listener
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a build listener if it was previously registered
|
||||
*
|
||||
* @since 2.18
|
||||
*/
|
||||
def void removeBuildListener(IBuildListener listener) {
|
||||
buildListeners.remove(listener)
|
||||
}
|
||||
|
||||
Map<String, ResourceDescriptionsData> fullIndex = newHashMap()
|
||||
|
||||
Map<URI, Document> openDocuments = newHashMap()
|
||||
|
||||
val openedDocumentsContentProvider = new IExternalContentProvider() {
|
||||
|
||||
override getActualContentProvider() {
|
||||
return this
|
||||
}
|
||||
|
||||
override getContent(URI uri) {
|
||||
openDocuments.get(uri)?.contents
|
||||
}
|
||||
|
||||
override hasContent(URI uri) {
|
||||
openDocuments.containsKey(uri)
|
||||
}
|
||||
};
|
||||
|
||||
@Inject
|
||||
def void setBuildManager(BuildManager buildManager) {
|
||||
buildManager.workspaceManager = this
|
||||
this.buildManager = buildManager
|
||||
}
|
||||
|
||||
def void initialize(URI baseDir, (URI, Iterable<Issue>)=>void issueAcceptor, CancelIndicator cancelIndicator) {
|
||||
this.baseDir = baseDir
|
||||
this.issueAcceptor = issueAcceptor
|
||||
refreshWorkspaceConfig(cancelIndicator)
|
||||
}
|
||||
|
||||
protected def void refreshWorkspaceConfig(CancelIndicator cancelIndicator) {
|
||||
workspaceConfig = workspaceConfigFactory.getWorkspaceConfig(baseDir)
|
||||
val newProjects = newArrayList
|
||||
val Set<String> remainingProjectNames = new HashSet(projectName2ProjectManager.keySet)
|
||||
workspaceConfig.projects.forEach [ projectConfig |
|
||||
if (projectName2ProjectManager.containsKey(projectConfig.name)) {
|
||||
remainingProjectNames.remove(projectConfig.name)
|
||||
} else {
|
||||
val projectManager = projectManagerProvider.get
|
||||
val projectDescription = projectDescriptionFactory.getProjectDescription(projectConfig)
|
||||
projectManager.initialize(projectDescription, projectConfig, issueAcceptor,
|
||||
openedDocumentsContentProvider, [fullIndex], cancelIndicator)
|
||||
projectName2ProjectManager.put(projectDescription.name, projectManager)
|
||||
newProjects.add(projectDescription)
|
||||
}
|
||||
]
|
||||
for (deletedProject : remainingProjectNames) {
|
||||
projectName2ProjectManager.remove(deletedProject)
|
||||
fullIndex.remove(deletedProject)
|
||||
}
|
||||
val result = buildManager.doInitialBuild(newProjects, cancelIndicator)
|
||||
afterBuild(result)
|
||||
}
|
||||
|
||||
protected def IWorkspaceConfig getWorkspaceConfig() {
|
||||
if (_workspaceConfig === null) {
|
||||
val error = new ResponseError(ResponseErrorCode.serverNotInitialized,
|
||||
"Workspace has not been initialized yet.", null)
|
||||
throw new ResponseErrorException(error)
|
||||
}
|
||||
return _workspaceConfig
|
||||
}
|
||||
|
||||
protected def void setWorkspaceConfig(IWorkspaceConfig workspaceConfig) {
|
||||
this._workspaceConfig = workspaceConfig
|
||||
}
|
||||
|
||||
protected def void afterBuild(List<Delta> deltas) {
|
||||
for (listener : buildListeners) {
|
||||
listener.afterBuild(deltas)
|
||||
}
|
||||
}
|
||||
|
||||
def Buildable didChangeFiles(List<URI> dirtyFiles, List<URI> deletedFiles) {
|
||||
val buildable = buildManager.submit(dirtyFiles, deletedFiles)
|
||||
return [ cancelIndicator |
|
||||
val deltas = buildable.build(cancelIndicator)
|
||||
afterBuild(deltas)
|
||||
return deltas
|
||||
]
|
||||
}
|
||||
|
||||
def List<IResourceDescription.Delta> doBuild(List<URI> dirtyFiles, List<URI> deletedFiles,
|
||||
CancelIndicator cancelIndicator) {
|
||||
return didChangeFiles(dirtyFiles, deletedFiles).build(cancelIndicator)
|
||||
}
|
||||
|
||||
def IResourceDescriptions getIndex() {
|
||||
return new ChunkedResourceDescriptions(fullIndex)
|
||||
}
|
||||
|
||||
def URI getProjectBaseDir(URI uri) {
|
||||
val projectConfig = workspaceConfig.findProjectContaining(uri)
|
||||
return projectConfig?.path
|
||||
}
|
||||
|
||||
def ProjectManager getProjectManager(URI uri) {
|
||||
val projectConfig = workspaceConfig.findProjectContaining(uri)
|
||||
return projectName2ProjectManager.get(projectConfig?.name)
|
||||
}
|
||||
|
||||
def ProjectManager getProjectManager(String projectName) {
|
||||
projectName2ProjectManager.get(projectName)
|
||||
}
|
||||
|
||||
def List<ProjectManager> getProjectManagers() {
|
||||
new ArrayList(projectName2ProjectManager.values)
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated the server should not apply {@link TextEdit}s but {@link TextDocumentContentChangeEvent}s.
|
||||
* Use {@link #didChangeTextDocumentContent(URI, Integer, Iterable)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
def didChange(URI uri, Integer version, Iterable<TextEdit> changes, CancelIndicator cancelIndicator) {
|
||||
didChange(uri, version, changes).build(cancelIndicator)
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated the server should not apply {@link TextEdit}s but {@link TextDocumentContentChangeEvent}s.
|
||||
* Use {@link #didChangeTextDocumentContent(URI, Integer, Iterable)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
def Buildable didChange(URI uri, Integer version, Iterable<TextEdit> changes) {
|
||||
if (!openDocuments.containsKey(uri)) {
|
||||
LOG.error("The document " + uri + " has not been opened.")
|
||||
return [];
|
||||
}
|
||||
val contents = openDocuments.get(uri)
|
||||
openDocuments.put(uri, contents.applyChanges(changes))
|
||||
return didChangeFiles(#[uri], newArrayList)
|
||||
}
|
||||
|
||||
/**
|
||||
* As opposed to {@link TextEdit}[] the positions in the edits of a
|
||||
* {@link DidChangeTextDocumentParams} refer to the state after applying the preceding edits. See
|
||||
* https://microsoft.github.io/language-server-protocol/specification#textedit-1 and
|
||||
* https://github.com/microsoft/vscode/issues/23173#issuecomment-289378160 for details.
|
||||
*
|
||||
* In particular, this has to be taken into account when undoing the deletion of multiple characters
|
||||
* at the end of a line.
|
||||
*
|
||||
* @since 2.18
|
||||
*/
|
||||
def Buildable didChangeTextDocumentContent(URI uri, Integer version, Iterable<TextDocumentContentChangeEvent> changes) {
|
||||
if (!openDocuments.containsKey(uri)) {
|
||||
LOG.error("The document " + uri + " has not been opened.")
|
||||
return [];
|
||||
}
|
||||
val contents = openDocuments.get(uri)
|
||||
openDocuments.put(uri, contents.applyTextDocumentChanges(changes))
|
||||
return didChangeFiles(#[uri], newArrayList)
|
||||
}
|
||||
|
||||
def didOpen(URI uri, Integer version, String contents, CancelIndicator cancelIndicator) {
|
||||
didOpen(uri, version, contents).build(cancelIndicator)
|
||||
}
|
||||
|
||||
def Buildable didOpen(URI uri, Integer version, String contents) {
|
||||
openDocuments.put(uri, new Document(version, contents))
|
||||
return didChangeFiles(#[uri], newArrayList)
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated this method is no longer called
|
||||
*/
|
||||
@Deprecated
|
||||
def didClose(URI uri, CancelIndicator cancelIndicator) {
|
||||
didClose(uri).build(cancelIndicator)
|
||||
}
|
||||
|
||||
def Buildable didClose(URI uri) {
|
||||
openDocuments.remove(uri)
|
||||
if (exists(uri)) {
|
||||
return didChangeFiles(#[uri], newArrayList)
|
||||
}
|
||||
return didChangeFiles(newArrayList, #[uri])
|
||||
}
|
||||
|
||||
protected def boolean exists(URI uri) {
|
||||
val rs = getProjectManager(uri)?.resourceSet
|
||||
if (rs === null)
|
||||
return false
|
||||
return rs.URIConverter.exists(uri, null)
|
||||
}
|
||||
|
||||
def <T> T doRead(URI uri, (Document, XtextResource)=>T work) {
|
||||
val resourceURI = uri.trimFragment
|
||||
val projectMnr = getProjectManager(resourceURI)
|
||||
val resource = projectMnr?.getResource(resourceURI) as XtextResource
|
||||
if (resource === null) {
|
||||
return work.apply(null, null)
|
||||
}
|
||||
var doc = getDocument(resource)
|
||||
return work.apply(doc, resource)
|
||||
}
|
||||
|
||||
protected def Document getDocument(XtextResource resource) {
|
||||
return openDocuments.get(resource.URI) // lets create a transient document, in case a document is not open (e.g. formatting is called just by uri)
|
||||
?: new Document(1, resource.parseResult.rootNode.text)
|
||||
}
|
||||
|
||||
def boolean isDocumentOpen(URI uri) {
|
||||
return openDocuments.containsKey(uri)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2017 TypeFox GmbH (http://www.typefox.io) 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.ide.server.findReferences;
|
||||
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.emf.ecore.resource.ResourceSet;
|
||||
import org.eclipse.xtext.findReferences.IReferenceFinder;
|
||||
import org.eclipse.xtext.ide.server.WorkspaceManager;
|
||||
import org.eclipse.xtext.util.Exceptions;
|
||||
import org.eclipse.xtext.util.concurrent.IUnitOfWork;
|
||||
|
||||
/**
|
||||
* @author kosyakov - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
public class WorkspaceResourceAccess implements IReferenceFinder.IResourceAccess {
|
||||
|
||||
private final WorkspaceManager workspaceManager;
|
||||
|
||||
/**
|
||||
* @param workspaceManager
|
||||
* the workspace manager
|
||||
*/
|
||||
public WorkspaceResourceAccess(WorkspaceManager workspaceManager) {
|
||||
this.workspaceManager = workspaceManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R readOnly(URI targetURI, IUnitOfWork<R, ResourceSet> work) {
|
||||
return workspaceManager.doRead(targetURI, (document, resource) -> {
|
||||
if (resource == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return work.exec(resource.getResourceSet());
|
||||
} catch (Exception e) {
|
||||
return Exceptions.throwUncheckedException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2017 TypeFox GmbH (http://www.typefox.io) 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.ide.server.findReferences
|
||||
|
||||
import org.eclipse.emf.common.util.URI
|
||||
import org.eclipse.emf.ecore.resource.ResourceSet
|
||||
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor
|
||||
import org.eclipse.xtext.findReferences.IReferenceFinder.IResourceAccess
|
||||
import org.eclipse.xtext.ide.server.WorkspaceManager
|
||||
import org.eclipse.xtext.util.concurrent.IUnitOfWork
|
||||
|
||||
/**
|
||||
* @author kosyakov - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
@FinalFieldsConstructor
|
||||
class WorkspaceResourceAccess implements IResourceAccess {
|
||||
|
||||
val WorkspaceManager workspaceManager
|
||||
|
||||
override <R> readOnly(URI targetURI, IUnitOfWork<R, ResourceSet> work) {
|
||||
return workspaceManager.doRead(targetURI) [ document, resource |
|
||||
if (resource === null) {
|
||||
return null
|
||||
}
|
||||
return work.exec(resource.resourceSet)
|
||||
]
|
||||
}
|
||||
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
/**
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) 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.ide.server.rename;
|
||||
|
||||
import org.eclipse.lsp4j.RenameParams;
|
||||
|
@ -15,11 +15,10 @@ import org.eclipse.xtext.util.CancelIndicator;
|
|||
/**
|
||||
* @author koehnlein - Initial contribution and API
|
||||
* @since 2.13
|
||||
* @deprecated use {IRenameService2} instead.
|
||||
* @deprecated use {@link IRenameService2} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("all")
|
||||
public interface IRenameService {
|
||||
@Deprecated
|
||||
public abstract WorkspaceEdit rename(final WorkspaceManager workspaceManager, final RenameParams renameParams, final CancelIndicator cancelIndicator);
|
||||
}
|
||||
@Deprecated
|
||||
WorkspaceEdit rename(WorkspaceManager workspaceManager, RenameParams renameParams, CancelIndicator cancelIndicator);
|
||||
}
|
|
@ -15,21 +15,8 @@ import org.eclipse.lsp4j.WorkspaceEdit
|
|||
import org.eclipse.lsp4j.jsonrpc.messages.Either
|
||||
import org.eclipse.xtend.lib.annotations.Accessors
|
||||
import org.eclipse.xtext.ide.server.ILanguageServerAccess
|
||||
import org.eclipse.xtext.ide.server.WorkspaceManager
|
||||
import org.eclipse.xtext.util.CancelIndicator
|
||||
|
||||
/**
|
||||
* @author koehnlein - Initial contribution and API
|
||||
* @since 2.13
|
||||
* @deprecated use {IRenameService2} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
interface IRenameService {
|
||||
|
||||
@Deprecated
|
||||
def WorkspaceEdit rename(WorkspaceManager workspaceManager, RenameParams renameParams, CancelIndicator cancelIndicator)
|
||||
}
|
||||
|
||||
/**
|
||||
* Service called for rename refactoring.
|
||||
*
|
|
@ -1,248 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2016, 2017 TypeFox GmbH (http://www.typefox.io) 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.ide.server;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.xtend.lib.annotations.AccessorType;
|
||||
import org.eclipse.xtend.lib.annotations.Accessors;
|
||||
import org.eclipse.xtend.lib.annotations.Data;
|
||||
import org.eclipse.xtext.build.IncrementalBuilder;
|
||||
import org.eclipse.xtext.diagnostics.Severity;
|
||||
import org.eclipse.xtext.ide.server.ProjectManager;
|
||||
import org.eclipse.xtext.ide.server.TopologicalSorter;
|
||||
import org.eclipse.xtext.ide.server.WorkspaceManager;
|
||||
import org.eclipse.xtext.resource.IResourceDescription;
|
||||
import org.eclipse.xtext.resource.impl.DefaultResourceDescriptionDelta;
|
||||
import org.eclipse.xtext.resource.impl.ProjectDescription;
|
||||
import org.eclipse.xtext.util.CancelIndicator;
|
||||
import org.eclipse.xtext.xbase.lib.CollectionLiterals;
|
||||
import org.eclipse.xtext.xbase.lib.Functions.Function1;
|
||||
import org.eclipse.xtext.xbase.lib.IterableExtensions;
|
||||
import org.eclipse.xtext.xbase.lib.ListExtensions;
|
||||
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
|
||||
import org.eclipse.xtext.xbase.lib.Pure;
|
||||
import org.eclipse.xtext.xbase.lib.util.ToStringBuilder;
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public class BuildManager {
|
||||
@Data
|
||||
protected static class ProjectBuildData {
|
||||
private final List<URI> dirtyFiles;
|
||||
|
||||
private final List<URI> deletedFiles;
|
||||
|
||||
public ProjectBuildData(final List<URI> dirtyFiles, final List<URI> deletedFiles) {
|
||||
super();
|
||||
this.dirtyFiles = dirtyFiles;
|
||||
this.deletedFiles = deletedFiles;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Pure
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((this.dirtyFiles== null) ? 0 : this.dirtyFiles.hashCode());
|
||||
return prime * result + ((this.deletedFiles== null) ? 0 : this.deletedFiles.hashCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Pure
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
BuildManager.ProjectBuildData other = (BuildManager.ProjectBuildData) obj;
|
||||
if (this.dirtyFiles == null) {
|
||||
if (other.dirtyFiles != null)
|
||||
return false;
|
||||
} else if (!this.dirtyFiles.equals(other.dirtyFiles))
|
||||
return false;
|
||||
if (this.deletedFiles == null) {
|
||||
if (other.deletedFiles != null)
|
||||
return false;
|
||||
} else if (!this.deletedFiles.equals(other.deletedFiles))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Pure
|
||||
public String toString() {
|
||||
ToStringBuilder b = new ToStringBuilder(this);
|
||||
b.add("dirtyFiles", this.dirtyFiles);
|
||||
b.add("deletedFiles", this.deletedFiles);
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
@Pure
|
||||
public List<URI> getDirtyFiles() {
|
||||
return this.dirtyFiles;
|
||||
}
|
||||
|
||||
@Pure
|
||||
public List<URI> getDeletedFiles() {
|
||||
return this.deletedFiles;
|
||||
}
|
||||
}
|
||||
|
||||
public interface Buildable {
|
||||
public abstract List<IResourceDescription.Delta> build(final CancelIndicator cancelIndicator);
|
||||
}
|
||||
|
||||
public static final String CYCLIC_PROJECT_DEPENDENCIES = (BuildManager.class.getCanonicalName() + ".cyclicProjectDependencies");
|
||||
|
||||
@Accessors(AccessorType.PUBLIC_SETTER)
|
||||
private WorkspaceManager workspaceManager;
|
||||
|
||||
@Inject
|
||||
private Provider<TopologicalSorter> sorterProvider;
|
||||
|
||||
private final LinkedHashSet<URI> dirtyFiles = CollectionLiterals.<URI>newLinkedHashSet();
|
||||
|
||||
private final LinkedHashSet<URI> deletedFiles = CollectionLiterals.<URI>newLinkedHashSet();
|
||||
|
||||
private List<IResourceDescription.Delta> unreportedDeltas = CollectionLiterals.<IResourceDescription.Delta>newArrayList();
|
||||
|
||||
public BuildManager.Buildable submit(final List<URI> dirtyFiles, final List<URI> deletedFiles) {
|
||||
this.queue(this.dirtyFiles, deletedFiles, dirtyFiles);
|
||||
this.queue(this.deletedFiles, dirtyFiles, deletedFiles);
|
||||
final BuildManager.Buildable _function = (CancelIndicator cancelIndicator) -> {
|
||||
return this.internalBuild(cancelIndicator);
|
||||
};
|
||||
return _function;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated this method is no longer used
|
||||
*/
|
||||
@Deprecated
|
||||
public List<IResourceDescription.Delta> doBuild(final List<URI> dirtyFiles, final List<URI> deletedFiles, final CancelIndicator cancelIndicator) {
|
||||
return this.submit(dirtyFiles, deletedFiles).build(cancelIndicator);
|
||||
}
|
||||
|
||||
protected void queue(final Set<URI> files, final Collection<URI> toRemove, final Collection<URI> toAdd) {
|
||||
Iterables.removeAll(files, toRemove);
|
||||
Iterables.<URI>addAll(files, toAdd);
|
||||
}
|
||||
|
||||
public List<IResourceDescription.Delta> doInitialBuild(final List<ProjectDescription> projects, final CancelIndicator indicator) {
|
||||
final List<ProjectDescription> sortedDescriptions = this.sortByDependencies(projects);
|
||||
final ArrayList<IResourceDescription.Delta> result = CollectionLiterals.<IResourceDescription.Delta>newArrayList();
|
||||
for (final ProjectDescription description : sortedDescriptions) {
|
||||
{
|
||||
final IncrementalBuilder.Result partialresult = this.workspaceManager.getProjectManager(description.getName()).doInitialBuild(indicator);
|
||||
result.addAll(partialresult.getAffectedResources());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected List<IResourceDescription.Delta> internalBuild(final CancelIndicator cancelIndicator) {
|
||||
final ArrayList<URI> allDirty = new ArrayList<URI>(this.dirtyFiles);
|
||||
final HashMultimap<ProjectDescription, URI> project2dirty = HashMultimap.<ProjectDescription, URI>create();
|
||||
for (final URI dirty : allDirty) {
|
||||
{
|
||||
final ProjectDescription projectManager = this.workspaceManager.getProjectManager(dirty).getProjectDescription();
|
||||
project2dirty.put(projectManager, dirty);
|
||||
}
|
||||
}
|
||||
final HashMultimap<ProjectDescription, URI> project2deleted = HashMultimap.<ProjectDescription, URI>create();
|
||||
for (final URI deleted : this.deletedFiles) {
|
||||
{
|
||||
final ProjectDescription projectManager = this.workspaceManager.getProjectManager(deleted).getProjectDescription();
|
||||
project2deleted.put(projectManager, deleted);
|
||||
}
|
||||
}
|
||||
Set<ProjectDescription> _keySet = project2dirty.keySet();
|
||||
Set<ProjectDescription> _keySet_1 = project2deleted.keySet();
|
||||
Iterable<ProjectDescription> _plus = Iterables.<ProjectDescription>concat(_keySet, _keySet_1);
|
||||
final List<ProjectDescription> sortedDescriptions = this.sortByDependencies(_plus);
|
||||
for (final ProjectDescription it : sortedDescriptions) {
|
||||
{
|
||||
final ProjectManager projectManager = this.workspaceManager.getProjectManager(it.getName());
|
||||
final List<URI> projectDirty = IterableExtensions.<URI>toList(project2dirty.get(it));
|
||||
final List<URI> projectDeleted = IterableExtensions.<URI>toList(project2deleted.get(it));
|
||||
final IncrementalBuilder.Result partialResult = projectManager.doBuild(projectDirty, projectDeleted, this.unreportedDeltas, cancelIndicator);
|
||||
final Function1<IResourceDescription.Delta, URI> _function = (IResourceDescription.Delta it_1) -> {
|
||||
return it_1.getUri();
|
||||
};
|
||||
allDirty.addAll(ListExtensions.<IResourceDescription.Delta, URI>map(partialResult.getAffectedResources(), _function));
|
||||
Iterables.removeAll(this.dirtyFiles, projectDirty);
|
||||
Iterables.removeAll(this.deletedFiles, projectDeleted);
|
||||
this.mergeWithUnreportedDeltas(partialResult.getAffectedResources());
|
||||
}
|
||||
}
|
||||
final List<IResourceDescription.Delta> result = this.unreportedDeltas;
|
||||
this.unreportedDeltas = CollectionLiterals.<IResourceDescription.Delta>newArrayList();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.18
|
||||
*/
|
||||
protected Boolean mergeWithUnreportedDeltas(final List<IResourceDescription.Delta> newDeltas) {
|
||||
boolean _xifexpression = false;
|
||||
boolean _isEmpty = this.unreportedDeltas.isEmpty();
|
||||
if (_isEmpty) {
|
||||
_xifexpression = Iterables.<IResourceDescription.Delta>addAll(this.unreportedDeltas, newDeltas);
|
||||
} else {
|
||||
final Function1<IResourceDescription.Delta, URI> _function = (IResourceDescription.Delta it) -> {
|
||||
return it.getUri();
|
||||
};
|
||||
final Map<URI, IResourceDescription.Delta> unreportedByUri = IterableExtensions.<URI, IResourceDescription.Delta>toMap(this.unreportedDeltas, _function);
|
||||
final Consumer<IResourceDescription.Delta> _function_1 = (IResourceDescription.Delta newDelta) -> {
|
||||
final IResourceDescription.Delta unreportedDelta = unreportedByUri.get(newDelta.getUri());
|
||||
if ((unreportedDelta == null)) {
|
||||
this.unreportedDeltas.add(newDelta);
|
||||
} else {
|
||||
this.unreportedDeltas.remove(unreportedDelta);
|
||||
IResourceDescription _old = unreportedDelta.getOld();
|
||||
IResourceDescription _new = newDelta.getNew();
|
||||
DefaultResourceDescriptionDelta _defaultResourceDescriptionDelta = new DefaultResourceDescriptionDelta(_old, _new);
|
||||
this.unreportedDeltas.add(_defaultResourceDescriptionDelta);
|
||||
}
|
||||
};
|
||||
newDeltas.forEach(_function_1);
|
||||
}
|
||||
return Boolean.valueOf(_xifexpression);
|
||||
}
|
||||
|
||||
protected List<ProjectDescription> sortByDependencies(final Iterable<ProjectDescription> projectDescriptions) {
|
||||
final Procedure1<ProjectDescription> _function = (ProjectDescription it) -> {
|
||||
this.reportDependencyCycle(this.workspaceManager.getProjectManager(it.getName()));
|
||||
};
|
||||
return this.sorterProvider.get().sortByDependencies(IterableExtensions.<ProjectDescription>toList(projectDescriptions), _function);
|
||||
}
|
||||
|
||||
protected void reportDependencyCycle(final ProjectManager manager) {
|
||||
manager.reportProjectIssue("Project has cyclic dependencies", BuildManager.CYCLIC_PROJECT_DEPENDENCIES, Severity.ERROR);
|
||||
}
|
||||
|
||||
public void setWorkspaceManager(final WorkspaceManager workspaceManager) {
|
||||
this.workspaceManager = workspaceManager;
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2016 TypeFox GmbH (http://www.typefox.io) 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.ide.server;
|
||||
|
||||
import org.eclipse.xtext.ide.server.IProjectDescriptionFactory;
|
||||
import org.eclipse.xtext.resource.impl.ProjectDescription;
|
||||
import org.eclipse.xtext.workspace.IProjectConfig;
|
||||
import org.eclipse.xtext.xbase.lib.ObjectExtensions;
|
||||
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public class DefaultProjectDescriptionFactory implements IProjectDescriptionFactory {
|
||||
@Override
|
||||
public ProjectDescription getProjectDescription(final IProjectConfig config) {
|
||||
ProjectDescription _projectDescription = new ProjectDescription();
|
||||
final Procedure1<ProjectDescription> _function = (ProjectDescription it) -> {
|
||||
it.setName(config.getName());
|
||||
};
|
||||
return ObjectExtensions.<ProjectDescription>operator_doubleArrow(_projectDescription, _function);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,49 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2016, 2017 TypeFox GmbH (http://www.typefox.io) 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.ide.server;
|
||||
|
||||
import java.io.File;
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.xtext.ide.server.ProjectWorkspaceConfigFactory;
|
||||
import org.eclipse.xtext.workspace.FileProjectConfig;
|
||||
import org.eclipse.xtext.workspace.WorkspaceConfig;
|
||||
import org.eclipse.xtext.xbase.lib.Conversions;
|
||||
import org.eclipse.xtext.xbase.lib.Functions.Function1;
|
||||
import org.eclipse.xtext.xbase.lib.IterableExtensions;
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public class MultiProjectWorkspaceConfigFactory extends ProjectWorkspaceConfigFactory {
|
||||
@Override
|
||||
public void findProjects(final WorkspaceConfig workspaceConfig, final URI uri) {
|
||||
if ((uri == null)) {
|
||||
return;
|
||||
}
|
||||
String _fileString = uri.toFileString();
|
||||
final File baseFile = new File(_fileString);
|
||||
boolean _isDirectory = baseFile.isDirectory();
|
||||
boolean _not = (!_isDirectory);
|
||||
if (_not) {
|
||||
return;
|
||||
}
|
||||
final Function1<File, Boolean> _function = (File it) -> {
|
||||
return Boolean.valueOf(it.isDirectory());
|
||||
};
|
||||
Iterable<File> _filter = IterableExtensions.<File>filter(((Iterable<File>)Conversions.doWrapArray(baseFile.listFiles())), _function);
|
||||
for (final File file : _filter) {
|
||||
{
|
||||
final FileProjectConfig project = new FileProjectConfig(file, workspaceConfig);
|
||||
project.addSourceFolder(".");
|
||||
workspaceConfig.addProject(project);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,234 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2016, 2017 TypeFox GmbH (http://www.typefox.io) 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.ide.server;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.emf.ecore.resource.Resource;
|
||||
import org.eclipse.xtend.lib.annotations.AccessorType;
|
||||
import org.eclipse.xtend.lib.annotations.Accessors;
|
||||
import org.eclipse.xtext.build.BuildRequest;
|
||||
import org.eclipse.xtext.build.IncrementalBuilder;
|
||||
import org.eclipse.xtext.build.IndexState;
|
||||
import org.eclipse.xtext.build.Source2GeneratedMapping;
|
||||
import org.eclipse.xtext.diagnostics.Severity;
|
||||
import org.eclipse.xtext.resource.IExternalContentSupport;
|
||||
import org.eclipse.xtext.resource.IResourceDescription;
|
||||
import org.eclipse.xtext.resource.IResourceServiceProvider;
|
||||
import org.eclipse.xtext.resource.XtextResourceSet;
|
||||
import org.eclipse.xtext.resource.impl.ChunkedResourceDescriptions;
|
||||
import org.eclipse.xtext.resource.impl.ProjectDescription;
|
||||
import org.eclipse.xtext.resource.impl.ResourceDescriptionsData;
|
||||
import org.eclipse.xtext.util.CancelIndicator;
|
||||
import org.eclipse.xtext.util.IFileSystemScanner;
|
||||
import org.eclipse.xtext.validation.Issue;
|
||||
import org.eclipse.xtext.workspace.IProjectConfig;
|
||||
import org.eclipse.xtext.workspace.ISourceFolder;
|
||||
import org.eclipse.xtext.workspace.ProjectConfigAdapter;
|
||||
import org.eclipse.xtext.xbase.lib.CollectionLiterals;
|
||||
import org.eclipse.xtext.xbase.lib.Functions.Function1;
|
||||
import org.eclipse.xtext.xbase.lib.ObjectExtensions;
|
||||
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
|
||||
import org.eclipse.xtext.xbase.lib.Procedures.Procedure2;
|
||||
import org.eclipse.xtext.xbase.lib.Pure;
|
||||
|
||||
/**
|
||||
* @author Sven Efftinge - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public class ProjectManager {
|
||||
@Inject
|
||||
protected IncrementalBuilder incrementalBuilder;
|
||||
|
||||
@Inject
|
||||
protected Provider<XtextResourceSet> resourceSetProvider;
|
||||
|
||||
@Inject
|
||||
protected IResourceServiceProvider.Registry languagesRegistry;
|
||||
|
||||
@Inject
|
||||
protected IFileSystemScanner fileSystemScanner;
|
||||
|
||||
@Inject
|
||||
protected IExternalContentSupport externalContentSupport;
|
||||
|
||||
@Accessors({ AccessorType.PUBLIC_GETTER, AccessorType.PROTECTED_SETTER })
|
||||
private IndexState indexState = new IndexState();
|
||||
|
||||
@Accessors(AccessorType.PUBLIC_GETTER)
|
||||
private URI baseDir;
|
||||
|
||||
@Accessors(AccessorType.PROTECTED_GETTER)
|
||||
private Procedure2<? super URI, ? super Iterable<Issue>> issueAcceptor;
|
||||
|
||||
@Accessors(AccessorType.PROTECTED_GETTER)
|
||||
private Provider<Map<String, ResourceDescriptionsData>> indexProvider;
|
||||
|
||||
@Accessors(AccessorType.PROTECTED_GETTER)
|
||||
private IExternalContentSupport.IExternalContentProvider openedDocumentsContentProvider;
|
||||
|
||||
@Accessors(AccessorType.PUBLIC_GETTER)
|
||||
private XtextResourceSet resourceSet;
|
||||
|
||||
@Accessors(AccessorType.PUBLIC_GETTER)
|
||||
private ProjectDescription projectDescription;
|
||||
|
||||
@Accessors(AccessorType.PUBLIC_GETTER)
|
||||
private IProjectConfig projectConfig;
|
||||
|
||||
public void initialize(final ProjectDescription description, final IProjectConfig projectConfig, final Procedure2<? super URI, ? super Iterable<Issue>> acceptor, final IExternalContentSupport.IExternalContentProvider openedDocumentsContentProvider, final Provider<Map<String, ResourceDescriptionsData>> indexProvider, final CancelIndicator cancelIndicator) {
|
||||
this.projectDescription = description;
|
||||
this.projectConfig = projectConfig;
|
||||
this.baseDir = projectConfig.getPath();
|
||||
this.issueAcceptor = acceptor;
|
||||
this.openedDocumentsContentProvider = openedDocumentsContentProvider;
|
||||
this.indexProvider = indexProvider;
|
||||
}
|
||||
|
||||
public IncrementalBuilder.Result doInitialBuild(final CancelIndicator cancelIndicator) {
|
||||
final ArrayList<URI> uris = CollectionLiterals.<URI>newArrayList();
|
||||
final Consumer<ISourceFolder> _function = (ISourceFolder it) -> {
|
||||
List<URI> _allResources = it.getAllResources(this.fileSystemScanner);
|
||||
Iterables.<URI>addAll(uris, _allResources);
|
||||
};
|
||||
this.projectConfig.getSourceFolders().forEach(_function);
|
||||
return this.doBuild(uris, CollectionLiterals.<URI>emptyList(), CollectionLiterals.<IResourceDescription.Delta>emptyList(), cancelIndicator);
|
||||
}
|
||||
|
||||
public IncrementalBuilder.Result doBuild(final List<URI> dirtyFiles, final List<URI> deletedFiles, final List<IResourceDescription.Delta> externalDeltas, final CancelIndicator cancelIndicator) {
|
||||
final BuildRequest request = this.newBuildRequest(dirtyFiles, deletedFiles, externalDeltas, cancelIndicator);
|
||||
final Function1<URI, IResourceServiceProvider> _function = (URI it) -> {
|
||||
return this.languagesRegistry.getResourceServiceProvider(it);
|
||||
};
|
||||
final IncrementalBuilder.Result result = this.incrementalBuilder.build(request, _function);
|
||||
this.indexState = result.getIndexState();
|
||||
this.resourceSet = request.getResourceSet();
|
||||
this.indexProvider.get().put(this.projectDescription.getName(), this.indexState.getResourceDescriptions());
|
||||
return result;
|
||||
}
|
||||
|
||||
protected BuildRequest newBuildRequest(final List<URI> changedFiles, final List<URI> deletedFiles, final List<IResourceDescription.Delta> externalDeltas, final CancelIndicator cancelIndicator) {
|
||||
BuildRequest _buildRequest = new BuildRequest();
|
||||
final Procedure1<BuildRequest> _function = (BuildRequest it) -> {
|
||||
it.setBaseDir(this.baseDir);
|
||||
ResourceDescriptionsData _copy = this.indexState.getResourceDescriptions().copy();
|
||||
Source2GeneratedMapping _copy_1 = this.indexState.getFileMappings().copy();
|
||||
IndexState _indexState = new IndexState(_copy, _copy_1);
|
||||
it.setState(_indexState);
|
||||
it.setResourceSet(this.createFreshResourceSet(it.getState().getResourceDescriptions()));
|
||||
it.setDirtyFiles(changedFiles);
|
||||
it.setDeletedFiles(deletedFiles);
|
||||
it.setExternalDeltas(externalDeltas);
|
||||
final BuildRequest.IPostValidationCallback _function_1 = (URI uri, Iterable<Issue> issues) -> {
|
||||
this.issueAcceptor.apply(uri, issues);
|
||||
return true;
|
||||
};
|
||||
it.setAfterValidate(_function_1);
|
||||
it.setCancelIndicator(cancelIndicator);
|
||||
};
|
||||
return ObjectExtensions.<BuildRequest>operator_doubleArrow(_buildRequest, _function);
|
||||
}
|
||||
|
||||
public XtextResourceSet createNewResourceSet(final ResourceDescriptionsData newIndex) {
|
||||
XtextResourceSet _get = this.resourceSetProvider.get();
|
||||
final Procedure1<XtextResourceSet> _function = (XtextResourceSet it) -> {
|
||||
this.projectDescription.attachToEmfObject(it);
|
||||
ProjectConfigAdapter.install(it, this.projectConfig);
|
||||
Map<String, ResourceDescriptionsData> _get_1 = this.indexProvider.get();
|
||||
final ChunkedResourceDescriptions index = new ChunkedResourceDescriptions(_get_1, it);
|
||||
index.setContainer(this.projectDescription.getName(), newIndex);
|
||||
this.externalContentSupport.configureResourceSet(it, this.openedDocumentsContentProvider);
|
||||
};
|
||||
return ObjectExtensions.<XtextResourceSet>operator_doubleArrow(_get, _function);
|
||||
}
|
||||
|
||||
protected XtextResourceSet createFreshResourceSet(final ResourceDescriptionsData newIndex) {
|
||||
if ((this.resourceSet == null)) {
|
||||
this.resourceSet = this.createNewResourceSet(newIndex);
|
||||
} else {
|
||||
final ChunkedResourceDescriptions resDescs = ChunkedResourceDescriptions.findInEmfObject(this.resourceSet);
|
||||
Set<Map.Entry<String, ResourceDescriptionsData>> _entrySet = this.indexProvider.get().entrySet();
|
||||
for (final Map.Entry<String, ResourceDescriptionsData> entry : _entrySet) {
|
||||
resDescs.setContainer(entry.getKey(), entry.getValue());
|
||||
}
|
||||
resDescs.setContainer(this.projectDescription.getName(), newIndex);
|
||||
}
|
||||
return this.resourceSet;
|
||||
}
|
||||
|
||||
public Resource getResource(final URI uri) {
|
||||
final Resource resource = this.resourceSet.getResource(uri, true);
|
||||
resource.getContents();
|
||||
return resource;
|
||||
}
|
||||
|
||||
public void reportProjectIssue(final String message, final String code, final Severity severity) {
|
||||
Issue.IssueImpl _issueImpl = new Issue.IssueImpl();
|
||||
final Procedure1<Issue.IssueImpl> _function = (Issue.IssueImpl it) -> {
|
||||
it.setMessage(message);
|
||||
it.setCode(code);
|
||||
it.setSeverity(severity);
|
||||
it.setUriToProblem(this.baseDir);
|
||||
};
|
||||
Issue.IssueImpl _doubleArrow = ObjectExtensions.<Issue.IssueImpl>operator_doubleArrow(_issueImpl, _function);
|
||||
this.issueAcceptor.apply(this.baseDir, Collections.<Issue>unmodifiableList(CollectionLiterals.<Issue>newArrayList(_doubleArrow)));
|
||||
}
|
||||
|
||||
@Pure
|
||||
public IndexState getIndexState() {
|
||||
return this.indexState;
|
||||
}
|
||||
|
||||
protected void setIndexState(final IndexState indexState) {
|
||||
this.indexState = indexState;
|
||||
}
|
||||
|
||||
@Pure
|
||||
public URI getBaseDir() {
|
||||
return this.baseDir;
|
||||
}
|
||||
|
||||
@Pure
|
||||
protected Procedure2<? super URI, ? super Iterable<Issue>> getIssueAcceptor() {
|
||||
return this.issueAcceptor;
|
||||
}
|
||||
|
||||
@Pure
|
||||
protected Provider<Map<String, ResourceDescriptionsData>> getIndexProvider() {
|
||||
return this.indexProvider;
|
||||
}
|
||||
|
||||
@Pure
|
||||
protected IExternalContentSupport.IExternalContentProvider getOpenedDocumentsContentProvider() {
|
||||
return this.openedDocumentsContentProvider;
|
||||
}
|
||||
|
||||
@Pure
|
||||
public XtextResourceSet getResourceSet() {
|
||||
return this.resourceSet;
|
||||
}
|
||||
|
||||
@Pure
|
||||
public ProjectDescription getProjectDescription() {
|
||||
return this.projectDescription;
|
||||
}
|
||||
|
||||
@Pure
|
||||
public IProjectConfig getProjectConfig() {
|
||||
return this.projectConfig;
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2016, 2017 TypeFox GmbH (http://www.typefox.io) 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.ide.server;
|
||||
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.xtext.ide.server.IWorkspaceConfigFactory;
|
||||
import org.eclipse.xtext.workspace.FileProjectConfig;
|
||||
import org.eclipse.xtext.workspace.IWorkspaceConfig;
|
||||
import org.eclipse.xtext.workspace.WorkspaceConfig;
|
||||
|
||||
/**
|
||||
* The workspace itself is a single project
|
||||
*
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public class ProjectWorkspaceConfigFactory implements IWorkspaceConfigFactory {
|
||||
@Override
|
||||
public IWorkspaceConfig getWorkspaceConfig(final URI workspaceBaseURI) {
|
||||
final WorkspaceConfig workspaceConfig = new WorkspaceConfig();
|
||||
this.findProjects(workspaceConfig, workspaceBaseURI);
|
||||
return workspaceConfig;
|
||||
}
|
||||
|
||||
public void findProjects(final WorkspaceConfig workspaceConfig, final URI uri) {
|
||||
if ((uri != null)) {
|
||||
final FileProjectConfig project = new FileProjectConfig(uri, workspaceConfig);
|
||||
project.addSourceFolder(".");
|
||||
workspaceConfig.addProject(project);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,355 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2016, 2017 TypeFox GmbH (http://www.typefox.io) 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.ide.server;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.emf.ecore.resource.Resource;
|
||||
import org.eclipse.lsp4j.DidChangeTextDocumentParams;
|
||||
import org.eclipse.lsp4j.TextDocumentContentChangeEvent;
|
||||
import org.eclipse.lsp4j.TextEdit;
|
||||
import org.eclipse.lsp4j.jsonrpc.ResponseErrorException;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.ResponseError;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.ResponseErrorCode;
|
||||
import org.eclipse.xtext.ide.server.BuildManager;
|
||||
import org.eclipse.xtext.ide.server.Document;
|
||||
import org.eclipse.xtext.ide.server.ILanguageServerAccess;
|
||||
import org.eclipse.xtext.ide.server.IProjectDescriptionFactory;
|
||||
import org.eclipse.xtext.ide.server.IWorkspaceConfigFactory;
|
||||
import org.eclipse.xtext.ide.server.ProjectManager;
|
||||
import org.eclipse.xtext.resource.IExternalContentSupport;
|
||||
import org.eclipse.xtext.resource.IResourceDescription;
|
||||
import org.eclipse.xtext.resource.IResourceDescriptions;
|
||||
import org.eclipse.xtext.resource.XtextResource;
|
||||
import org.eclipse.xtext.resource.XtextResourceSet;
|
||||
import org.eclipse.xtext.resource.impl.ChunkedResourceDescriptions;
|
||||
import org.eclipse.xtext.resource.impl.ProjectDescription;
|
||||
import org.eclipse.xtext.resource.impl.ResourceDescriptionsData;
|
||||
import org.eclipse.xtext.util.CancelIndicator;
|
||||
import org.eclipse.xtext.util.internal.Log;
|
||||
import org.eclipse.xtext.validation.Issue;
|
||||
import org.eclipse.xtext.workspace.IProjectConfig;
|
||||
import org.eclipse.xtext.workspace.IWorkspaceConfig;
|
||||
import org.eclipse.xtext.xbase.lib.CollectionLiterals;
|
||||
import org.eclipse.xtext.xbase.lib.Functions.Function2;
|
||||
import org.eclipse.xtext.xbase.lib.Procedures.Procedure2;
|
||||
|
||||
/**
|
||||
* @author Sven Efftinge - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
@Log
|
||||
@SuppressWarnings("all")
|
||||
public class WorkspaceManager {
|
||||
@Inject
|
||||
private Provider<ProjectManager> projectManagerProvider;
|
||||
|
||||
@Inject
|
||||
private IWorkspaceConfigFactory workspaceConfigFactory;
|
||||
|
||||
@Inject
|
||||
private IProjectDescriptionFactory projectDescriptionFactory;
|
||||
|
||||
private BuildManager buildManager;
|
||||
|
||||
private Map<String, ProjectManager> projectName2ProjectManager = CollectionLiterals.<String, ProjectManager>newHashMap();
|
||||
|
||||
private URI baseDir;
|
||||
|
||||
private Procedure2<? super URI, ? super Iterable<Issue>> issueAcceptor;
|
||||
|
||||
private IWorkspaceConfig _workspaceConfig;
|
||||
|
||||
private List<ILanguageServerAccess.IBuildListener> buildListeners = CollectionLiterals.<ILanguageServerAccess.IBuildListener>newArrayList();
|
||||
|
||||
public void addBuildListener(final ILanguageServerAccess.IBuildListener listener) {
|
||||
this.buildListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a build listener if it was previously registered
|
||||
*
|
||||
* @since 2.18
|
||||
*/
|
||||
public void removeBuildListener(final ILanguageServerAccess.IBuildListener listener) {
|
||||
this.buildListeners.remove(listener);
|
||||
}
|
||||
|
||||
private Map<String, ResourceDescriptionsData> fullIndex = CollectionLiterals.<String, ResourceDescriptionsData>newHashMap();
|
||||
|
||||
private Map<URI, Document> openDocuments = CollectionLiterals.<URI, Document>newHashMap();
|
||||
|
||||
private final IExternalContentSupport.IExternalContentProvider openedDocumentsContentProvider = new IExternalContentSupport.IExternalContentProvider() {
|
||||
@Override
|
||||
public IExternalContentSupport.IExternalContentProvider getActualContentProvider() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContent(final URI uri) {
|
||||
Document _get = WorkspaceManager.this.openDocuments.get(uri);
|
||||
String _contents = null;
|
||||
if (_get!=null) {
|
||||
_contents=_get.getContents();
|
||||
}
|
||||
return _contents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasContent(final URI uri) {
|
||||
return WorkspaceManager.this.openDocuments.containsKey(uri);
|
||||
}
|
||||
};
|
||||
|
||||
@Inject
|
||||
public void setBuildManager(final BuildManager buildManager) {
|
||||
buildManager.setWorkspaceManager(this);
|
||||
this.buildManager = buildManager;
|
||||
}
|
||||
|
||||
public void initialize(final URI baseDir, final Procedure2<? super URI, ? super Iterable<Issue>> issueAcceptor, final CancelIndicator cancelIndicator) {
|
||||
this.baseDir = baseDir;
|
||||
this.issueAcceptor = issueAcceptor;
|
||||
this.refreshWorkspaceConfig(cancelIndicator);
|
||||
}
|
||||
|
||||
protected void refreshWorkspaceConfig(final CancelIndicator cancelIndicator) {
|
||||
this.setWorkspaceConfig(this.workspaceConfigFactory.getWorkspaceConfig(this.baseDir));
|
||||
final ArrayList<ProjectDescription> newProjects = CollectionLiterals.<ProjectDescription>newArrayList();
|
||||
Set<String> _keySet = this.projectName2ProjectManager.keySet();
|
||||
final Set<String> remainingProjectNames = new HashSet<String>(_keySet);
|
||||
final Consumer<IProjectConfig> _function = (IProjectConfig projectConfig) -> {
|
||||
boolean _containsKey = this.projectName2ProjectManager.containsKey(projectConfig.getName());
|
||||
if (_containsKey) {
|
||||
remainingProjectNames.remove(projectConfig.getName());
|
||||
} else {
|
||||
final ProjectManager projectManager = this.projectManagerProvider.get();
|
||||
final ProjectDescription projectDescription = this.projectDescriptionFactory.getProjectDescription(projectConfig);
|
||||
final Provider<Map<String, ResourceDescriptionsData>> _function_1 = () -> {
|
||||
return this.fullIndex;
|
||||
};
|
||||
projectManager.initialize(projectDescription, projectConfig, this.issueAcceptor,
|
||||
this.openedDocumentsContentProvider, _function_1, cancelIndicator);
|
||||
this.projectName2ProjectManager.put(projectDescription.getName(), projectManager);
|
||||
newProjects.add(projectDescription);
|
||||
}
|
||||
};
|
||||
this.getWorkspaceConfig().getProjects().forEach(_function);
|
||||
for (final String deletedProject : remainingProjectNames) {
|
||||
{
|
||||
this.projectName2ProjectManager.remove(deletedProject);
|
||||
this.fullIndex.remove(deletedProject);
|
||||
}
|
||||
}
|
||||
final List<IResourceDescription.Delta> result = this.buildManager.doInitialBuild(newProjects, cancelIndicator);
|
||||
this.afterBuild(result);
|
||||
}
|
||||
|
||||
protected IWorkspaceConfig getWorkspaceConfig() {
|
||||
if ((this._workspaceConfig == null)) {
|
||||
final ResponseError error = new ResponseError(ResponseErrorCode.serverNotInitialized,
|
||||
"Workspace has not been initialized yet.", null);
|
||||
throw new ResponseErrorException(error);
|
||||
}
|
||||
return this._workspaceConfig;
|
||||
}
|
||||
|
||||
protected void setWorkspaceConfig(final IWorkspaceConfig workspaceConfig) {
|
||||
this._workspaceConfig = workspaceConfig;
|
||||
}
|
||||
|
||||
protected void afterBuild(final List<IResourceDescription.Delta> deltas) {
|
||||
for (final ILanguageServerAccess.IBuildListener listener : this.buildListeners) {
|
||||
listener.afterBuild(deltas);
|
||||
}
|
||||
}
|
||||
|
||||
public BuildManager.Buildable didChangeFiles(final List<URI> dirtyFiles, final List<URI> deletedFiles) {
|
||||
final BuildManager.Buildable buildable = this.buildManager.submit(dirtyFiles, deletedFiles);
|
||||
final BuildManager.Buildable _function = (CancelIndicator cancelIndicator) -> {
|
||||
final List<IResourceDescription.Delta> deltas = buildable.build(cancelIndicator);
|
||||
this.afterBuild(deltas);
|
||||
return deltas;
|
||||
};
|
||||
return _function;
|
||||
}
|
||||
|
||||
public List<IResourceDescription.Delta> doBuild(final List<URI> dirtyFiles, final List<URI> deletedFiles, final CancelIndicator cancelIndicator) {
|
||||
return this.didChangeFiles(dirtyFiles, deletedFiles).build(cancelIndicator);
|
||||
}
|
||||
|
||||
public IResourceDescriptions getIndex() {
|
||||
return new ChunkedResourceDescriptions(this.fullIndex);
|
||||
}
|
||||
|
||||
public URI getProjectBaseDir(final URI uri) {
|
||||
final IProjectConfig projectConfig = this.getWorkspaceConfig().findProjectContaining(uri);
|
||||
URI _path = null;
|
||||
if (projectConfig!=null) {
|
||||
_path=projectConfig.getPath();
|
||||
}
|
||||
return _path;
|
||||
}
|
||||
|
||||
public ProjectManager getProjectManager(final URI uri) {
|
||||
final IProjectConfig projectConfig = this.getWorkspaceConfig().findProjectContaining(uri);
|
||||
String _name = null;
|
||||
if (projectConfig!=null) {
|
||||
_name=projectConfig.getName();
|
||||
}
|
||||
return this.projectName2ProjectManager.get(_name);
|
||||
}
|
||||
|
||||
public ProjectManager getProjectManager(final String projectName) {
|
||||
return this.projectName2ProjectManager.get(projectName);
|
||||
}
|
||||
|
||||
public List<ProjectManager> getProjectManagers() {
|
||||
Collection<ProjectManager> _values = this.projectName2ProjectManager.values();
|
||||
return new ArrayList<ProjectManager>(_values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated the server should not apply {@link TextEdit}s but {@link TextDocumentContentChangeEvent}s.
|
||||
* Use {@link #didChangeTextDocumentContent(URI, Integer, Iterable)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public List<IResourceDescription.Delta> didChange(final URI uri, final Integer version, final Iterable<TextEdit> changes, final CancelIndicator cancelIndicator) {
|
||||
return this.didChange(uri, version, changes).build(cancelIndicator);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated the server should not apply {@link TextEdit}s but {@link TextDocumentContentChangeEvent}s.
|
||||
* Use {@link #didChangeTextDocumentContent(URI, Integer, Iterable)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public BuildManager.Buildable didChange(final URI uri, final Integer version, final Iterable<TextEdit> changes) {
|
||||
boolean _containsKey = this.openDocuments.containsKey(uri);
|
||||
boolean _not = (!_containsKey);
|
||||
if (_not) {
|
||||
WorkspaceManager.LOG.error((("The document " + uri) + " has not been opened."));
|
||||
final BuildManager.Buildable _function = (CancelIndicator it) -> {
|
||||
return null;
|
||||
};
|
||||
return _function;
|
||||
}
|
||||
final Document contents = this.openDocuments.get(uri);
|
||||
this.openDocuments.put(uri, contents.applyChanges(changes));
|
||||
return this.didChangeFiles(Collections.<URI>unmodifiableList(CollectionLiterals.<URI>newArrayList(uri)), CollectionLiterals.<URI>newArrayList());
|
||||
}
|
||||
|
||||
/**
|
||||
* As opposed to {@link TextEdit}[] the positions in the edits of a
|
||||
* {@link DidChangeTextDocumentParams} refer to the state after applying the preceding edits. See
|
||||
* https://microsoft.github.io/language-server-protocol/specification#textedit-1 and
|
||||
* https://github.com/microsoft/vscode/issues/23173#issuecomment-289378160 for details.
|
||||
*
|
||||
* In particular, this has to be taken into account when undoing the deletion of multiple characters
|
||||
* at the end of a line.
|
||||
*
|
||||
* @since 2.18
|
||||
*/
|
||||
public BuildManager.Buildable didChangeTextDocumentContent(final URI uri, final Integer version, final Iterable<TextDocumentContentChangeEvent> changes) {
|
||||
boolean _containsKey = this.openDocuments.containsKey(uri);
|
||||
boolean _not = (!_containsKey);
|
||||
if (_not) {
|
||||
WorkspaceManager.LOG.error((("The document " + uri) + " has not been opened."));
|
||||
final BuildManager.Buildable _function = (CancelIndicator it) -> {
|
||||
return null;
|
||||
};
|
||||
return _function;
|
||||
}
|
||||
final Document contents = this.openDocuments.get(uri);
|
||||
this.openDocuments.put(uri, contents.applyTextDocumentChanges(changes));
|
||||
return this.didChangeFiles(Collections.<URI>unmodifiableList(CollectionLiterals.<URI>newArrayList(uri)), CollectionLiterals.<URI>newArrayList());
|
||||
}
|
||||
|
||||
public List<IResourceDescription.Delta> didOpen(final URI uri, final Integer version, final String contents, final CancelIndicator cancelIndicator) {
|
||||
return this.didOpen(uri, version, contents).build(cancelIndicator);
|
||||
}
|
||||
|
||||
public BuildManager.Buildable didOpen(final URI uri, final Integer version, final String contents) {
|
||||
Document _document = new Document(version, contents);
|
||||
this.openDocuments.put(uri, _document);
|
||||
return this.didChangeFiles(Collections.<URI>unmodifiableList(CollectionLiterals.<URI>newArrayList(uri)), CollectionLiterals.<URI>newArrayList());
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated this method is no longer called
|
||||
*/
|
||||
@Deprecated
|
||||
public List<IResourceDescription.Delta> didClose(final URI uri, final CancelIndicator cancelIndicator) {
|
||||
return this.didClose(uri).build(cancelIndicator);
|
||||
}
|
||||
|
||||
public BuildManager.Buildable didClose(final URI uri) {
|
||||
this.openDocuments.remove(uri);
|
||||
boolean _exists = this.exists(uri);
|
||||
if (_exists) {
|
||||
return this.didChangeFiles(Collections.<URI>unmodifiableList(CollectionLiterals.<URI>newArrayList(uri)), CollectionLiterals.<URI>newArrayList());
|
||||
}
|
||||
return this.didChangeFiles(CollectionLiterals.<URI>newArrayList(), Collections.<URI>unmodifiableList(CollectionLiterals.<URI>newArrayList(uri)));
|
||||
}
|
||||
|
||||
protected boolean exists(final URI uri) {
|
||||
ProjectManager _projectManager = this.getProjectManager(uri);
|
||||
XtextResourceSet _resourceSet = null;
|
||||
if (_projectManager!=null) {
|
||||
_resourceSet=_projectManager.getResourceSet();
|
||||
}
|
||||
final XtextResourceSet rs = _resourceSet;
|
||||
if ((rs == null)) {
|
||||
return false;
|
||||
}
|
||||
return rs.getURIConverter().exists(uri, null);
|
||||
}
|
||||
|
||||
public <T extends Object> T doRead(final URI uri, final Function2<? super Document, ? super XtextResource, ? extends T> work) {
|
||||
final URI resourceURI = uri.trimFragment();
|
||||
final ProjectManager projectMnr = this.getProjectManager(resourceURI);
|
||||
Resource _resource = null;
|
||||
if (projectMnr!=null) {
|
||||
_resource=projectMnr.getResource(resourceURI);
|
||||
}
|
||||
final XtextResource resource = ((XtextResource) _resource);
|
||||
if ((resource == null)) {
|
||||
return work.apply(null, null);
|
||||
}
|
||||
Document doc = this.getDocument(resource);
|
||||
return work.apply(doc, resource);
|
||||
}
|
||||
|
||||
protected Document getDocument(final XtextResource resource) {
|
||||
Document _elvis = null;
|
||||
Document _get = this.openDocuments.get(resource.getURI());
|
||||
if (_get != null) {
|
||||
_elvis = _get;
|
||||
} else {
|
||||
String _text = resource.getParseResult().getRootNode().getText();
|
||||
Document _document = new Document(Integer.valueOf(1), _text);
|
||||
_elvis = _document;
|
||||
}
|
||||
return _elvis;
|
||||
}
|
||||
|
||||
public boolean isDocumentOpen(final URI uri) {
|
||||
return this.openDocuments.containsKey(uri);
|
||||
}
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(WorkspaceManager.class);
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2016, 2017 TypeFox GmbH (http://www.typefox.io) 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.ide.server.findReferences;
|
||||
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.emf.ecore.resource.ResourceSet;
|
||||
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor;
|
||||
import org.eclipse.xtext.findReferences.IReferenceFinder;
|
||||
import org.eclipse.xtext.ide.server.Document;
|
||||
import org.eclipse.xtext.ide.server.WorkspaceManager;
|
||||
import org.eclipse.xtext.resource.XtextResource;
|
||||
import org.eclipse.xtext.util.concurrent.IUnitOfWork;
|
||||
import org.eclipse.xtext.xbase.lib.Exceptions;
|
||||
import org.eclipse.xtext.xbase.lib.Functions.Function2;
|
||||
|
||||
/**
|
||||
* @author kosyakov - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
@FinalFieldsConstructor
|
||||
@SuppressWarnings("all")
|
||||
public class WorkspaceResourceAccess implements IReferenceFinder.IResourceAccess {
|
||||
private final WorkspaceManager workspaceManager;
|
||||
|
||||
@Override
|
||||
public <R extends Object> R readOnly(final URI targetURI, final IUnitOfWork<R, ResourceSet> work) {
|
||||
final Function2<Document, XtextResource, R> _function = (Document document, XtextResource resource) -> {
|
||||
try {
|
||||
if ((resource == null)) {
|
||||
return null;
|
||||
}
|
||||
return work.exec(resource.getResourceSet());
|
||||
} catch (Throwable _e) {
|
||||
throw Exceptions.sneakyThrow(_e);
|
||||
}
|
||||
};
|
||||
return this.workspaceManager.<R>doRead(targetURI, _function);
|
||||
}
|
||||
|
||||
public WorkspaceResourceAccess(final WorkspaceManager workspaceManager) {
|
||||
super();
|
||||
this.workspaceManager = workspaceManager;
|
||||
}
|
||||
}
|
|
@ -64,7 +64,7 @@ abstract class AbstractIncrementalBuilderTest {
|
|||
|
||||
protected def IndexState build(BuildRequest buildRequest) {
|
||||
clean()
|
||||
this.indexState = incrementalBuilder.build(buildRequest, [getLanguages.getResourceServiceProvider(it)]).indexState
|
||||
this.indexState = incrementalBuilder.build(buildRequest, [getLanguages.getResourceServiceProvider(it)]).getIndexState
|
||||
return indexState
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2019 Sebastian Zarnekow 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.util;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.xtext.util.CancelIndicator;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Ticker;
|
||||
|
||||
/**
|
||||
* A cancel indicator that will not cancel immediately but only after a delay to
|
||||
* allow short running tasks to complete despite an attempt to cancel.
|
||||
*/
|
||||
public class BufferedCancelIndicator implements CancelIndicator {
|
||||
|
||||
private static final long ONE_SECOND = TimeUnit.SECONDS.toNanos(1);
|
||||
|
||||
private final CancelIndicator delegate;
|
||||
|
||||
private final Ticker clock;
|
||||
|
||||
private final long delayInNanos;
|
||||
|
||||
private long cancelAt;
|
||||
|
||||
/**
|
||||
* Buffer the cancellation attempts that are issued by the given delegate.
|
||||
*/
|
||||
public BufferedCancelIndicator(CancelIndicator delegate) {
|
||||
this(delegate, Ticker.systemTicker(), ONE_SECOND);
|
||||
}
|
||||
|
||||
/**
|
||||
* Buffer the cancellation attempts that are issued by the given delegate.
|
||||
* Use the given clock as the source for the time.
|
||||
*
|
||||
* This is public for testing purpose.
|
||||
*/
|
||||
public BufferedCancelIndicator(CancelIndicator delegate, Ticker clock, long delayInNanos) {
|
||||
this.delegate = Preconditions.checkNotNull(delegate);
|
||||
this.clock = Preconditions.checkNotNull(clock);
|
||||
this.delayInNanos = delayInNanos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCanceled() {
|
||||
if (cancelAt == 0) {
|
||||
if (delegate.isCanceled()) {
|
||||
cancelAt = clock.read() + delayInNanos;
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return clock.read() > cancelAt;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2015, 2016 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.build;
|
||||
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.emf.ecore.resource.Resource;
|
||||
import org.eclipse.xtext.resource.IResourceServiceProvider;
|
||||
import org.eclipse.xtext.resource.XtextResourceSet;
|
||||
import org.eclipse.xtext.resource.clustering.IResourceClusteringPolicy;
|
||||
import org.eclipse.xtext.util.CancelIndicator;
|
||||
import org.eclipse.xtext.xbase.lib.Functions.Function1;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
* @since 2.9
|
||||
*/
|
||||
public class BuildContext {
|
||||
private final Function1<? super URI, ? extends IResourceServiceProvider> resourceServiceProviderProvider;
|
||||
|
||||
private final XtextResourceSet resourceSet;
|
||||
|
||||
private final IndexState oldState;
|
||||
|
||||
private final IResourceClusteringPolicy clusteringPolicy;
|
||||
|
||||
private final CancelIndicator cancelIndicator;
|
||||
|
||||
private ClusteringStorageAwareResourceLoader loader;
|
||||
|
||||
public BuildContext(Function1<? super URI, ? extends IResourceServiceProvider> resourceServiceProviderProvider,
|
||||
XtextResourceSet resourceSet, IndexState oldState, IResourceClusteringPolicy clusteringPolicy,
|
||||
CancelIndicator cancelIndicator) {
|
||||
this.resourceServiceProviderProvider = resourceServiceProviderProvider;
|
||||
this.resourceSet = resourceSet;
|
||||
this.oldState = oldState;
|
||||
this.clusteringPolicy = clusteringPolicy;
|
||||
this.cancelIndicator = cancelIndicator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the given logic on all uris with clustering enabled.
|
||||
*/
|
||||
public <T> Iterable<T> executeClustered(Iterable<URI> uris, Function1<? super Resource, ? extends T> operation) {
|
||||
if (loader == null) {
|
||||
loader = new ClusteringStorageAwareResourceLoader(this);
|
||||
}
|
||||
return loader.executeClustered(Iterables.filter(uris, this::canHandle), operation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true, if the given URI can be handled by an available language.
|
||||
*/
|
||||
protected boolean canHandle(URI uri) {
|
||||
IResourceServiceProvider resourceServiceProvider = getResourceServiceProvider(uri);
|
||||
if (resourceServiceProvider == null) {
|
||||
return false;
|
||||
}
|
||||
return resourceServiceProvider.canHandle(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the resource service provider for this URI.
|
||||
*/
|
||||
public IResourceServiceProvider getResourceServiceProvider(URI uri) {
|
||||
return resourceServiceProviderProvider.apply(uri);
|
||||
}
|
||||
|
||||
public XtextResourceSet getResourceSet() {
|
||||
return resourceSet;
|
||||
}
|
||||
|
||||
public IndexState getOldState() {
|
||||
return oldState;
|
||||
}
|
||||
|
||||
public IResourceClusteringPolicy getClusteringPolicy() {
|
||||
return clusteringPolicy;
|
||||
}
|
||||
|
||||
public CancelIndicator getCancelIndicator() {
|
||||
return cancelIndicator;
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2015, 2016 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.build
|
||||
|
||||
import org.eclipse.emf.common.util.URI
|
||||
import org.eclipse.emf.ecore.resource.Resource
|
||||
import org.eclipse.xtend.lib.annotations.Accessors
|
||||
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor
|
||||
import org.eclipse.xtext.resource.IResourceServiceProvider
|
||||
import org.eclipse.xtext.resource.XtextResourceSet
|
||||
import org.eclipse.xtext.resource.clustering.IResourceClusteringPolicy
|
||||
import org.eclipse.xtext.util.CancelIndicator
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
* @since 2.9
|
||||
*/
|
||||
@FinalFieldsConstructor
|
||||
class BuildContext {
|
||||
val (URI)=>IResourceServiceProvider resourceServiceProviderProvider
|
||||
@Accessors val XtextResourceSet resourceSet
|
||||
@Accessors val IndexState oldState
|
||||
@Accessors val IResourceClusteringPolicy clusteringPolicy
|
||||
@Accessors val CancelIndicator cancelIndicator
|
||||
|
||||
ClusteringStorageAwareResourceLoader loader
|
||||
|
||||
def <T> Iterable<T> executeClustered(Iterable<URI> uri, (Resource)=>T operation) {
|
||||
if(loader === null)
|
||||
loader = new ClusteringStorageAwareResourceLoader(this)
|
||||
return loader.executeClustered(uri.filter[canHandle], operation)
|
||||
}
|
||||
|
||||
protected def boolean canHandle(URI uri) {
|
||||
val resourceServiceProvider = resourceServiceProviderProvider.apply(uri)
|
||||
if (resourceServiceProvider === null)
|
||||
return false
|
||||
|
||||
return resourceServiceProvider.canHandle(uri)
|
||||
}
|
||||
|
||||
def getResourceServiceProvider(URI uri) {
|
||||
val resourceServiceProvider = resourceServiceProviderProvider.apply(uri)
|
||||
return resourceServiceProvider
|
||||
}
|
||||
|
||||
}
|
198
org.eclipse.xtext/src/org/eclipse/xtext/build/BuildRequest.java
Normal file
198
org.eclipse.xtext/src/org/eclipse/xtext/build/BuildRequest.java
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2015, 2016 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.build;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.xtext.diagnostics.Severity;
|
||||
import org.eclipse.xtext.resource.IResourceDescription;
|
||||
import org.eclipse.xtext.resource.XtextResourceSet;
|
||||
import org.eclipse.xtext.util.CancelIndicator;
|
||||
import org.eclipse.xtext.util.UriUtil;
|
||||
import org.eclipse.xtext.validation.Issue;
|
||||
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
|
||||
import org.eclipse.xtext.xbase.lib.Procedures.Procedure2;
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
* @since 2.9
|
||||
*/
|
||||
public class BuildRequest {
|
||||
/**
|
||||
* Callback after a resource was validated.
|
||||
*/
|
||||
public interface IPostValidationCallback {
|
||||
/**
|
||||
* @return whether the build can proceed, <code>false</code> if the build should be interrupted
|
||||
*/
|
||||
boolean afterValidate(URI validated, Iterable<Issue> issues);
|
||||
}
|
||||
|
||||
private static class DefaultValidationCallback implements IPostValidationCallback {
|
||||
private static final Logger LOG = Logger.getLogger(DefaultValidationCallback.class);
|
||||
|
||||
@Override
|
||||
public boolean afterValidate(URI validated, Iterable<Issue> issues) {
|
||||
for (Issue issue : issues) {
|
||||
Severity severity = issue.getSeverity();
|
||||
if (severity != null) {
|
||||
switch (severity) {
|
||||
case ERROR:
|
||||
LOG.error(issue.toString());
|
||||
return false;
|
||||
case WARNING:
|
||||
LOG.warn(issue.toString());
|
||||
break;
|
||||
case INFO:
|
||||
LOG.info(issue.toString());
|
||||
break;
|
||||
case IGNORE:
|
||||
LOG.debug(issue.toString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private URI baseDir;
|
||||
|
||||
private List<URI> dirtyFiles = new ArrayList<>();
|
||||
|
||||
private List<URI> deletedFiles = new ArrayList<>();
|
||||
|
||||
private List<IResourceDescription.Delta> externalDeltas = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Callback after validation, return <code>false</code> will stop the build.
|
||||
*/
|
||||
private BuildRequest.IPostValidationCallback afterValidate = new BuildRequest.DefaultValidationCallback();
|
||||
|
||||
private Procedure2<? super URI, ? super URI> afterGenerateFile = (source, generated) -> {
|
||||
/* nothing to do */
|
||||
};
|
||||
|
||||
private Procedure1<? super URI> afterDeleteFile = (file) -> {
|
||||
/* nothing to do */
|
||||
};
|
||||
|
||||
private IndexState state = new IndexState();
|
||||
|
||||
private boolean writeStorageResources = false;
|
||||
|
||||
private boolean indexOnly = false;
|
||||
|
||||
private XtextResourceSet resourceSet;
|
||||
|
||||
private CancelIndicator cancelIndicator = CancelIndicator.NullImpl;
|
||||
|
||||
public void setBaseDir(URI baseDir) {
|
||||
this.baseDir = baseDir;
|
||||
}
|
||||
|
||||
public URI getBaseDir() {
|
||||
if (baseDir == null) {
|
||||
String userDir = System.getProperty("user.dir");
|
||||
baseDir = UriUtil.createFolderURI(new File(userDir));
|
||||
}
|
||||
return baseDir;
|
||||
}
|
||||
|
||||
public List<URI> getDirtyFiles() {
|
||||
return dirtyFiles;
|
||||
}
|
||||
|
||||
public void setDirtyFiles(List<URI> dirtyFiles) {
|
||||
this.dirtyFiles = dirtyFiles;
|
||||
}
|
||||
|
||||
public List<URI> getDeletedFiles() {
|
||||
return deletedFiles;
|
||||
}
|
||||
|
||||
public void setDeletedFiles(List<URI> deletedFiles) {
|
||||
this.deletedFiles = deletedFiles;
|
||||
}
|
||||
|
||||
public List<IResourceDescription.Delta> getExternalDeltas() {
|
||||
return externalDeltas;
|
||||
}
|
||||
|
||||
public void setExternalDeltas(List<IResourceDescription.Delta> externalDeltas) {
|
||||
this.externalDeltas = externalDeltas;
|
||||
}
|
||||
|
||||
public BuildRequest.IPostValidationCallback getAfterValidate() {
|
||||
return afterValidate;
|
||||
}
|
||||
|
||||
public void setAfterValidate(BuildRequest.IPostValidationCallback afterValidate) {
|
||||
this.afterValidate = afterValidate;
|
||||
}
|
||||
|
||||
public Procedure2<? super URI, ? super URI> getAfterGenerateFile() {
|
||||
return afterGenerateFile;
|
||||
}
|
||||
|
||||
public void setAfterGenerateFile(Procedure2<? super URI, ? super URI> afterGenerateFile) {
|
||||
this.afterGenerateFile = afterGenerateFile;
|
||||
}
|
||||
|
||||
public Procedure1<? super URI> getAfterDeleteFile() {
|
||||
return afterDeleteFile;
|
||||
}
|
||||
|
||||
public void setAfterDeleteFile(Procedure1<? super URI> afterDeleteFile) {
|
||||
this.afterDeleteFile = afterDeleteFile;
|
||||
}
|
||||
|
||||
public IndexState getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(IndexState state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public boolean isWriteStorageResources() {
|
||||
return writeStorageResources;
|
||||
}
|
||||
|
||||
public void setWriteStorageResources(boolean writeStorageResources) {
|
||||
this.writeStorageResources = writeStorageResources;
|
||||
}
|
||||
|
||||
public boolean isIndexOnly() {
|
||||
return indexOnly;
|
||||
}
|
||||
|
||||
public void setIndexOnly(boolean indexOnly) {
|
||||
this.indexOnly = indexOnly;
|
||||
}
|
||||
|
||||
public XtextResourceSet getResourceSet() {
|
||||
return resourceSet;
|
||||
}
|
||||
|
||||
public void setResourceSet(XtextResourceSet resourceSet) {
|
||||
this.resourceSet = resourceSet;
|
||||
}
|
||||
|
||||
public CancelIndicator getCancelIndicator() {
|
||||
return cancelIndicator;
|
||||
}
|
||||
|
||||
public void setCancelIndicator(CancelIndicator cancelIndicator) {
|
||||
this.cancelIndicator = cancelIndicator;
|
||||
}
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2015, 2016 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.build
|
||||
|
||||
import java.io.File
|
||||
import java.util.List
|
||||
import org.eclipse.emf.common.util.URI
|
||||
import org.eclipse.xtend.lib.annotations.Accessors
|
||||
import org.eclipse.xtext.resource.IResourceDescription
|
||||
import org.eclipse.xtext.resource.XtextResourceSet
|
||||
import org.eclipse.xtext.util.internal.Log
|
||||
import org.eclipse.xtext.validation.Issue
|
||||
import org.eclipse.xtext.util.UriUtil
|
||||
import org.eclipse.xtext.util.CancelIndicator
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
* @since 2.9
|
||||
*/
|
||||
@Accessors
|
||||
class BuildRequest {
|
||||
|
||||
URI baseDir
|
||||
def URI getBaseDir() {
|
||||
if (baseDir === null) {
|
||||
val userDir = System.getProperty('user.dir')
|
||||
baseDir = UriUtil.createFolderURI(new File(userDir))
|
||||
}
|
||||
return baseDir
|
||||
}
|
||||
|
||||
List<URI> dirtyFiles = newArrayList
|
||||
List<URI> deletedFiles = newArrayList;
|
||||
List<IResourceDescription.Delta> externalDeltas = newArrayList()
|
||||
|
||||
/**
|
||||
* call back after validation, return <code>false</code> will stop the build.
|
||||
*/
|
||||
IPostValidationCallback afterValidate = new DefaultValidationCallback()
|
||||
(URI, URI)=>void afterGenerateFile = []
|
||||
(URI)=>void afterDeleteFile = []
|
||||
|
||||
IndexState state = new IndexState
|
||||
|
||||
boolean writeStorageResources = false
|
||||
boolean indexOnly = false
|
||||
|
||||
XtextResourceSet resourceSet
|
||||
CancelIndicator cancelIndicator = CancelIndicator.NullImpl
|
||||
|
||||
interface IPostValidationCallback {
|
||||
|
||||
/**
|
||||
* @return whether the build can proceed, <code>false</code> if the build should be interrupted
|
||||
*/
|
||||
def boolean afterValidate(URI validated, Iterable<Issue> issues);
|
||||
}
|
||||
|
||||
@Log private static class DefaultValidationCallback implements IPostValidationCallback {
|
||||
|
||||
override afterValidate(URI validated, Iterable<Issue> issues) {
|
||||
var boolean errorFree = true;
|
||||
for (Issue issue : issues) {
|
||||
switch (issue.getSeverity()) {
|
||||
case ERROR : {
|
||||
LOG.error(issue.toString())
|
||||
errorFree = false
|
||||
}
|
||||
case WARNING :
|
||||
LOG.warn(issue.toString())
|
||||
case INFO:
|
||||
LOG.info(issue.toString())
|
||||
case IGNORE:
|
||||
LOG.debug(issue.toString())
|
||||
}
|
||||
}
|
||||
return errorFree;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2015 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.build;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.emf.ecore.resource.Resource;
|
||||
import org.eclipse.xtext.resource.IResourceServiceProvider;
|
||||
import org.eclipse.xtext.resource.IResourceServiceProviderExtension;
|
||||
import org.eclipse.xtext.resource.XtextResourceSet;
|
||||
import org.eclipse.xtext.resource.persistence.SourceLevelURIsAdapter;
|
||||
import org.eclipse.xtext.resource.persistence.StorageAwareResource;
|
||||
import org.eclipse.xtext.xbase.lib.Functions.Function1;
|
||||
|
||||
import com.google.common.collect.FluentIterable;
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
*/
|
||||
public class ClusteringStorageAwareResourceLoader {
|
||||
private final BuildContext context;
|
||||
|
||||
public ClusteringStorageAwareResourceLoader(BuildContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given operation in a clustered fashion.
|
||||
*/
|
||||
public <T> Iterable<T> executeClustered(Iterable<URI> uris, Function1<? super Resource, ? extends T> operation) {
|
||||
int loadedURIsCount = 0;
|
||||
Set<URI> sourceLevelURIs = new HashSet<>();
|
||||
List<Resource> resources = new ArrayList<>();
|
||||
List<T> result = new ArrayList<>();
|
||||
Iterator<URI> iter = uris.iterator();
|
||||
while (iter.hasNext()) {
|
||||
URI uri = iter.next();
|
||||
XtextResourceSet resourceSet = context.getResourceSet();
|
||||
if (!context.getClusteringPolicy().continueProcessing(resourceSet, uri, loadedURIsCount)) {
|
||||
FluentIterable.from(resources).transform(operation::apply).copyInto(result);
|
||||
clearResourceSet();
|
||||
resources.clear();
|
||||
loadedURIsCount = 0;
|
||||
}
|
||||
loadedURIsCount++;
|
||||
if (isSource(uri)) {
|
||||
sourceLevelURIs.add(uri);
|
||||
Resource existingResource = resourceSet.getResource(uri, false);
|
||||
if (existingResource instanceof StorageAwareResource) {
|
||||
if (((StorageAwareResource) existingResource).isLoadedFromStorage()) {
|
||||
existingResource.unload();
|
||||
}
|
||||
}
|
||||
SourceLevelURIsAdapter.setSourceLevelUrisWithoutCopy(resourceSet, sourceLevelURIs);
|
||||
}
|
||||
resources.add(resourceSet.getResource(uri, true));
|
||||
}
|
||||
FluentIterable.from(resources).transform(operation::apply).copyInto(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the given uri must be loaded from source.
|
||||
*/
|
||||
protected boolean isSource(URI uri) {
|
||||
IResourceServiceProvider provider = context.getResourceServiceProvider(uri);
|
||||
return provider instanceof IResourceServiceProviderExtension
|
||||
&& ((IResourceServiceProviderExtension) provider).isSource(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all resoures from the resource set without delivering notifications.
|
||||
*/
|
||||
protected void clearResourceSet() {
|
||||
XtextResourceSet resourceSet = context.getResourceSet();
|
||||
boolean wasDeliver = resourceSet.eDeliver();
|
||||
try {
|
||||
resourceSet.eSetDeliver(false);
|
||||
resourceSet.getResources().clear();
|
||||
} finally {
|
||||
resourceSet.eSetDeliver(wasDeliver);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2015 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.build
|
||||
|
||||
import org.eclipse.emf.common.util.URI
|
||||
import org.eclipse.emf.ecore.resource.Resource
|
||||
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor
|
||||
import org.eclipse.xtext.resource.IResourceServiceProviderExtension
|
||||
import org.eclipse.xtext.resource.persistence.SourceLevelURIsAdapter
|
||||
import org.eclipse.xtext.resource.persistence.StorageAwareResource
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
*/
|
||||
@FinalFieldsConstructor
|
||||
class ClusteringStorageAwareResourceLoader {
|
||||
|
||||
val extension BuildContext context
|
||||
|
||||
def <T> Iterable<T> executeClustered(Iterable<URI> uris, (Resource)=>T operation) {
|
||||
var loadedURIsCount = 0
|
||||
val sourceLevelURIs = <URI>newHashSet
|
||||
val resources = newArrayList
|
||||
val result = newArrayList
|
||||
val iter = uris.iterator
|
||||
while (iter.hasNext) {
|
||||
val uri = iter.next
|
||||
if (!clusteringPolicy.continueProcessing(resourceSet, uri, loadedURIsCount)) {
|
||||
result += resources.map[operation.apply(it)]
|
||||
clearResourceSet
|
||||
loadedURIsCount = 0
|
||||
}
|
||||
loadedURIsCount++;
|
||||
if (uri.isSource) {
|
||||
sourceLevelURIs.add(uri)
|
||||
val existingResource = resourceSet.getResource(uri, false)
|
||||
if(existingResource instanceof StorageAwareResource) {
|
||||
if(existingResource.isLoadedFromStorage)
|
||||
existingResource.unload
|
||||
}
|
||||
SourceLevelURIsAdapter.setSourceLevelUrisWithoutCopy(resourceSet, sourceLevelURIs)
|
||||
}
|
||||
resources += resourceSet.getResource(uri, true)
|
||||
}
|
||||
result += resources.map[operation.apply(it)]
|
||||
return result
|
||||
}
|
||||
|
||||
protected def isSource(URI uri) {
|
||||
val provider = context.getResourceServiceProvider(uri)
|
||||
return provider instanceof IResourceServiceProviderExtension &&
|
||||
(provider as IResourceServiceProviderExtension).isSource(uri)
|
||||
}
|
||||
|
||||
protected def void clearResourceSet() {
|
||||
val wasDeliver = resourceSet.eDeliver();
|
||||
try {
|
||||
resourceSet.eSetDeliver(false);
|
||||
resourceSet.getResources().clear();
|
||||
} finally {
|
||||
resourceSet.eSetDeliver(wasDeliver);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,409 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2015, 2017 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.build;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.emf.ecore.resource.Resource;
|
||||
import org.eclipse.emf.ecore.resource.URIConverter;
|
||||
import org.eclipse.xtext.EcoreUtil2;
|
||||
import org.eclipse.xtext.generator.GeneratorContext;
|
||||
import org.eclipse.xtext.generator.GeneratorDelegate;
|
||||
import org.eclipse.xtext.generator.IContextualOutputConfigurationProvider;
|
||||
import org.eclipse.xtext.generator.IContextualOutputConfigurationProvider2;
|
||||
import org.eclipse.xtext.generator.IFilePostProcessor;
|
||||
import org.eclipse.xtext.generator.IFileSystemAccess;
|
||||
import org.eclipse.xtext.generator.IShouldGenerate;
|
||||
import org.eclipse.xtext.generator.OutputConfiguration;
|
||||
import org.eclipse.xtext.generator.URIBasedFileSystemAccess;
|
||||
import org.eclipse.xtext.generator.trace.TraceFileNameProvider;
|
||||
import org.eclipse.xtext.generator.trace.TraceRegionSerializer;
|
||||
import org.eclipse.xtext.parser.IEncodingProvider;
|
||||
import org.eclipse.xtext.resource.IResourceDescription;
|
||||
import org.eclipse.xtext.resource.IResourceDescription.Delta;
|
||||
import org.eclipse.xtext.resource.IResourceServiceProvider;
|
||||
import org.eclipse.xtext.resource.XtextResource;
|
||||
import org.eclipse.xtext.resource.XtextResourceSet;
|
||||
import org.eclipse.xtext.resource.clustering.DisabledClusteringPolicy;
|
||||
import org.eclipse.xtext.resource.clustering.IResourceClusteringPolicy;
|
||||
import org.eclipse.xtext.resource.persistence.IResourceStorageFacade;
|
||||
import org.eclipse.xtext.resource.persistence.SerializableResourceDescription;
|
||||
import org.eclipse.xtext.resource.persistence.StorageAwareResource;
|
||||
import org.eclipse.xtext.service.OperationCanceledManager;
|
||||
import org.eclipse.xtext.util.CancelIndicator;
|
||||
import org.eclipse.xtext.util.RuntimeIOException;
|
||||
import org.eclipse.xtext.validation.CheckMode;
|
||||
import org.eclipse.xtext.validation.IResourceValidator;
|
||||
import org.eclipse.xtext.validation.Issue;
|
||||
import org.eclipse.xtext.workspace.IProjectConfig;
|
||||
import org.eclipse.xtext.workspace.IProjectConfigProvider;
|
||||
import org.eclipse.xtext.workspace.ISourceFolder;
|
||||
import org.eclipse.xtext.xbase.lib.Functions.Function1;
|
||||
import org.eclipse.xtext.xbase.lib.IterableExtensions;
|
||||
import org.eclipse.xtext.xbase.lib.util.ToStringBuilder;
|
||||
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
* @since 2.9
|
||||
*/
|
||||
public class IncrementalBuilder {
|
||||
/**
|
||||
* The result of the build. Encapsulates the new index state and the list of changes.
|
||||
*/
|
||||
public static class Result {
|
||||
private final IndexState indexState;
|
||||
|
||||
private final List<IResourceDescription.Delta> affectedResources;
|
||||
|
||||
public Result(IndexState indexState, List<IResourceDescription.Delta> affectedResources) {
|
||||
this.indexState = indexState;
|
||||
this.affectedResources = affectedResources;
|
||||
}
|
||||
|
||||
public IndexState getIndexState() {
|
||||
return indexState;
|
||||
}
|
||||
|
||||
public List<IResourceDescription.Delta> getAffectedResources() {
|
||||
return affectedResources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + (indexState == null ? 0 : indexState.hashCode());
|
||||
return prime * result + (affectedResources == null ? 0 : affectedResources.hashCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
IncrementalBuilder.Result other = (IncrementalBuilder.Result) obj;
|
||||
if (indexState == null) {
|
||||
if (other.indexState != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!indexState.equals(other.indexState)) {
|
||||
return false;
|
||||
}
|
||||
if (affectedResources == null) {
|
||||
if (other.affectedResources != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!affectedResources.equals(other.affectedResources)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
ToStringBuilder b = new ToStringBuilder(this);
|
||||
b.add("indexState", indexState);
|
||||
b.add("affectedResources", affectedResources);
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder instance that is bound to a single running build.
|
||||
*/
|
||||
public static class InternalStatefulIncrementalBuilder {
|
||||
|
||||
/**
|
||||
* Creates an {@link IFileSystemAccess file system access} that is backed by a {@link URIConverter}.
|
||||
*/
|
||||
@Singleton
|
||||
public static class URIBasedFileSystemAccessFactory {
|
||||
@Inject
|
||||
private IContextualOutputConfigurationProvider outputConfigurationProvider;
|
||||
|
||||
@Inject
|
||||
private IFilePostProcessor postProcessor;
|
||||
|
||||
@Inject(optional = true)
|
||||
private IEncodingProvider encodingProvider;
|
||||
|
||||
@Inject
|
||||
private TraceFileNameProvider traceFileNameProvider;
|
||||
|
||||
@Inject
|
||||
private TraceRegionSerializer traceRegionSerializer;
|
||||
|
||||
@Inject(optional = true)
|
||||
private IProjectConfigProvider projectConfigProvider;
|
||||
|
||||
public URIBasedFileSystemAccess newFileSystemAccess(Resource resource, BuildRequest request) {
|
||||
URIBasedFileSystemAccess uriBasedFileSystemAccess = new URIBasedFileSystemAccess();
|
||||
uriBasedFileSystemAccess.setOutputConfigurations(IterableExtensions.toMap(
|
||||
outputConfigurationProvider.getOutputConfigurations(resource), OutputConfiguration::getName));
|
||||
uriBasedFileSystemAccess.setPostProcessor(postProcessor);
|
||||
if (encodingProvider != null) {
|
||||
uriBasedFileSystemAccess.setEncodingProvider(encodingProvider);
|
||||
}
|
||||
uriBasedFileSystemAccess.setTraceFileNameProvider(traceFileNameProvider);
|
||||
uriBasedFileSystemAccess.setTraceRegionSerializer(traceRegionSerializer);
|
||||
uriBasedFileSystemAccess.setGenerateTraces(true);
|
||||
uriBasedFileSystemAccess.setBaseDir(request.getBaseDir());
|
||||
if (projectConfigProvider != null) {
|
||||
IProjectConfig projectConfig = projectConfigProvider.getProjectConfig(resource.getResourceSet());
|
||||
if (projectConfig != null) {
|
||||
ISourceFolder sourceFolder = projectConfig.findSourceFolderContaining(resource.getURI());
|
||||
if (sourceFolder != null) {
|
||||
uriBasedFileSystemAccess.setCurrentSource(sourceFolder.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
uriBasedFileSystemAccess.setConverter(resource.getResourceSet().getURIConverter());
|
||||
return uriBasedFileSystemAccess;
|
||||
}
|
||||
}
|
||||
|
||||
private BuildContext context;
|
||||
|
||||
private BuildRequest request;
|
||||
|
||||
@Inject
|
||||
private Indexer indexer;
|
||||
|
||||
@Inject
|
||||
private OperationCanceledManager operationCanceledManager;
|
||||
|
||||
protected void unloadResource(URI uri) {
|
||||
XtextResourceSet resourceSet = request.getResourceSet();
|
||||
Resource resource = resourceSet.getResource(uri, false);
|
||||
if (resource != null) {
|
||||
resourceSet.getResources().remove(resource);
|
||||
// proxify
|
||||
resource.unload();
|
||||
}
|
||||
}
|
||||
|
||||
public IncrementalBuilder.Result launch() {
|
||||
Source2GeneratedMapping newSource2GeneratedMapping = request.getState().getFileMappings();
|
||||
Set<URI> unloaded = new HashSet<>();
|
||||
for (URI deleted : request.getDeletedFiles()) {
|
||||
if (unloaded.add(deleted)) {
|
||||
unloadResource(deleted);
|
||||
}
|
||||
}
|
||||
for (URI dirty : request.getDirtyFiles()) {
|
||||
if (unloaded.add(dirty)) {
|
||||
unloadResource(dirty);
|
||||
}
|
||||
}
|
||||
for (URI source : request.getDeletedFiles()) {
|
||||
request.getAfterValidate().afterValidate(source, Collections.emptyList());
|
||||
Map<URI, String> outputConfigs = newSource2GeneratedMapping.deleteSourceAndGetOutputConfigs(source);
|
||||
for (URI generated : outputConfigs.keySet()) {
|
||||
IResourceServiceProvider serviceProvider = context.getResourceServiceProvider(source);
|
||||
XtextResourceSet resourceSet = request.getResourceSet();
|
||||
Set<OutputConfiguration> configs = serviceProvider
|
||||
.get(IContextualOutputConfigurationProvider2.class).getOutputConfigurations(resourceSet);
|
||||
String configName = outputConfigs.get(generated);
|
||||
OutputConfiguration config = FluentIterable.from(configs)
|
||||
.firstMatch(it -> it.getName().equals(configName)).orNull();
|
||||
if (config != null && config.isCleanUpDerivedResources()) {
|
||||
try {
|
||||
resourceSet.getURIConverter().delete(generated, Collections.emptyMap());
|
||||
request.getAfterDeleteFile().apply(generated);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeIOException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Indexer.IndexResult result = indexer.computeAndIndexAffected(request, context);
|
||||
operationCanceledManager.checkCanceled(request.getCancelIndicator());
|
||||
|
||||
List<IResourceDescription.Delta> resolvedDeltas = new ArrayList<>();
|
||||
for (IResourceDescription.Delta delta : result.getResourceDeltas()) {
|
||||
URI uri = delta.getUri();
|
||||
if (delta.getOld() != null && unloaded.add(uri)) {
|
||||
unloadResource(uri);
|
||||
}
|
||||
if (delta.getNew() == null) {
|
||||
resolvedDeltas.add(delta);
|
||||
}
|
||||
}
|
||||
|
||||
Iterable<IResourceDescription.Delta> deltas = context.executeClustered(FluentIterable
|
||||
.from(result.getResourceDeltas()).filter((it) -> it.getNew() != null).transform(Delta::getUri),
|
||||
(resource) -> {
|
||||
CancelIndicator cancelIndicator = request.getCancelIndicator();
|
||||
operationCanceledManager.checkCanceled(cancelIndicator);
|
||||
// trigger init
|
||||
resource.getContents();
|
||||
EcoreUtil2.resolveLazyCrossReferences(resource, CancelIndicator.NullImpl);
|
||||
operationCanceledManager.checkCanceled(cancelIndicator);
|
||||
IResourceServiceProvider serviceProvider = getResourceServiceProvider(resource);
|
||||
IResourceDescription.Manager manager = serviceProvider.getResourceDescriptionManager();
|
||||
IResourceDescription description = manager.getResourceDescription(resource);
|
||||
SerializableResourceDescription copiedDescription = SerializableResourceDescription
|
||||
.createCopy(description);
|
||||
result.getNewIndex().addDescription(resource.getURI(), copiedDescription);
|
||||
operationCanceledManager.checkCanceled(cancelIndicator);
|
||||
if (!request.isIndexOnly() && validate(resource) && serviceProvider.get(IShouldGenerate.class)
|
||||
.shouldGenerate(resource, CancelIndicator.NullImpl)) {
|
||||
operationCanceledManager.checkCanceled(cancelIndicator);
|
||||
generate(resource, request, newSource2GeneratedMapping);
|
||||
}
|
||||
IResourceDescription old = context.getOldState().getResourceDescriptions()
|
||||
.getResourceDescription(resource.getURI());
|
||||
return manager.createDelta(old, copiedDescription);
|
||||
});
|
||||
|
||||
Iterables.addAll(resolvedDeltas, deltas);
|
||||
return new IncrementalBuilder.Result(request.getState(), resolvedDeltas);
|
||||
}
|
||||
|
||||
private IResourceServiceProvider getResourceServiceProvider(Resource resource) {
|
||||
if (resource instanceof XtextResource) {
|
||||
return ((XtextResource) resource).getResourceServiceProvider();
|
||||
}
|
||||
return context.getResourceServiceProvider(resource.getURI());
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the resource and return true, if the build should proceed for the current state.
|
||||
*/
|
||||
protected boolean validate(Resource resource) {
|
||||
IResourceValidator resourceValidator = getResourceServiceProvider(resource).getResourceValidator();
|
||||
if (resourceValidator == null) {
|
||||
return true;
|
||||
}
|
||||
List<Issue> validationResult = resourceValidator.validate(resource, CheckMode.ALL,
|
||||
request.getCancelIndicator());
|
||||
return request.getAfterValidate().afterValidate(resource.getURI(), validationResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate code for the given resource
|
||||
*/
|
||||
protected void generate(Resource resource, BuildRequest request, Source2GeneratedMapping newMappings) {
|
||||
IResourceServiceProvider serviceProvider = getResourceServiceProvider(resource);
|
||||
GeneratorDelegate generator = serviceProvider.get(GeneratorDelegate.class);
|
||||
if (generator == null) {
|
||||
return;
|
||||
}
|
||||
Set<URI> previous = newMappings.deleteSource(resource.getURI());
|
||||
URIBasedFileSystemAccess fileSystemAccess = createFileSystemAccess(serviceProvider, resource);
|
||||
fileSystemAccess.setBeforeWrite((uri, outputCfgName, contents) -> {
|
||||
newMappings.addSource2Generated(resource.getURI(), uri, outputCfgName);
|
||||
previous.remove(uri);
|
||||
request.getAfterGenerateFile().apply(resource.getURI(), uri);
|
||||
return contents;
|
||||
});
|
||||
fileSystemAccess.setBeforeDelete((uri) -> {
|
||||
newMappings.deleteGenerated(uri);
|
||||
request.getAfterDeleteFile().apply(uri);
|
||||
return true;
|
||||
});
|
||||
fileSystemAccess.setContext(resource);
|
||||
if (request.isWriteStorageResources() && resource instanceof StorageAwareResource) {
|
||||
IResourceStorageFacade resourceStorageFacade = ((StorageAwareResource) resource)
|
||||
.getResourceStorageFacade();
|
||||
if (resourceStorageFacade != null) {
|
||||
resourceStorageFacade.saveResource((StorageAwareResource) resource, fileSystemAccess);
|
||||
}
|
||||
}
|
||||
GeneratorContext generatorContext = new GeneratorContext();
|
||||
generatorContext.setCancelIndicator(request.getCancelIndicator());
|
||||
generator.generate(resource, fileSystemAccess, generatorContext);
|
||||
XtextResourceSet resourceSet = request.getResourceSet();
|
||||
for (URI noLongerCreated : previous) {
|
||||
try {
|
||||
resourceSet.getURIConverter().delete(noLongerCreated, Collections.emptyMap());
|
||||
request.getAfterDeleteFile().apply(noLongerCreated);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeIOException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected URIBasedFileSystemAccess createFileSystemAccess(IResourceServiceProvider serviceProvider,
|
||||
Resource resource) {
|
||||
return serviceProvider.get(URIBasedFileSystemAccessFactory.class).newFileSystemAccess(resource, request);
|
||||
}
|
||||
|
||||
protected BuildContext getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
protected void setContext(BuildContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
protected BuildRequest getRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
protected void setRequest(BuildRequest request) {
|
||||
this.request = request;
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
private Provider<IncrementalBuilder.InternalStatefulIncrementalBuilder> provider;
|
||||
|
||||
@Inject
|
||||
private OperationCanceledManager operationCanceledManager;
|
||||
|
||||
/**
|
||||
* Run the build without clustering.
|
||||
*/
|
||||
public IncrementalBuilder.Result build(BuildRequest request,
|
||||
Function1<? super URI, ? extends IResourceServiceProvider> languages) {
|
||||
return build(request, languages, new DisabledClusteringPolicy());
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the build.
|
||||
*/
|
||||
public IncrementalBuilder.Result build(BuildRequest request,
|
||||
Function1<? super URI, ? extends IResourceServiceProvider> languages,
|
||||
IResourceClusteringPolicy clusteringPolicy) {
|
||||
XtextResourceSet resourceSet = request.getResourceSet();
|
||||
IndexState oldState = new IndexState(request.getState().getResourceDescriptions().copy(),
|
||||
request.getState().getFileMappings().copy());
|
||||
BuildContext context = new BuildContext(languages, resourceSet, oldState, clusteringPolicy,
|
||||
request.getCancelIndicator());
|
||||
IncrementalBuilder.InternalStatefulIncrementalBuilder builder = provider.get();
|
||||
builder.setContext(context);
|
||||
builder.setRequest(request);
|
||||
try {
|
||||
return builder.launch();
|
||||
} catch (Throwable t) {
|
||||
operationCanceledManager.propagateIfCancelException(t);
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,247 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2015, 2017 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.build
|
||||
|
||||
import com.google.inject.Inject
|
||||
import com.google.inject.Provider
|
||||
import java.util.List
|
||||
import org.eclipse.emf.common.util.URI
|
||||
import org.eclipse.emf.ecore.resource.Resource
|
||||
import org.eclipse.xtend.lib.annotations.Accessors
|
||||
import org.eclipse.xtend.lib.annotations.Data
|
||||
import org.eclipse.xtext.EcoreUtil2
|
||||
import org.eclipse.xtext.generator.GeneratorDelegate
|
||||
import org.eclipse.xtext.generator.IContextualOutputConfigurationProvider
|
||||
import org.eclipse.xtext.generator.IContextualOutputConfigurationProvider2
|
||||
import org.eclipse.xtext.generator.IFilePostProcessor
|
||||
import org.eclipse.xtext.generator.IShouldGenerate
|
||||
import org.eclipse.xtext.generator.URIBasedFileSystemAccess
|
||||
import org.eclipse.xtext.generator.trace.TraceFileNameProvider
|
||||
import org.eclipse.xtext.generator.trace.TraceRegionSerializer
|
||||
import org.eclipse.xtext.parser.IEncodingProvider
|
||||
import org.eclipse.xtext.resource.IResourceDescription
|
||||
import org.eclipse.xtext.resource.IResourceServiceProvider
|
||||
import org.eclipse.xtext.resource.clustering.DisabledClusteringPolicy
|
||||
import org.eclipse.xtext.resource.clustering.IResourceClusteringPolicy
|
||||
import org.eclipse.xtext.resource.persistence.SerializableResourceDescription
|
||||
import org.eclipse.xtext.resource.persistence.StorageAwareResource
|
||||
import org.eclipse.xtext.service.OperationCanceledManager
|
||||
import org.eclipse.xtext.util.CancelIndicator
|
||||
import org.eclipse.xtext.validation.CheckMode
|
||||
import org.eclipse.xtext.workspace.IProjectConfigProvider
|
||||
import org.eclipse.xtext.generator.GeneratorContext
|
||||
import org.eclipse.xtext.resource.XtextResource
|
||||
import com.google.inject.Singleton
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
* @since 2.9
|
||||
*/
|
||||
class IncrementalBuilder {
|
||||
|
||||
@Data static class Result {
|
||||
IndexState indexState
|
||||
List<IResourceDescription.Delta> affectedResources
|
||||
}
|
||||
|
||||
static class InternalStatefulIncrementalBuilder {
|
||||
|
||||
@Accessors(#[PROTECTED_SETTER, PROTECTED_GETTER]) extension BuildContext context
|
||||
@Accessors(#[PROTECTED_SETTER, PROTECTED_GETTER]) BuildRequest request
|
||||
|
||||
@Inject Indexer indexer
|
||||
@Inject extension OperationCanceledManager
|
||||
|
||||
protected def void unloadResource(URI uri) {
|
||||
val resource = request.resourceSet.getResource(uri, false)
|
||||
if (resource !== null) {
|
||||
request.resourceSet.resources.remove(resource)
|
||||
resource.unload
|
||||
}
|
||||
}
|
||||
|
||||
def Result launch() {
|
||||
val newSource2GeneratedMapping = request.state.fileMappings
|
||||
val unloaded = newHashSet()
|
||||
for (deleted : request.deletedFiles) {
|
||||
if (unloaded.add(deleted)) {
|
||||
unloadResource(deleted)
|
||||
}
|
||||
}
|
||||
for (dirty : request.dirtyFiles) {
|
||||
if (unloaded.add(dirty)) {
|
||||
unloadResource(dirty)
|
||||
}
|
||||
}
|
||||
request.deletedFiles.forEach [ source |
|
||||
request.afterValidate.afterValidate(source, newArrayList)
|
||||
newSource2GeneratedMapping.deleteSource(source).forEach [ generated |
|
||||
val serviceProvider = source.resourceServiceProvider
|
||||
val configs = serviceProvider.get(IContextualOutputConfigurationProvider2).getOutputConfigurations(request.resourceSet)
|
||||
val configName = newSource2GeneratedMapping.getOutputConfigName(generated)
|
||||
val config = configs.findFirst[name == configName]
|
||||
if (config !== null && config.isCleanUpDerivedResources) {
|
||||
context.resourceSet.getURIConverter.delete(generated, emptyMap)
|
||||
request.afterDeleteFile.apply(generated)
|
||||
}
|
||||
]
|
||||
]
|
||||
val result = indexer.computeAndIndexAffected(request, context)
|
||||
request.cancelIndicator.checkCanceled
|
||||
for (delta : result.resourceDeltas) {
|
||||
if (delta.old !== null && unloaded.add(delta.uri)) {
|
||||
unloadResource(delta.uri)
|
||||
}
|
||||
}
|
||||
|
||||
val resolvedDeltas = newArrayList
|
||||
// add deleted deltas
|
||||
resolvedDeltas += result.resourceDeltas.filter[getNew === null]
|
||||
// add changed and added as fully resolved
|
||||
resolvedDeltas += result.resourceDeltas.filter[getNew !== null].map[uri]
|
||||
.executeClustered [
|
||||
Resource resource |
|
||||
request.cancelIndicator.checkCanceled
|
||||
resource.contents // fully initialize
|
||||
EcoreUtil2.resolveLazyCrossReferences(resource, CancelIndicator.NullImpl)
|
||||
request.cancelIndicator.checkCanceled
|
||||
val serviceProvider = resource.resourceServiceProvider
|
||||
val manager = serviceProvider.resourceDescriptionManager
|
||||
val description = manager.getResourceDescription(resource);
|
||||
val copiedDescription = SerializableResourceDescription.createCopy(description);
|
||||
result.newIndex.addDescription(resource.getURI, copiedDescription)
|
||||
request.cancelIndicator.checkCanceled
|
||||
if (!request.indexOnly
|
||||
&& resource.validate
|
||||
&& serviceProvider.get(IShouldGenerate).shouldGenerate(resource, CancelIndicator.NullImpl)
|
||||
) {
|
||||
request.cancelIndicator.checkCanceled
|
||||
resource.generate(request, newSource2GeneratedMapping)
|
||||
}
|
||||
val old = oldState.resourceDescriptions.getResourceDescription(resource.getURI)
|
||||
return manager.createDelta(old, copiedDescription)
|
||||
]
|
||||
return new Result(request.state, resolvedDeltas)
|
||||
}
|
||||
|
||||
def private IResourceServiceProvider getResourceServiceProvider(Resource resource) {
|
||||
if (resource instanceof XtextResource) {
|
||||
return resource.resourceServiceProvider;
|
||||
}
|
||||
return resource.getURI.resourceServiceProvider
|
||||
}
|
||||
|
||||
def protected boolean validate(Resource resource) {
|
||||
val resourceValidator = resource.resourceServiceProvider.resourceValidator;
|
||||
if (resourceValidator === null) {
|
||||
return true
|
||||
}
|
||||
val validationResult = resourceValidator.validate(resource, CheckMode.ALL, null);
|
||||
return request.afterValidate.afterValidate(resource.getURI, validationResult)
|
||||
}
|
||||
|
||||
protected def void generate(Resource resource, BuildRequest request, Source2GeneratedMapping newMappings) {
|
||||
val serviceProvider = resource.resourceServiceProvider
|
||||
val generator = serviceProvider.get(GeneratorDelegate)
|
||||
if (generator === null) {
|
||||
return;
|
||||
}
|
||||
val previous = newMappings.deleteSource(resource.getURI)
|
||||
val fileSystemAccess = createFileSystemAccess(serviceProvider, resource) => [
|
||||
beforeWrite = [ uri, outputCfgName, contents |
|
||||
newMappings.addSource2Generated(resource.getURI, uri, outputCfgName)
|
||||
previous.remove(uri)
|
||||
request.afterGenerateFile.apply(resource.getURI, uri)
|
||||
return contents
|
||||
]
|
||||
beforeDelete = [ uri |
|
||||
newMappings.deleteGenerated(uri)
|
||||
request.afterDeleteFile.apply(uri)
|
||||
return true
|
||||
]
|
||||
]
|
||||
fileSystemAccess.context = resource
|
||||
if (request.isWriteStorageResources) {
|
||||
switch resource {
|
||||
StorageAwareResource case resource.resourceStorageFacade !== null: {
|
||||
resource.resourceStorageFacade.saveResource(resource, fileSystemAccess)
|
||||
}
|
||||
}
|
||||
}
|
||||
val generatorContext = new GeneratorContext
|
||||
generatorContext.cancelIndicator = request.cancelIndicator
|
||||
generator.generate(resource, fileSystemAccess, generatorContext)
|
||||
// delete everything that was previously generated, but not this time
|
||||
previous.forEach[
|
||||
context.resourceSet.getURIConverter.delete(it, emptyMap)
|
||||
request.getAfterDeleteFile.apply(it)
|
||||
]
|
||||
}
|
||||
|
||||
@Singleton
|
||||
static class URIBasedFileSystemAccessFactory {
|
||||
@Inject IContextualOutputConfigurationProvider outputConfigurationProvider;
|
||||
@Inject IFilePostProcessor postProcessor;
|
||||
@Inject(optional=true) IEncodingProvider encodingProvider
|
||||
@Inject TraceFileNameProvider traceFileNameProvider
|
||||
@Inject TraceRegionSerializer traceRegionSerializer
|
||||
@Inject(optional=true) IProjectConfigProvider projectConfigProvider
|
||||
|
||||
def URIBasedFileSystemAccess newFileSystemAccess(Resource resource, BuildRequest request) {
|
||||
return new URIBasedFileSystemAccess() => [
|
||||
outputConfigurations = outputConfigurationProvider.getOutputConfigurations(resource).toMap[name]
|
||||
|
||||
it.postProcessor = postProcessor
|
||||
if (encodingProvider !== null)
|
||||
it.encodingProvider = encodingProvider
|
||||
it.traceFileNameProvider = traceFileNameProvider
|
||||
it.traceRegionSerializer = traceRegionSerializer
|
||||
generateTraces = true
|
||||
|
||||
baseDir = request.baseDir
|
||||
if (projectConfigProvider !== null) {
|
||||
val sourceFolder = projectConfigProvider.getProjectConfig(resource.resourceSet)?.findSourceFolderContaining(resource.getURI)
|
||||
currentSource = sourceFolder?.name
|
||||
}
|
||||
converter = resource.resourceSet.getURIConverter
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
protected def createFileSystemAccess(IResourceServiceProvider serviceProvider, Resource resource) {
|
||||
return serviceProvider.get(URIBasedFileSystemAccessFactory).newFileSystemAccess(resource, request)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Inject Provider<IncrementalBuilder.InternalStatefulIncrementalBuilder> provider
|
||||
@Inject extension OperationCanceledManager
|
||||
|
||||
def Result build(BuildRequest request, (URI)=>IResourceServiceProvider languages) {
|
||||
build(request, languages, new DisabledClusteringPolicy())
|
||||
}
|
||||
|
||||
def Result build(BuildRequest request, (URI)=>IResourceServiceProvider languages, IResourceClusteringPolicy clusteringPolicy) {
|
||||
val resourceSet = request.resourceSet
|
||||
val oldState = new IndexState(request.state.resourceDescriptions.copy, request.state.fileMappings.copy)
|
||||
val context = new BuildContext(languages
|
||||
, resourceSet
|
||||
, oldState
|
||||
, clusteringPolicy,
|
||||
request.cancelIndicator)
|
||||
val builder = provider.get
|
||||
builder.setContext(context)
|
||||
builder.setRequest(request)
|
||||
try {
|
||||
return builder.launch
|
||||
} catch(Throwable t) {
|
||||
t.propagateIfCancelException
|
||||
throw t
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2015 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.build;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.eclipse.xtext.resource.impl.ResourceDescriptionsData;
|
||||
|
||||
/**
|
||||
* @author Sven Efftinge - Initial contribution and API
|
||||
*/
|
||||
public class IndexState {
|
||||
private final ResourceDescriptionsData resourceDescriptions;
|
||||
|
||||
private final Source2GeneratedMapping fileMappings;
|
||||
|
||||
public IndexState() {
|
||||
this(new ResourceDescriptionsData(Collections.emptySet()), new Source2GeneratedMapping());
|
||||
}
|
||||
|
||||
public IndexState(ResourceDescriptionsData resourceDescriptions, Source2GeneratedMapping fileMappings) {
|
||||
this.resourceDescriptions = resourceDescriptions;
|
||||
this.fileMappings = fileMappings;
|
||||
}
|
||||
|
||||
public ResourceDescriptionsData getResourceDescriptions() {
|
||||
return resourceDescriptions;
|
||||
}
|
||||
|
||||
public Source2GeneratedMapping getFileMappings() {
|
||||
return fileMappings;
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2015 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.build
|
||||
|
||||
import org.eclipse.xtend.lib.annotations.Accessors
|
||||
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor
|
||||
import org.eclipse.xtext.resource.impl.ResourceDescriptionsData
|
||||
|
||||
/**
|
||||
* @author Sven Efftinge - Initial contribution and API
|
||||
*/
|
||||
@FinalFieldsConstructor @Accessors class IndexState {
|
||||
|
||||
val ResourceDescriptionsData resourceDescriptions
|
||||
val Source2GeneratedMapping fileMappings
|
||||
|
||||
new () {
|
||||
this(new ResourceDescriptionsData(emptySet), new Source2GeneratedMapping)
|
||||
}
|
||||
|
||||
}
|
282
org.eclipse.xtext/src/org/eclipse/xtext/build/Indexer.java
Normal file
282
org.eclipse.xtext/src/org/eclipse/xtext/build/Indexer.java
Normal file
|
@ -0,0 +1,282 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2015, 2016 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.build;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.emf.ecore.InternalEObject;
|
||||
import org.eclipse.emf.ecore.resource.Resource;
|
||||
import org.eclipse.emf.ecore.util.EcoreUtil;
|
||||
import org.eclipse.xtext.naming.QualifiedName;
|
||||
import org.eclipse.xtext.resource.CompilerPhases;
|
||||
import org.eclipse.xtext.resource.EObjectDescription;
|
||||
import org.eclipse.xtext.resource.IEObjectDescription;
|
||||
import org.eclipse.xtext.resource.IReferenceDescription;
|
||||
import org.eclipse.xtext.resource.IResourceDescription;
|
||||
import org.eclipse.xtext.resource.IResourceDescription.Delta;
|
||||
import org.eclipse.xtext.resource.IResourceDescriptions;
|
||||
import org.eclipse.xtext.resource.IResourceServiceProvider;
|
||||
import org.eclipse.xtext.resource.impl.AbstractResourceDescription;
|
||||
import org.eclipse.xtext.resource.impl.DefaultResourceDescriptionDelta;
|
||||
import org.eclipse.xtext.resource.impl.ResourceDescriptionsData;
|
||||
import org.eclipse.xtext.resource.persistence.SerializableEObjectDescriptionProvider;
|
||||
import org.eclipse.xtext.service.OperationCanceledManager;
|
||||
import org.eclipse.xtext.xbase.lib.IterableExtensions;
|
||||
import org.eclipse.xtext.xbase.lib.util.ToStringBuilder;
|
||||
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
* @since 2.9
|
||||
*/
|
||||
public class Indexer {
|
||||
|
||||
public static class IndexResult {
|
||||
private final List<IResourceDescription.Delta> resourceDeltas;
|
||||
|
||||
private final ResourceDescriptionsData newIndex;
|
||||
|
||||
public IndexResult(List<IResourceDescription.Delta> resourceDeltas, ResourceDescriptionsData newIndex) {
|
||||
this.resourceDeltas = resourceDeltas;
|
||||
this.newIndex = newIndex;
|
||||
}
|
||||
|
||||
public List<IResourceDescription.Delta> getResourceDeltas() {
|
||||
return resourceDeltas;
|
||||
}
|
||||
|
||||
public ResourceDescriptionsData getNewIndex() {
|
||||
return newIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + (resourceDeltas == null ? 0 : resourceDeltas.hashCode());
|
||||
return prime * result + (newIndex == null ? 0 : newIndex.hashCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Indexer.IndexResult other = (Indexer.IndexResult) obj;
|
||||
if (resourceDeltas == null) {
|
||||
if (other.resourceDeltas != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!resourceDeltas.equals(other.resourceDeltas)) {
|
||||
return false;
|
||||
}
|
||||
if (newIndex == null) {
|
||||
if (other.newIndex != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!newIndex.equals(other.newIndex)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
ToStringBuilder b = new ToStringBuilder(this);
|
||||
b.add("resourceDeltas", resourceDeltas);
|
||||
b.add("newIndex", newIndex);
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A resource description that has no references to the origin resource anymore. Imported names and reference
|
||||
* descriptions are not available.
|
||||
*/
|
||||
protected static class ResolvedResourceDescription extends AbstractResourceDescription {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(ResolvedResourceDescription.class);
|
||||
|
||||
private URI uri;
|
||||
|
||||
private ImmutableList<IEObjectDescription> exported;
|
||||
|
||||
public ResolvedResourceDescription(IResourceDescription original) {
|
||||
uri = original.getURI();
|
||||
exported = FluentIterable.from(original.getExportedObjects()).transform(from -> {
|
||||
if (from instanceof SerializableEObjectDescriptionProvider) {
|
||||
return ((SerializableEObjectDescriptionProvider) from).toSerializableEObjectDescription();
|
||||
}
|
||||
if (from.getEObjectOrProxy().eIsProxy()) {
|
||||
return from;
|
||||
}
|
||||
InternalEObject result = (InternalEObject) EcoreUtil.create(from.getEClass());
|
||||
result.eSetProxyURI(from.getEObjectURI());
|
||||
Map<String, String> userData = null;
|
||||
String[] userDataKeys = from.getUserDataKeys();
|
||||
for (String key : userDataKeys) {
|
||||
if (userData == null) {
|
||||
userData = Maps.newHashMapWithExpectedSize(userDataKeys.length);
|
||||
}
|
||||
userData.put(key, from.getUserData(key));
|
||||
}
|
||||
return EObjectDescription.create(from.getName(), result, userData);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<IEObjectDescription> computeExportedObjects() {
|
||||
return exported;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<QualifiedName> getImportedNames() {
|
||||
IllegalStateException exception = new IllegalStateException("getImportedNames" + getURI());
|
||||
LOG.error(exception, exception);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<IReferenceDescription> getReferenceDescriptions() {
|
||||
IllegalStateException exception = new IllegalStateException("getReferenceDescriptions" + getURI());
|
||||
LOG.error(exception, exception);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getURI() {
|
||||
return uri;
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
private CompilerPhases compilerPhases;
|
||||
|
||||
@Inject
|
||||
private OperationCanceledManager operationCanceledManager;
|
||||
|
||||
/**
|
||||
* Compute an updated index.
|
||||
*/
|
||||
public Indexer.IndexResult computeAndIndexAffected(BuildRequest request, BuildContext context) {
|
||||
ResourceDescriptionsData previousIndex = context.getOldState().getResourceDescriptions();
|
||||
ResourceDescriptionsData newIndex = request.getState().getResourceDescriptions();
|
||||
List<IResourceDescription.Delta> deltas = new ArrayList<>();
|
||||
deltas.addAll(getDeltasForDeletedResources(request, previousIndex, context));
|
||||
deltas.addAll(getDeltasForChangedResources(request.getDirtyFiles(), previousIndex, context));
|
||||
for (IResourceDescription.Delta delta : deltas) {
|
||||
newIndex.register(delta);
|
||||
}
|
||||
Set<IResourceDescription.Delta> allDeltas = new HashSet<>(deltas);
|
||||
allDeltas.addAll(request.getExternalDeltas());
|
||||
Set<URI> remainingURIs = FluentIterable.from(previousIndex.getAllResourceDescriptions())
|
||||
.transform(IResourceDescription::getURI).copyInto(new HashSet<>());
|
||||
remainingURIs.removeAll(FluentIterable.from(deltas).transform(Delta::getUri).toSet());
|
||||
List<URI> allAffected = FluentIterable.from(remainingURIs).filter(it -> {
|
||||
IResourceDescription.Manager manager = context.getResourceServiceProvider(it)
|
||||
.getResourceDescriptionManager();
|
||||
IResourceDescription resourceDescription = previousIndex.getResourceDescription(it);
|
||||
return isAffected(resourceDescription, manager, allDeltas, allDeltas, newIndex);
|
||||
}).toList();
|
||||
deltas.addAll(getDeltasForChangedResources(allAffected, previousIndex, context));
|
||||
return new Indexer.IndexResult(deltas, newIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the deleted resources.
|
||||
*/
|
||||
protected List<IResourceDescription.Delta> getDeltasForDeletedResources(BuildRequest request,
|
||||
ResourceDescriptionsData oldIndex, BuildContext context) {
|
||||
List<IResourceDescription.Delta> deltas = new ArrayList<>();
|
||||
for (URI deleted : request.getDeletedFiles()) {
|
||||
IResourceServiceProvider resourceServiceProvider = context.getResourceServiceProvider(deleted);
|
||||
if (resourceServiceProvider != null) {
|
||||
operationCanceledManager.checkCanceled(context.getCancelIndicator());
|
||||
IResourceDescription oldDescription = oldIndex != null ? oldIndex.getResourceDescription(deleted)
|
||||
: null;
|
||||
if (oldDescription != null) {
|
||||
DefaultResourceDescriptionDelta delta = new DefaultResourceDescriptionDelta(oldDescription, null);
|
||||
deltas.add(delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
return deltas;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the changed resources.
|
||||
*/
|
||||
protected List<IResourceDescription.Delta> getDeltasForChangedResources(Iterable<URI> affectedUris,
|
||||
ResourceDescriptionsData oldIndex, BuildContext context) {
|
||||
try {
|
||||
compilerPhases.setIndexing(context.getResourceSet(), true);
|
||||
// Since context.executeClustered, we can avoid a copy due of the list due to the impl detail of
|
||||
// IterableExtensions.toList
|
||||
return IterableExtensions
|
||||
.toList(context.executeClustered(affectedUris, it -> addToIndex(it, true, oldIndex, context)));
|
||||
} finally {
|
||||
compilerPhases.setIndexing(context.getResourceSet(), false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Index the given resource.
|
||||
*
|
||||
* @param isPreIndexing
|
||||
* can be evaluated to produce different index entries depending on the phase
|
||||
*/
|
||||
protected IResourceDescription.Delta addToIndex(Resource resource, boolean isPreIndexing,
|
||||
ResourceDescriptionsData oldIndex, BuildContext context) {
|
||||
operationCanceledManager.checkCanceled(context.getCancelIndicator());
|
||||
URI uri = resource.getURI();
|
||||
IResourceServiceProvider serviceProvider = context.getResourceServiceProvider(uri);
|
||||
IResourceDescription.Manager manager = serviceProvider.getResourceDescriptionManager();
|
||||
IResourceDescription newDescription = manager.getResourceDescription(resource);
|
||||
IResourceDescription toBeAdded = new Indexer.ResolvedResourceDescription(newDescription);
|
||||
IResourceDescription.Delta delta = manager
|
||||
.createDelta(oldIndex != null ? oldIndex.getResourceDescription(uri) : null, toBeAdded);
|
||||
return delta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true, if the given resource must be processed due to the given changes.
|
||||
*/
|
||||
protected boolean isAffected(IResourceDescription affectionCandidate, IResourceDescription.Manager manager,
|
||||
Collection<IResourceDescription.Delta> newDeltas, Collection<IResourceDescription.Delta> allDeltas,
|
||||
IResourceDescriptions resourceDescriptions) {
|
||||
if (manager instanceof IResourceDescription.Manager.AllChangeAware) {
|
||||
return ((IResourceDescription.Manager.AllChangeAware) manager).isAffectedByAny(allDeltas,
|
||||
affectionCandidate, resourceDescriptions);
|
||||
} else {
|
||||
if (newDeltas.isEmpty()) {
|
||||
return false;
|
||||
} else {
|
||||
return manager.isAffected(newDeltas, affectionCandidate, resourceDescriptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,185 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2015, 2016 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.build
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.google.common.collect.Maps
|
||||
import com.google.inject.Inject
|
||||
import java.util.Collection
|
||||
import java.util.HashSet
|
||||
import java.util.List
|
||||
import java.util.Map
|
||||
import org.eclipse.emf.common.util.URI
|
||||
import org.eclipse.emf.ecore.InternalEObject
|
||||
import org.eclipse.emf.ecore.resource.Resource
|
||||
import org.eclipse.emf.ecore.util.EcoreUtil
|
||||
import org.eclipse.xtend.lib.annotations.Accessors
|
||||
import org.eclipse.xtend.lib.annotations.Data
|
||||
import org.eclipse.xtext.naming.QualifiedName
|
||||
import org.eclipse.xtext.resource.CompilerPhases
|
||||
import org.eclipse.xtext.resource.EObjectDescription
|
||||
import org.eclipse.xtext.resource.IEObjectDescription
|
||||
import org.eclipse.xtext.resource.IReferenceDescription
|
||||
import org.eclipse.xtext.resource.IResourceDescription
|
||||
import org.eclipse.xtext.resource.IResourceDescription.Delta
|
||||
import org.eclipse.xtext.resource.IResourceDescriptions
|
||||
import org.eclipse.xtext.resource.impl.AbstractResourceDescription
|
||||
import org.eclipse.xtext.resource.impl.DefaultResourceDescriptionDelta
|
||||
import org.eclipse.xtext.resource.impl.ResourceDescriptionsData
|
||||
import org.eclipse.xtext.util.internal.Log
|
||||
import org.eclipse.xtext.service.OperationCanceledManager
|
||||
import org.eclipse.xtext.resource.persistence.SerializableEObjectDescriptionProvider
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
* @since 2.9
|
||||
*/
|
||||
class Indexer {
|
||||
|
||||
@Inject CompilerPhases compilerPhases
|
||||
@Inject extension OperationCanceledManager
|
||||
|
||||
@Data static class IndexResult {
|
||||
List<Delta> resourceDeltas
|
||||
ResourceDescriptionsData newIndex
|
||||
}
|
||||
|
||||
def IndexResult computeAndIndexAffected(BuildRequest request, extension BuildContext context) {
|
||||
val previousIndex = context.oldState.resourceDescriptions
|
||||
val newIndex = request.state.resourceDescriptions
|
||||
|
||||
// get the direct deltas
|
||||
val List<Delta> deltas = newArrayList
|
||||
deltas.addAll(getDeltasForDeletedResources(request, previousIndex, context))
|
||||
deltas.addAll(getDeltasForChangedResources(request.dirtyFiles, previousIndex, context))
|
||||
// update the index with the direct deltas
|
||||
for (delta : deltas)
|
||||
newIndex.register(delta)
|
||||
|
||||
// add external deltas
|
||||
val allDeltas = new HashSet<Delta>(deltas)
|
||||
if (!request.externalDeltas.empty)
|
||||
allDeltas.addAll(request.externalDeltas)
|
||||
|
||||
val remainingURIs = previousIndex.allResourceDescriptions.map[getURI].toSet
|
||||
remainingURIs.removeAll(deltas.map[uri])
|
||||
|
||||
val allAffected = remainingURIs.filter [
|
||||
val manager = getResourceServiceProvider.resourceDescriptionManager
|
||||
val resourceDescription = previousIndex.getResourceDescription(it)
|
||||
val isAffected = resourceDescription.isAffected(manager, allDeltas, allDeltas, newIndex)
|
||||
return isAffected
|
||||
].toList
|
||||
deltas.addAll(getDeltasForChangedResources(allAffected, previousIndex, context))
|
||||
|
||||
return new IndexResult(deltas, newIndex)
|
||||
}
|
||||
|
||||
protected def List<Delta> getDeltasForDeletedResources(BuildRequest request, ResourceDescriptionsData oldIndex,
|
||||
extension BuildContext context) {
|
||||
val deltas = <Delta>newArrayList()
|
||||
request.deletedFiles.filter[context.getResourceServiceProvider(it) !== null].forEach [
|
||||
context.cancelIndicator.checkCanceled
|
||||
val IResourceDescription oldDescription = oldIndex?.getResourceDescription(it)
|
||||
if (oldDescription !== null) {
|
||||
val delta = new DefaultResourceDescriptionDelta(oldDescription, null)
|
||||
deltas += delta
|
||||
}
|
||||
]
|
||||
return deltas
|
||||
}
|
||||
|
||||
protected def List<Delta> getDeltasForChangedResources(Iterable<URI> affectedUris,
|
||||
ResourceDescriptionsData oldIndex, extension BuildContext context) {
|
||||
try {
|
||||
compilerPhases.setIndexing(resourceSet, true)
|
||||
return affectedUris.executeClustered [
|
||||
addToIndex(true, oldIndex, context)
|
||||
].toList
|
||||
} finally {
|
||||
compilerPhases.setIndexing(resourceSet, false)
|
||||
}
|
||||
}
|
||||
|
||||
def protected Delta addToIndex(Resource resource, boolean isPreIndexing, ResourceDescriptionsData oldIndex,
|
||||
BuildContext context) {
|
||||
context.cancelIndicator.checkCanceled
|
||||
val uri = resource.getURI
|
||||
val serviceProvider = context.getResourceServiceProvider(uri)
|
||||
val manager = serviceProvider.resourceDescriptionManager
|
||||
val newDescription = manager.getResourceDescription(resource)
|
||||
val IResourceDescription toBeAdded = new ResolvedResourceDescription(newDescription)
|
||||
val delta = manager.createDelta(oldIndex?.getResourceDescription(uri), toBeAdded)
|
||||
return delta
|
||||
}
|
||||
|
||||
def protected boolean isAffected(IResourceDescription affectionCandidate, IResourceDescription.Manager manager,
|
||||
Collection<IResourceDescription.Delta> newDeltas, Collection<IResourceDescription.Delta> allDeltas,
|
||||
IResourceDescriptions resourceDescriptions) {
|
||||
if ((manager instanceof IResourceDescription.Manager.AllChangeAware)) {
|
||||
return manager.isAffectedByAny(allDeltas, affectionCandidate, resourceDescriptions);
|
||||
} else {
|
||||
if (newDeltas.empty) {
|
||||
return false;
|
||||
} else {
|
||||
return manager.isAffected(newDeltas, affectionCandidate, resourceDescriptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Log protected static class ResolvedResourceDescription extends AbstractResourceDescription {
|
||||
|
||||
@Accessors(PUBLIC_GETTER)
|
||||
URI URI
|
||||
|
||||
ImmutableList<IEObjectDescription> exported
|
||||
|
||||
new(IResourceDescription original) {
|
||||
this.URI = original.getURI
|
||||
this.exported = ImmutableList.copyOf(
|
||||
original.exportedObjects.map [ IEObjectDescription from |
|
||||
if (from instanceof SerializableEObjectDescriptionProvider) {
|
||||
return from.toSerializableEObjectDescription()
|
||||
}
|
||||
if (from.getEObjectOrProxy.eIsProxy)
|
||||
return from
|
||||
var result = EcoreUtil.create(from.getEClass()) as InternalEObject
|
||||
result.eSetProxyURI(from.getEObjectURI)
|
||||
var Map<String, String> userData = null
|
||||
for (key : from.userDataKeys) {
|
||||
if (userData === null)
|
||||
userData = Maps.newHashMapWithExpectedSize(2)
|
||||
userData.put(key, from.getUserData(key))
|
||||
}
|
||||
return EObjectDescription.create(from.name, result, userData)
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
override protected List<IEObjectDescription> computeExportedObjects() {
|
||||
return exported
|
||||
}
|
||||
|
||||
override Iterable<QualifiedName> getImportedNames() {
|
||||
// Should never be called during indexing.
|
||||
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=344373
|
||||
var IllegalStateException exception = new IllegalStateException('''getImportedNames «URI»''')
|
||||
LOG.error(exception, exception)
|
||||
return emptyList
|
||||
}
|
||||
|
||||
override Iterable<IReferenceDescription> getReferenceDescriptions() {
|
||||
// Should never be called during indexing.
|
||||
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=344373
|
||||
var IllegalStateException exception = new IllegalStateException('''getReferenceDescriptions «URI»''')
|
||||
LOG.error(exception, exception)
|
||||
return emptyList
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2015 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.build;
|
||||
|
||||
import java.io.Externalizable;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.xtext.generator.IFileSystemAccess;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
*/
|
||||
public class Source2GeneratedMapping implements Externalizable {
|
||||
private final Multimap<URI, URI> source2generated;
|
||||
|
||||
private final Multimap<URI, URI> generated2source;
|
||||
|
||||
private final Map<URI, String> generated2OutputConfigName;
|
||||
|
||||
public Source2GeneratedMapping() {
|
||||
this(HashMultimap.create(), HashMultimap.create(), new HashMap<>());
|
||||
}
|
||||
|
||||
public Source2GeneratedMapping(Multimap<URI, URI> source2generated, Multimap<URI, URI> generated2source,
|
||||
Map<URI, String> generated2OutputConfigName) {
|
||||
this.source2generated = source2generated;
|
||||
this.generated2source = generated2source;
|
||||
this.generated2OutputConfigName = generated2OutputConfigName;
|
||||
}
|
||||
|
||||
public Source2GeneratedMapping copy() {
|
||||
return new Source2GeneratedMapping(HashMultimap.create(source2generated), HashMultimap.create(generated2source),
|
||||
new HashMap<>(generated2OutputConfigName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a mapping in the {@link IFileSystemAccess#DEFAULT_OUTPUT default output}.
|
||||
*/
|
||||
public void addSource2Generated(URI source, URI generated) {
|
||||
addSource2Generated(source, generated, IFileSystemAccess.DEFAULT_OUTPUT);
|
||||
}
|
||||
|
||||
public void addSource2Generated(URI source, URI generated, String outputCfgName) {
|
||||
source2generated.put(source, generated);
|
||||
generated2source.put(generated, source);
|
||||
generated2OutputConfigName.put(generated,
|
||||
outputCfgName == null ? IFileSystemAccess.DEFAULT_OUTPUT : outputCfgName);
|
||||
}
|
||||
|
||||
public void removeSource2Generated(URI source, URI generated) {
|
||||
source2generated.remove(source, generated);
|
||||
generated2source.remove(generated, source);
|
||||
if (!generated2source.containsKey(generated)) {
|
||||
generated2OutputConfigName.remove(generated);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the source as deleted and return all the former generated uris.
|
||||
*/
|
||||
public Set<URI> deleteSource(URI source) {
|
||||
Set<URI> generated = new HashSet<>(source2generated.removeAll(source));
|
||||
for (URI gen : generated) {
|
||||
generated2source.remove(gen, source);
|
||||
if (!generated2source.containsKey(gen)) {
|
||||
generated2OutputConfigName.remove(gen);
|
||||
}
|
||||
}
|
||||
return generated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the source as deleted and return all the former generated uris.
|
||||
*/
|
||||
public Map<URI, String> deleteSourceAndGetOutputConfigs(URI source) {
|
||||
Set<URI> generated = new HashSet<>(source2generated.removeAll(source));
|
||||
Map<URI, String> result = new HashMap<>();
|
||||
for (URI gen : generated) {
|
||||
generated2source.remove(gen, source);
|
||||
result.put(gen, generated2OutputConfigName.get(gen));
|
||||
if (!generated2source.containsKey(gen)) {
|
||||
generated2OutputConfigName.remove(gen);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the generated file from this mapping.
|
||||
*/
|
||||
public void deleteGenerated(URI generated) {
|
||||
generated2source.removeAll(generated).forEach(it -> {
|
||||
source2generated.remove(it, generated);
|
||||
});
|
||||
generated2OutputConfigName.remove(generated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the output configuration that led to the given generated URI.
|
||||
*/
|
||||
public String getOutputConfigName(URI generated) {
|
||||
return generated2OutputConfigName.get(generated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the generated resources for the given source.
|
||||
*/
|
||||
public List<URI> getGenerated(URI source) {
|
||||
return new ArrayList<>(source2generated.get(source));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the source resources for the given generated resource.
|
||||
*/
|
||||
public List<URI> getSource(URI generated) {
|
||||
return new ArrayList<>(generated2source.get(generated));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the generated resources.
|
||||
*/
|
||||
public List<URI> getAllGenerated() {
|
||||
return new ArrayList<>(generated2source.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
|
||||
int numEntries = in.readInt();
|
||||
while (numEntries > 0) {
|
||||
numEntries--;
|
||||
URI source = URI.createURI(in.readUTF());
|
||||
int numGenerated = in.readInt();
|
||||
while (numGenerated > 0) {
|
||||
numGenerated--;
|
||||
URI generated = URI.createURI(in.readUTF());
|
||||
String outputConfig = in.readUTF();
|
||||
this.addSource2Generated(source, generated, outputConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
Set<Map.Entry<URI, Collection<URI>>> entries = source2generated.asMap().entrySet();
|
||||
out.writeInt(entries.size());
|
||||
for (Map.Entry<URI, Collection<URI>> it : entries) {
|
||||
out.writeUTF(it.getKey().toString());
|
||||
out.writeInt(it.getValue().size());
|
||||
for (URI value : it.getValue()) {
|
||||
out.writeUTF(value.toString());
|
||||
out.writeUTF(generated2OutputConfigName.get(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2015 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.build
|
||||
|
||||
import com.google.common.collect.HashMultimap
|
||||
import com.google.common.collect.Lists
|
||||
import com.google.common.collect.Multimap
|
||||
import java.io.Externalizable
|
||||
import java.io.IOException
|
||||
import java.io.ObjectInput
|
||||
import java.io.ObjectOutput
|
||||
import java.util.HashMap
|
||||
import java.util.HashSet
|
||||
import java.util.List
|
||||
import java.util.Map
|
||||
import java.util.Set
|
||||
import org.eclipse.emf.common.util.URI
|
||||
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor
|
||||
import org.eclipse.xtext.generator.IFileSystemAccess
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
*/
|
||||
@FinalFieldsConstructor class Source2GeneratedMapping implements Externalizable {
|
||||
|
||||
val Multimap<URI, URI> source2generated
|
||||
val Multimap<URI, URI> generated2source
|
||||
val Map<URI,String> generated2OutputConfigName
|
||||
|
||||
new() {
|
||||
this(HashMultimap.create, HashMultimap.create, newHashMap)
|
||||
}
|
||||
|
||||
def copy() {
|
||||
new Source2GeneratedMapping(HashMultimap.create(source2generated), HashMultimap.create(generated2source), new HashMap(generated2OutputConfigName))
|
||||
}
|
||||
|
||||
def void addSource2Generated(URI source, URI generated) {
|
||||
addSource2Generated(source, generated, IFileSystemAccess.DEFAULT_OUTPUT)
|
||||
}
|
||||
|
||||
def void addSource2Generated(URI source, URI generated, String outputCfgName) {
|
||||
source2generated.put(source, generated)
|
||||
generated2source.put(generated, source)
|
||||
generated2OutputConfigName.put(generated, outputCfgName)
|
||||
}
|
||||
|
||||
def void removeSource2Generated(URI source, URI generated) {
|
||||
source2generated.remove(source, generated)
|
||||
generated2source.remove(generated, source)
|
||||
}
|
||||
|
||||
def Set<URI> deleteSource(URI source) {
|
||||
val generated = new HashSet<URI>(source2generated.removeAll(source))
|
||||
generated.forEach[
|
||||
generated2source.remove(it, source)
|
||||
]
|
||||
return generated
|
||||
}
|
||||
|
||||
def void deleteGenerated(URI generated) {
|
||||
generated2source.removeAll(generated).forEach[
|
||||
source2generated.remove(it, generated)
|
||||
]
|
||||
generated2OutputConfigName.remove(generated)
|
||||
}
|
||||
|
||||
def String getOutputConfigName(URI generated) {
|
||||
return generated2OutputConfigName.get(generated)
|
||||
}
|
||||
|
||||
def List<URI> getGenerated(URI source) {
|
||||
return Lists.newArrayList(source2generated.get(source))
|
||||
}
|
||||
|
||||
def List<URI> getSource(URI generated) {
|
||||
return Lists.newArrayList(generated2source.get(generated))
|
||||
}
|
||||
|
||||
def List<URI> getAllGenerated() {
|
||||
return Lists.newArrayList(generated2source.keySet)
|
||||
}
|
||||
|
||||
override readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
|
||||
val numEntries = in.readInt
|
||||
for(i: 0..<numEntries) {
|
||||
val source = URI.createURI(in.readUTF)
|
||||
val numGenerated = in.readInt
|
||||
for(j: 0..<numGenerated) {
|
||||
val generated = URI.createURI(in.readUTF)
|
||||
val outputConfig = in.readUTF
|
||||
addSource2Generated(source, generated, outputConfig)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override writeExternal(ObjectOutput out) throws IOException {
|
||||
val entries = source2generated.asMap.entrySet
|
||||
out.writeInt(entries.size)
|
||||
entries.forEach [
|
||||
out.writeUTF(key.toString)
|
||||
out.writeInt(value.size)
|
||||
value.forEach[
|
||||
out.writeUTF(toString)
|
||||
out.writeUTF(generated2OutputConfigName.get(it)?:IFileSystemAccess.DEFAULT_OUTPUT)
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2015, 2016 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.build;
|
||||
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.emf.ecore.resource.Resource;
|
||||
import org.eclipse.xtend.lib.annotations.Accessors;
|
||||
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor;
|
||||
import org.eclipse.xtext.build.ClusteringStorageAwareResourceLoader;
|
||||
import org.eclipse.xtext.build.IndexState;
|
||||
import org.eclipse.xtext.resource.IResourceServiceProvider;
|
||||
import org.eclipse.xtext.resource.XtextResourceSet;
|
||||
import org.eclipse.xtext.resource.clustering.IResourceClusteringPolicy;
|
||||
import org.eclipse.xtext.util.CancelIndicator;
|
||||
import org.eclipse.xtext.xbase.lib.Functions.Function1;
|
||||
import org.eclipse.xtext.xbase.lib.IterableExtensions;
|
||||
import org.eclipse.xtext.xbase.lib.Pure;
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
* @since 2.9
|
||||
*/
|
||||
@FinalFieldsConstructor
|
||||
@SuppressWarnings("all")
|
||||
public class BuildContext {
|
||||
private final Function1<? super URI, ? extends IResourceServiceProvider> resourceServiceProviderProvider;
|
||||
|
||||
@Accessors
|
||||
private final XtextResourceSet resourceSet;
|
||||
|
||||
@Accessors
|
||||
private final IndexState oldState;
|
||||
|
||||
@Accessors
|
||||
private final IResourceClusteringPolicy clusteringPolicy;
|
||||
|
||||
@Accessors
|
||||
private final CancelIndicator cancelIndicator;
|
||||
|
||||
private ClusteringStorageAwareResourceLoader loader;
|
||||
|
||||
public <T extends Object> Iterable<T> executeClustered(final Iterable<URI> uri, final Function1<? super Resource, ? extends T> operation) {
|
||||
if ((this.loader == null)) {
|
||||
ClusteringStorageAwareResourceLoader _clusteringStorageAwareResourceLoader = new ClusteringStorageAwareResourceLoader(this);
|
||||
this.loader = _clusteringStorageAwareResourceLoader;
|
||||
}
|
||||
final Function1<URI, Boolean> _function = (URI it) -> {
|
||||
return Boolean.valueOf(this.canHandle(it));
|
||||
};
|
||||
return this.loader.<T>executeClustered(IterableExtensions.<URI>filter(uri, _function), operation);
|
||||
}
|
||||
|
||||
protected boolean canHandle(final URI uri) {
|
||||
final IResourceServiceProvider resourceServiceProvider = this.resourceServiceProviderProvider.apply(uri);
|
||||
if ((resourceServiceProvider == null)) {
|
||||
return false;
|
||||
}
|
||||
return resourceServiceProvider.canHandle(uri);
|
||||
}
|
||||
|
||||
public IResourceServiceProvider getResourceServiceProvider(final URI uri) {
|
||||
final IResourceServiceProvider resourceServiceProvider = this.resourceServiceProviderProvider.apply(uri);
|
||||
return resourceServiceProvider;
|
||||
}
|
||||
|
||||
public BuildContext(final Function1<? super URI, ? extends IResourceServiceProvider> resourceServiceProviderProvider, final XtextResourceSet resourceSet, final IndexState oldState, final IResourceClusteringPolicy clusteringPolicy, final CancelIndicator cancelIndicator) {
|
||||
super();
|
||||
this.resourceServiceProviderProvider = resourceServiceProviderProvider;
|
||||
this.resourceSet = resourceSet;
|
||||
this.oldState = oldState;
|
||||
this.clusteringPolicy = clusteringPolicy;
|
||||
this.cancelIndicator = cancelIndicator;
|
||||
}
|
||||
|
||||
@Pure
|
||||
public XtextResourceSet getResourceSet() {
|
||||
return this.resourceSet;
|
||||
}
|
||||
|
||||
@Pure
|
||||
public IndexState getOldState() {
|
||||
return this.oldState;
|
||||
}
|
||||
|
||||
@Pure
|
||||
public IResourceClusteringPolicy getClusteringPolicy() {
|
||||
return this.clusteringPolicy;
|
||||
}
|
||||
|
||||
@Pure
|
||||
public CancelIndicator getCancelIndicator() {
|
||||
return this.cancelIndicator;
|
||||
}
|
||||
}
|
|
@ -1,215 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2015, 2016 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.build;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.xtend.lib.annotations.Accessors;
|
||||
import org.eclipse.xtext.build.IndexState;
|
||||
import org.eclipse.xtext.diagnostics.Severity;
|
||||
import org.eclipse.xtext.resource.IResourceDescription;
|
||||
import org.eclipse.xtext.resource.XtextResourceSet;
|
||||
import org.eclipse.xtext.util.CancelIndicator;
|
||||
import org.eclipse.xtext.util.UriUtil;
|
||||
import org.eclipse.xtext.util.internal.Log;
|
||||
import org.eclipse.xtext.validation.Issue;
|
||||
import org.eclipse.xtext.xbase.lib.CollectionLiterals;
|
||||
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
|
||||
import org.eclipse.xtext.xbase.lib.Procedures.Procedure2;
|
||||
import org.eclipse.xtext.xbase.lib.Pure;
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
* @since 2.9
|
||||
*/
|
||||
@Accessors
|
||||
@SuppressWarnings("all")
|
||||
public class BuildRequest {
|
||||
public interface IPostValidationCallback {
|
||||
/**
|
||||
* @return whether the build can proceed, <code>false</code> if the build should be interrupted
|
||||
*/
|
||||
public abstract boolean afterValidate(final URI validated, final Iterable<Issue> issues);
|
||||
}
|
||||
|
||||
@Log
|
||||
private static class DefaultValidationCallback implements BuildRequest.IPostValidationCallback {
|
||||
@Override
|
||||
public boolean afterValidate(final URI validated, final Iterable<Issue> issues) {
|
||||
boolean errorFree = true;
|
||||
for (final Issue issue : issues) {
|
||||
Severity _severity = issue.getSeverity();
|
||||
if (_severity != null) {
|
||||
switch (_severity) {
|
||||
case ERROR:
|
||||
BuildRequest.DefaultValidationCallback.LOG.error(issue.toString());
|
||||
errorFree = false;
|
||||
break;
|
||||
case WARNING:
|
||||
BuildRequest.DefaultValidationCallback.LOG.warn(issue.toString());
|
||||
break;
|
||||
case INFO:
|
||||
BuildRequest.DefaultValidationCallback.LOG.info(issue.toString());
|
||||
break;
|
||||
case IGNORE:
|
||||
BuildRequest.DefaultValidationCallback.LOG.debug(issue.toString());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return errorFree;
|
||||
}
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(DefaultValidationCallback.class);
|
||||
}
|
||||
|
||||
private URI baseDir;
|
||||
|
||||
public URI getBaseDir() {
|
||||
if ((this.baseDir == null)) {
|
||||
final String userDir = System.getProperty("user.dir");
|
||||
File _file = new File(userDir);
|
||||
this.baseDir = UriUtil.createFolderURI(_file);
|
||||
}
|
||||
return this.baseDir;
|
||||
}
|
||||
|
||||
private List<URI> dirtyFiles = CollectionLiterals.<URI>newArrayList();
|
||||
|
||||
private List<URI> deletedFiles = CollectionLiterals.<URI>newArrayList();
|
||||
|
||||
private List<IResourceDescription.Delta> externalDeltas = CollectionLiterals.<IResourceDescription.Delta>newArrayList();
|
||||
|
||||
/**
|
||||
* call back after validation, return <code>false</code> will stop the build.
|
||||
*/
|
||||
private BuildRequest.IPostValidationCallback afterValidate = new BuildRequest.DefaultValidationCallback();
|
||||
|
||||
private Procedure2<? super URI, ? super URI> afterGenerateFile = ((Procedure2<URI, URI>) (URI $0, URI $1) -> {
|
||||
});
|
||||
|
||||
private Procedure1<? super URI> afterDeleteFile = ((Procedure1<URI>) (URI it) -> {
|
||||
});
|
||||
|
||||
private IndexState state = new IndexState();
|
||||
|
||||
private boolean writeStorageResources = false;
|
||||
|
||||
private boolean indexOnly = false;
|
||||
|
||||
private XtextResourceSet resourceSet;
|
||||
|
||||
private CancelIndicator cancelIndicator = CancelIndicator.NullImpl;
|
||||
|
||||
public void setBaseDir(final URI baseDir) {
|
||||
this.baseDir = baseDir;
|
||||
}
|
||||
|
||||
@Pure
|
||||
public List<URI> getDirtyFiles() {
|
||||
return this.dirtyFiles;
|
||||
}
|
||||
|
||||
public void setDirtyFiles(final List<URI> dirtyFiles) {
|
||||
this.dirtyFiles = dirtyFiles;
|
||||
}
|
||||
|
||||
@Pure
|
||||
public List<URI> getDeletedFiles() {
|
||||
return this.deletedFiles;
|
||||
}
|
||||
|
||||
public void setDeletedFiles(final List<URI> deletedFiles) {
|
||||
this.deletedFiles = deletedFiles;
|
||||
}
|
||||
|
||||
@Pure
|
||||
public List<IResourceDescription.Delta> getExternalDeltas() {
|
||||
return this.externalDeltas;
|
||||
}
|
||||
|
||||
public void setExternalDeltas(final List<IResourceDescription.Delta> externalDeltas) {
|
||||
this.externalDeltas = externalDeltas;
|
||||
}
|
||||
|
||||
@Pure
|
||||
public BuildRequest.IPostValidationCallback getAfterValidate() {
|
||||
return this.afterValidate;
|
||||
}
|
||||
|
||||
public void setAfterValidate(final BuildRequest.IPostValidationCallback afterValidate) {
|
||||
this.afterValidate = afterValidate;
|
||||
}
|
||||
|
||||
@Pure
|
||||
public Procedure2<? super URI, ? super URI> getAfterGenerateFile() {
|
||||
return this.afterGenerateFile;
|
||||
}
|
||||
|
||||
public void setAfterGenerateFile(final Procedure2<? super URI, ? super URI> afterGenerateFile) {
|
||||
this.afterGenerateFile = afterGenerateFile;
|
||||
}
|
||||
|
||||
@Pure
|
||||
public Procedure1<? super URI> getAfterDeleteFile() {
|
||||
return this.afterDeleteFile;
|
||||
}
|
||||
|
||||
public void setAfterDeleteFile(final Procedure1<? super URI> afterDeleteFile) {
|
||||
this.afterDeleteFile = afterDeleteFile;
|
||||
}
|
||||
|
||||
@Pure
|
||||
public IndexState getState() {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
public void setState(final IndexState state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@Pure
|
||||
public boolean isWriteStorageResources() {
|
||||
return this.writeStorageResources;
|
||||
}
|
||||
|
||||
public void setWriteStorageResources(final boolean writeStorageResources) {
|
||||
this.writeStorageResources = writeStorageResources;
|
||||
}
|
||||
|
||||
@Pure
|
||||
public boolean isIndexOnly() {
|
||||
return this.indexOnly;
|
||||
}
|
||||
|
||||
public void setIndexOnly(final boolean indexOnly) {
|
||||
this.indexOnly = indexOnly;
|
||||
}
|
||||
|
||||
@Pure
|
||||
public XtextResourceSet getResourceSet() {
|
||||
return this.resourceSet;
|
||||
}
|
||||
|
||||
public void setResourceSet(final XtextResourceSet resourceSet) {
|
||||
this.resourceSet = resourceSet;
|
||||
}
|
||||
|
||||
@Pure
|
||||
public CancelIndicator getCancelIndicator() {
|
||||
return this.cancelIndicator;
|
||||
}
|
||||
|
||||
public void setCancelIndicator(final CancelIndicator cancelIndicator) {
|
||||
this.cancelIndicator = cancelIndicator;
|
||||
}
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2015 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.build;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.emf.ecore.resource.Resource;
|
||||
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor;
|
||||
import org.eclipse.xtext.build.BuildContext;
|
||||
import org.eclipse.xtext.resource.IResourceServiceProvider;
|
||||
import org.eclipse.xtext.resource.IResourceServiceProviderExtension;
|
||||
import org.eclipse.xtext.resource.persistence.SourceLevelURIsAdapter;
|
||||
import org.eclipse.xtext.resource.persistence.StorageAwareResource;
|
||||
import org.eclipse.xtext.xbase.lib.CollectionLiterals;
|
||||
import org.eclipse.xtext.xbase.lib.Extension;
|
||||
import org.eclipse.xtext.xbase.lib.Functions.Function1;
|
||||
import org.eclipse.xtext.xbase.lib.ListExtensions;
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
*/
|
||||
@FinalFieldsConstructor
|
||||
@SuppressWarnings("all")
|
||||
public class ClusteringStorageAwareResourceLoader {
|
||||
@Extension
|
||||
private final BuildContext context;
|
||||
|
||||
public <T extends Object> Iterable<T> executeClustered(final Iterable<URI> uris, final Function1<? super Resource, ? extends T> operation) {
|
||||
int loadedURIsCount = 0;
|
||||
final HashSet<URI> sourceLevelURIs = CollectionLiterals.<URI>newHashSet();
|
||||
final ArrayList<Resource> resources = CollectionLiterals.<Resource>newArrayList();
|
||||
final ArrayList<T> result = CollectionLiterals.<T>newArrayList();
|
||||
final Iterator<URI> iter = uris.iterator();
|
||||
while (iter.hasNext()) {
|
||||
{
|
||||
final URI uri = iter.next();
|
||||
boolean _continueProcessing = this.context.getClusteringPolicy().continueProcessing(this.context.getResourceSet(), uri, loadedURIsCount);
|
||||
boolean _not = (!_continueProcessing);
|
||||
if (_not) {
|
||||
final Function1<Resource, T> _function = (Resource it) -> {
|
||||
return operation.apply(it);
|
||||
};
|
||||
List<T> _map = ListExtensions.<Resource, T>map(resources, _function);
|
||||
Iterables.<T>addAll(result, _map);
|
||||
this.clearResourceSet();
|
||||
loadedURIsCount = 0;
|
||||
}
|
||||
loadedURIsCount++;
|
||||
boolean _isSource = this.isSource(uri);
|
||||
if (_isSource) {
|
||||
sourceLevelURIs.add(uri);
|
||||
final Resource existingResource = this.context.getResourceSet().getResource(uri, false);
|
||||
if ((existingResource instanceof StorageAwareResource)) {
|
||||
boolean _isLoadedFromStorage = ((StorageAwareResource)existingResource).isLoadedFromStorage();
|
||||
if (_isLoadedFromStorage) {
|
||||
((StorageAwareResource)existingResource).unload();
|
||||
}
|
||||
}
|
||||
SourceLevelURIsAdapter.setSourceLevelUrisWithoutCopy(this.context.getResourceSet(), sourceLevelURIs);
|
||||
}
|
||||
Resource _resource = this.context.getResourceSet().getResource(uri, true);
|
||||
resources.add(_resource);
|
||||
}
|
||||
}
|
||||
final Function1<Resource, T> _function = (Resource it) -> {
|
||||
return operation.apply(it);
|
||||
};
|
||||
List<T> _map = ListExtensions.<Resource, T>map(resources, _function);
|
||||
Iterables.<T>addAll(result, _map);
|
||||
return result;
|
||||
}
|
||||
|
||||
protected boolean isSource(final URI uri) {
|
||||
final IResourceServiceProvider provider = this.context.getResourceServiceProvider(uri);
|
||||
return ((provider instanceof IResourceServiceProviderExtension) &&
|
||||
((IResourceServiceProviderExtension) provider).isSource(uri));
|
||||
}
|
||||
|
||||
protected void clearResourceSet() {
|
||||
final boolean wasDeliver = this.context.getResourceSet().eDeliver();
|
||||
try {
|
||||
this.context.getResourceSet().eSetDeliver(false);
|
||||
this.context.getResourceSet().getResources().clear();
|
||||
} finally {
|
||||
this.context.getResourceSet().eSetDeliver(wasDeliver);
|
||||
}
|
||||
}
|
||||
|
||||
public ClusteringStorageAwareResourceLoader(final BuildContext context) {
|
||||
super();
|
||||
this.context = context;
|
||||
}
|
||||
}
|
|
@ -1,432 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2015, 2017 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.build;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.Singleton;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.emf.ecore.resource.Resource;
|
||||
import org.eclipse.xtend.lib.annotations.AccessorType;
|
||||
import org.eclipse.xtend.lib.annotations.Accessors;
|
||||
import org.eclipse.xtend.lib.annotations.Data;
|
||||
import org.eclipse.xtext.EcoreUtil2;
|
||||
import org.eclipse.xtext.build.BuildContext;
|
||||
import org.eclipse.xtext.build.BuildRequest;
|
||||
import org.eclipse.xtext.build.IndexState;
|
||||
import org.eclipse.xtext.build.Indexer;
|
||||
import org.eclipse.xtext.build.Source2GeneratedMapping;
|
||||
import org.eclipse.xtext.generator.GeneratorContext;
|
||||
import org.eclipse.xtext.generator.GeneratorDelegate;
|
||||
import org.eclipse.xtext.generator.IContextualOutputConfigurationProvider;
|
||||
import org.eclipse.xtext.generator.IContextualOutputConfigurationProvider2;
|
||||
import org.eclipse.xtext.generator.IFilePostProcessor;
|
||||
import org.eclipse.xtext.generator.IShouldGenerate;
|
||||
import org.eclipse.xtext.generator.OutputConfiguration;
|
||||
import org.eclipse.xtext.generator.URIBasedFileSystemAccess;
|
||||
import org.eclipse.xtext.generator.trace.TraceFileNameProvider;
|
||||
import org.eclipse.xtext.generator.trace.TraceRegionSerializer;
|
||||
import org.eclipse.xtext.parser.IEncodingProvider;
|
||||
import org.eclipse.xtext.resource.IResourceDescription;
|
||||
import org.eclipse.xtext.resource.IResourceServiceProvider;
|
||||
import org.eclipse.xtext.resource.XtextResource;
|
||||
import org.eclipse.xtext.resource.XtextResourceSet;
|
||||
import org.eclipse.xtext.resource.clustering.DisabledClusteringPolicy;
|
||||
import org.eclipse.xtext.resource.clustering.IResourceClusteringPolicy;
|
||||
import org.eclipse.xtext.resource.impl.ResourceDescriptionsData;
|
||||
import org.eclipse.xtext.resource.persistence.IResourceStorageFacade;
|
||||
import org.eclipse.xtext.resource.persistence.SerializableResourceDescription;
|
||||
import org.eclipse.xtext.resource.persistence.StorageAwareResource;
|
||||
import org.eclipse.xtext.service.OperationCanceledManager;
|
||||
import org.eclipse.xtext.util.CancelIndicator;
|
||||
import org.eclipse.xtext.validation.CheckMode;
|
||||
import org.eclipse.xtext.validation.IResourceValidator;
|
||||
import org.eclipse.xtext.validation.Issue;
|
||||
import org.eclipse.xtext.workspace.IProjectConfig;
|
||||
import org.eclipse.xtext.workspace.IProjectConfigProvider;
|
||||
import org.eclipse.xtext.workspace.ISourceFolder;
|
||||
import org.eclipse.xtext.xbase.lib.CollectionLiterals;
|
||||
import org.eclipse.xtext.xbase.lib.Exceptions;
|
||||
import org.eclipse.xtext.xbase.lib.Extension;
|
||||
import org.eclipse.xtext.xbase.lib.Functions.Function1;
|
||||
import org.eclipse.xtext.xbase.lib.IterableExtensions;
|
||||
import org.eclipse.xtext.xbase.lib.ObjectExtensions;
|
||||
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
|
||||
import org.eclipse.xtext.xbase.lib.Pure;
|
||||
import org.eclipse.xtext.xbase.lib.util.ToStringBuilder;
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
* @since 2.9
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public class IncrementalBuilder {
|
||||
@Data
|
||||
public static class Result {
|
||||
private final IndexState indexState;
|
||||
|
||||
private final List<IResourceDescription.Delta> affectedResources;
|
||||
|
||||
public Result(final IndexState indexState, final List<IResourceDescription.Delta> affectedResources) {
|
||||
super();
|
||||
this.indexState = indexState;
|
||||
this.affectedResources = affectedResources;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Pure
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((this.indexState== null) ? 0 : this.indexState.hashCode());
|
||||
return prime * result + ((this.affectedResources== null) ? 0 : this.affectedResources.hashCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Pure
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
IncrementalBuilder.Result other = (IncrementalBuilder.Result) obj;
|
||||
if (this.indexState == null) {
|
||||
if (other.indexState != null)
|
||||
return false;
|
||||
} else if (!this.indexState.equals(other.indexState))
|
||||
return false;
|
||||
if (this.affectedResources == null) {
|
||||
if (other.affectedResources != null)
|
||||
return false;
|
||||
} else if (!this.affectedResources.equals(other.affectedResources))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Pure
|
||||
public String toString() {
|
||||
ToStringBuilder b = new ToStringBuilder(this);
|
||||
b.add("indexState", this.indexState);
|
||||
b.add("affectedResources", this.affectedResources);
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
@Pure
|
||||
public IndexState getIndexState() {
|
||||
return this.indexState;
|
||||
}
|
||||
|
||||
@Pure
|
||||
public List<IResourceDescription.Delta> getAffectedResources() {
|
||||
return this.affectedResources;
|
||||
}
|
||||
}
|
||||
|
||||
public static class InternalStatefulIncrementalBuilder {
|
||||
@Singleton
|
||||
public static class URIBasedFileSystemAccessFactory {
|
||||
@Inject
|
||||
private IContextualOutputConfigurationProvider outputConfigurationProvider;
|
||||
|
||||
@Inject
|
||||
private IFilePostProcessor postProcessor;
|
||||
|
||||
@Inject(optional = true)
|
||||
private IEncodingProvider encodingProvider;
|
||||
|
||||
@Inject
|
||||
private TraceFileNameProvider traceFileNameProvider;
|
||||
|
||||
@Inject
|
||||
private TraceRegionSerializer traceRegionSerializer;
|
||||
|
||||
@Inject(optional = true)
|
||||
private IProjectConfigProvider projectConfigProvider;
|
||||
|
||||
public URIBasedFileSystemAccess newFileSystemAccess(final Resource resource, final BuildRequest request) {
|
||||
URIBasedFileSystemAccess _uRIBasedFileSystemAccess = new URIBasedFileSystemAccess();
|
||||
final Procedure1<URIBasedFileSystemAccess> _function = (URIBasedFileSystemAccess it) -> {
|
||||
final Function1<OutputConfiguration, String> _function_1 = (OutputConfiguration it_1) -> {
|
||||
return it_1.getName();
|
||||
};
|
||||
it.setOutputConfigurations(IterableExtensions.<String, OutputConfiguration>toMap(this.outputConfigurationProvider.getOutputConfigurations(resource), _function_1));
|
||||
it.setPostProcessor(this.postProcessor);
|
||||
if ((this.encodingProvider != null)) {
|
||||
it.setEncodingProvider(this.encodingProvider);
|
||||
}
|
||||
it.setTraceFileNameProvider(this.traceFileNameProvider);
|
||||
it.setTraceRegionSerializer(this.traceRegionSerializer);
|
||||
it.setGenerateTraces(true);
|
||||
it.setBaseDir(request.getBaseDir());
|
||||
if ((this.projectConfigProvider != null)) {
|
||||
IProjectConfig _projectConfig = this.projectConfigProvider.getProjectConfig(resource.getResourceSet());
|
||||
ISourceFolder _findSourceFolderContaining = null;
|
||||
if (_projectConfig!=null) {
|
||||
_findSourceFolderContaining=_projectConfig.findSourceFolderContaining(resource.getURI());
|
||||
}
|
||||
final ISourceFolder sourceFolder = _findSourceFolderContaining;
|
||||
String _name = null;
|
||||
if (sourceFolder!=null) {
|
||||
_name=sourceFolder.getName();
|
||||
}
|
||||
it.setCurrentSource(_name);
|
||||
}
|
||||
it.setConverter(resource.getResourceSet().getURIConverter());
|
||||
};
|
||||
return ObjectExtensions.<URIBasedFileSystemAccess>operator_doubleArrow(_uRIBasedFileSystemAccess, _function);
|
||||
}
|
||||
}
|
||||
|
||||
@Accessors({ AccessorType.PROTECTED_SETTER, AccessorType.PROTECTED_GETTER })
|
||||
@Extension
|
||||
private BuildContext context;
|
||||
|
||||
@Accessors({ AccessorType.PROTECTED_SETTER, AccessorType.PROTECTED_GETTER })
|
||||
private BuildRequest request;
|
||||
|
||||
@Inject
|
||||
private Indexer indexer;
|
||||
|
||||
@Inject
|
||||
@Extension
|
||||
private OperationCanceledManager _operationCanceledManager;
|
||||
|
||||
protected void unloadResource(final URI uri) {
|
||||
final Resource resource = this.request.getResourceSet().getResource(uri, false);
|
||||
if ((resource != null)) {
|
||||
this.request.getResourceSet().getResources().remove(resource);
|
||||
resource.unload();
|
||||
}
|
||||
}
|
||||
|
||||
public IncrementalBuilder.Result launch() {
|
||||
final Source2GeneratedMapping newSource2GeneratedMapping = this.request.getState().getFileMappings();
|
||||
final HashSet<URI> unloaded = CollectionLiterals.<URI>newHashSet();
|
||||
List<URI> _deletedFiles = this.request.getDeletedFiles();
|
||||
for (final URI deleted : _deletedFiles) {
|
||||
boolean _add = unloaded.add(deleted);
|
||||
if (_add) {
|
||||
this.unloadResource(deleted);
|
||||
}
|
||||
}
|
||||
List<URI> _dirtyFiles = this.request.getDirtyFiles();
|
||||
for (final URI dirty : _dirtyFiles) {
|
||||
boolean _add_1 = unloaded.add(dirty);
|
||||
if (_add_1) {
|
||||
this.unloadResource(dirty);
|
||||
}
|
||||
}
|
||||
final Consumer<URI> _function = (URI source) -> {
|
||||
this.request.getAfterValidate().afterValidate(source, CollectionLiterals.<Issue>newArrayList());
|
||||
final Consumer<URI> _function_1 = (URI generated) -> {
|
||||
try {
|
||||
final IResourceServiceProvider serviceProvider = this.context.getResourceServiceProvider(source);
|
||||
final Set<OutputConfiguration> configs = serviceProvider.<IContextualOutputConfigurationProvider2>get(IContextualOutputConfigurationProvider2.class).getOutputConfigurations(this.request.getResourceSet());
|
||||
final String configName = newSource2GeneratedMapping.getOutputConfigName(generated);
|
||||
final Function1<OutputConfiguration, Boolean> _function_2 = (OutputConfiguration it) -> {
|
||||
String _name = it.getName();
|
||||
return Boolean.valueOf(Objects.equal(_name, configName));
|
||||
};
|
||||
final OutputConfiguration config = IterableExtensions.<OutputConfiguration>findFirst(configs, _function_2);
|
||||
if (((config != null) && config.isCleanUpDerivedResources())) {
|
||||
this.context.getResourceSet().getURIConverter().delete(generated, CollectionLiterals.<Object, Object>emptyMap());
|
||||
this.request.getAfterDeleteFile().apply(generated);
|
||||
}
|
||||
} catch (Throwable _e) {
|
||||
throw Exceptions.sneakyThrow(_e);
|
||||
}
|
||||
};
|
||||
newSource2GeneratedMapping.deleteSource(source).forEach(_function_1);
|
||||
};
|
||||
this.request.getDeletedFiles().forEach(_function);
|
||||
final Indexer.IndexResult result = this.indexer.computeAndIndexAffected(this.request, this.context);
|
||||
this._operationCanceledManager.checkCanceled(this.request.getCancelIndicator());
|
||||
List<IResourceDescription.Delta> _resourceDeltas = result.getResourceDeltas();
|
||||
for (final IResourceDescription.Delta delta : _resourceDeltas) {
|
||||
if (((delta.getOld() != null) && unloaded.add(delta.getUri()))) {
|
||||
this.unloadResource(delta.getUri());
|
||||
}
|
||||
}
|
||||
final ArrayList<IResourceDescription.Delta> resolvedDeltas = CollectionLiterals.<IResourceDescription.Delta>newArrayList();
|
||||
final Function1<IResourceDescription.Delta, Boolean> _function_1 = (IResourceDescription.Delta it) -> {
|
||||
IResourceDescription _new = it.getNew();
|
||||
return Boolean.valueOf((_new == null));
|
||||
};
|
||||
Iterable<IResourceDescription.Delta> _filter = IterableExtensions.<IResourceDescription.Delta>filter(result.getResourceDeltas(), _function_1);
|
||||
Iterables.<IResourceDescription.Delta>addAll(resolvedDeltas, _filter);
|
||||
final Function1<IResourceDescription.Delta, Boolean> _function_2 = (IResourceDescription.Delta it) -> {
|
||||
IResourceDescription _new = it.getNew();
|
||||
return Boolean.valueOf((_new != null));
|
||||
};
|
||||
final Function1<IResourceDescription.Delta, URI> _function_3 = (IResourceDescription.Delta it) -> {
|
||||
return it.getUri();
|
||||
};
|
||||
final Function1<Resource, IResourceDescription.Delta> _function_4 = (Resource resource) -> {
|
||||
this._operationCanceledManager.checkCanceled(this.request.getCancelIndicator());
|
||||
resource.getContents();
|
||||
EcoreUtil2.resolveLazyCrossReferences(resource, CancelIndicator.NullImpl);
|
||||
this._operationCanceledManager.checkCanceled(this.request.getCancelIndicator());
|
||||
final IResourceServiceProvider serviceProvider = this.getResourceServiceProvider(resource);
|
||||
final IResourceDescription.Manager manager = serviceProvider.getResourceDescriptionManager();
|
||||
final IResourceDescription description = manager.getResourceDescription(resource);
|
||||
final SerializableResourceDescription copiedDescription = SerializableResourceDescription.createCopy(description);
|
||||
result.getNewIndex().addDescription(resource.getURI(), copiedDescription);
|
||||
this._operationCanceledManager.checkCanceled(this.request.getCancelIndicator());
|
||||
if ((((!this.request.isIndexOnly()) && this.validate(resource)) && serviceProvider.<IShouldGenerate>get(IShouldGenerate.class).shouldGenerate(resource, CancelIndicator.NullImpl))) {
|
||||
this._operationCanceledManager.checkCanceled(this.request.getCancelIndicator());
|
||||
this.generate(resource, this.request, newSource2GeneratedMapping);
|
||||
}
|
||||
final IResourceDescription old = this.context.getOldState().getResourceDescriptions().getResourceDescription(resource.getURI());
|
||||
return manager.createDelta(old, copiedDescription);
|
||||
};
|
||||
Iterable<IResourceDescription.Delta> _executeClustered = this.context.<IResourceDescription.Delta>executeClustered(IterableExtensions.<IResourceDescription.Delta, URI>map(IterableExtensions.<IResourceDescription.Delta>filter(result.getResourceDeltas(), _function_2), _function_3), _function_4);
|
||||
Iterables.<IResourceDescription.Delta>addAll(resolvedDeltas, _executeClustered);
|
||||
IndexState _state = this.request.getState();
|
||||
return new IncrementalBuilder.Result(_state, resolvedDeltas);
|
||||
}
|
||||
|
||||
private IResourceServiceProvider getResourceServiceProvider(final Resource resource) {
|
||||
if ((resource instanceof XtextResource)) {
|
||||
return ((XtextResource)resource).getResourceServiceProvider();
|
||||
}
|
||||
return this.context.getResourceServiceProvider(resource.getURI());
|
||||
}
|
||||
|
||||
protected boolean validate(final Resource resource) {
|
||||
final IResourceValidator resourceValidator = this.getResourceServiceProvider(resource).getResourceValidator();
|
||||
if ((resourceValidator == null)) {
|
||||
return true;
|
||||
}
|
||||
final List<Issue> validationResult = resourceValidator.validate(resource, CheckMode.ALL, null);
|
||||
return this.request.getAfterValidate().afterValidate(resource.getURI(), validationResult);
|
||||
}
|
||||
|
||||
protected void generate(final Resource resource, final BuildRequest request, final Source2GeneratedMapping newMappings) {
|
||||
final IResourceServiceProvider serviceProvider = this.getResourceServiceProvider(resource);
|
||||
final GeneratorDelegate generator = serviceProvider.<GeneratorDelegate>get(GeneratorDelegate.class);
|
||||
if ((generator == null)) {
|
||||
return;
|
||||
}
|
||||
final Set<URI> previous = newMappings.deleteSource(resource.getURI());
|
||||
URIBasedFileSystemAccess _createFileSystemAccess = this.createFileSystemAccess(serviceProvider, resource);
|
||||
final Procedure1<URIBasedFileSystemAccess> _function = (URIBasedFileSystemAccess it) -> {
|
||||
final URIBasedFileSystemAccess.BeforeWrite _function_1 = (URI uri, String outputCfgName, InputStream contents) -> {
|
||||
newMappings.addSource2Generated(resource.getURI(), uri, outputCfgName);
|
||||
previous.remove(uri);
|
||||
request.getAfterGenerateFile().apply(resource.getURI(), uri);
|
||||
return contents;
|
||||
};
|
||||
it.setBeforeWrite(_function_1);
|
||||
final URIBasedFileSystemAccess.BeforeDelete _function_2 = (URI uri) -> {
|
||||
newMappings.deleteGenerated(uri);
|
||||
request.getAfterDeleteFile().apply(uri);
|
||||
return true;
|
||||
};
|
||||
it.setBeforeDelete(_function_2);
|
||||
};
|
||||
final URIBasedFileSystemAccess fileSystemAccess = ObjectExtensions.<URIBasedFileSystemAccess>operator_doubleArrow(_createFileSystemAccess, _function);
|
||||
fileSystemAccess.setContext(resource);
|
||||
boolean _isWriteStorageResources = request.isWriteStorageResources();
|
||||
if (_isWriteStorageResources) {
|
||||
boolean _matched = false;
|
||||
if (resource instanceof StorageAwareResource) {
|
||||
IResourceStorageFacade _resourceStorageFacade = ((StorageAwareResource)resource).getResourceStorageFacade();
|
||||
boolean _tripleNotEquals = (_resourceStorageFacade != null);
|
||||
if (_tripleNotEquals) {
|
||||
_matched=true;
|
||||
((StorageAwareResource)resource).getResourceStorageFacade().saveResource(((StorageAwareResource)resource), fileSystemAccess);
|
||||
}
|
||||
}
|
||||
}
|
||||
final GeneratorContext generatorContext = new GeneratorContext();
|
||||
generatorContext.setCancelIndicator(request.getCancelIndicator());
|
||||
generator.generate(resource, fileSystemAccess, generatorContext);
|
||||
final Consumer<URI> _function_1 = (URI it) -> {
|
||||
try {
|
||||
this.context.getResourceSet().getURIConverter().delete(it, CollectionLiterals.<Object, Object>emptyMap());
|
||||
request.getAfterDeleteFile().apply(it);
|
||||
} catch (Throwable _e) {
|
||||
throw Exceptions.sneakyThrow(_e);
|
||||
}
|
||||
};
|
||||
previous.forEach(_function_1);
|
||||
}
|
||||
|
||||
protected URIBasedFileSystemAccess createFileSystemAccess(final IResourceServiceProvider serviceProvider, final Resource resource) {
|
||||
return serviceProvider.<IncrementalBuilder.InternalStatefulIncrementalBuilder.URIBasedFileSystemAccessFactory>get(IncrementalBuilder.InternalStatefulIncrementalBuilder.URIBasedFileSystemAccessFactory.class).newFileSystemAccess(resource, this.request);
|
||||
}
|
||||
|
||||
@Pure
|
||||
protected BuildContext getContext() {
|
||||
return this.context;
|
||||
}
|
||||
|
||||
protected void setContext(final BuildContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Pure
|
||||
protected BuildRequest getRequest() {
|
||||
return this.request;
|
||||
}
|
||||
|
||||
protected void setRequest(final BuildRequest request) {
|
||||
this.request = request;
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
private Provider<IncrementalBuilder.InternalStatefulIncrementalBuilder> provider;
|
||||
|
||||
@Inject
|
||||
@Extension
|
||||
private OperationCanceledManager _operationCanceledManager;
|
||||
|
||||
public IncrementalBuilder.Result build(final BuildRequest request, final Function1<? super URI, ? extends IResourceServiceProvider> languages) {
|
||||
DisabledClusteringPolicy _disabledClusteringPolicy = new DisabledClusteringPolicy();
|
||||
return this.build(request, languages, _disabledClusteringPolicy);
|
||||
}
|
||||
|
||||
public IncrementalBuilder.Result build(final BuildRequest request, final Function1<? super URI, ? extends IResourceServiceProvider> languages, final IResourceClusteringPolicy clusteringPolicy) {
|
||||
try {
|
||||
final XtextResourceSet resourceSet = request.getResourceSet();
|
||||
ResourceDescriptionsData _copy = request.getState().getResourceDescriptions().copy();
|
||||
Source2GeneratedMapping _copy_1 = request.getState().getFileMappings().copy();
|
||||
final IndexState oldState = new IndexState(_copy, _copy_1);
|
||||
CancelIndicator _cancelIndicator = request.getCancelIndicator();
|
||||
final BuildContext context = new BuildContext(languages, resourceSet, oldState, clusteringPolicy, _cancelIndicator);
|
||||
final IncrementalBuilder.InternalStatefulIncrementalBuilder builder = this.provider.get();
|
||||
builder.setContext(context);
|
||||
builder.setRequest(request);
|
||||
try {
|
||||
return builder.launch();
|
||||
} catch (final Throwable _t) {
|
||||
if (_t instanceof Throwable) {
|
||||
final Throwable t = (Throwable)_t;
|
||||
this._operationCanceledManager.propagateIfCancelException(t);
|
||||
throw t;
|
||||
} else {
|
||||
throw Exceptions.sneakyThrow(_t);
|
||||
}
|
||||
}
|
||||
} catch (Throwable _e) {
|
||||
throw Exceptions.sneakyThrow(_e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2015 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.build;
|
||||
|
||||
import org.eclipse.xtend.lib.annotations.Accessors;
|
||||
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor;
|
||||
import org.eclipse.xtext.build.Source2GeneratedMapping;
|
||||
import org.eclipse.xtext.resource.IResourceDescription;
|
||||
import org.eclipse.xtext.resource.impl.ResourceDescriptionsData;
|
||||
import org.eclipse.xtext.xbase.lib.CollectionLiterals;
|
||||
import org.eclipse.xtext.xbase.lib.Pure;
|
||||
|
||||
/**
|
||||
* @author Sven Efftinge - Initial contribution and API
|
||||
*/
|
||||
@FinalFieldsConstructor
|
||||
@Accessors
|
||||
@SuppressWarnings("all")
|
||||
public class IndexState {
|
||||
private final ResourceDescriptionsData resourceDescriptions;
|
||||
|
||||
private final Source2GeneratedMapping fileMappings;
|
||||
|
||||
public IndexState() {
|
||||
this(new ResourceDescriptionsData(CollectionLiterals.<IResourceDescription>emptySet()), new Source2GeneratedMapping());
|
||||
}
|
||||
|
||||
public IndexState(final ResourceDescriptionsData resourceDescriptions, final Source2GeneratedMapping fileMappings) {
|
||||
super();
|
||||
this.resourceDescriptions = resourceDescriptions;
|
||||
this.fileMappings = fileMappings;
|
||||
}
|
||||
|
||||
@Pure
|
||||
public ResourceDescriptionsData getResourceDescriptions() {
|
||||
return this.resourceDescriptions;
|
||||
}
|
||||
|
||||
@Pure
|
||||
public Source2GeneratedMapping getFileMappings() {
|
||||
return this.fileMappings;
|
||||
}
|
||||
}
|
|
@ -1,295 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2015, 2016 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.build;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.inject.Inject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.emf.ecore.InternalEObject;
|
||||
import org.eclipse.emf.ecore.resource.Resource;
|
||||
import org.eclipse.emf.ecore.util.EcoreUtil;
|
||||
import org.eclipse.xtend.lib.annotations.AccessorType;
|
||||
import org.eclipse.xtend.lib.annotations.Accessors;
|
||||
import org.eclipse.xtend.lib.annotations.Data;
|
||||
import org.eclipse.xtend2.lib.StringConcatenation;
|
||||
import org.eclipse.xtext.build.BuildContext;
|
||||
import org.eclipse.xtext.build.BuildRequest;
|
||||
import org.eclipse.xtext.naming.QualifiedName;
|
||||
import org.eclipse.xtext.resource.CompilerPhases;
|
||||
import org.eclipse.xtext.resource.EObjectDescription;
|
||||
import org.eclipse.xtext.resource.IEObjectDescription;
|
||||
import org.eclipse.xtext.resource.IReferenceDescription;
|
||||
import org.eclipse.xtext.resource.IResourceDescription;
|
||||
import org.eclipse.xtext.resource.IResourceDescriptions;
|
||||
import org.eclipse.xtext.resource.IResourceServiceProvider;
|
||||
import org.eclipse.xtext.resource.impl.AbstractResourceDescription;
|
||||
import org.eclipse.xtext.resource.impl.DefaultResourceDescriptionDelta;
|
||||
import org.eclipse.xtext.resource.impl.ResourceDescriptionsData;
|
||||
import org.eclipse.xtext.resource.persistence.SerializableEObjectDescriptionProvider;
|
||||
import org.eclipse.xtext.service.OperationCanceledManager;
|
||||
import org.eclipse.xtext.util.internal.Log;
|
||||
import org.eclipse.xtext.xbase.lib.CollectionLiterals;
|
||||
import org.eclipse.xtext.xbase.lib.Extension;
|
||||
import org.eclipse.xtext.xbase.lib.Functions.Function1;
|
||||
import org.eclipse.xtext.xbase.lib.IterableExtensions;
|
||||
import org.eclipse.xtext.xbase.lib.ListExtensions;
|
||||
import org.eclipse.xtext.xbase.lib.Pure;
|
||||
import org.eclipse.xtext.xbase.lib.util.ToStringBuilder;
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
* @since 2.9
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public class Indexer {
|
||||
@Data
|
||||
public static class IndexResult {
|
||||
private final List<IResourceDescription.Delta> resourceDeltas;
|
||||
|
||||
private final ResourceDescriptionsData newIndex;
|
||||
|
||||
public IndexResult(final List<IResourceDescription.Delta> resourceDeltas, final ResourceDescriptionsData newIndex) {
|
||||
super();
|
||||
this.resourceDeltas = resourceDeltas;
|
||||
this.newIndex = newIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Pure
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((this.resourceDeltas== null) ? 0 : this.resourceDeltas.hashCode());
|
||||
return prime * result + ((this.newIndex== null) ? 0 : this.newIndex.hashCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Pure
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Indexer.IndexResult other = (Indexer.IndexResult) obj;
|
||||
if (this.resourceDeltas == null) {
|
||||
if (other.resourceDeltas != null)
|
||||
return false;
|
||||
} else if (!this.resourceDeltas.equals(other.resourceDeltas))
|
||||
return false;
|
||||
if (this.newIndex == null) {
|
||||
if (other.newIndex != null)
|
||||
return false;
|
||||
} else if (!this.newIndex.equals(other.newIndex))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Pure
|
||||
public String toString() {
|
||||
ToStringBuilder b = new ToStringBuilder(this);
|
||||
b.add("resourceDeltas", this.resourceDeltas);
|
||||
b.add("newIndex", this.newIndex);
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
@Pure
|
||||
public List<IResourceDescription.Delta> getResourceDeltas() {
|
||||
return this.resourceDeltas;
|
||||
}
|
||||
|
||||
@Pure
|
||||
public ResourceDescriptionsData getNewIndex() {
|
||||
return this.newIndex;
|
||||
}
|
||||
}
|
||||
|
||||
@Log
|
||||
protected static class ResolvedResourceDescription extends AbstractResourceDescription {
|
||||
@Accessors(AccessorType.PUBLIC_GETTER)
|
||||
private URI URI;
|
||||
|
||||
private ImmutableList<IEObjectDescription> exported;
|
||||
|
||||
public ResolvedResourceDescription(final IResourceDescription original) {
|
||||
this.URI = original.getURI();
|
||||
final Function1<IEObjectDescription, IEObjectDescription> _function = (IEObjectDescription from) -> {
|
||||
if ((from instanceof SerializableEObjectDescriptionProvider)) {
|
||||
return ((SerializableEObjectDescriptionProvider)from).toSerializableEObjectDescription();
|
||||
}
|
||||
boolean _eIsProxy = from.getEObjectOrProxy().eIsProxy();
|
||||
if (_eIsProxy) {
|
||||
return from;
|
||||
}
|
||||
EObject _create = EcoreUtil.create(from.getEClass());
|
||||
InternalEObject result = ((InternalEObject) _create);
|
||||
result.eSetProxyURI(from.getEObjectURI());
|
||||
Map<String, String> userData = null;
|
||||
String[] _userDataKeys = from.getUserDataKeys();
|
||||
for (final String key : _userDataKeys) {
|
||||
{
|
||||
if ((userData == null)) {
|
||||
userData = Maps.<String, String>newHashMapWithExpectedSize(2);
|
||||
}
|
||||
userData.put(key, from.getUserData(key));
|
||||
}
|
||||
}
|
||||
return EObjectDescription.create(from.getName(), result, userData);
|
||||
};
|
||||
this.exported = ImmutableList.<IEObjectDescription>copyOf(
|
||||
IterableExtensions.<IEObjectDescription, IEObjectDescription>map(original.getExportedObjects(), _function));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<IEObjectDescription> computeExportedObjects() {
|
||||
return this.exported;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<QualifiedName> getImportedNames() {
|
||||
StringConcatenation _builder = new StringConcatenation();
|
||||
_builder.append("getImportedNames ");
|
||||
_builder.append(this.URI);
|
||||
IllegalStateException exception = new IllegalStateException(_builder.toString());
|
||||
Indexer.ResolvedResourceDescription.LOG.error(exception, exception);
|
||||
return CollectionLiterals.<QualifiedName>emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<IReferenceDescription> getReferenceDescriptions() {
|
||||
StringConcatenation _builder = new StringConcatenation();
|
||||
_builder.append("getReferenceDescriptions ");
|
||||
_builder.append(this.URI);
|
||||
IllegalStateException exception = new IllegalStateException(_builder.toString());
|
||||
Indexer.ResolvedResourceDescription.LOG.error(exception, exception);
|
||||
return CollectionLiterals.<IReferenceDescription>emptyList();
|
||||
}
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(ResolvedResourceDescription.class);
|
||||
|
||||
@Pure
|
||||
public URI getURI() {
|
||||
return this.URI;
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
private CompilerPhases compilerPhases;
|
||||
|
||||
@Inject
|
||||
@Extension
|
||||
private OperationCanceledManager _operationCanceledManager;
|
||||
|
||||
public Indexer.IndexResult computeAndIndexAffected(final BuildRequest request, @Extension final BuildContext context) {
|
||||
final ResourceDescriptionsData previousIndex = context.getOldState().getResourceDescriptions();
|
||||
final ResourceDescriptionsData newIndex = request.getState().getResourceDescriptions();
|
||||
final List<IResourceDescription.Delta> deltas = CollectionLiterals.<IResourceDescription.Delta>newArrayList();
|
||||
deltas.addAll(this.getDeltasForDeletedResources(request, previousIndex, context));
|
||||
deltas.addAll(this.getDeltasForChangedResources(request.getDirtyFiles(), previousIndex, context));
|
||||
for (final IResourceDescription.Delta delta : deltas) {
|
||||
newIndex.register(delta);
|
||||
}
|
||||
final HashSet<IResourceDescription.Delta> allDeltas = new HashSet<IResourceDescription.Delta>(deltas);
|
||||
boolean _isEmpty = request.getExternalDeltas().isEmpty();
|
||||
boolean _not = (!_isEmpty);
|
||||
if (_not) {
|
||||
allDeltas.addAll(request.getExternalDeltas());
|
||||
}
|
||||
final Function1<IResourceDescription, URI> _function = (IResourceDescription it) -> {
|
||||
return it.getURI();
|
||||
};
|
||||
final Set<URI> remainingURIs = IterableExtensions.<URI>toSet(IterableExtensions.<IResourceDescription, URI>map(previousIndex.getAllResourceDescriptions(), _function));
|
||||
final Function1<IResourceDescription.Delta, URI> _function_1 = (IResourceDescription.Delta it) -> {
|
||||
return it.getUri();
|
||||
};
|
||||
remainingURIs.removeAll(ListExtensions.<IResourceDescription.Delta, URI>map(deltas, _function_1));
|
||||
final Function1<URI, Boolean> _function_2 = (URI it) -> {
|
||||
final IResourceDescription.Manager manager = context.getResourceServiceProvider(it).getResourceDescriptionManager();
|
||||
final IResourceDescription resourceDescription = previousIndex.getResourceDescription(it);
|
||||
final boolean isAffected = this.isAffected(resourceDescription, manager, allDeltas, allDeltas, newIndex);
|
||||
return Boolean.valueOf(isAffected);
|
||||
};
|
||||
final List<URI> allAffected = IterableExtensions.<URI>toList(IterableExtensions.<URI>filter(remainingURIs, _function_2));
|
||||
deltas.addAll(this.getDeltasForChangedResources(allAffected, previousIndex, context));
|
||||
return new Indexer.IndexResult(deltas, newIndex);
|
||||
}
|
||||
|
||||
protected List<IResourceDescription.Delta> getDeltasForDeletedResources(final BuildRequest request, final ResourceDescriptionsData oldIndex, @Extension final BuildContext context) {
|
||||
final ArrayList<IResourceDescription.Delta> deltas = CollectionLiterals.<IResourceDescription.Delta>newArrayList();
|
||||
final Function1<URI, Boolean> _function = (URI it) -> {
|
||||
IResourceServiceProvider _resourceServiceProvider = context.getResourceServiceProvider(it);
|
||||
return Boolean.valueOf((_resourceServiceProvider != null));
|
||||
};
|
||||
final Consumer<URI> _function_1 = (URI it) -> {
|
||||
this._operationCanceledManager.checkCanceled(context.getCancelIndicator());
|
||||
IResourceDescription _resourceDescription = null;
|
||||
if (oldIndex!=null) {
|
||||
_resourceDescription=oldIndex.getResourceDescription(it);
|
||||
}
|
||||
final IResourceDescription oldDescription = _resourceDescription;
|
||||
if ((oldDescription != null)) {
|
||||
final DefaultResourceDescriptionDelta delta = new DefaultResourceDescriptionDelta(oldDescription, null);
|
||||
deltas.add(delta);
|
||||
}
|
||||
};
|
||||
IterableExtensions.<URI>filter(request.getDeletedFiles(), _function).forEach(_function_1);
|
||||
return deltas;
|
||||
}
|
||||
|
||||
protected List<IResourceDescription.Delta> getDeltasForChangedResources(final Iterable<URI> affectedUris, final ResourceDescriptionsData oldIndex, @Extension final BuildContext context) {
|
||||
try {
|
||||
this.compilerPhases.setIndexing(context.getResourceSet(), true);
|
||||
final Function1<Resource, IResourceDescription.Delta> _function = (Resource it) -> {
|
||||
return this.addToIndex(it, true, oldIndex, context);
|
||||
};
|
||||
return IterableExtensions.<IResourceDescription.Delta>toList(context.<IResourceDescription.Delta>executeClustered(affectedUris, _function));
|
||||
} finally {
|
||||
this.compilerPhases.setIndexing(context.getResourceSet(), false);
|
||||
}
|
||||
}
|
||||
|
||||
protected IResourceDescription.Delta addToIndex(final Resource resource, final boolean isPreIndexing, final ResourceDescriptionsData oldIndex, final BuildContext context) {
|
||||
this._operationCanceledManager.checkCanceled(context.getCancelIndicator());
|
||||
final URI uri = resource.getURI();
|
||||
final IResourceServiceProvider serviceProvider = context.getResourceServiceProvider(uri);
|
||||
final IResourceDescription.Manager manager = serviceProvider.getResourceDescriptionManager();
|
||||
final IResourceDescription newDescription = manager.getResourceDescription(resource);
|
||||
final IResourceDescription toBeAdded = new Indexer.ResolvedResourceDescription(newDescription);
|
||||
IResourceDescription _resourceDescription = null;
|
||||
if (oldIndex!=null) {
|
||||
_resourceDescription=oldIndex.getResourceDescription(uri);
|
||||
}
|
||||
final IResourceDescription.Delta delta = manager.createDelta(_resourceDescription, toBeAdded);
|
||||
return delta;
|
||||
}
|
||||
|
||||
protected boolean isAffected(final IResourceDescription affectionCandidate, final IResourceDescription.Manager manager, final Collection<IResourceDescription.Delta> newDeltas, final Collection<IResourceDescription.Delta> allDeltas, final IResourceDescriptions resourceDescriptions) {
|
||||
if ((manager instanceof IResourceDescription.Manager.AllChangeAware)) {
|
||||
return ((IResourceDescription.Manager.AllChangeAware)manager).isAffectedByAny(allDeltas, affectionCandidate, resourceDescriptions);
|
||||
} else {
|
||||
boolean _isEmpty = newDeltas.isEmpty();
|
||||
if (_isEmpty) {
|
||||
return false;
|
||||
} else {
|
||||
return manager.isAffected(newDeltas, affectionCandidate, resourceDescriptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,160 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2015 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.build;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Multimap;
|
||||
import java.io.Externalizable;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor;
|
||||
import org.eclipse.xtext.generator.IFileSystemAccess;
|
||||
import org.eclipse.xtext.xbase.lib.CollectionLiterals;
|
||||
import org.eclipse.xtext.xbase.lib.Exceptions;
|
||||
import org.eclipse.xtext.xbase.lib.ExclusiveRange;
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
*/
|
||||
@FinalFieldsConstructor
|
||||
@SuppressWarnings("all")
|
||||
public class Source2GeneratedMapping implements Externalizable {
|
||||
private final Multimap<URI, URI> source2generated;
|
||||
|
||||
private final Multimap<URI, URI> generated2source;
|
||||
|
||||
private final Map<URI, String> generated2OutputConfigName;
|
||||
|
||||
public Source2GeneratedMapping() {
|
||||
this(HashMultimap.<URI, URI>create(), HashMultimap.<URI, URI>create(), CollectionLiterals.<URI, String>newHashMap());
|
||||
}
|
||||
|
||||
public Source2GeneratedMapping copy() {
|
||||
HashMultimap<URI, URI> _create = HashMultimap.<URI, URI>create(this.source2generated);
|
||||
HashMultimap<URI, URI> _create_1 = HashMultimap.<URI, URI>create(this.generated2source);
|
||||
HashMap<URI, String> _hashMap = new HashMap<URI, String>(this.generated2OutputConfigName);
|
||||
return new Source2GeneratedMapping(_create, _create_1, _hashMap);
|
||||
}
|
||||
|
||||
public void addSource2Generated(final URI source, final URI generated) {
|
||||
this.addSource2Generated(source, generated, IFileSystemAccess.DEFAULT_OUTPUT);
|
||||
}
|
||||
|
||||
public void addSource2Generated(final URI source, final URI generated, final String outputCfgName) {
|
||||
this.source2generated.put(source, generated);
|
||||
this.generated2source.put(generated, source);
|
||||
this.generated2OutputConfigName.put(generated, outputCfgName);
|
||||
}
|
||||
|
||||
public void removeSource2Generated(final URI source, final URI generated) {
|
||||
this.source2generated.remove(source, generated);
|
||||
this.generated2source.remove(generated, source);
|
||||
}
|
||||
|
||||
public Set<URI> deleteSource(final URI source) {
|
||||
Collection<URI> _removeAll = this.source2generated.removeAll(source);
|
||||
final HashSet<URI> generated = new HashSet<URI>(_removeAll);
|
||||
final Consumer<URI> _function = (URI it) -> {
|
||||
this.generated2source.remove(it, source);
|
||||
};
|
||||
generated.forEach(_function);
|
||||
return generated;
|
||||
}
|
||||
|
||||
public void deleteGenerated(final URI generated) {
|
||||
final Consumer<URI> _function = (URI it) -> {
|
||||
this.source2generated.remove(it, generated);
|
||||
};
|
||||
this.generated2source.removeAll(generated).forEach(_function);
|
||||
this.generated2OutputConfigName.remove(generated);
|
||||
}
|
||||
|
||||
public String getOutputConfigName(final URI generated) {
|
||||
return this.generated2OutputConfigName.get(generated);
|
||||
}
|
||||
|
||||
public List<URI> getGenerated(final URI source) {
|
||||
return Lists.<URI>newArrayList(this.source2generated.get(source));
|
||||
}
|
||||
|
||||
public List<URI> getSource(final URI generated) {
|
||||
return Lists.<URI>newArrayList(this.generated2source.get(generated));
|
||||
}
|
||||
|
||||
public List<URI> getAllGenerated() {
|
||||
return Lists.<URI>newArrayList(this.generated2source.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
|
||||
final int numEntries = in.readInt();
|
||||
ExclusiveRange _doubleDotLessThan = new ExclusiveRange(0, numEntries, true);
|
||||
for (final Integer i : _doubleDotLessThan) {
|
||||
{
|
||||
final URI source = URI.createURI(in.readUTF());
|
||||
final int numGenerated = in.readInt();
|
||||
ExclusiveRange _doubleDotLessThan_1 = new ExclusiveRange(0, numGenerated, true);
|
||||
for (final Integer j : _doubleDotLessThan_1) {
|
||||
{
|
||||
final URI generated = URI.createURI(in.readUTF());
|
||||
final String outputConfig = in.readUTF();
|
||||
this.addSource2Generated(source, generated, outputConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeExternal(final ObjectOutput out) throws IOException {
|
||||
final Set<Map.Entry<URI, Collection<URI>>> entries = this.source2generated.asMap().entrySet();
|
||||
out.writeInt(entries.size());
|
||||
final Consumer<Map.Entry<URI, Collection<URI>>> _function = (Map.Entry<URI, Collection<URI>> it) -> {
|
||||
try {
|
||||
out.writeUTF(it.getKey().toString());
|
||||
out.writeInt(it.getValue().size());
|
||||
final Consumer<URI> _function_1 = (URI it_1) -> {
|
||||
try {
|
||||
out.writeUTF(it_1.toString());
|
||||
String _elvis = null;
|
||||
String _get = this.generated2OutputConfigName.get(it_1);
|
||||
if (_get != null) {
|
||||
_elvis = _get;
|
||||
} else {
|
||||
_elvis = IFileSystemAccess.DEFAULT_OUTPUT;
|
||||
}
|
||||
out.writeUTF(_elvis);
|
||||
} catch (Throwable _e) {
|
||||
throw Exceptions.sneakyThrow(_e);
|
||||
}
|
||||
};
|
||||
it.getValue().forEach(_function_1);
|
||||
} catch (Throwable _e) {
|
||||
throw Exceptions.sneakyThrow(_e);
|
||||
}
|
||||
};
|
||||
entries.forEach(_function);
|
||||
}
|
||||
|
||||
public Source2GeneratedMapping(final Multimap<URI, URI> source2generated, final Multimap<URI, URI> generated2source, final Map<URI, String> generated2OutputConfigName) {
|
||||
super();
|
||||
this.source2generated = source2generated;
|
||||
this.generated2source = generated2source;
|
||||
this.generated2OutputConfigName = generated2OutputConfigName;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue