[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:
Sebastian Zarnekow 2019-10-31 16:06:12 +01:00 committed by GitHub
parent 33a64fb2ee
commit eea345fba1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
51 changed files with 3646 additions and 6063 deletions

View file

@ -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;
}
}

View file

@ -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)
}
}

View file

@ -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()
]
}
}

View file

@ -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;
}
}
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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

View file

@ -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
}
}

View file

@ -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);
}
}
}

View file

@ -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)
}
}
}

View file

@ -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;
}
}

View file

@ -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
]
])
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}

View file

@ -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)
}
}

View file

@ -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);
}
});
}
}

View file

@ -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)
]
}
}

View file

@ -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);
}

View file

@ -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.
*

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}

View file

@ -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;
}
}

View file

@ -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
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}

View file

@ -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
}
}

View 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;
}
}

View file

@ -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;
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}
}

View file

@ -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
}
}
}

View file

@ -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;
}
}

View file

@ -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)
}
}

View 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);
}
}
}
}

View file

@ -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
}
}
}

View file

@ -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));
}
}
}
}

View file

@ -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)
]
]
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}
}
}

View file

@ -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;
}
}