Skip to content

Commit

Permalink
Adding support for opening clj files for the project, and in the arch…
Browse files Browse the repository at this point in the history
…ives or their sources if available
  • Loading branch information
laurentpetit committed Oct 22, 2009
1 parent c13c965 commit 9ac3ad7
Show file tree
Hide file tree
Showing 5 changed files with 314 additions and 10 deletions.
10 changes: 9 additions & 1 deletion plugin.xml
Expand Up @@ -61,7 +61,7 @@
modes="run, debug"
name="Clojure"
public="true"
sourceLocatorId="org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector"
sourceLocatorId="ccw.sourceLocator"
sourcePathComputerId="ccw.sourcePathComputer">
<fileExtension extension="clj" default="true"/>
</launchConfigurationType>
Expand Down Expand Up @@ -555,4 +555,12 @@
id="ccw.sourcePathComputer">
</sourcePathComputer>
</extension>
<extension
point="org.eclipse.debug.core.sourceLocators">
<sourceLocator
class="ccw.launching.ClojureSourceLookupDirector"
id="ccw.sourceLocator"
name="Clojure code source lookup director">
</sourceLocator>
</extension>
</plugin>
53 changes: 53 additions & 0 deletions src/ccw/launching/ClojureSourceContainer.java
@@ -0,0 +1,53 @@
package ccw.launching;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.sourcelookup.ISourceContainer;
import org.eclipse.debug.core.sourcelookup.ISourceContainerType;
import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector;

/**
* does not dispose delegatee resources
* @author lpetit
*
*/
public class ClojureSourceContainer implements
ISourceContainer {

private final ISourceContainer delegatee;

public ClojureSourceContainer(ISourceContainer delegatee) {
this.delegatee = delegatee;
}

public void dispose() {
// Nothing yet
}

public Object[] findSourceElements(String name) throws CoreException {
return delegatee.findSourceElements(name);
}

public String getName() {
return "Clojure decorator source container on top of " + delegatee.getName();
}

public ISourceContainer[] getSourceContainers() throws CoreException {
return delegatee.getSourceContainers();
}

public ISourceContainerType getType() {
return delegatee.getType();
}

public void init(ISourceLookupDirector director) {
delegatee.init(director);
}

public boolean isComposite() {
return delegatee.isComposite();
}

public Object getAdapter(Class adapter) {
return delegatee.getAdapter(adapter);
}
}
44 changes: 44 additions & 0 deletions src/ccw/launching/ClojureSourceLookupDirector.java
@@ -0,0 +1,44 @@
package ccw.launching;

import java.util.HashSet;
import java.util.Set;

import org.eclipse.debug.core.model.IPersistableSourceLocator;
import org.eclipse.debug.core.sourcelookup.AbstractSourceLookupDirector;
import org.eclipse.debug.core.sourcelookup.ISourceContainerType;
import org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant;
import org.eclipse.debug.core.sourcelookup.containers.ProjectSourceContainer;
import org.eclipse.debug.core.sourcelookup.containers.WorkspaceSourceContainer;
import org.eclipse.jdt.launching.sourcelookup.containers.JavaSourceLookupParticipant;

/**
* Source locator that not only locates java sources (via composition with JavaSourceLookupDirector)
* @author lpetit
*
*/
/*
* TODO We could do better than just have copied the code from JavaSourceLookupDirector
* and rather have included a JavaSourceLookupDirector instance as a participant ?
*/
public class ClojureSourceLookupDirector extends AbstractSourceLookupDirector
implements IPersistableSourceLocator {

private static Set fFilteredTypes;

static {
fFilteredTypes = new HashSet();
fFilteredTypes.add(ProjectSourceContainer.TYPE_ID);
fFilteredTypes.add(WorkspaceSourceContainer.TYPE_ID);
// can't reference UI constant
fFilteredTypes.add("org.eclipse.debug.ui.containerType.workingSet"); //$NON-NLS-1$
}

public void initializeParticipants() {
addParticipants(new ISourceLookupParticipant[] {new ClojureSourceLookupParticipant(), new JavaSourceLookupParticipant()});
}

public boolean supportsSourceContainerType(ISourceContainerType type) {
return !fFilteredTypes.contains(type.getId());
}

}
148 changes: 148 additions & 0 deletions src/ccw/launching/ClojureSourceLookupParticipant.java
@@ -0,0 +1,148 @@
package ccw.launching;

import java.util.HashMap;
import java.util.Map;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.debug.core.sourcelookup.AbstractSourceLookupParticipant;
import org.eclipse.debug.core.sourcelookup.ISourceContainer;
import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector;
import org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant;
import org.eclipse.debug.core.sourcelookup.containers.ArchiveSourceContainer;
import org.eclipse.debug.core.sourcelookup.containers.ExternalArchiveSourceContainer;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.launching.sourcelookup.containers.JavaSourceLookupParticipant;

/**
* Clojure code source lookup participant.
*
* Some JDT utility classes are not accessible.
* So this class presumes that it is used with a sibling
* JavaSourceLookupParticipant in a same SourceLookupDirector
*
* @note some code borrowed from the JDT
* @author lpetit
*
*/
public class ClojureSourceLookupParticipant extends
AbstractSourceLookupParticipant implements ISourceLookupParticipant {

/**
* Cache of sibling java lookup participant with performance considerations in mind.
* This object is necessary so that we can access certain hidden utility methods indirectly
* (e.g. have cachedSiblingJavaParticipant.getSourceName() do the job for us)
* */
JavaSourceLookupParticipant cachedSiblingJavaParticipant;

/**
* Map of delegate source containers.
* Everything possible is converted to plain FolderSourceContainer or ArchiveSourceContainer
* if possible.
* @note borrowed from the JDT (JavaSourceLookupParticipant)
*/
private Map<ISourceContainer, ISourceContainer> delegateContainers;


public String getSourceName(Object object) throws CoreException {
JavaSourceLookupParticipant javaParticipant = findSiblingJavaParticipant();
if (javaParticipant == null) {
return null;
} else {
return javaParticipant.getSourceName(object);
}
}

private JavaSourceLookupParticipant findSiblingJavaParticipant() throws CoreException {
if (cachedSiblingJavaParticipant == null) {
for (ISourceLookupParticipant p: getDirector().getParticipants()) {
if (p instanceof JavaSourceLookupParticipant) {
this.cachedSiblingJavaParticipant = (JavaSourceLookupParticipant) p;
break;
}
}
}
return cachedSiblingJavaParticipant;
}

public void init(ISourceLookupDirector director) {
super.init(director);
delegateContainers = new HashMap<ISourceContainer, ISourceContainer>();
}

protected ISourceContainer getDelegateContainer(ISourceContainer container) {
ISourceContainer delegate = delegateContainers.get(container);
if (delegate == null) {
return container;
}
return delegate;
}


public void sourceContainersChanged(ISourceLookupDirector director) {
disposeAndClearDelegateContainers(delegateContainers);

for (ISourceContainer container: director.getSourceContainers()) {
delegateContainers.put(container, new ClojureSourceContainer(container));
// // TODO creer que des ArchiveSourceContainer pour que ca trouve les fichiers clojure
// // en cherchant qd mm a utiliser les archives de sources en priorite
// if (container.getType().getId().equals(ArchiveSourceContainer.TYPE_ID)) {
// IFile file = ((ArchiveSourceContainer)container).getFile();
// IProject project = file.getProject();
// IJavaProject javaProject = JavaCore.create(project);
// if (javaProject.exists()) {
// try {
// IPackageFragmentRoot[] roots = javaProject.getPackageFragmentRoots();
// for (int j = 0; j < roots.length; j++) {
// IPackageFragmentRoot root = roots[j];
// if (file.equals(root.getUnderlyingResource())) {
// IPath sourcePath = root.getSourceAttachmentPath();
// if (sourcePath != null) {
// delegateContainers.put(container, new ExternalArchiveSourceContainer(
// sourcePath.toOSString(), true));
//// } else {
//// delegateContainers.put(container, new ArchiveSourceContainer(file, true));
// }
// } else {
// IPath path = root.getSourceAttachmentPath();
// if (path != null) {
// if (file.getFullPath().equals(path)) {
// delegateContainers.put(container, new ExternalArchiveSourceContainer(
// path.toOSString(), true));
//// } else {
//// delegateContainers.put(container, new ArchiveSourceContainer(file, true));
// }
// }
// }
// }
// } catch (JavaModelException e) {
// }
// }
// }
}
}

@Override
public void dispose() {
this.cachedSiblingJavaParticipant = null;

disposeAndClearDelegateContainers(delegateContainers);
delegateContainers = null;

super.dispose();
}

private void disposeAndClearDelegateContainers(Map<ISourceContainer, ISourceContainer> delegateContainers) {
if (delegateContainers != null) {
for (ISourceContainer sc: delegateContainers.values()) {
sc.dispose();
}
}
delegateContainers.clear();
}
}
69 changes: 60 additions & 9 deletions src/ccw/launching/SourcePathComputerDelegate.java
@@ -1,14 +1,23 @@
package ccw.launching;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.sourcelookup.ISourceContainer;
import org.eclipse.debug.core.sourcelookup.containers.DirectorySourceContainer;
import org.eclipse.debug.core.sourcelookup.containers.ExternalArchiveSourceContainer;
import org.eclipse.debug.core.sourcelookup.containers.FolderSourceContainer;
import org.eclipse.jdt.launching.sourcelookup.containers.JavaProjectSourceContainer;
import org.eclipse.jdt.launching.sourcelookup.containers.JavaSourcePathComputer;
import org.eclipse.jdt.launching.sourcelookup.containers.PackageFragmentRootSourceContainer;

