blob: 244787fb783fede3c3b95d684f906bde14c22e87 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2016 xored software, Inc. and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* xored software, Inc. - initial API and Implementation (Alex Panchenko)
*******************************************************************************/
package org.eclipse.dltk.launching.sourcelookup;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.IExternalSourceModule;
import org.eclipse.dltk.core.IModelElement;
import org.eclipse.dltk.core.IModelElementVisitor;
import org.eclipse.dltk.core.IProjectFragment;
import org.eclipse.dltk.core.IScriptProject;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.core.ModelException;
import org.eclipse.dltk.core.environment.EnvironmentManager;
import org.eclipse.dltk.core.environment.EnvironmentPathUtils;
import org.eclipse.dltk.core.environment.IEnvironment;
import org.eclipse.dltk.core.environment.IFileHandle;
import org.eclipse.dltk.internal.launching.DLTKLaunchingPlugin;
import org.eclipse.dltk.internal.launching.IPathEquality;
import org.eclipse.dltk.internal.launching.PathEqualityUtils;
/**
* @since 2.0
*/
public class ProjectSourceLookup {
private final IProject project;
public ProjectSourceLookup(IProject project) {
this.project = project;
}
private static final class ExternalSourceModuleFinder
implements IModelElementVisitor {
private final IPath fileFullPath;
private ExternalSourceModuleFinder(IPath fileFullPath) {
this.fileFullPath = fileFullPath;
}
private final IPathEquality pathEquality = PathEqualityUtils
.getInstance();
private final ISourceModule[] result = new ISourceModule[1];
@Override
public boolean visit(IModelElement element) {
if (element.getElementType() == IModelElement.PROJECT_FRAGMENT) {
IProjectFragment fragment = (IProjectFragment) element;
if (!fragment.isExternal()) {
return false;
}
}
if (element.getElementType() == IModelElement.SOURCE_MODULE) {
ISourceModule module = (ISourceModule) element;
IPath modulePath = module.getPath();
if (module instanceof IExternalSourceModule) {
IEnvironment environment = EnvironmentManager
.getEnvironment(element);
IExternalSourceModule mdl = (IExternalSourceModule) module;
modulePath = mdl.getFullPath();
if (!EnvironmentPathUtils.isFull(modulePath))
modulePath = EnvironmentPathUtils
.getFullPath(environment, modulePath);
}
if (pathEquality.equals(fileFullPath, modulePath)) {
result[0] = module;
}
return false;
}
return true;
}
public boolean isFound() {
return result[0] != null;
}
public ISourceModule[] getResult() {
return result;
}
}
private static final class LocalSourceModuleFinder
implements IModelElementVisitor {
private final IPath fileFullPath;
private LocalSourceModuleFinder(IPath fileFullPath) {
this.fileFullPath = fileFullPath;
}
private final IPathEquality pathEquality = PathEqualityUtils
.getInstance();
private final IFile[] result = new IFile[1];
@Override
public boolean visit(IModelElement element) {
if (element.getElementType() == IModelElement.PROJECT_FRAGMENT) {
IProjectFragment fragment = (IProjectFragment) element;
if (fragment.isExternal()) {
return false;
}
}
if (element.getElementType() == IModelElement.SOURCE_MODULE) {
ISourceModule module = (ISourceModule) element;
IEnvironment environment = EnvironmentManager
.getEnvironment(element.getScriptProject());
final IResource resource = module.getResource();
if (resource != null) {
final IFileHandle file = environment
.getFile(resource.getLocationURI());
if (pathEquality.equals(fileFullPath, file.getPath())) {
result[0] = (IFile) resource;
}
}
return false;
}
return true;
}
public boolean isFound() {
return result[0] != null;
}
public IFile[] getResult() {
return result;
}
}
private static final class WorkspaceLookupResult
implements IProjectLookupResult {
private final IFile[] files;
public WorkspaceLookupResult(IFile[] files) {
this.files = files;
}
@Override
public Object[] toArray() {
return files;
}
@Override
public int size() {
return files.length;
}
}
private static final class SourceModuleLookupResult
implements IProjectLookupResult {
private final ISourceModule[] modules;
public SourceModuleLookupResult(ISourceModule[] modules) {
this.modules = modules;
}
@Override
public Object[] toArray() {
return modules;
}
@Override
public int size() {
return modules.length;
}
}
private IEnvironment environment = null;
private IEnvironment getEnvironment() {
if (environment == null) {
environment = EnvironmentManager.getEnvironment(project);
}
return environment;
}
private IScriptProject scriptProject = null;
public IScriptProject getScriptProject() {
if (scriptProject == null) {
scriptProject = DLTKCore.create(project);
}
return scriptProject;
}
/**
* Finds project elements matching to the specified environment-local path.
* Returns the {@link IProjectLookupResult} or <code>null</code> if nothing
* found.
*
* @param path
* @return
*/
public IProjectLookupResult find(IPath path) {
final IFileHandle file = getEnvironment().getFile(path);
if (file.exists()) {
// check if file is available in workspace
final IFile[] workspaceFiles = getWorkspaceRoot()
.findFilesForLocationURI(file.toURI());
if (workspaceFiles.length != 0 && workspaceFiles[0].exists()) {
return new WorkspaceLookupResult(workspaceFiles);
}
try {
// Try to open external source module.
final ExternalSourceModuleFinder finder = new ExternalSourceModuleFinder(
file.getFullPath());
getScriptProject().accept(finder);
if (finder.isFound()) {
return new SourceModuleLookupResult(finder.getResult());
}
// Last attempt - iterate over workspace files
// TODO make it configurable
final LocalSourceModuleFinder finder2 = new LocalSourceModuleFinder(
file.getPath());
getScriptProject().accept(finder2);
if (finder2.isFound()) {
return new WorkspaceLookupResult(finder2.getResult());
}
} catch (ModelException e) {
DLTKLaunchingPlugin.log(e);
}
}
return null;
}
private static IWorkspaceRoot getWorkspaceRoot() {
return ResourcesPlugin.getWorkspace().getRoot();
}
}