diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml
index 9aa9a79..9ecd7ae 100644
--- a/.github/workflows/CI.yml
+++ b/.github/workflows/CI.yml
@@ -47,7 +47,7 @@ jobs:
dev.jbang.eclipse.site/target/flat-repository/*
- name: Upload code coverage
uses: codecov/codecov-action@v3
- if: github.ref == 'refs/heads/main' && runner.os == 'Linux'
+ if: runner.os == 'Linux'
with:
files: ./coverage/target/site/jacoco-aggregate/jacoco.xml
flags: ${{ runner.os }} # optional
diff --git a/dev.jbang.eclipse.core/plugin.xml b/dev.jbang.eclipse.core/plugin.xml
index d332230..5cbea56 100644
--- a/dev.jbang.eclipse.core/plugin.xml
+++ b/dev.jbang.eclipse.core/plugin.xml
@@ -16,7 +16,7 @@
-
diff --git a/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/JBangClasspathUtils.java b/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/JBangClasspathUtils.java
index 8a4678d..42d4344 100644
--- a/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/JBangClasspathUtils.java
+++ b/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/JBangClasspathUtils.java
@@ -98,7 +98,7 @@ static File getContainerStateFile(IProject project) {
public static boolean isOnClasspath(IJavaProject javaProject, IFile script) throws CoreException {
- if (script != null && JavaCore.isJavaLikeFileName(script.getName())) {
+ if (script != null && (JavaCore.isJavaLikeFileName(script.getName()) || JBangFileUtils.isJBangBuildFile(script)) ) {
IClasspathEntry[] entries = javaProject.getRawClasspath();
for (IClasspathEntry entry : entries) {
if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE &&
@@ -110,6 +110,24 @@ public static boolean isOnClasspath(IJavaProject javaProject, IFile script) thro
return false;
}
+ public static boolean isOnOutputLocation(IJavaProject javaProject, IFile script) throws CoreException {
+ if (script != null) {
+ if (javaProject.getOutputLocation() != null && javaProject.getOutputLocation().isPrefixOf(script.getFullPath())) {
+ return true;
+ }
+
+ IClasspathEntry[] entries = javaProject.getRawClasspath();
+ for (IClasspathEntry entry : entries) {
+ if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE &&
+ entry.getOutputLocation() != null &&
+ entry.getOutputLocation().isPrefixOf(script.getFullPath())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
public static boolean hasAttribute(IClasspathEntry entry, String attribute) throws CoreException {
for (IClasspathAttribute attr : entry.getExtraAttributes()) {
diff --git a/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/JBangConstants.java b/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/JBangConstants.java
index 91970b1..a9e09d8 100644
--- a/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/JBangConstants.java
+++ b/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/JBangConstants.java
@@ -11,23 +11,31 @@ public final class JBangConstants {
public static final String BUILDER_ID = PLUGIN_ID + ".jbangbuilder"; //$NON-NLS-1$
public static final String MARKER_ID = PLUGIN_ID + ".jbangproblem"; //$NON-NLS-1$
-
+
public static final String MARKER_RESOLUTION_ID = MARKER_ID + ".resolution"; //$NON-NLS-1$
-
- private static final String PREFIX = "dev.jbang.";
-
- /** String, list of configured JBang installations separated by '|', see {@link JBangRuntimeManager} */
- public static final String P_RUNTIMES = PREFIX + "runtimes"; //$NON-NLS-1$
- /** Root node of extended JBang installation attributes, see {@link JBangRuntimeManager} */
- public static final String P_RUNTIMES_NODE = PREFIX + "runtimesNodes"; //$NON-NLS-1$
+ private static final String PREFIX = "dev.jbang.";
- /** String */
- public static final String P_DEFAULT_RUNTIME = PREFIX + "defaultRuntime"; //$NON-NLS-1$
+ /**
+ * String, list of configured JBang installations separated by '|', see
+ * {@link JBangRuntimeManager}
+ */
+ public static final String P_RUNTIMES = PREFIX + "runtimes"; //$NON-NLS-1$
+ /**
+ * Root node of extended JBang installation attributes, see
+ * {@link JBangRuntimeManager}
+ */
+ public static final String P_RUNTIMES_NODE = PREFIX + "runtimesNodes"; //$NON-NLS-1$
+
+ public static final String P_DEFAULT_RUNTIME = PREFIX + "defaultRuntime"; //$NON-NLS-1$
+
+ public static final String JBANG_BUILD = "build.jbang";
- private JBangConstants(){
- //no instanciation
- }
+ public static final String JBANG_MAIN = "main.java";
+
+ private JBangConstants() {
+ // no instanciation
+ }
}
diff --git a/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/JBangFileUtils.java b/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/JBangFileUtils.java
index d9bdd72..bf7a3cb 100644
--- a/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/JBangFileUtils.java
+++ b/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/JBangFileUtils.java
@@ -1,10 +1,7 @@
package dev.jbang.eclipse.core.internal;
-import java.io.BufferedInputStream;
import java.io.BufferedReader;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.file.Files;
@@ -15,7 +12,6 @@
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
-import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.CompilationUnit;
@@ -67,6 +63,13 @@ public static boolean isJBangFile(IResource resource) {
return false;
}
+ public static boolean isJBangBuildFile(IResource resource) {
+ if (!(resource instanceof IFile)) {
+ return false;
+ }
+ return JBangConstants.JBANG_BUILD.equals(((IFile) resource).getName());
+ }
+
public static boolean isJBangFile(Path file) {
if (!(Files.isRegularFile(file))) {
return false;
@@ -84,6 +87,20 @@ public static boolean isJBangFile(Path file) {
return false;
}
+ public static boolean isJBangBuildFile(Path file) {
+ if (!(Files.isRegularFile(file))) {
+ return false;
+ }
+ return JBangConstants.JBANG_BUILD.equals(file.getFileName().toString());
+ }
+
+ public static boolean isMainFile(Path file) {
+ if (!(Files.isRegularFile(file))) {
+ return false;
+ }
+ return JBangConstants.JBANG_MAIN.equals(file.getFileName().toString());
+ }
+
public static String getJavaVersion(String line) {
return getMatch(JAVA_INSTRUCTION, line);
}
@@ -114,28 +131,33 @@ private static String getMatch(Pattern pattern, String line) {
public static String getPackageName(IJavaProject javaProject, IFile file) {
//TODO probably not the most efficient way to get the package name as this reads the whole file;
- char[] source = null;
- try (InputStream is = new BufferedInputStream(file.getContents(true));
- ByteArrayOutputStream result = new ByteArrayOutputStream()) {
- byte[] buffer = new byte[1024];
- for (int length; (length = is.read(buffer)) != -1; ) {
- result.write(buffer, 0, length);
- }
- source = result.toString(file.getCharset()).toCharArray();
- } catch (IOException | CoreException e) {
+ var ast = createCompilationUnit(file);
+ if (ast != null) {
+ PackageDeclaration pkg = ast.getPackage();
+ if (pkg != null && pkg.getName() != null) {
+ return pkg.getName().getFullyQualifiedName();
+ }
+ }
+ return null;
+ }
+
+ public static CompilationUnit createCompilationUnit(IFile file) {
+ String content = null;
+ try {
+ content = ResourceUtil.getContent(file);
+ } catch (Exception e) {
e.printStackTrace();
}
- if (source == null) {
+ if (content == null) {
return null;
}
+ char[] source = content.toCharArray();
ASTParser parser = ASTParser.newParser(IASTSharedValues.SHARED_AST_LEVEL);
- parser.setProject(javaProject);
parser.setIgnoreMethodBodies(true);
parser.setSource(source);
CompilationUnit ast = (CompilationUnit) parser.createAST(null);
- PackageDeclaration pkg = ast.getPackage();
- return (pkg == null || pkg.getName() == null)? null :pkg.getName().getFullyQualifiedName();
+ return ast;
}
private static boolean hasJBangInstructions(Reader reader) throws IOException {
diff --git a/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/builder/JBangBuilder.java b/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/builder/JBangBuilder.java
index 7e1cf60..8d31f81 100644
--- a/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/builder/JBangBuilder.java
+++ b/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/builder/JBangBuilder.java
@@ -1,6 +1,8 @@
package dev.jbang.eclipse.core.internal.builder;
import static dev.jbang.eclipse.core.JBangCorePlugin.logInfo;
+import static dev.jbang.eclipse.core.internal.JBangFileUtils.createCompilationUnit;
+import static dev.jbang.eclipse.core.internal.JBangFileUtils.isJBangBuildFile;
import static dev.jbang.eclipse.core.internal.JBangFileUtils.isJBangFile;
import java.util.ArrayList;
@@ -26,6 +28,7 @@
import org.eclipse.jdt.core.manipulation.CoreASTProvider;
import dev.jbang.eclipse.core.JBangCorePlugin;
+import dev.jbang.eclipse.core.internal.ResourceUtil;
import dev.jbang.eclipse.core.internal.project.JBangProject;
import dev.jbang.eclipse.core.internal.project.ProjectConfigurationManager;
import dev.jbang.eclipse.core.internal.runtime.JBangRuntimesDiscoveryJob;
@@ -143,7 +146,7 @@ public boolean visit(IResourceDelta delta) {
case IResourceDelta.CHANGED: {
// if the content has changed clean + scan
if ((delta.getFlags() & IResourceDelta.CONTENT) > 0) {
- if (isJBangFile(resource)) {
+ if (isJBangBuildFile(resource) || isJBangFile(resource)) {
jbangFiles.add((IFile) resource);
}
return true;
@@ -166,21 +169,34 @@ void cleanMarkers(IProject p) {
@SuppressWarnings("unchecked")
static Integer getConfigHash(IFile file, IProgressMonitor monitor) throws CoreException {
- if (!"java".equals(file.getFileExtension())) {
+ if (!JavaCore.isJavaLikeFileName(file.getName()) && !isJBangBuildFile(file) ) {
return null;
}
- ICompilationUnit typeRoot = JavaCore.createCompilationUnitFrom(file);
- //FIXME This is uber slow. Once a file is saved, its AST is disposed, we're not benefiting from reusing a cached AST,
- // hence pay the price of recomputing it from scratch
- CompilationUnit root = CoreASTProvider.getInstance().getAST(typeRoot, CoreASTProvider.WAIT_YES, monitor);
+
+ CompilationUnit root = null;
+ String source = null;
+ if (isJBangBuildFile(file)) {
+ root = createCompilationUnit(file);
+ source = ResourceUtil.getContent(file);
+ } else {
+ ICompilationUnit typeRoot = JavaCore.createCompilationUnitFrom(file);
+ if (typeRoot != null) {
+ //FIXME This is uber slow. Once a file is saved, its AST is disposed, we're not benefiting from reusing a cached AST,
+ // hence pay the price of recomputing it from scratch
+ root = CoreASTProvider.getInstance().getAST(typeRoot, CoreASTProvider.WAIT_YES, monitor);
+ source = typeRoot.getSource();
+ }
+ }
if (root == null) {
return 0;
}
- JBangConfigVisitor configCollector = new JBangConfigVisitor(typeRoot.getSource());
+
+ JBangConfigVisitor configCollector = new JBangConfigVisitor(source);
root.accept(configCollector);
for (Comment comment : (List) root.getCommentList()) {
comment.accept(configCollector);
}
return configCollector.getConfigElements().hashCode();
- }
+ }
+
}
diff --git a/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/classpath/AnnotationProcessorUtils.java b/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/classpath/AnnotationProcessorUtils.java
index cd1a54f..2e6274e 100644
--- a/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/classpath/AnnotationProcessorUtils.java
+++ b/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/classpath/AnnotationProcessorUtils.java
@@ -12,7 +12,6 @@
import java.io.File;
import java.io.IOException;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@@ -21,14 +20,10 @@
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import java.util.stream.Collectors;
import org.eclipse.core.resources.IProject;
-import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
-import org.eclipse.jdt.core.IJavaProject;
-import org.eclipse.jdt.core.JavaCore;
import dev.jbang.eclipse.core.internal.classpath.AnnotationServiceLocator.ServiceEntry;
diff --git a/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/expressions/JBangResourceTester.java b/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/expressions/JBangResourceTester.java
index cccdaf6..03e41d6 100644
--- a/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/expressions/JBangResourceTester.java
+++ b/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/expressions/JBangResourceTester.java
@@ -17,7 +17,7 @@ public class JBangResourceTester extends PropertyTester {
public boolean test(Object receiver, String property, Object[] args, Object expectedValue) {
if (receiver instanceof IResource) {
IResource resource = (IResource) receiver;
- boolean isJBangFile = JBangFileUtils.isJBangFile(resource);
+ boolean isJBangFile = JBangFileUtils.isJBangFile(resource) || JBangFileUtils.isJBangBuildFile(resource);
return Objects.equals(isJBangFile, expectedValue);
}
return false;
diff --git a/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/imports/ImportJBangScriptsJob.java b/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/imports/ImportJBangScriptsJob.java
index 3e8698a..53a91d9 100644
--- a/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/imports/ImportJBangScriptsJob.java
+++ b/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/imports/ImportJBangScriptsJob.java
@@ -36,7 +36,7 @@ public IStatus runInWorkspace(IProgressMonitor monitor) {
var configuration = new JBangProjectConfiguration();
for (Path script : scripts) {
try {
- if (JBangFileUtils.isJBangFile(script)) {
+ if (JBangFileUtils.isJBangFile(script) || JBangFileUtils.isJBangBuildFile(script)) {
projectManager.createJBangProject(script, configuration, monitor);
}
} catch (Exception e) {
diff --git a/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/project/ProjectConfigurationManager.java b/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/project/ProjectConfigurationManager.java
index 5f278eb..06493c8 100644
--- a/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/project/ProjectConfigurationManager.java
+++ b/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/project/ProjectConfigurationManager.java
@@ -38,7 +38,6 @@
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.JavaRuntime;
import org.eclipse.jdt.launching.environments.IExecutionEnvironment;
import org.eclipse.jdt.launching.environments.IExecutionEnvironmentsManager;
@@ -46,6 +45,7 @@
import dev.jbang.eclipse.core.JBangCorePlugin;
import dev.jbang.eclipse.core.internal.JBangClasspathUtils;
import dev.jbang.eclipse.core.internal.JBangConstants;
+import dev.jbang.eclipse.core.internal.JBangFileUtils;
import dev.jbang.eclipse.core.internal.ProjectUtils;
import dev.jbang.eclipse.core.internal.ResourceUtil;
import dev.jbang.eclipse.core.internal.classpath.AnnotationProcessorUtils;
@@ -315,6 +315,9 @@ public JBangProject createJBangProject(java.nio.file.Path script, JBangProjectCo
String fileName = script.getFileName().toString();
String name = fileName; //fileName.substring(0, fileName.lastIndexOf("."));
+ if (JBangFileUtils.isJBangBuildFile(script) || JBangFileUtils.isMainFile(script)) {
+ name = script.getParent().getFileName().toString();
+ }
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(name);
if (!project.exists()) {
@@ -353,7 +356,12 @@ public JBangProject createJBangProject(java.nio.file.Path script, JBangProjectCo
javaProject.setOutputLocation(bin.getFullPath(), monitor);
- IFile mainFile = link(info.getBackingResource(), project, configuration, monitor);
+ IFile mainFile;
+ if (JBangFileUtils.isJBangBuildFile(script)) {
+ mainFile = link(script.toAbsolutePath().toString(), project, configuration, monitor);
+ } else {
+ mainFile = link(info.getBackingResource(), project, configuration, monitor);
+ }
if (info.getSources() != null && !info.getSources().isEmpty()) {
for (JBangFile s : info.getSources()) {
link(s.originalResource, project, configuration, monitor);
@@ -398,12 +406,18 @@ private IFile link(String resource, String link, IProject project, JBangProjectC
}
public void synchronize(IFile file, IProgressMonitor monitor) throws CoreException {
- monitor.setTaskName("Updating JBang configuration from " + file.getName());
//System.err.println(file + " configuration changed, checking jbang info");
- JBangProject jbp = getJBangProject(file.getProject(), monitor);
+ IProject project = file.getProject();
+ JBangProject jbp = getJBangProject(project, monitor);
if (jbp == null) {
return;
}
+
+ if (isJavaProject(project) && JBangClasspathUtils.isOnOutputLocation(JavaCore.create(project), file)) {
+ return;
+ }
+ monitor.setTaskName("Updating JBang configuration from " + file.getName());
+
jbp.setMainSourceFile(file);
var jbang = jbp.getRuntime();
@@ -424,10 +438,12 @@ public void synchronize(IFile file, IProgressMonitor monitor) throws CoreExcepti
});
}
}
-
}
- private String getSource(IFile file) throws JavaModelException {
+ private String getSource(IFile file) throws CoreException {
+ if (JBangFileUtils.isJBangBuildFile(file)) {
+ return ResourceUtil.getContent(file);
+ }
ICompilationUnit typeRoot = JavaCore.createCompilationUnitFrom(file);
return typeRoot.getBuffer().getContents();
}
diff --git a/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/project/SynchronizeJBangJob.java b/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/project/SynchronizeJBangJob.java
index 5cf1f51..0702e96 100644
--- a/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/project/SynchronizeJBangJob.java
+++ b/dev.jbang.eclipse.core/src/main/java/dev/jbang/eclipse/core/internal/project/SynchronizeJBangJob.java
@@ -2,6 +2,7 @@
import static dev.jbang.eclipse.core.internal.JBangClasspathUtils.hasAttribute;
import static dev.jbang.eclipse.core.internal.JBangClasspathUtils.isOnClasspath;
+import static dev.jbang.eclipse.core.internal.JBangClasspathUtils.isOnOutputLocation;
import static dev.jbang.eclipse.core.internal.JBangFileUtils.getPackageName;
import static dev.jbang.eclipse.core.internal.ProjectUtils.addJBangNature;
import static dev.jbang.eclipse.core.internal.ProjectUtils.addJavaNature;
@@ -66,6 +67,9 @@ public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
//check source folder
IJavaProject javaProject = JavaCore.create(project);
+ if (isOnOutputLocation(javaProject, file)) {
+ continue;
+ }
if (!isOnClasspath(javaProject, file) || newJavaProject) {
//TODO display wizard to configure build output?
configureJava(javaProject, file, monitor);
diff --git a/dev.jbang.eclipse.ls/src/main/java/dev/jbang/eclipse/ls/internal/JBangBuildSupport.java b/dev.jbang.eclipse.ls/src/main/java/dev/jbang/eclipse/ls/internal/JBangBuildSupport.java
index 1c5467b..4b0f1b9 100644
--- a/dev.jbang.eclipse.ls/src/main/java/dev/jbang/eclipse/ls/internal/JBangBuildSupport.java
+++ b/dev.jbang.eclipse.ls/src/main/java/dev/jbang/eclipse/ls/internal/JBangBuildSupport.java
@@ -4,6 +4,7 @@
import org.eclipse.core.resources.IResource;
import org.eclipse.jdt.ls.core.internal.managers.IBuildSupport;
+import dev.jbang.eclipse.core.internal.JBangFileUtils;
import dev.jbang.eclipse.core.internal.ProjectUtils;
@SuppressWarnings("restriction")
@@ -16,7 +17,7 @@ public boolean applies(IProject project) {
@Override
public boolean isBuildFile(IResource resource) {
- return false;
+ return JBangFileUtils.isJBangBuildFile(resource);
}
}
diff --git a/dev.jbang.eclipse.ls/src/main/java/dev/jbang/eclipse/ls/internal/JBangDelegateCommandHandler.java b/dev.jbang.eclipse.ls/src/main/java/dev/jbang/eclipse/ls/internal/JBangDelegateCommandHandler.java
index 9e511e6..3310d85 100644
--- a/dev.jbang.eclipse.ls/src/main/java/dev/jbang/eclipse/ls/internal/JBangDelegateCommandHandler.java
+++ b/dev.jbang.eclipse.ls/src/main/java/dev/jbang/eclipse/ls/internal/JBangDelegateCommandHandler.java
@@ -1,6 +1,6 @@
package dev.jbang.eclipse.ls.internal;
-import static dev.jbang.eclipse.core.internal.JBangFileUtils.isJBangFile;
+import static dev.jbang.eclipse.core.internal.JBangFileUtils.*;
import java.net.URI;
import java.net.URISyntaxException;
@@ -65,7 +65,7 @@ private Set collectFiles(Collection