import ccw.clojure.util.ClojurePlugin;

Expand All @@ -19,25 +28,67 @@ public ISourceContainer[] computeSourceContainers(
ILaunchConfiguration configuration, IProgressMonitor monitor)
throws CoreException {


ISourceContainer[] superResult = super.computeSourceContainers(configuration, monitor);
ISourceContainer[] result = new ISourceContainer[superResult.length + 1];
System.arraycopy(superResult, 0, result, 1, superResult.length);
result[0] = getSrcFolderAsISourceContainer(configuration);
return result;

List<ISourceContainer> result = new ArrayList<ISourceContainer>(superResult.length * 2);
result.addAll(getSrcFoldersAsISourceContainers(configuration));

for (ISourceContainer sourceContainer: superResult) {
if (sourceContainer instanceof PackageFragmentRootSourceContainer) {
PackageFragmentRootSourceContainer sc = (PackageFragmentRootSourceContainer) sourceContainer;
// soit attacher la source, soit le path, en tant que simple external folder ou archive,
// en plus
IPath maybeSourcePath = sc.getPackageFragmentRoot().getSourceAttachmentPath();
if (maybeSourcePath != null) {
if (maybeSourcePath.toFile().isFile()) {
result.add(new ExternalArchiveSourceContainer(maybeSourcePath.toOSString(), false));
} else {
result.add(new DirectorySourceContainer(maybeSourcePath, false));
}
}
} else if (sourceContainer instanceof ExternalArchiveSourceContainer) {
// TODO
ExternalArchiveSourceContainer sc = (ExternalArchiveSourceContainer) sourceContainer;
} else if (sourceContainer instanceof JavaProjectSourceContainer) {
// TODO
JavaProjectSourceContainer sc = (JavaProjectSourceContainer) sourceContainer;
sc.getJavaProject();
} else {
/* TODO manager other kinds ?
DirectorySourceContainer
ISourceContainer
ArchiveSourceContainer
ClassPathContainerSourceContainer
ClassPathVariableSourceContainer
FolderSourceContainer
ProjectSourceContainer
WorkingSetSourceContainer
WorkspaceSourceContainer
*/
}
result.add(sourceContainer);
}
return result.toArray(new ISourceContainer[result.size()]);
}

private ISourceContainer getSrcFolderAsISourceContainer(ILaunchConfiguration configuration) throws CoreException {
/*
* TODO : remove the hard coded src/ folder and really returns all java source folders instead
*/
private List<ISourceContainer> getSrcFoldersAsISourceContainers(ILaunchConfiguration configuration) throws CoreException {
String projectName = configuration.getAttribute(LaunchUtils.ATTR_PROJECT_NAME, (String) null);

if (projectName == null) {
throw new CoreException(new Status(IStatus.ERROR, ClojurePlugin.ID, "Clojure SourcePathComputerDelegate unable to correctly set the clojure sources in the class because the considered launch configuration does not have an associated project"));
} else {
// TODO be smarter here : currently only works if src/ is the name of the dir :(
// and only if one source directory is defined in the project :(
return new FolderSourceContainer(
ResourcesPlugin.getWorkspace().getRoot().getProject(projectName).getFolder("src")
, true);

return Arrays.asList(new ISourceContainer[] {
new FolderSourceContainer(
ResourcesPlugin.getWorkspace().getRoot().getProject(projectName).getFolder("src")
, true)
});
}
}

Expand Down

0 comments on commit 9ac3ad7

Please sign in to comment.