IGV can jump to JMH sources & more (#4008)

Improvements to behavior and visual appearance of IGV Enso integration.
This commit is contained in:
Jaroslav Tulach 2022-12-30 06:30:32 +01:00 committed by GitHub
parent e6838bc90d
commit 0041b649eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 589 additions and 82 deletions

View File

@ -494,6 +494,7 @@
- [Add executionContext/interrupt API command][3952]
- [Any.== is a builtin method][3956]
- [Simplify exception handling for polyglot exceptions][3981]
- [IGV can jump to JMH sources & more][4008]
[3227]: https://github.com/enso-org/enso/pull/3227
[3248]: https://github.com/enso-org/enso/pull/3248
@ -571,6 +572,7 @@
[3952]: https://github.com/enso-org/enso/pull/3952
[3956]: https://github.com/enso-org/enso/pull/3956
[3981]: https://github.com/enso-org/enso/pull/3981
[4008]: https://github.com/enso-org/enso/pull/4008
# Enso 2.0.0-alpha.18 (2021-10-12)

View File

@ -349,7 +349,8 @@ However, as we don't want these things polluting our standard builds, we provide
a helper SBT command `withDebug` to allow for passing these options. It supports
the following flags:
- `--dumpGraphs`: This dumps the IGV (a Graal tool) graphs for the program to
- `--dumpGraphs`: This dumps the IGV (read about
[Enso tooling for IGV](../tools/enso4igv/README.md)) graphs for the program to
allow for manual analysis and discovery of optimisation failures.
- `--showCompilations`: Prints the truffle compilation trace information.
- `--printAssembly`: Prints the assembly output from the HotSpot JIT tier.

View File

@ -36,7 +36,7 @@ E.g. in Chrome open: devtools://devtools/bundled/js_app.html?ws=127.0.0.1:9229/W
copy the printed URL into chrome browser and you should see:
![Chrome Debugger](chrome-debugger.png)
![Chrome Debugger](https://user-images.githubusercontent.com/26887752/209614265-684f530e-cf7e-45d5-9450-7ea1e4f65986.png)
Step in, step over, set breakpoints, watch values of the variables as well as
evaluate arbitrary expressions in the console. Note that as of December 2022,
@ -72,7 +72,7 @@ and then _Debug/Attach Debugger_. Once connected suspend the execution and (if
the Enso language has already been started) choose the _Toggle Pause in GraalVM
Script_ button in the toolbar:
![NetBeans Debugger](java-debugger.png)
![NetBeans Debugger](https://user-images.githubusercontent.com/26887752/209614191-b0513635-819b-4c64-a6f9-9823b90a1513.png)
and your execution shall stop on the next `.enso` line of code. This mode allows
to debug both - the Enso code as well as Java code. The stack traces shows a

Binary file not shown.

Before

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

View File

@ -96,7 +96,8 @@ order: 7
something wrong.
10. Avoid
[deoptimizations](https://www.graalvm.org/22.2/graalvm-as-a-platform/language-implementation-framework/Optimizing/#debugging-deoptimizations).
Understanding IGV graphs can be a very time-consuming and complex process.
Understanding IGV graphs can be a very time-consuming and complex process
(even with the help of [Enso tooling for IGV](../tools/enso4igv/README.md)).
Sometimes it is sufficient to only look at the compilation traces to
discover repeated or unnecessary deoptimizations which can significantly
affect overall performance of your program. You can tell runner to generate

View File

@ -66,16 +66,15 @@ object FrgaalJavaCompiler {
val sources = sources0 map {
case x: PathBasedFile => x.toPath.toAbsolutePath.toString
}
val out = output.getSingleOutputAsPath().get()
val shared = sources0.fold(out)((a, b) => {
var ap = a match {
def asPath(a: Any) : Path = a match {
case p: PathBasedFile => p.toPath
case p: Path => p
}
val bp = b match {
case p: PathBasedFile => p.toPath
case p: Path => p
}
}
def asCommon(a: Any, b: Any): Path = {
var ap = asPath(a)
val bp = asPath(b)
var i = 0
while (i < Math.min(ap.getNameCount(), bp.getNameCount()) && ap.getName(i) == bp.getName(i)) {
@ -86,7 +85,45 @@ object FrgaalJavaCompiler {
ap = ap.getParent()
}
ap
}).asInstanceOf[Path]
}
val out = output.getSingleOutputAsPath().get()
val shared = sources0.fold(out)(asCommon).asInstanceOf[Path]
// searching for $shared/src/main/java or
// $shared/src/test/java or
// $shared/src/bench/java or etc.
def findUnder(depth : Int, dir : Path): Path = {
var d = dir
while (d.getNameCount() > depth) {
val threeUp = d.subpath(0, d.getNameCount() - depth)
val relShare = shared.subpath(0, shared.getNameCount())
if (relShare.equals(threeUp)) {
return d
} else {
d = d.getParent()
}
}
throw new IllegalArgumentException(
"Cannot findUnder for " + dir + " and " + shared +
"\nout: " + out + "\nsources: " + sources
)
}
def checkTarget(x : Any) = {
val p = asPath(x)
val namesCheck = for (i <- 0 until p.getNameCount)
yield "target".equals(p.getName(i).toString())
val inATargetDir = namesCheck.exists(x => x)
inATargetDir
}
val (withTarget, noTarget) = sources0.partition(checkTarget)
val in = findUnder(3, noTarget.tail.fold(asPath(noTarget.head))(asCommon).asInstanceOf[Path])
val generated = if (withTarget.isEmpty) {
None
} else {
Some(findUnder(4, withTarget.tail.fold(asPath(withTarget.head))(asCommon).asInstanceOf[Path]))
}
if (shared.toFile().exists()) {
val ensoMarker = new File(shared.toFile(), ENSO_SOURCES)
@ -97,6 +134,10 @@ object FrgaalJavaCompiler {
values.zipWithIndex.foreach { case (value, idx) => ensoProperties.setProperty(s"$name.$idx", value) }
}
ensoProperties.setProperty("input", in.toString())
if (generated.isDefined) {
ensoProperties.setProperty("generated", generated.get.toString())
}
ensoProperties.setProperty("output", out.toString())
storeArray("options", options)
source.foreach(v => ensoProperties.setProperty("source", v))

View File

@ -101,7 +101,10 @@ and open it as _"project"_ in IGV:
The project directories (not only `runtime`, but also other like
`runtime-language-epb`, etc.) are recognized only if you have built the Enso
engine sources with `sbt buildEngineDistribution`.
engine sources with `sbt buildEngineDistribution`. Once the IGV opens the
`runtime` & co. projects, it allows smooth navigation among the sources
![IGV Projects view](https://user-images.githubusercontent.com/26887752/209615348-8911af4c-4680-4e61-ac87-19a19738e2ca.png)
With such setup let's open graph for one of the top-most functions:
`TruffleHotSpotCompilation*Primes*next*.bgv`. Choose compilation phase _"Before
@ -142,7 +145,7 @@ environment. Switch to this directory and invoke:
```bash
enso/tools/enso4igv$ mvn clean install
enso/tools/enso4igv$ ls target/*.nbm
target/enso4igv-1.0-SNAPSHOT.nbm
target/enso4igv-*-SNAPSHOT.nbm
```
an NBM file is generated which can be installed into IGV, NetBeans or any other

View File

@ -5,7 +5,7 @@
<artifactId>enso4igv</artifactId>
<packaging>nbm</packaging>
<name>Enso Language Support for NetBeans &amp; Ideal Graph Visualizer</name>
<version>1.3-SNAPSHOT</version>
<version>1.7-SNAPSHOT</version>
<build>
<plugins>
<plugin>
@ -69,6 +69,11 @@
<artifactId>org-netbeans-modules-projectapi</artifactId>
<version>${netbeans.version}</version>
</dependency>
<dependency>
<groupId>org.netbeans.api</groupId>
<artifactId>org-netbeans-modules-projectuiapi</artifactId>
<version>${netbeans.version}</version>
</dependency>
<dependency>
<groupId>org.netbeans.api</groupId>
<artifactId>org-netbeans-api-templates</artifactId>
@ -132,31 +137,37 @@
<dependency>
<groupId>org.netbeans.api</groupId>
<artifactId>org-netbeans-modules-projectuiapi-base</artifactId>
<version>RELEASE113</version>
<version>${netbeans.version}</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.netbeans.api</groupId>
<artifactId>org-netbeans-api-java-classpath</artifactId>
<version>RELEASE113</version>
<version>${netbeans.version}</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.netbeans.api</groupId>
<artifactId>org-netbeans-modules-java-project</artifactId>
<version>RELEASE113</version>
<version>${netbeans.version}</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.netbeans.api</groupId>
<artifactId>org-netbeans-modules-java-platform</artifactId>
<version>RELEASE113</version>
<version>${netbeans.version}</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.netbeans.api</groupId>
<artifactId>org-netbeans-api-java</artifactId>
<version>RELEASE113</version>
<version>${netbeans.version}</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.netbeans.api</groupId>
<artifactId>org-netbeans-modules-java-project-ui</artifactId>
<version>${netbeans.version}</version>
<type>jar</type>
</dependency>
</dependencies>

View File

@ -28,7 +28,7 @@ import org.openide.windows.TopComponent;
@GrammarRegistration(mimeType = "application/x-enso", grammar = "enso.tmLanguage.json")
@DataObject.Registration(
mimeType = "application/x-enso",
iconBase = "org/enso/tools/enso4igv/enso.png",
iconBase = "org/enso/tools/enso4igv/enso.svg",
displayName = "#LBL_Enso_LOADER",
position = 300
)
@ -98,7 +98,7 @@ public class EnsoDataObject extends MultiDataObject {
@MultiViewElement.Registration(
displayName = "#LBL_Enso_EDITOR",
iconBase = "org/enso/tools/enso4igv/enso.png",
iconBase = "org/enso/tools/enso4igv/enso.svg",
mimeType = "application/x-enso",
persistenceType = TopComponent.PERSISTENCE_ONLY_OPENED,
preferredID = "Enso",

View File

@ -0,0 +1,119 @@
package org.enso.tools.enso4igv;
import java.util.Arrays;
import java.util.List;
import javax.swing.Action;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.enso.tools.enso4igv.EnsoSbtClassPathProvider.EnsoSources;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectUtils;
import org.netbeans.api.project.SourceGroup;
import org.netbeans.spi.java.project.support.ui.PackageView;
import org.netbeans.spi.project.ui.LogicalViewProvider;
import org.netbeans.spi.project.ui.support.CommonProjectActions;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionReferences;
import org.openide.filesystems.*;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.util.NbCollections;
import org.openide.util.lookup.Lookups;
@ActionReferences({
@ActionReference(position = 3100, id = @ActionID(category = "Project", id = "org-netbeans-modules-project-ui-CloseProject"), path = "Projects/ensosbtprj/Actions", separatorBefore = 3000),
})
final class EnsoLogicalView implements LogicalViewProvider {
private final EnsoSbtProject p;
EnsoLogicalView(EnsoSbtProject p) {
this.p = p;
}
@Override
public Node createLogicalView() {
return new EnsoSbtProjectNode(p);
}
@Override
public Node findPath(Node root, Object target) {
Project prj = root.getLookup().lookup(Project.class);
if (prj == null) {
return null;
}
if (target instanceof FileObject) {
FileObject fo = (FileObject) target;
for (Node n : root.getChildren().getNodes(true)) {
Node result = PackageView.findPath(n, target);
if (result != null) {
return result;
}
}
}
return null;
}
private static final class EnsoSbtProjectNode extends AbstractNode {
private final EnsoSbtProject project;
public EnsoSbtProjectNode(EnsoSbtProject p) {
super(Children.create(new EnsoRoots(p), true), Lookups.fixed(p));
this.project = p;
setDisplayName();
setIconBaseWithExtension("org/enso/tools/enso4igv/enso.svg");
}
private void setDisplayName() {
setDisplayName(ProjectUtils.getInformation(project).getDisplayName());
}
@Override
public String getHtmlDisplayName() {
return null;
}
@Override
public Action[] getActions(boolean context) {
return CommonProjectActions.forType("ensosbtprj"); // NOI18N
}
}
private static final class EnsoRoots extends ChildFactory<SourceGroup> implements ChangeListener {
private final EnsoSbtProject prj;
EnsoRoots(EnsoSbtProject project) {
this.prj = project;
}
@Override
protected boolean createKeys(List<SourceGroup> toPopulate) {
var arr = Arrays.asList(ProjectUtils.getSources(prj).getSourceGroups(null));
var enso = NbCollections.checkedListByCopy(arr, EnsoSources.class, true);
for (var e : enso) {
toPopulate.add(e);
}
for (var e : enso) {
}
return true;
}
@Override
protected Node createNodeForKey(SourceGroup key) {
return PackageView.createPackageView(key);
}
@Override
public void stateChanged(ChangeEvent e) {
refresh(false);
}
record Entry(String prefix, FileObject root) {
}
}
}

View File

@ -1,73 +1,89 @@
package org.enso.tools.enso4igv;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Properties;
import javax.swing.Icon;
import javax.swing.event.ChangeListener;
import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.java.classpath.GlobalPathRegistry;
import org.netbeans.api.java.platform.JavaPlatform;
import org.netbeans.api.java.queries.SourceForBinaryQuery;
import org.netbeans.api.project.SourceGroup;
import org.netbeans.api.project.Sources;
import org.netbeans.spi.java.classpath.ClassPathProvider;
import org.netbeans.spi.java.classpath.support.ClassPathSupport;
import org.netbeans.spi.java.project.support.ProjectPlatform;
import org.netbeans.spi.java.queries.BinaryForSourceQueryImplementation2;
import org.netbeans.spi.java.queries.CompilerOptionsQueryImplementation;
import org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation2;
import org.netbeans.spi.java.queries.SourceLevelQueryImplementation2;
import org.netbeans.spi.project.ui.ProjectOpenedHook;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.filesystems.URLMapper;
import org.openide.util.Exceptions;
final class EnsoSbtClassPathProvider extends ProjectOpenedHook
implements ClassPathProvider, SourceLevelQueryImplementation2, CompilerOptionsQueryImplementation {
implements ClassPathProvider, SourceLevelQueryImplementation2, CompilerOptionsQueryImplementation,
Sources, BinaryForSourceQueryImplementation2<EnsoSbtClassPathProvider.EnsoSources>, SourceForBinaryQueryImplementation2 {
private static final String BOOT = "classpath/boot";
private static final String SOURCE = "classpath/source";
private static final String COMPILE = "classpath/compile";
private final EnsoSbtProject project;
private final EnsoSources info;
private final EnsoSources[] sources;
EnsoSbtClassPathProvider(EnsoSbtProject prj) {
this.project = prj;
this.info = computeSbtClassPath(prj);
this.sources = computeSbtClassPath(prj);
}
@Override
public ClassPath findClassPath(FileObject file, String type) {
if (FileUtil.isParentOf(project.getProjectDirectory(), file)) {
return switch (type) {
case SOURCE -> info.srcCp;
case COMPILE -> info.cp;
case BOOT -> info.platform.getBootstrapLibraries();
default -> null;
};
} else {
return null;
for (var i : sources) {
if (i.controlsSource(file)) {
return switch (type) {
case SOURCE -> i.srcCp;
case COMPILE -> i.cp;
case BOOT -> i.platform.getBootstrapLibraries();
default -> null;
};
}
}
return null;
}
@Override
public void projectOpened() {
GlobalPathRegistry.getDefault().register(COMPILE, new ClassPath[] { info.cp });
GlobalPathRegistry.getDefault().register(SOURCE, new ClassPath[] { info.srcCp });
for (var i : sources) {
GlobalPathRegistry.getDefault().register(COMPILE, new ClassPath[] { i.cp });
GlobalPathRegistry.getDefault().register(SOURCE, new ClassPath[] { i.srcCp });
}
}
@Override
public void projectClosed() {
GlobalPathRegistry.getDefault().unregister(COMPILE, new ClassPath[] { info.cp });
GlobalPathRegistry.getDefault().unregister(SOURCE, new ClassPath[] { info.srcCp });
for (var i : sources) {
GlobalPathRegistry.getDefault().unregister(COMPILE, new ClassPath[] { i.cp });
GlobalPathRegistry.getDefault().unregister(SOURCE, new ClassPath[] { i.srcCp });
}
}
private static EnsoSources computeSbtClassPath(EnsoSbtProject prj) {
private static EnsoSources[] computeSbtClassPath(EnsoSbtProject prj) {
var sources = new ArrayList<EnsoSources>();
var platform = JavaPlatform.getDefault();
var roots = new LinkedHashSet<>();
var generatedSources = new LinkedHashSet<>();
var source = "11";
var source = "19";
var options = new ArrayList<String>();
for (FileObject ch : prj.getProjectDirectory().getChildren()) {
if (ch.getNameExt().startsWith(".enso-sources")) {
if (ch.getNameExt().startsWith(".enso-sources-")) {
Properties p = new Properties();
try (InputStream is = ch.getInputStream()) {
p.load(is);
@ -116,70 +132,238 @@ implements ClassPathProvider, SourceLevelQueryImplementation2, CompilerOptionsQu
}
options.add(prop);
}
}
}
var srcRoots = new LinkedHashSet<>();
var srcRoots = new LinkedHashSet<>();
var srcDir = prj.getProjectDirectory().getFileObject("src");
if (srcDir != null) {
for (var group : srcDir.getChildren()) {
if (group.isFolder()) {
for (var ch : group.getChildren()) {
if (ch.isFolder()) {
srcRoots.add(ch);
var inputSrc = p.getProperty("input");
var inputDir = inputSrc != null ? FileUtil.toFileObject(new File(inputSrc)) : null;
if (inputDir != null) {
if (inputDir.getNameExt().equals("org")) {
// lib/rust/parser doesn't follow typical project conventions
inputDir = inputDir.getParent();
}
srcRoots.add(inputDir);
}
var srcDir = prj.getProjectDirectory().getFileObject("src");
if (srcDir != null) {
for (var group : srcDir.getChildren()) {
if (group.isFolder()) {
for (var child : group.getChildren()) {
if (child.isFolder()) {
srcRoots.add(child);
}
}
}
}
}
srcRoots.addAll(generatedSources);
var outputSrc = p.getProperty("output");
var outputDir = outputSrc != null ? FileUtil.toFileObject(new File(outputSrc)) : null;
var generatedSrc = p.getProperty("generated");
var generatedDir = generatedSrc != null ? FileUtil.toFileObject(new File(generatedSrc)) : null;
if (generatedDir != null) {
srcRoots.add(generatedDir);
}
var cp = ClassPathSupport.createClassPath(roots.toArray(new FileObject[0]));
var srcCp = ClassPathSupport.createClassPath(srcRoots.toArray(new FileObject[0]));
var s = new EnsoSources(cp, srcCp, platform, outputDir, source, options);
if ("main".equals(s.getName())) {
sources.add(0, s);
} else {
sources.add(s);
}
}
}
srcRoots.addAll(generatedSources);
var cp = ClassPathSupport.createClassPath(roots.toArray(new FileObject[0]));
var srcCp = ClassPathSupport.createClassPath(srcRoots.toArray(new FileObject[0]));
return new EnsoSources(cp, srcCp, platform, source, options);
return sources.toArray(new EnsoSources[0]);
}
@Override
public SourceLevelQueryImplementation2.Result getSourceLevel(FileObject fo) {
return new SourceLevelQueryImplementation2.Result() {
@Override
public String getSourceLevel() {
return info.source;
}
for (var i : sources) {
if (i.controlsSource(fo)) {
return new SourceLevelQueryImplementation2.Result() {
@Override
public String getSourceLevel() {
return i.source;
}
@Override
public void addChangeListener(ChangeListener cl) {
}
@Override
public void addChangeListener(ChangeListener cl) {
}
@Override
public void removeChangeListener(ChangeListener cl) {
@Override
public void removeChangeListener(ChangeListener cl) {
}
};
}
};
}
return null;
}
@Override
public CompilerOptionsQueryImplementation.Result getOptions(FileObject fo) {
return new CompilerOptionsQueryImplementation.Result() {
@Override
public List<? extends String> getArguments() {
return info.options;
}
for (var i : sources) {
if (i.controlsSource(fo)) {
return new CompilerOptionsQueryImplementation.Result() {
@Override
public List<? extends String> getArguments() {
return i.options;
}
@Override
public void addChangeListener(ChangeListener cl) {
}
@Override
public void addChangeListener(ChangeListener cl) {
}
@Override
public void removeChangeListener(ChangeListener cl) {
@Override
public void removeChangeListener(ChangeListener cl) {
}
};
}
};
}
return null;
}
@Override
public SourceGroup[] getSourceGroups(String string) {
return sources;
}
@Override
public void addChangeListener(ChangeListener cl) {
}
private record EnsoSources(
@Override
public void removeChangeListener(ChangeListener cl) {
}
@Override
public EnsoSources findBinaryRoots2(URL url) {
var fo = URLMapper.findFileObject(url);
for (var i : sources) {
if (i.outputsTo(fo) || i.controlsSource(fo)) {
return i;
}
}
return null;
}
@Override
public URL[] computeRoots(EnsoSources result) {
return new URL[] { result.output().toURL() };
}
@Override
public boolean computePreferBinaries(EnsoSources result) {
return true;
}
@Override
public void computeChangeListener(EnsoSources result, boolean bln, ChangeListener cl) {
}
@Override
public SourceForBinaryQueryImplementation2.Result findSourceRoots2(URL url) {
var fo = URLMapper.findFileObject(url);
if (fo == null) {
return null;
}
for (var i : sources) {
if (i.outputsTo(fo) || i.controlsSource(fo)) {
return new SourceForBinaryQueryImplementation2.Result() {
@Override
public boolean preferSources() {
return false;
}
@Override
public FileObject[] getRoots() {
return i.getRoots();
}
@Override
public void addChangeListener(ChangeListener l) {
}
@Override
public void removeChangeListener(ChangeListener l) {
}
};
}
}
return null;
}
@Override
public SourceForBinaryQuery.Result findSourceRoots(URL binaryRoot) {
return findSourceRoots2(binaryRoot);
}
record EnsoSources(
ClassPath cp, ClassPath srcCp,
JavaPlatform platform,
FileObject output,
String source, List<String> options
) {
) implements SourceGroup {
@Override
public FileObject getRootFolder() {
return srcCp.getRoots()[0];
}
private FileObject[] getRoots() {
return srcCp.getRoots();
}
@Override
public String getName() {
return getRootFolder().getParent().getNameExt();
}
@Override
public String getDisplayName() {
return getName();
}
@Override
public Icon getIcon(boolean bln) {
return null;
}
@Override
public boolean contains(FileObject fo) {
if (getRootFolder().equals(fo)) {
return true;
}
return FileUtil.isParentOf(getRootFolder(), fo);
}
@Override
public void addPropertyChangeListener(PropertyChangeListener pl) {
}
@Override
public void removePropertyChangeListener(PropertyChangeListener pl) {
}
private boolean controlsSource(FileObject fo) {
return contains(fo) || srcCp.contains(fo);
}
private boolean outputsTo(FileObject fo) {
if (fo == null || output() == null) {
return false;
}
if (fo.equals(output())) {
return true;
}
return FileUtil.isParentOf(output(), fo);
}
public String toString() {
return "EnsoSources[name=" + getName() + ",root=" + getRootFolder() + ",output=" + output() + "]";
}
}
}

View File

@ -22,7 +22,8 @@ public class EnsoSbtProject implements Project {
this.ps = ps;
this.lkp = Lookups.fixed(
this,
new EnsoSbtClassPathProvider(this)
new EnsoSbtClassPathProvider(this),
new EnsoLogicalView(this)
);
}
@ -59,7 +60,7 @@ public class EnsoSbtProject implements Project {
@Override
public ProjectManager.Result isProject2(FileObject fo) {
if (isProject(fo)) {
var img = ImageUtilities.loadImage("org/enso/tools/enso4igv/enso.png");
var img = ImageUtilities.loadImage("org/enso/tools/enso4igv/enso.svg");
return new ProjectManager.Result(ImageUtilities.image2Icon(img));
}
return null;

View File

@ -0,0 +1,85 @@
package org.enso.tools.enso4igv;
import java.net.URL;
import java.net.MalformedURLException;
import javax.swing.event.ChangeListener;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.filesystems.URLMapper;
import org.netbeans.api.java.queries.SourceForBinaryQuery;
import org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation;
import org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation2;
import org.openide.util.Exceptions;
@org.openide.util.lookup.ServiceProvider(service = SourceForBinaryQueryImplementation.class, position = 100000)
public class GraalVMSourceForBinaryQuery implements SourceForBinaryQueryImplementation2 {
public GraalVMSourceForBinaryQuery() {
}
@Override
public SourceForBinaryQueryImplementation2.Result findSourceRoots2(URL binaryRoot) {
var binaryRootS = binaryRoot.toExternalForm();
String srcZipS = null;
String srcZipIn = null;
if (binaryRootS.startsWith("nbjrt:")) {
int end = binaryRootS.indexOf('!');
if (end >= 0) {
srcZipS = binaryRootS.substring(6, end) + "lib/src.zip";
String reminder = binaryRootS.substring(end + 1);
final String prefix = "/modules/";
if (reminder.startsWith(prefix)) {
srcZipIn = reminder.substring(prefix.length());
}
}
}
if (srcZipS != null) {
try {
URL srcZip = FileUtil.getArchiveRoot(new URL(srcZipS));
FileObject fo = URLMapper.findFileObject(srcZip);
if (fo != null) {
if (srcZipIn != null) {
fo = fo.getFileObject(srcZipIn);
}
if (fo != null) {
return new R(fo);
}
}
} catch (MalformedURLException mue) {
Exceptions.printStackTrace(mue);
}
}
return null;
}
@Override
public SourceForBinaryQuery.Result findSourceRoots(URL binaryRoot) {
return this.findSourceRoots2(binaryRoot);
}
private static class R implements SourceForBinaryQueryImplementation2.Result {
private final FileObject root;
private R(FileObject fo) {
root = fo;
}
@Override
public FileObject[] getRoots() {
return root.isValid() ? new FileObject[]{root} : new FileObject[0];
}
@Override
public void addChangeListener(ChangeListener l) {
}
@Override
public void removeChangeListener(ChangeListener l) {
}
@Override
public boolean preferSources() {
return false;
}
}
}

View File

@ -0,0 +1,47 @@
package org.enso.tools.enso4igv;
import java.net.URL;
import javax.swing.event.ChangeListener;
import org.netbeans.api.java.queries.SourceForBinaryQuery;
import org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation;
import org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation2;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.filesystems.URLMapper;
import org.openide.util.lookup.ServiceProvider;
@ServiceProvider(service = SourceForBinaryQueryImplementation.class)
public final class NextToSourceForBinaryQueryImpl implements SourceForBinaryQueryImplementation {
@Override
public SourceForBinaryQuery.Result findSourceRoots(URL binaryRoot) {
var file = FileUtil.getArchiveFile(binaryRoot);
if (file != null) {
var fo = URLMapper.findFileObject(file);
if (fo != null) {
var src = fo.getParent().getFileObject(fo.getName() + "-sources", fo.getExt());
if (src != null) {
return new SourceForBinaryQueryImplementation2.Result() {
@Override
public boolean preferSources() {
return false;
}
@Override
public FileObject[] getRoots() {
return new FileObject[] { FileUtil.getArchiveRoot(src) };
}
@Override
public void addChangeListener(ChangeListener l) {
}
@Override
public void removeChangeListener(ChangeListener l) {
}
};
}
}
}
return null;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg x="0px" y="0px" width="16px" height="16px"
viewBox="0 0 40 40"
class="h-8 self-center mr-8 fill-current content-extrastrong"
xmlns="http://www.w3.org/2000/svg"
>
<g>
<circle cx="20" cy="20" r="20" fill="white"></circle>
<path d="M20.0519 0C8.93506 0 0 8.93506 0 20.0519C0 31.1688 8.93506 40.1039 20.0519 40.1039C31.0649 40.1039 40.1039 31.1688 40.1039 20.0519C40.1039 8.93506 31.0649 0 20.0519 0ZM20.0519 36.0519C11.1169 36.0519 3.94805 28.8831 3.94805 19.9481C3.94805 11.013 11.1169 3.84416 20.0519 3.84416C28.987 3.84416 36.1558 11.013 36.1558 19.9481C36.0519 28.8831 28.8831 36.0519 20.0519 36.0519Z"></path>
<path d="M27.1169 17.7662C29.4026 18.8051 30.3377 21.4025 29.5065 23.6882C28.1558 27.6363 24.3117 30.5454 19.9481 30.5454C14.3377 30.5454 9.76623 25.974 9.76623 20.3636C9.76623 20.3636 11.3247 22.4415 14.3377 22.4415C17.3506 22.4415 18.7013 21.2986 19.9481 20.3636C21.1948 19.4285 22.026 17.3506 25.1429 17.3506C25.8701 17.3506 26.5974 17.5584 27.1169 17.7662Z"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB