Bug 574940: refactor Code completion
Change-Id: Ia6cd4e90df4388b4d8ed66172aa35484a519a53f
diff --git a/features/org.eclipse.ease.ui.feature/feature.xml b/features/org.eclipse.ease.ui.feature/feature.xml
index 3729105..8d00715 100644
--- a/features/org.eclipse.ease.ui.feature/feature.xml
+++ b/features/org.eclipse.ease.ui.feature/feature.xml
@@ -51,7 +51,6 @@
id="org.eclipse.ease.ui.completions.java"
download-size="0"
install-size="0"
- version="0.0.0"
- fragment="true"/>
+ version="0.0.0"/>
</feature>
diff --git a/plugins/org.eclipse.ease.lang.groovy/META-INF/MANIFEST.MF b/plugins/org.eclipse.ease.lang.groovy/META-INF/MANIFEST.MF
index daf15e6..0c1cb91 100644
--- a/plugins/org.eclipse.ease.lang.groovy/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.ease.lang.groovy/META-INF/MANIFEST.MF
@@ -4,7 +4,8 @@
Bundle-SymbolicName: org.eclipse.ease.lang.groovy;singleton:=true
Bundle-Version: 0.9.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Require-Bundle: org.eclipse.ease
+Require-Bundle: org.eclipse.ease,
+ org.eclipse.ease.ui
Bundle-Vendor: Eclipse.org
Export-Package: org.eclipse.ease.lang.groovy
Automatic-Module-Name: org.eclipse.ease.lang.groovy
diff --git a/plugins/org.eclipse.ease.lang.groovy/src/org/eclipse/ease/lang/groovy/GroovyCodeParser.java b/plugins/org.eclipse.ease.lang.groovy/src/org/eclipse/ease/lang/groovy/GroovyCodeParser.java
index e52947d..123a9a7 100644
--- a/plugins/org.eclipse.ease.lang.groovy/src/org/eclipse/ease/lang/groovy/GroovyCodeParser.java
+++ b/plugins/org.eclipse.ease.lang.groovy/src/org/eclipse/ease/lang/groovy/GroovyCodeParser.java
@@ -13,6 +13,9 @@
package org.eclipse.ease.lang.groovy;
import org.eclipse.ease.AbstractCodeParser;
+import org.eclipse.ease.ICompletionContext;
+import org.eclipse.ease.IScriptEngine;
+import org.eclipse.ease.ui.completion.BasicContext;
public class GroovyCodeParser extends AbstractCodeParser {
@@ -39,4 +42,10 @@
protected String getBlockCommentEndToken() {
return BLOCK_COMMENT_END;
}
+
+ @Override
+ public ICompletionContext getContext(IScriptEngine scriptEngine, Object resource, String contents, int position, int selectionRange) {
+ return (scriptEngine != null) ? new BasicContext(scriptEngine, contents, position)
+ : new BasicContext(GroovyHelper.getScriptType(), resource, contents, position);
+ }
}
\ No newline at end of file
diff --git a/plugins/org.eclipse.ease.lang.groovy/src/org/eclipse/ease/lang/groovy/GroovyHelper.java b/plugins/org.eclipse.ease.lang.groovy/src/org/eclipse/ease/lang/groovy/GroovyHelper.java
index 6ef1024..9bc9b0a 100644
--- a/plugins/org.eclipse.ease.lang.groovy/src/org/eclipse/ease/lang/groovy/GroovyHelper.java
+++ b/plugins/org.eclipse.ease.lang.groovy/src/org/eclipse/ease/lang/groovy/GroovyHelper.java
@@ -15,7 +15,24 @@
import java.util.regex.Pattern;
-public class GroovyHelper {
+import org.eclipse.ease.service.IScriptService;
+import org.eclipse.ease.service.ScriptService;
+import org.eclipse.ease.service.ScriptType;
+
+public final class GroovyHelper {
+
+ /** Script type identifier for JavaScript. Must match with the script type 'name' from plugin.xml. */
+ public static final String SCRIPT_TYPE_GROOVY = "Groovy";
+
+ /**
+ * Get the {@link ScriptType} for java script.
+ *
+ * @return script type definition
+ */
+ public static ScriptType getScriptType() {
+ final IScriptService scriptService = ScriptService.getInstance();
+ return scriptService.getAvailableScriptTypes().get(SCRIPT_TYPE_GROOVY);
+ }
public static boolean isSaveName(final String identifier) {
return Pattern.matches("[a-zA-Z_$][a-zA-Z0-9_$]*", identifier);
diff --git a/plugins/org.eclipse.ease.lang.javascript.ui/src/org/eclipse/ease/lang/javascript/ui/completion/JavaScriptEditorCompletionComputer.java b/plugins/org.eclipse.ease.lang.javascript.ui/src/org/eclipse/ease/lang/javascript/ui/completion/JavaScriptEditorCompletionComputer.java
index 196c12b..6731ee2 100644
--- a/plugins/org.eclipse.ease.lang.javascript.ui/src/org/eclipse/ease/lang/javascript/ui/completion/JavaScriptEditorCompletionComputer.java
+++ b/plugins/org.eclipse.ease.lang.javascript.ui/src/org/eclipse/ease/lang/javascript/ui/completion/JavaScriptEditorCompletionComputer.java
@@ -13,6 +13,7 @@
package org.eclipse.ease.lang.javascript.ui.completion;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -23,7 +24,7 @@
import org.eclipse.ease.service.IScriptService;
import org.eclipse.ease.service.ScriptType;
import org.eclipse.ease.ui.completion.CodeCompletionAggregator;
-import org.eclipse.ease.ui.completion.ICompletionProvider;
+import org.eclipse.ease.ui.completion.provider.ICompletionProvider;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
@@ -43,10 +44,6 @@
* JSDT JavaScript Editors. So all editors of this type share the same instance.
*/
public class JavaScriptEditorCompletionComputer implements IJavaCompletionProposalComputer {
- /**
- * {@link CodeCompletionAggregator} to handle the actual creation of proposals.
- */
- private final CodeCompletionAggregator fCompletionAggregator = new CodeCompletionAggregator();
/**
* Constructor sets up {@link CodeCompletionAggregator} and loads registered {@link ICompletionProvider}.
@@ -54,9 +51,6 @@
public JavaScriptEditorCompletionComputer() {
final IScriptService scriptService = PlatformUI.getWorkbench().getService(IScriptService.class);
final ScriptType scriptType = scriptService.getAvailableScriptTypes().get(JavaScriptHelper.SCRIPT_TYPE_JAVASCRIPT);
-
- fCompletionAggregator.setScriptType(scriptType);
- fCompletionAggregator.setCodeParser(scriptType.getCodeParser());
}
@Override
@@ -80,7 +74,10 @@
final int cursorPosition = context.getInvocationOffset();
final int selectionRange = context.getViewer().getSelectedRange().y;
- return fCompletionAggregator.getCompletionProposals(resource, relevantText, cursorPosition, selectionRange, monitor);
+
+ final CodeCompletionAggregator aggregator = new CodeCompletionAggregator(resource, JavaScriptHelper.getScriptType());
+
+ return new ArrayList<>(aggregator.getProposals(relevantText, cursorPosition, monitor));
} catch (final BadLocationException e) {
Logger.error(PluginConstants.PLUGIN_ID, "Failed to calculate proposals for JavaScript editor", e);
diff --git a/plugins/org.eclipse.ease.lang.javascript/src/org/eclipse/ease/lang/javascript/JavaScriptCodeParser.java b/plugins/org.eclipse.ease.lang.javascript/src/org/eclipse/ease/lang/javascript/JavaScriptCodeParser.java
index eb2ba8d..b2e0c38 100644
--- a/plugins/org.eclipse.ease.lang.javascript/src/org/eclipse/ease/lang/javascript/JavaScriptCodeParser.java
+++ b/plugins/org.eclipse.ease.lang.javascript/src/org/eclipse/ease/lang/javascript/JavaScriptCodeParser.java
@@ -12,11 +12,11 @@
*******************************************************************************/
package org.eclipse.ease.lang.javascript;
+import org.eclipse.ease.AbstractCodeParser;
import org.eclipse.ease.ICompletionContext;
import org.eclipse.ease.IScriptEngine;
-import org.eclipse.ease.ui.completion.AbstractCompletionParser;
-public class JavaScriptCodeParser extends AbstractCompletionParser {
+public class JavaScriptCodeParser extends AbstractCodeParser {
private static final String LINE_COMMENT = "//";
private static final String BLOCK_COMMENT_START = "/*";
@@ -44,9 +44,7 @@
@Override
public ICompletionContext getContext(IScriptEngine scriptEngine, Object resource, String contents, int position, int selectionRange) {
- final JavaScriptCompletionContext context = new JavaScriptCompletionContext(scriptEngine);
- context.calculateContext(resource, contents, position, selectionRange);
-
- return context;
+ return (scriptEngine != null) ? new JavaScriptCompletionContext(scriptEngine, contents, position)
+ : new JavaScriptCompletionContext(resource, contents, position);
}
}
diff --git a/plugins/org.eclipse.ease.lang.javascript/src/org/eclipse/ease/lang/javascript/JavaScriptCompletionContext.java b/plugins/org.eclipse.ease.lang.javascript/src/org/eclipse/ease/lang/javascript/JavaScriptCompletionContext.java
index a0c8070..4dff27a 100644
--- a/plugins/org.eclipse.ease.lang.javascript/src/org/eclipse/ease/lang/javascript/JavaScriptCompletionContext.java
+++ b/plugins/org.eclipse.ease.lang.javascript/src/org/eclipse/ease/lang/javascript/JavaScriptCompletionContext.java
@@ -14,41 +14,69 @@
package org.eclipse.ease.lang.javascript;
import org.eclipse.ease.IScriptEngine;
-import org.eclipse.ease.ui.completion.CompletionContext;
+import org.eclipse.ease.ui.completion.BasicContext;
+import org.eclipse.ease.ui.completion.tokenizer.IVariablesResolver;
+import org.eclipse.ease.ui.completion.tokenizer.InputTokenizer;
-public class JavaScriptCompletionContext extends CompletionContext {
+public class JavaScriptCompletionContext extends BasicContext {
- public JavaScriptCompletionContext(final IScriptEngine scriptEngine) {
- super(scriptEngine, JavaScriptHelper.getScriptType());
+ public JavaScriptCompletionContext(IScriptEngine scriptEngine, String contents, int position) {
+ super(scriptEngine, contents, position);
+ }
+
+ public JavaScriptCompletionContext(Object resource, String contents, int position) {
+ super(JavaScriptHelper.getScriptType(), resource, contents, position);
}
@Override
- protected boolean isLiteral(final char candidate) {
- for (final char literal : "'\"".toCharArray()) {
- if (candidate == literal)
- return true;
+ protected InputTokenizer getInputTokenizer() {
+ if (getScriptEngine() != null)
+ return new JavaScriptInputTokenizer(v -> {
+ final Object variable = getScriptEngine().getVariable(v);
+ return (variable == null) ? null : variable.getClass();
+ });
+
+ return new JavaScriptInputTokenizer();
+ }
+
+ private final class JavaScriptInputTokenizer extends InputTokenizer {
+
+ private static final String PACKAGES_PREFIX = "Packages.";
+
+ private JavaScriptInputTokenizer() {
+ super();
}
- return false;
- }
+ private JavaScriptInputTokenizer(IVariablesResolver variablesResolver) {
+ super(variablesResolver);
+ }
- @Override
- protected String simplifyCode() {
- final String code = super.simplifyCode();
- if (code.startsWith("Packages."))
- return code.substring("Packages.".length());
+ @Override
+ protected Class<?> getClass(String input) {
+ if (input.startsWith(PACKAGES_PREFIX))
+ return filterRhinoClasses(super.getClass(input.substring(PACKAGES_PREFIX.length())));
- return code;
- }
+ return filterRhinoClasses(super.getClass(input));
+ }
- @Override
- protected Class<? extends Object> getVariableClazz(final String name) {
- final Class<? extends Object> clazz = super.getVariableClazz(name);
+ private Class<?> filterRhinoClasses(Class<?> clazz) {
+ if ((clazz != null) && (clazz.getName().startsWith("org.mozilla.javascript")))
+ return null;
- // skip all rhino specific classes
- if ((clazz != null) && (clazz.getName().startsWith("org.mozilla.javascript")))
- return null;
+ return clazz;
+ }
- return clazz;
+ @Override
+ protected Package getPackage(String input) {
+ if (input.startsWith(PACKAGES_PREFIX))
+ return super.getPackage(input.substring(PACKAGES_PREFIX.length()));
+
+ return super.getPackage(input);
+ }
+
+ @Override
+ protected boolean isLiteral(final char candidate) {
+ return ('"' == candidate) || ('\'' == candidate);
+ }
}
}
diff --git a/plugins/org.eclipse.ease.lang.jvm.compiled/src/org/eclipse/ease/lang/jvm/compiled/JVMCompiledHeaderParser.java b/plugins/org.eclipse.ease.lang.jvm.compiled/src/org/eclipse/ease/lang/jvm/compiled/JVMCompiledHeaderParser.java
index 0812a6f..7c6feb9 100644
--- a/plugins/org.eclipse.ease.lang.jvm.compiled/src/org/eclipse/ease/lang/jvm/compiled/JVMCompiledHeaderParser.java
+++ b/plugins/org.eclipse.ease.lang.jvm.compiled/src/org/eclipse/ease/lang/jvm/compiled/JVMCompiledHeaderParser.java
@@ -13,6 +13,8 @@
package org.eclipse.ease.lang.jvm.compiled;
import org.eclipse.ease.AbstractCodeParser;
+import org.eclipse.ease.ICompletionContext;
+import org.eclipse.ease.IScriptEngine;
public class JVMCompiledHeaderParser extends AbstractCodeParser {
@@ -39,4 +41,9 @@
protected boolean hasBlockComment() {
return true;
}
+
+ @Override
+ public ICompletionContext getContext(IScriptEngine scriptEngine, Object resource, String contents, int position, int selectionRange) {
+ return null;
+ }
}
diff --git a/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/PythonCodeParser.java b/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/PythonCodeParser.java
index d735696..74c35c4 100644
--- a/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/PythonCodeParser.java
+++ b/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/PythonCodeParser.java
@@ -44,9 +44,7 @@
@Override
public ICompletionContext getContext(IScriptEngine scriptEngine, Object resource, String contents, int position, int selectionRange) {
- final PythonCompletionContext context = new PythonCompletionContext(scriptEngine);
- context.calculateContext(resource, contents, position, selectionRange);
-
- return context;
+ return (scriptEngine != null) ? new PythonCompletionContext(scriptEngine, contents, position)
+ : new PythonCompletionContext(resource, contents, position);
}
}
diff --git a/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/PythonCompletionContext.java b/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/PythonCompletionContext.java
index 0a7c399..79b45ce 100644
--- a/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/PythonCompletionContext.java
+++ b/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/PythonCompletionContext.java
@@ -14,30 +14,58 @@
package org.eclipse.ease.lang.python;
import org.eclipse.ease.IScriptEngine;
-import org.eclipse.ease.ui.completion.CompletionContext;
+import org.eclipse.ease.ui.completion.BasicContext;
+import org.eclipse.ease.ui.completion.tokenizer.IVariablesResolver;
+import org.eclipse.ease.ui.completion.tokenizer.InputTokenizer;
-public class PythonCompletionContext extends CompletionContext {
+public class PythonCompletionContext extends BasicContext {
- public PythonCompletionContext(IScriptEngine scriptEngine) {
- super(scriptEngine, PythonHelper.getScriptType());
+ public PythonCompletionContext(IScriptEngine scriptEngine, String contents, int position) {
+ super(scriptEngine, contents, position);
}
- @Override
- protected String simplifyCode() {
- final String code = super.simplifyCode();
-
- // XXX: API needs a review here, these simplifications are Py4J specific, not
- // all Python code.
- if (code.startsWith("jvm.gateway."))
- return code.substring("jvm.gateway.".length());
- if (code.startsWith("gateway."))
- return code.substring("gateway.".length());
-
- return code;
+ public PythonCompletionContext(Object resource, String contents, int position) {
+ super(PythonHelper.getScriptType(), resource, contents, position);
}
+ // @Override
+ // protected String simplifyCode() {
+ // final String code = super.simplifyCode();
+ //
+ // // XXX: API needs a review here, these simplifications are Py4J specific, not
+ // // all Python code.
+ // if (code.startsWith("jvm.gateway."))
+ // return code.substring("jvm.gateway.".length());
+ // if (code.startsWith("gateway."))
+ // return code.substring("gateway.".length());
+ //
+ // return code;
+ // }
+
@Override
- protected boolean isLiteral(final char candidate) {
- return "'\"".indexOf(candidate) != -1;
+ protected InputTokenizer getInputTokenizer() {
+ if (getScriptEngine() != null)
+ return new PythonInputTokenizer(v -> {
+ final Object variable = getScriptEngine().getVariable(v);
+ return variable == null ? null : variable.getClass();
+ });
+
+ return new PythonInputTokenizer();
+ }
+
+ private final class PythonInputTokenizer extends InputTokenizer {
+
+ private PythonInputTokenizer() {
+ super();
+ }
+
+ private PythonInputTokenizer(IVariablesResolver variablesResolver) {
+ super(variablesResolver);
+ }
+
+ @Override
+ protected boolean isLiteral(final char candidate) {
+ return ('"' == candidate) || ('\'' == candidate);
+ }
}
}
diff --git a/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/ui/completion/PythonCompletionProviderWrapper.java b/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/ui/completion/PythonCompletionProviderWrapper.java
index 2ed64ca..9e18a95 100644
--- a/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/ui/completion/PythonCompletionProviderWrapper.java
+++ b/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/ui/completion/PythonCompletionProviderWrapper.java
@@ -10,6 +10,7 @@
* Contributors:
* Martin Kloesch - initial API and implementation
*******************************************************************************/
+
package org.eclipse.ease.lang.python.ui.completion;
import java.io.InputStream;
@@ -21,8 +22,8 @@
import org.eclipse.ease.Logger;
import org.eclipse.ease.lang.python.Activator;
import org.eclipse.ease.lang.python.debugger.ResourceHelper;
-import org.eclipse.ease.ui.completion.ICompletionProvider;
import org.eclipse.ease.ui.completion.ScriptCompletionProposal;
+import org.eclipse.ease.ui.completion.provider.ICompletionProvider;
/**
* {@link ICompletionProvider} dispatching actual completion calculation to Python.
@@ -43,13 +44,8 @@
fPythonProvider = provider;
}
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.ease.ui.completion.ICompletionProvider#getProposals(org. eclipse.ease.ICompletionContext)
- */
@Override
- public Collection<? extends ScriptCompletionProposal> getProposals(ICompletionContext context) {
+ public Collection<ScriptCompletionProposal> getProposals(ICompletionContext context) {
if (!isActive(context)) {
return new ArrayList<>();
}
@@ -78,11 +74,6 @@
return new ArrayList<>();
}
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.ease.ui.completion.ICompletionProvider#isActive(org.eclipse. ease.ICompletionContext)
- */
@Override
public boolean isActive(ICompletionContext context) {
if (fPythonProvider == null) {
@@ -91,5 +82,4 @@
return fPythonProvider.isActive(context);
}
}
-
}
diff --git a/plugins/org.eclipse.ease.lang.ruby/src/org/eclipse/ease/lang/ruby/RubyCodeParser.java b/plugins/org.eclipse.ease.lang.ruby/src/org/eclipse/ease/lang/ruby/RubyCodeParser.java
index 5a17c51..07044f7 100644
--- a/plugins/org.eclipse.ease.lang.ruby/src/org/eclipse/ease/lang/ruby/RubyCodeParser.java
+++ b/plugins/org.eclipse.ease.lang.ruby/src/org/eclipse/ease/lang/ruby/RubyCodeParser.java
@@ -13,6 +13,8 @@
package org.eclipse.ease.lang.ruby;
import org.eclipse.ease.AbstractCodeParser;
+import org.eclipse.ease.ICompletionContext;
+import org.eclipse.ease.IScriptEngine;
public class RubyCodeParser extends AbstractCodeParser {
@@ -39,4 +41,9 @@
protected String getBlockCommentEndToken() {
return BLOCK_COMMENT_END;
}
+
+ @Override
+ public ICompletionContext getContext(IScriptEngine scriptEngine, Object resource, String contents, int position, int selectionRange) {
+ return null;
+ }
}
\ No newline at end of file
diff --git a/plugins/org.eclipse.ease.ui.completions.java/META-INF/MANIFEST.MF b/plugins/org.eclipse.ease.ui.completions.java/META-INF/MANIFEST.MF
index 4f30ffc..763a6ac 100644
--- a/plugins/org.eclipse.ease.ui.completions.java/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.ease.ui.completions.java/META-INF/MANIFEST.MF
@@ -4,12 +4,16 @@
Bundle-SymbolicName: org.eclipse.ease.ui.completions.java;singleton:=true
Bundle-Version: 0.9.0.qualifier
Bundle-Vendor: Eclipse.org
-Fragment-Host: org.eclipse.ease.ui;bundle-version="0.9.0"
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Require-Bundle: org.eclipse.jdt.ui;bundle-version="[3.7.2,4.0.0)",
org.eclipse.jdt.core;bundle-version="[3.7.3,4.0.0)",
- org.objectweb.asm;bundle-version="[3.3.1,10.0.0)"
-Export-Package: org.eclipse.ease.ui.completions.java.help.handlers;x-internal:=true,
- org.eclipse.ease.ui.completions.java.help.hovers.internal;x-internal:=true,
- org.eclipse.ease.ui.completions.java.provider;x-internal:=true
+ org.objectweb.asm;bundle-version="[3.3.1,10.0.0)",
+ org.eclipse.ease.ui,
+ org.eclipse.core.resources,
+ org.eclipse.core.runtime;bundle-version="3.22.0",
+ org.eclipse.jface.text;bundle-version="3.18.0",
+ org.eclipse.jface;bundle-version="3.22.200",
+ org.eclipse.ease
Automatic-Module-Name: org.eclipse.ease.ui.completions.java
+Bundle-ActivationPolicy: lazy
+Bundle-ClassPath: .
diff --git a/plugins/org.eclipse.ease.ui.completions.java/build.properties b/plugins/org.eclipse.ease.ui.completions.java/build.properties
index 9bd91bb..b7ceb4c 100644
--- a/plugins/org.eclipse.ease.ui.completions.java/build.properties
+++ b/plugins/org.eclipse.ease.ui.completions.java/build.properties
@@ -2,6 +2,7 @@
output.. = bin/
bin.includes = META-INF/,\
.,\
- fragment.xml,\
+ plugin.xml,\
icons/,\
- about.html
+ about.html,\
+ resources/
\ No newline at end of file
diff --git a/plugins/org.eclipse.ease.ui.completions.java/fragment.xml b/plugins/org.eclipse.ease.ui.completions.java/plugin.xml
similarity index 96%
rename from plugins/org.eclipse.ease.ui.completions.java/fragment.xml
rename to plugins/org.eclipse.ease.ui.completions.java/plugin.xml
index b07ead4..f333a21 100644
--- a/plugins/org.eclipse.ease.ui.completions.java/fragment.xml
+++ b/plugins/org.eclipse.ease.ui.completions.java/plugin.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
-<fragment>
+<plugin>
<extension
point="org.eclipse.ease.ui.codeCompletionProvider">
<codeCompletionProvider
@@ -14,4 +14,4 @@
</codeCompletionProvider>
</extension>
-</fragment>
+</plugin>
diff --git a/plugins/org.eclipse.ease.ui/resources/java10 classes.txt b/plugins/org.eclipse.ease.ui.completions.java/resources/java10 classes.txt
similarity index 100%
rename from plugins/org.eclipse.ease.ui/resources/java10 classes.txt
rename to plugins/org.eclipse.ease.ui.completions.java/resources/java10 classes.txt
diff --git a/plugins/org.eclipse.ease.ui/resources/java11 classes.txt b/plugins/org.eclipse.ease.ui.completions.java/resources/java11 classes.txt
similarity index 100%
rename from plugins/org.eclipse.ease.ui/resources/java11 classes.txt
rename to plugins/org.eclipse.ease.ui.completions.java/resources/java11 classes.txt
diff --git a/plugins/org.eclipse.ease.ui/resources/java12 classes.txt b/plugins/org.eclipse.ease.ui.completions.java/resources/java12 classes.txt
similarity index 100%
rename from plugins/org.eclipse.ease.ui/resources/java12 classes.txt
rename to plugins/org.eclipse.ease.ui.completions.java/resources/java12 classes.txt
diff --git a/plugins/org.eclipse.ease.ui/resources/java7 classes.txt b/plugins/org.eclipse.ease.ui.completions.java/resources/java7 classes.txt
similarity index 100%
rename from plugins/org.eclipse.ease.ui/resources/java7 classes.txt
rename to plugins/org.eclipse.ease.ui.completions.java/resources/java7 classes.txt
diff --git a/plugins/org.eclipse.ease.ui/resources/java8 classes.txt b/plugins/org.eclipse.ease.ui.completions.java/resources/java8 classes.txt
similarity index 100%
rename from plugins/org.eclipse.ease.ui/resources/java8 classes.txt
rename to plugins/org.eclipse.ease.ui.completions.java/resources/java8 classes.txt
diff --git a/plugins/org.eclipse.ease.ui/resources/java9 classes.txt b/plugins/org.eclipse.ease.ui.completions.java/resources/java9 classes.txt
similarity index 100%
rename from plugins/org.eclipse.ease.ui/resources/java9 classes.txt
rename to plugins/org.eclipse.ease.ui.completions.java/resources/java9 classes.txt
diff --git a/plugins/org.eclipse.ease.ui.completions.java/src/org/eclipse/ease/ui/completions/java/EaseUICompletionsJavaFragment.java b/plugins/org.eclipse.ease.ui.completions.java/src/org/eclipse/ease/ui/completions/java/EaseUICompletionsJavaFragment.java
deleted file mode 100644
index 67443ef..0000000
--- a/plugins/org.eclipse.ease.ui.completions.java/src/org/eclipse/ease/ui/completions/java/EaseUICompletionsJavaFragment.java
+++ /dev/null
@@ -1,18 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2016 Kichwa Coders and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v2.0
- * which accompanies this distribution, and is available at
- * https://www.eclipse.org/legal/epl-2.0/
- *
- * SPDX-License_Identifier: EPL-2.0
- *
- * Contributors:
- * Jonah Graham (Kichwa Coders) - initial API and implementation
- *******************************************************************************/
-package org.eclipse.ease.ui.completions.java;
-
-public class EaseUICompletionsJavaFragment {
-
- public static final String FRAGMENT_ID = "org.eclipse.ease.ui.completions.java";
-}
diff --git a/plugins/org.eclipse.ease.ui.completions.java/src/org/eclipse/ease/ui/completions/java/provider/JavaClassCompletionProvider.java b/plugins/org.eclipse.ease.ui.completions.java/src/org/eclipse/ease/ui/completions/java/provider/JavaClassCompletionProvider.java
index e7b2632..0a7a253 100644
--- a/plugins/org.eclipse.ease.ui.completions.java/src/org/eclipse/ease/ui/completions/java/provider/JavaClassCompletionProvider.java
+++ b/plugins/org.eclipse.ease.ui.completions.java/src/org/eclipse/ease/ui/completions/java/provider/JavaClassCompletionProvider.java
@@ -12,48 +12,92 @@
*******************************************************************************/
package org.eclipse.ease.ui.completions.java.provider;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.URL;
import java.util.Collection;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
import java.util.Map.Entry;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-import java.util.regex.Pattern;
-import org.eclipse.core.runtime.FileLocator;
import org.eclipse.ease.ICompletionContext;
-import org.eclipse.ease.ICompletionContext.Type;
-import org.eclipse.ease.Logger;
-import org.eclipse.ease.ui.completion.AbstractCompletionProvider;
import org.eclipse.ease.ui.completion.IHelpResolver;
import org.eclipse.ease.ui.completion.IImageResolver;
import org.eclipse.ease.ui.completion.ScriptCompletionProposal;
-import org.eclipse.ease.ui.completions.java.EaseUICompletionsJavaFragment;
+import org.eclipse.ease.ui.completion.provider.AbstractCompletionProvider;
+import org.eclipse.ease.ui.completion.tokenizer.InputTokenizer;
+import org.eclipse.ease.ui.completion.tokenizer.TokenList;
import org.eclipse.ease.ui.completions.java.help.handlers.JavaClassHelpResolver;
import org.eclipse.ease.ui.completions.java.provider.JavaMethodCompletionProvider.JDTImageResolver;
-import org.eclipse.ease.ui.tools.Timer;
import org.eclipse.jdt.ui.ISharedImages;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.StyledString;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
public class JavaClassCompletionProvider extends AbstractCompletionProvider {
- private class JavaClassImageResolver extends DescriptorImageResolver {
+ @Override
+ public boolean isActive(final ICompletionContext context) {
+ return (super.isActive(context) && (isPackage(context))) || (isClass(context))
+ // also activate when no package is provided and the first letter is capitalized and we see at least 3 characters
+ || ((context.getFilter().length() >= 3) && (Character.isUpperCase(context.getFilter().charAt(0))));
+ }
+
+ private boolean isClass(ICompletionContext context) {
+ return new TokenList(context.getTokens()).getFromLast(Class.class).size() == 1;
+ }
+
+ private boolean isPackage(ICompletionContext context) {
+ final TokenList tokens = new TokenList(context.getTokens()).getFromLast(Package.class);
+ if (!tokens.isEmpty()) {
+ tokens.remove(0);
+ tokens.removeIfMatches(0, ".");
+
+ return (tokens.isEmpty()) || InputTokenizer.isTextFilter(tokens.get(0));
+ }
+
+ return false;
+ }
+
+ @Override
+ protected void prepareProposals(final ICompletionContext context) {
+
+ final String filter = context.getFilter();
+
+ if (isPackage(context)) {
+ final Collection<String> candidates = JavaResources.getInstance().getClasses(getPackageName(context));
+
+ for (final String candidate : candidates) {
+ if (candidate.startsWith(filter)) {
+ final IHelpResolver helpResolver = new JavaClassHelpResolver(getPackageName(context), candidate);
+ final IImageResolver imageResolver = new JavaClassImageResolver(getPackageName(context), candidate);
+
+ addProposal(candidate, candidate, imageResolver, ScriptCompletionProposal.ORDER_CLASS, helpResolver);
+ }
+ }
+
+ } else {
+ // no package provided, look in all packages for matching class
+
+ for (final Entry<String, Collection<String>> packageEntry : JavaResources.getInstance().getClasses().entrySet()) {
+ for (final String candidate : packageEntry.getValue()) {
+ if (candidate.startsWith(filter)) {
+ final IHelpResolver helpResolver = new JavaClassHelpResolver(packageEntry.getKey(), candidate);
+ final IImageResolver imageResolver = new JavaClassImageResolver(packageEntry.getKey(), candidate);
+
+ final StyledString styledString = new StyledString(candidate);
+ styledString.append(" - " + packageEntry.getKey(), StyledString.QUALIFIER_STYLER);
+
+ addProposal(styledString, packageEntry.getKey() + "." + candidate, imageResolver, ScriptCompletionProposal.ORDER_CLASS, helpResolver);
+ }
+ }
+ }
+ }
+ }
+
+ private String getPackageName(ICompletionContext context) {
+ return ((Package) (new TokenList(context.getTokens()).getFromLast(Package.class).get(0))).getName();
+ }
+
+ private static final class JavaClassImageResolver extends DescriptorImageResolver {
private final String fPackageName;
private final String fClassName;
- public JavaClassImageResolver(final String packageName, final String className) {
+ private JavaClassImageResolver(final String packageName, final String className) {
fPackageName = packageName;
fClassName = className;
}
@@ -75,232 +119,4 @@
return JDTImageResolver.getDescriptor(ISharedImages.IMG_OBJS_CLASS);
}
}
-
- /** Maps Package name -> contained classes. */
- private static Map<String, Collection<String>> CLASSES = null;
-
- @Override
- public boolean isActive(final ICompletionContext context) {
- return super.isActive(context) && ((context.getType() == Type.PACKAGE)
- // also activate when no package is provided and the first letter is capitalized and we see at least 3 characters
- || ((context.getType() == Type.NONE) && (context.getFilter().length() >= 3) && (Character.isUpperCase(context.getFilter().charAt(0)))));
- }
-
- @Override
- protected void prepareProposals(final ICompletionContext context) {
-
- if (getClasses().get(context.getPackage()) != null) {
- // dedicated package provided, only query this package
-
- for (final String className : getClasses().get(context.getPackage())) {
- if (matchesFilter(className)) {
-
- // add class name
- final IHelpResolver helpResolver = new JavaClassHelpResolver(context.getPackage(), className);
-
- // retrieve image
- final IImageResolver imageResolver = new JavaClassImageResolver(context.getPackage(), className);
-
- addProposal(className, className, imageResolver, ScriptCompletionProposal.ORDER_CLASS, helpResolver);
- }
- }
-
- } else {
- // no package provided, look in all packages for matching class
- final String filter = context.getFilter();
- final Pattern classPattern = Pattern.compile(filter + ".*");
-
- for (final Entry<String, Collection<String>> packageEntry : getClasses().entrySet()) {
- for (final String candidate : packageEntry.getValue()) {
- if (classPattern.matcher(candidate).matches()) {
- // add class proposal
- // add class name
- final IHelpResolver helpResolver = new JavaClassHelpResolver(packageEntry.getKey(), candidate);
-
- // retrieve image
- final IImageResolver imageResolver = new JavaClassImageResolver(packageEntry.getKey(), candidate);
-
- final StyledString styledString = new StyledString(candidate);
- styledString.append(" - " + packageEntry.getKey(), StyledString.QUALIFIER_STYLER);
-
- addProposal(styledString, packageEntry.getKey() + "." + candidate, imageResolver, ScriptCompletionProposal.ORDER_CLASS, helpResolver);
- }
- }
- }
- }
- }
-
- private static Map<String, Collection<String>> getClasses() {
- if (CLASSES == null) {
- CLASSES = new HashMap<>();
-
- Timer timer = new Timer();
-
- // read java classes
- try (BufferedReader reader = JavaPackagesCompletionProvider.getJavaClassDefinitions()) {
- String fullQualifiedName;
- while ((fullQualifiedName = reader.readLine()) != null) {
- addClass(fullQualifiedName);
- }
-
- reader.close();
-
- } catch (final IOException e) {
- Logger.error(EaseUICompletionsJavaFragment.FRAGMENT_ID, "Cannot read class list for code completion", e);
- }
-
- Logger.trace(EaseUICompletionsJavaFragment.FRAGMENT_ID, TRACE_CODE_COMPLETION, "Load java classes took: " + timer.getMilliSeconds() + " ms");
-
- // read eclipse classes
- timer = new Timer();
-
- final BundleContext context = FrameworkUtil.getBundle(JavaClassCompletionProvider.class).getBundleContext();
- for (final Bundle bundle : context.getBundles()) {
- final Collection<String> exportedPackages = JavaPackagesCompletionProvider.getExportedPackages(bundle);
-
- // first look for class signatures in manifest, so we do not need to parse the whole bundle
- boolean signedContent = false;
- try {
- final URL manifest = bundle.getEntry("/META-INF/MANIFEST.MF");
- final InputStream inputStream = manifest.openConnection().getInputStream();
- final BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
- String line;
- while ((line = reader.readLine()) != null) {
- if ((line.startsWith("Name:")) && (line.endsWith(".class")) && (!line.contains("$")) && (!line.contains("package-info"))) {
- final String fullQualifiedName = line.substring(5, line.length() - 6).trim().replace('/', '.');
- final String packageName = fullQualifiedName.contains(".") ? fullQualifiedName.substring(0, fullQualifiedName.lastIndexOf('.'))
- : "";
- if (exportedPackages.contains(packageName))
- addClass(fullQualifiedName);
-
- signedContent = true;
- }
- }
- } catch (final IOException e) {
- Logger.error(EaseUICompletionsJavaFragment.FRAGMENT_ID, "Could not parse manifest of bundle \"" + bundle.getBundleId() + "\"", e);
- }
-
- if (!signedContent) {
- // we did not find a signed bundle, try to parse the bundle
-
- try {
- final File bundleFile = FileLocator.getBundleFile(bundle);
-
- if (bundleFile.isDirectory()) {
- // bundle stored as folder
- for (final String packageName : exportedPackages) {
- final String packagePath = bundleFile.getAbsolutePath() + File.separatorChar + packageName.replace('.', File.separatorChar);
- final File packageFile = new File(packagePath);
- if (packageFile.isDirectory()) {
- for (final String candidate : packageFile.list()) {
- if ((candidate.endsWith(".class")) && (!candidate.contains("$")))
- addClass(packageName + "." + candidate.substring(0, candidate.length() - 6));
- }
- }
- }
-
- } else if (bundleFile.isFile()) {
- // bundle stored as jar
- final JarFile jarFile = new JarFile(bundleFile);
- final Enumeration<JarEntry> entries = jarFile.entries();
- while (entries.hasMoreElements()) {
- final String candidate = entries.nextElement().getName();
- if ((candidate.endsWith(".class")) && (!candidate.contains("$"))) {
- final String fullQualifiedName = candidate.substring(0, candidate.length() - 6).replace('/', '.');
- final String packageName = fullQualifiedName.contains(".")
- ? fullQualifiedName.substring(0, fullQualifiedName.lastIndexOf('.'))
- : "";
- if (exportedPackages.contains(packageName))
- addClass(fullQualifiedName);
- }
- }
-
- jarFile.close();
-
- }
- } catch (final IOException e) {
- Logger.error(EaseUICompletionsJavaFragment.FRAGMENT_ID, "Cannot resolve location for bundle \"" + bundle.getBundleId() + "\"", e);
- }
- }
- }
- Logger.trace(EaseUICompletionsJavaFragment.FRAGMENT_ID, TRACE_CODE_COMPLETION, "Load eclipse classes took: " + timer.getMilliSeconds() + " ms");
- }
-
- return CLASSES;
- }
-
- /**
- * @param packageName
- * @param substring
- */
- private static void addClass(final String fullQualifiedName) {
-
- final String packageName = getPackage(fullQualifiedName);
-
- if (!CLASSES.containsKey(packageName))
- CLASSES.put(packageName, new HashSet<String>());
-
- CLASSES.get(packageName).add(fullQualifiedName.substring(packageName.length() + 1));
- }
-
- /**
- * @param className
- * @return
- */
- private static String getPackage(final String className) {
- final int lastDot = className.lastIndexOf('.');
- if (lastDot == -1)
- return null;
-
- final String candidate = className.substring(0, lastDot);
- if (JavaPackagesCompletionProvider.containsPackage(candidate))
- return candidate;
-
- return getPackage(candidate);
- }
-
- /**
- * Helper method to extract class names from public javadoc. Not needed for productive use. May be helpful when new java version gets released.
- */
- // public static void main(final String[] args) {
- // // read java packages
- // try {
- // URL url = new URL("https://docs.oracle.com/javase/6/docs/api/allclasses-frame.html");
- // System.out.print("fetching data ... ");
- // InputStream inputStream = url.openConnection().getInputStream();
- // String htmlContent = StringTools.toString(inputStream);
- // inputStream.close();
- // System.out.println("done");
- //
- // int start = htmlContent.indexOf("<body>");
- // int end = htmlContent.indexOf("</body>");
- //
- // // preparing data
- // htmlContent = htmlContent.substring(start, end + 7);
- // htmlContent = htmlContent.replaceAll(" ", " ");
- //
- // System.out.print("parsing data ... ");
- // XMLMemento root = XMLMemento.createReadRoot(new StringReader(htmlContent));
- //
- // File file = new File("/tmp/Java 6 classes.txt");
- // if (!file.exists())
- // file.createNewFile();
- //
- // FileOutputStream outputStream = new FileOutputStream(file);
- // for (IMemento listNode : root.getChild("div").getChild("ul").getChildren("li")) {
- // String className = listNode.getChild("a").getString("href").replace('/', '.').replace(".html", "");
- // outputStream.write((className + "\n").getBytes());
- // }
- // outputStream.close();
- //
- // System.out.println("done");
- //
- // } catch (IOException e) {
- // Logger.logError("Cannot read package list for code completion", e);
- // } catch (WorkbenchException e) {
- // // TODO handle this exception (but for now, at least know it happened)
- // throw new RuntimeException(e);
- //
- // }
- // }
}
diff --git a/plugins/org.eclipse.ease.ui.completions.java/src/org/eclipse/ease/ui/completions/java/provider/JavaMethodCompletionProvider.java b/plugins/org.eclipse.ease.ui.completions.java/src/org/eclipse/ease/ui/completions/java/provider/JavaMethodCompletionProvider.java
index 06c4542..8ca0e89 100644
--- a/plugins/org.eclipse.ease.ui.completions.java/src/org/eclipse/ease/ui/completions/java/provider/JavaMethodCompletionProvider.java
+++ b/plugins/org.eclipse.ease.ui.completions.java/src/org/eclipse/ease/ui/completions/java/provider/JavaMethodCompletionProvider.java
@@ -10,6 +10,7 @@
* Contributors:
* Christian Pontesegger - initial API and implementation
*******************************************************************************/
+
package org.eclipse.ease.ui.completions.java.provider;
import java.lang.reflect.Field;
@@ -18,12 +19,13 @@
import java.lang.reflect.Parameter;
import org.eclipse.ease.ICompletionContext;
-import org.eclipse.ease.ICompletionContext.Type;
import org.eclipse.ease.ui.Activator;
-import org.eclipse.ease.ui.completion.AbstractCompletionProvider;
import org.eclipse.ease.ui.completion.IHelpResolver;
import org.eclipse.ease.ui.completion.IImageResolver;
import org.eclipse.ease.ui.completion.ScriptCompletionProposal;
+import org.eclipse.ease.ui.completion.provider.AbstractCompletionProvider;
+import org.eclipse.ease.ui.completion.tokenizer.InputTokenizer;
+import org.eclipse.ease.ui.completion.tokenizer.TokenList;
import org.eclipse.ease.ui.completions.java.help.handlers.JavaFieldHelpResolver;
import org.eclipse.ease.ui.completions.java.help.handlers.JavaMethodHelpResolver;
import org.eclipse.jdt.ui.ISharedImages;
@@ -33,6 +35,105 @@
public class JavaMethodCompletionProvider extends AbstractCompletionProvider {
+ @Override
+ public boolean isActive(final ICompletionContext context) {
+ return super.isActive(context) && isJavaClassContext(context);
+ }
+
+ @Override
+ protected void prepareProposals(final ICompletionContext context) {
+ final boolean isStatic = isStaticClassContext(context);
+
+ final Class<? extends Object> clazz = getJavaClass(context);
+ final String filter = context.getFilter();
+
+ for (final Method method : clazz.getMethods()) {
+ if ((isStatic) != (Modifier.isStatic(method.getModifiers())))
+ continue;
+
+ if (method.getName().startsWith(filter))
+ addMethodProposal(method);
+ }
+
+ for (final Field field : clazz.getFields()) {
+ if ((isStatic) != (Modifier.isStatic(field.getModifiers())))
+ continue;
+
+ if (field.getName().startsWith(filter))
+ addFieldProposal(field);
+ }
+ }
+
+ private void addFieldProposal(Field field) {
+ final IHelpResolver helpResolver = new JavaFieldHelpResolver(field);
+
+ final StyledString styledString = new StyledString(field.getName() + " : " + field.getType().getSimpleName());
+ styledString.append(" - " + field.getDeclaringClass().getSimpleName(), StyledString.QUALIFIER_STYLER);
+
+ final IImageResolver imageResolver = Modifier.isStatic(field.getModifiers())
+ ? new DescriptorImageResolver(Activator.getImageDescriptor(Activator.PLUGIN_ID, "/icons/eobj16/static_field.png"))
+ : new JDTImageResolver(ISharedImages.IMG_FIELD_PUBLIC);
+
+ addProposal(styledString, field.getName(), imageResolver, ScriptCompletionProposal.ORDER_FIELD, helpResolver);
+ }
+
+ private void addMethodProposal(Method method) {
+ final IHelpResolver helpResolver = new JavaMethodHelpResolver(method);
+
+ final StyledString styledString = new StyledString(method.getName() + "(" + getMethodSignature(method) + ") : " + getMethodReturnType(method));
+ styledString.append(" - " + method.getDeclaringClass().getSimpleName(), StyledString.QUALIFIER_STYLER);
+
+ final IImageResolver imageResolver = Modifier.isStatic(method.getModifiers())
+ ? new DescriptorImageResolver(Activator.getImageDescriptor(Activator.PLUGIN_ID, "/icons/eobj16/static_function.png"))
+ : new JDTImageResolver(ISharedImages.IMG_OBJS_PUBLIC);
+
+ if (method.getParameterTypes().length > 0)
+ addProposal(styledString, method.getName() + "(", imageResolver, ScriptCompletionProposal.ORDER_METHOD, helpResolver);
+ else
+ addProposal(styledString, method.getName() + "()", imageResolver, ScriptCompletionProposal.ORDER_METHOD, helpResolver);
+ }
+
+ private boolean isJavaClassContext(ICompletionContext context) {
+ final TokenList tokens = new TokenList(context.getTokens()).getFromLast(Class.class);
+ if (!tokens.isEmpty()) {
+ tokens.remove(0);
+ tokens.removeIfMatches(0, "()");
+ tokens.removeIfMatches(0, ".");
+
+ return (tokens.isEmpty()) || ((tokens.size() == 1) && (!InputTokenizer.isDelimiter(tokens.get(0))));
+ }
+
+ return false;
+ }
+
+ private boolean isStaticClassContext(ICompletionContext context) {
+ final TokenList tokens = new TokenList(context.getTokens()).getFromLast(Class.class);
+ return (tokens.size() == 1) || (!"()".equals(tokens.get(1)));
+ }
+
+ private Class<?> getJavaClass(ICompletionContext context) {
+ return (Class<?>) new TokenList(context.getTokens()).getFromLast(Class.class).get(0);
+ }
+
+ private String getMethodReturnType(final Method method) {
+ final Class<?> returnType = method.getReturnType();
+ return (returnType == null) ? "void" : returnType.getSimpleName();
+ }
+
+ private String getMethodSignature(final Method method) {
+ final StringBuilder result = new StringBuilder();
+
+ for (final Parameter parameter : method.getParameters()) {
+ if (result.length() > 0)
+ result.append(", ");
+
+ result.append(parameter.getType().getSimpleName());
+ result.append(' ').append(parameter.getName());
+ }
+
+ return result.toString();
+ }
+
public static class JDTImageResolver extends DescriptorImageResolver {
private final String fImageIdentifier;
@@ -52,73 +153,4 @@
return JavaUI.getSharedImages().getImageDescriptor(imageIdentifier);
}
}
-
- @Override
- public boolean isActive(final ICompletionContext context) {
- return context.getReferredClazz() != null;
- }
-
- @Override
- protected void prepareProposals(final ICompletionContext context) {
- final Class<? extends Object> clazz = context.getReferredClazz();
-
- for (final Method method : clazz.getMethods()) {
- if ((context.getType() == Type.STATIC_CLASS) && (!Modifier.isStatic(method.getModifiers())))
- continue;
-
- if (matchesFilterIgnoreCase(method.getName())) {
-
- final IHelpResolver helpResolver = new JavaMethodHelpResolver(method);
-
- final StyledString styledString = new StyledString(method.getName() + "(" + getMethodSignature(method) + ") : " + getMethodReturnType(method));
- styledString.append(" - " + method.getDeclaringClass().getSimpleName(), StyledString.QUALIFIER_STYLER);
-
- final IImageResolver imageResolver = Modifier.isStatic(method.getModifiers())
- ? new DescriptorImageResolver(Activator.getImageDescriptor(Activator.PLUGIN_ID, "/icons/eobj16/static_function.png"))
- : new JDTImageResolver(ISharedImages.IMG_OBJS_PUBLIC);
-
- if (method.getParameterTypes().length > 0)
- addProposal(styledString, method.getName() + "(", imageResolver, ScriptCompletionProposal.ORDER_METHOD, helpResolver);
- else
- addProposal(styledString, method.getName() + "()", imageResolver, ScriptCompletionProposal.ORDER_METHOD, helpResolver);
- }
- }
-
- for (final Field field : clazz.getFields()) {
- if ((context.getType() == Type.STATIC_CLASS) && (!Modifier.isStatic(field.getModifiers())))
- continue;
-
- if (matchesFilterIgnoreCase(field.getName())) {
- final IHelpResolver helpResolver = new JavaFieldHelpResolver(field);
-
- final StyledString styledString = new StyledString(field.getName() + " : " + field.getType().getSimpleName());
- styledString.append(" - " + field.getDeclaringClass().getSimpleName(), StyledString.QUALIFIER_STYLER);
-
- final IImageResolver imageResolver = Modifier.isStatic(field.getModifiers())
- ? new DescriptorImageResolver(Activator.getImageDescriptor(Activator.PLUGIN_ID, "/icons/eobj16/static_field.png"))
- : new JDTImageResolver(ISharedImages.IMG_FIELD_PUBLIC);
-
- addProposal(styledString, field.getName(), imageResolver, ScriptCompletionProposal.ORDER_FIELD, helpResolver);
- }
- }
- }
-
- public static String getMethodReturnType(final Method method) {
- final Class<?> returnType = method.getReturnType();
- return (returnType != null) ? returnType.getSimpleName() : "void";
- }
-
- public static String getMethodSignature(final Method method) {
- final StringBuilder result = new StringBuilder();
-
- for (final Parameter parameter : method.getParameters()) {
- if (result.length() > 0)
- result.append(", ");
-
- result.append(parameter.getType().getSimpleName());
- result.append(' ').append(parameter.getName());
- }
-
- return result.toString();
- }
}
diff --git a/plugins/org.eclipse.ease.ui.completions.java/src/org/eclipse/ease/ui/completions/java/provider/JavaPackagesCompletionProvider.java b/plugins/org.eclipse.ease.ui.completions.java/src/org/eclipse/ease/ui/completions/java/provider/JavaPackagesCompletionProvider.java
index a65cef2..0e0696c 100644
--- a/plugins/org.eclipse.ease.ui.completions.java/src/org/eclipse/ease/ui/completions/java/provider/JavaPackagesCompletionProvider.java
+++ b/plugins/org.eclipse.ease.ui.completions.java/src/org/eclipse/ease/ui/completions/java/provider/JavaPackagesCompletionProvider.java
@@ -10,183 +10,74 @@
* Contributors:
* Christian Pontesegger - initial API and implementation
*******************************************************************************/
+
package org.eclipse.ease.ui.completions.java.provider;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.net.URL;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import org.eclipse.ease.ICompletionContext;
-import org.eclipse.ease.ICompletionContext.Type;
-import org.eclipse.ease.Logger;
-import org.eclipse.ease.ui.Activator;
-import org.eclipse.ease.ui.completion.AbstractCompletionProvider;
-import org.eclipse.ease.ui.completion.IHelpResolver;
import org.eclipse.ease.ui.completion.ScriptCompletionProposal;
-import org.eclipse.ease.ui.completions.java.EaseUICompletionsJavaFragment;
+import org.eclipse.ease.ui.completion.provider.AbstractCompletionProvider;
+import org.eclipse.ease.ui.completion.tokenizer.InputTokenizer;
+import org.eclipse.ease.ui.completion.tokenizer.TokenList;
import org.eclipse.ease.ui.completions.java.help.handlers.JavaPackageHelpResolver;
import org.eclipse.jdt.ui.ISharedImages;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
public class JavaPackagesCompletionProvider extends AbstractCompletionProvider {
- private static Map<String, Collection<String>> PACKAGES = null;
-
- private static final Pattern JAVA_VERSION_MATCHER = Pattern.compile("1\\.(\\d)\\..*");
-
- /**
- * Get the major version number of the java runtime.
- *
- * @return java major version, eg 6, 8, 12
- */
- private static int getJavaMajorVersion() {
- int result = 0;
-
- final String version = System.getProperty("java.runtime.version");
- final Matcher matcher = JAVA_VERSION_MATCHER.matcher(version);
- if (matcher.matches())
- result = Integer.parseInt(matcher.group(1));
- else
- result = Integer.parseInt(version.substring(0, version.indexOf('.')));
-
- return Math.min(result, Activator.JAVA_CLASSES_MAX_VERSION);
- }
-
@Override
public boolean isActive(final ICompletionContext context) {
- return super.isActive(context) && ((context.getType() == Type.NONE) || (context.getType() == Type.PACKAGE));
+ return super.isActive(context) && !isCallChain(context);
+ }
+
+ private boolean isCallChain(ICompletionContext context) {
+ final TokenList tokens = new TokenList(context.getTokens()).getFromLast("()");
+
+ return (!tokens.isEmpty()) && tokens.getFromLast("(").isEmpty();
}
@Override
protected void prepareProposals(final ICompletionContext context) {
- final String parentPackage = (context.getType() == Type.NONE) ? "" : context.getPackage();
+ final String packageFilter = getFilter(context);
- if (getPackages().get(parentPackage) != null) {
- for (final String packageName : getPackages().get(parentPackage)) {
-
- if (matchesFilter(packageName)) {
- final IHelpResolver helpResolver = new JavaPackageHelpResolver(parentPackage + "." + packageName);
-
- if (parentPackage.isEmpty())
- // add root package
- addProposal(packageName, packageName + ".", new JavaMethodCompletionProvider.JDTImageResolver(ISharedImages.IMG_OBJS_PACKAGE),
- ScriptCompletionProposal.ORDER_PACKAGE, helpResolver);
- else
- // add sub package
- addProposal(parentPackage + "." + packageName, packageName + ".",
- new JavaMethodCompletionProvider.JDTImageResolver(ISharedImages.IMG_OBJS_PACKAGE), ScriptCompletionProposal.ORDER_PACKAGE,
- helpResolver);
- }
+ for (final String candidate : JavaResources.getInstance().getPackages()) {
+ if (isValidCandidate(candidate, packageFilter)) {
+ addProposal(candidate, candidate.substring(packageFilter.length() - context.getFilter().length()) + ".",
+ new JavaMethodCompletionProvider.JDTImageResolver(ISharedImages.IMG_OBJS_PACKAGE), ScriptCompletionProposal.ORDER_PACKAGE,
+ new JavaPackageHelpResolver(candidate));
}
}
}
- public static BufferedReader getJavaClassDefinitions() throws IOException {
- final URL url = new URL("platform:/plugin/org.eclipse.ease.ui/resources/java" + getJavaMajorVersion() + " classes.txt");
- return new BufferedReader(new InputStreamReader(url.openConnection().getInputStream()));
- }
-
- public static Map<String, Collection<String>> getPackages() {
- if (PACKAGES == null) {
- PACKAGES = new HashMap<>();
-
- // read java packages
- try (BufferedReader reader = getJavaClassDefinitions()) {
- String className;
- while ((className = reader.readLine()) != null) {
- final String packageName = className.substring(0, className.lastIndexOf('.'));
- registerPackage(packageName);
- }
-
- reader.close();
-
- } catch (final IOException e) {
- Logger.error(EaseUICompletionsJavaFragment.FRAGMENT_ID, "Cannot read package list for code completion", e);
- }
-
- // read eclipse packages
- final BundleContext context = FrameworkUtil.getBundle(JavaPackagesCompletionProvider.class).getBundleContext();
- for (final Bundle bundle : context.getBundles()) {
-
- for (final String packageName : getExportedPackages(bundle))
- registerPackage(packageName);
- }
- }
-
- return PACKAGES;
- }
-
- /**
- * Get a list of all exported packages of a bundle.
- *
- * @param bundle
- * bundle instance
- * @return collection of exported packages
- */
- public static Collection<String> getExportedPackages(final Bundle bundle) {
- final Collection<String> exportedPackages = new HashSet<>();
-
- final String exportPackage = bundle.getHeaders().get("Export-Package");
- if (exportPackage != null) {
- final String[] packages = exportPackage.split(",");
- for (final String packageEntry : packages) {
- String candidate = packageEntry.trim().split(";")[0];
- if (candidate.endsWith("\""))
- candidate = candidate.substring(0, candidate.length() - 1);
-
- if ((candidate.contains(".internal")) || (packageEntry.contains(";x-internal:=true")))
- // ignore internal packages
- continue;
-
- if ((candidate.startsWith("Lib")) || (candidate.startsWith("about_files")) || (candidate.startsWith("META")))
- // ignore some dedicated packages
- continue;
-
- exportedPackages.add(candidate);
- }
- }
-
- return exportedPackages;
- }
-
- private static void registerPackage(final String packageName) {
- final int lastIndex = packageName.lastIndexOf('.');
- final String key = (lastIndex == -1) ? "" : packageName.substring(0, lastIndex);
- final String value = (lastIndex == -1) ? packageName : packageName.substring(lastIndex + 1);
-
- if (!PACKAGES.containsKey(key))
- PACKAGES.put(key, new HashSet<String>());
-
- PACKAGES.get(key).add(value);
-
- if (!key.isEmpty())
- registerPackage(key);
- }
-
- /**
- * Try to find a package in the registered package list
- *
- * @param candidate
- * package name to look up
- * @return <code>true</code> when package is registered
- */
- public static boolean containsPackage(final String candidate) {
- final int lastDot = candidate.lastIndexOf('.');
- final Collection<String> packageList = (lastDot > 0) ? getPackages().get(candidate.substring(0, lastDot)) : getPackages().get("");
-
- if (packageList != null)
- return packageList.contains(candidate.substring(lastDot + 1));
+ private boolean isValidCandidate(String candidate, String packageFilter) {
+ if (candidate.startsWith(packageFilter))
+ return !candidate.substring(packageFilter.length()).contains(".");
return false;
}
+
+ private String getFilter(final ICompletionContext context) {
+ final StringBuilder filter = new StringBuilder();
+
+ final List<Object> reversedTokens = new ArrayList<>(context.getTokens());
+ Collections.reverse(reversedTokens);
+
+ for (final Object token : reversedTokens) {
+ if (token instanceof Package) {
+ filter.insert(0, ((Package) token).getName());
+ break;
+
+ } else if ((InputTokenizer.isDelimiter(token)) && (!".".equals(token))) {
+ break;
+ } else if (token instanceof String) {
+ filter.insert(0, token);
+ } else
+ break;
+ }
+
+ return filter.toString();
+ }
}
diff --git a/plugins/org.eclipse.ease.ui.completions.java/src/org/eclipse/ease/ui/completions/java/provider/JavaResources.java b/plugins/org.eclipse.ease.ui.completions.java/src/org/eclipse/ease/ui/completions/java/provider/JavaResources.java
new file mode 100644
index 0000000..91d9b24
--- /dev/null
+++ b/plugins/org.eclipse.ease.ui.completions.java/src/org/eclipse/ease/ui/completions/java/provider/JavaResources.java
@@ -0,0 +1,209 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Christian Pontesegger and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License_Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian Pontesegger - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.ui.completions.java.provider;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.ease.Logger;
+import org.eclipse.ease.ui.Activator;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+
+public final class JavaResources {
+
+ private static final JavaResources INSTANCE = new JavaResources();
+
+ private static final String PLUGIN_ID = "org.eclipse.ease.ui.completions.java";
+
+ private static final Pattern FQN_CLASSNAME_PATTERN = Pattern.compile("(\\p{Lower}+(?:\\.\\p{Lower}+)*)\\.(\\p{Upper}.*)");
+
+ private static final Collection<String> FILTERED_PACKAGES = Arrays.asList("java.awt", "java.applet", "groovy", "netscape", "kotlin");
+
+ public static JavaResources getInstance() {
+ return INSTANCE;
+ }
+
+ /** Maps packageName -> {classNames}, eg 'java.io' -> {File, FileBuffer, ...}. */
+ private Map<String, Collection<String>> fPackagesAndClasses = Collections.emptyMap();
+ private boolean fisLoadingTriggered = false;
+
+ private JavaResources() {
+ }
+
+ public Map<String, Collection<String>> getClasses() {
+ if (fPackagesAndClasses.isEmpty())
+ loadClasses();
+
+ return fPackagesAndClasses;
+ }
+
+ public Collection<String> getPackages() {
+ return getClasses().keySet();
+ }
+
+ public Collection<String> getClasses(String packageName) {
+ if (getClasses().containsKey(packageName))
+ return getClasses().get(packageName);
+
+ return Collections.emptySet();
+ }
+
+ private void loadClasses() {
+ if (!fisLoadingTriggered) {
+ fisLoadingTriggered = true;
+
+ final Job job = new Job("Load Java code completion") {
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ final Map<String, Collection<String>> loadingContent = new TreeMap<>();
+
+ readJavaPackagesAndClasses(loadingContent);
+ readEclipsePackages(loadingContent);
+
+ fPackagesAndClasses = loadingContent;
+
+ return Status.OK_STATUS;
+ }
+ };
+
+ job.setSystem(true);
+ job.schedule();
+ }
+ }
+
+ private void readEclipsePackages(Map<String, Collection<String>> target) {
+ final BundleContext context = FrameworkUtil.getBundle(getClass()).getBundleContext();
+
+ for (final Bundle bundle : context.getBundles()) {
+ for (final String packageName : getExportedPackages(bundle)) {
+ if (!isFiltered(packageName))
+ registerPackage(target, packageName);
+ }
+ }
+ }
+
+ private void readJavaPackagesAndClasses(Map<String, Collection<String>> target) {
+ try (BufferedReader reader = getJavaClassDefinitions()) {
+ String entry = reader.readLine();
+ while (entry != null) {
+ final Matcher matcher = FQN_CLASSNAME_PATTERN.matcher(entry);
+ if (matcher.matches())
+ registerClass(target, matcher.group(1), matcher.group(2));
+
+ entry = reader.readLine();
+ }
+
+ } catch (final IOException e) {
+ Logger.error(PLUGIN_ID, "Cannot read package list for code completion", e);
+ }
+ }
+
+ private void registerPackage(Map<String, Collection<String>> target, String packageName) {
+ if (!target.containsKey(packageName)) {
+ target.put(packageName, new TreeSet<String>());
+ }
+
+ final int delimiterPosition = packageName.lastIndexOf('.');
+ if (delimiterPosition > 0)
+ registerPackage(target, packageName.substring(0, delimiterPosition));
+ }
+
+ private void registerClass(Map<String, Collection<String>> target, final String packageName, String className) {
+ if (!isFiltered(packageName)) {
+ registerPackage(target, packageName);
+ target.get(packageName).add(className);
+ }
+ }
+
+ private boolean isFiltered(String packageName) {
+ for (final String filter : FILTERED_PACKAGES) {
+ if (packageName.startsWith(filter))
+ return true;
+ }
+
+ return false;
+ }
+
+ private BufferedReader getJavaClassDefinitions() throws IOException {
+ final URL url = new URL("platform:/plugin/" + PLUGIN_ID + "/resources/java" + getJavaMajorVersion() + " classes.txt");
+ return new BufferedReader(new InputStreamReader(url.openConnection().getInputStream()));
+ }
+
+ /**
+ * Get the major version number of the java runtime.
+ *
+ * @return java major version, eg 6, 8, 12
+ */
+ private int getJavaMajorVersion() {
+ int result = 1000; // set to a high value so that the min function below will pick the highest supported version
+
+ final Pattern versionPattern = Pattern.compile("(?:1\\.)?(\\d+).*");
+ final String version = System.getProperty("java.runtime.version");
+ final Matcher matcher = versionPattern.matcher(version);
+ if (matcher.matches())
+ result = Integer.parseInt(matcher.group(1));
+
+ return Math.min(result, Activator.JAVA_CLASSES_MAX_VERSION);
+ }
+
+ /**
+ * Get a list of all exported packages of a bundle.
+ *
+ * @param bundle
+ * bundle instance
+ * @return collection of exported packages
+ */
+ private Collection<String> getExportedPackages(final Bundle bundle) {
+ final Collection<String> exportedPackages = new HashSet<>();
+
+ final String exportPackage = bundle.getHeaders().get("Export-Package");
+ if (exportPackage != null) {
+ final String[] packages = exportPackage.split(",");
+ for (final String packageEntry : packages) {
+ String candidate = packageEntry.trim().split(";")[0];
+ if (candidate.endsWith("\""))
+ candidate = candidate.substring(0, candidate.length() - 1);
+
+ if ((candidate.contains(".internal")) || (packageEntry.contains(";x-internal:=true")))
+ // ignore internal packages
+ continue;
+
+ if ((candidate.startsWith("Lib")) || (candidate.startsWith("about_files")) || (candidate.startsWith("META")))
+ // ignore some dedicated packages
+ continue;
+
+ exportedPackages.add(candidate);
+ }
+ }
+
+ return exportedPackages;
+ }
+}
diff --git a/plugins/org.eclipse.ease.ui/.classpath b/plugins/org.eclipse.ease.ui/.classpath
index 43b9862..c93a9d1 100644
--- a/plugins/org.eclipse.ease.ui/.classpath
+++ b/plugins/org.eclipse.ease.ui/.classpath
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
diff --git a/plugins/org.eclipse.ease.ui/META-INF/MANIFEST.MF b/plugins/org.eclipse.ease.ui/META-INF/MANIFEST.MF
index 119da71..c3d6fa9 100644
--- a/plugins/org.eclipse.ease.ui/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.ease.ui/META-INF/MANIFEST.MF
@@ -6,7 +6,7 @@
Bundle-ClassPath: .
Bundle-Vendor: Eclipse.org
Bundle-Localization: plugin
-Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Bundle-RequiredExecutionEnvironment: JavaSE-11
Require-Bundle: org.eclipse.ui.console;bundle-version="[3.5.100,4.0.0)",
org.eclipse.ui.ide;bundle-version="[3.7.0,4.0.0)",
org.eclipse.core.expressions;bundle-version="[3.4.300,4.0.0)",
@@ -26,6 +26,7 @@
Export-Package: org.eclipse.ease.ui,
org.eclipse.ease.ui.completion,
org.eclipse.ease.ui.completion.provider,
+ org.eclipse.ease.ui.completion.tokenizer,
org.eclipse.ease.ui.console,
org.eclipse.ease.ui.console.actions;x-internal:=true,
org.eclipse.ease.ui.debugging.model,
diff --git a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/AbstractCompletionParser.java b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/AbstractCompletionParser.java
deleted file mode 100644
index 29cd109..0000000
--- a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/AbstractCompletionParser.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Christian Pontesegger and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v2.0
- * which accompanies this distribution, and is available at
- * https://www.eclipse.org/legal/epl-2.0/
- *
- * SPDX-License_Identifier: EPL-2.0
- *
- * Contributors:
- * Christian Pontesegger - initial API and implementation
- *******************************************************************************/
-
-package org.eclipse.ease.ui.completion;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.eclipse.ease.AbstractCodeParser;
-import org.eclipse.jface.text.Position;
-
-public abstract class AbstractCompletionParser extends AbstractCodeParser {
-
- public static List<Position> findInvocations(final String call, final String code) {
- List<Position> result = new ArrayList<Position>();
-
- String methodName = (call.contains("(")) ? call.substring(0, call.indexOf('(')) : call;
-
- // group 1: full call
- // group 2: parameters
- Pattern methodPattern = Pattern.compile("^.*(" + methodName + "\\s*\\((.*)\\))\\s*;?\\s*$", Pattern.MULTILINE);
- Matcher matcher = methodPattern.matcher(code);
-
- while (matcher.find()) {
- // pattern found
- result.add(new Position(matcher.start(1), matcher.end(1) - matcher.start(1)));
- }
-
- return result;
- }
-
- public static String[] getParameters(final String call) {
- int start = call.indexOf('(');
- int end = call.lastIndexOf(')');
- if ((start > 0) && (end > start))
- return call.substring(start + 1, end).split(",");
-
- return new String[0];
- }
-}
diff --git a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/AbstractCompletionProvider.java b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/AbstractCompletionProvider.java
deleted file mode 100644
index b06ca41..0000000
--- a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/AbstractCompletionProvider.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Christian Pontesegger and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v2.0
- * which accompanies this distribution, and is available at
- * https://www.eclipse.org/legal/epl-2.0/
- *
- * SPDX-License_Identifier: EPL-2.0
- *
- * Contributors:
- * Christian Pontesegger - initial API and implementation
- *******************************************************************************/
-
-package org.eclipse.ease.ui.completion;
-
-import java.util.ArrayList;
-import java.util.Collection;
-
-import org.eclipse.ease.ICompletionContext;
-import org.eclipse.ease.ICompletionContext.Type;
-import org.eclipse.jface.resource.ImageDescriptor;
-import org.eclipse.jface.viewers.StyledString;
-import org.eclipse.swt.graphics.Image;
-
-public abstract class AbstractCompletionProvider implements ICompletionProvider {
-
- public static class DescriptorImageResolver implements IImageResolver {
- private final ImageDescriptor fDescriptor;
-
- public DescriptorImageResolver() {
- fDescriptor = null;
- }
-
- public DescriptorImageResolver(ImageDescriptor descriptor) {
- fDescriptor = descriptor;
- }
-
- @Override
- public Image getImage() {
- return (getDescriptor() != null) ? getDescriptor().createImage() : null;
- }
-
- protected ImageDescriptor getDescriptor() {
- return fDescriptor;
- }
- }
-
- private Collection<ScriptCompletionProposal> fProposals = null;
- private ICompletionContext fContext;
-
- @Override
- public boolean isActive(final ICompletionContext context) {
- return context.getType() != Type.UNKNOWN;
- }
-
- @Override
- public Collection<? extends ScriptCompletionProposal> getProposals(final ICompletionContext context) {
- fContext = context;
- fProposals = new ArrayList<>();
-
- prepareProposals(context);
-
- final Collection<ScriptCompletionProposal> result = fProposals;
- fProposals = null;
- fContext = null;
- return result;
- }
-
- /**
- * Get the current context. Only valid during proposal evaluation. Clients may retrieve the content when {@link #prepareProposals(ICompletionContext)} is
- * called.
- *
- * @return the current context or <code>null</code> when proposals are not evaluated
- */
- public ICompletionContext getContext() {
- return fContext;
- }
-
- protected void addProposal(final ScriptCompletionProposal proposal) {
- fProposals.add(proposal);
- }
-
- protected void addProposal(final StyledString displayString, final String replacementString, final IImageResolver imageResolver, final int priority,
- final IHelpResolver helpResolver) {
-
- fProposals.add(new ScriptCompletionProposal(fContext, displayString, replacementString, imageResolver, priority, helpResolver));
- }
-
- protected void addProposal(final String displayString, final String replacementString, final IImageResolver imageResolver, final int priority,
- final IHelpResolver helpResolver) {
-
- fProposals.add(new ScriptCompletionProposal(fContext, displayString, replacementString, imageResolver, priority, helpResolver));
- }
-
- protected boolean matchesFilter(final String proposal) {
- return matches(fContext.getFilter(), proposal);
- }
-
- protected boolean matchesFilterIgnoreCase(final String proposal) {
- return matchesIgnoreCase(fContext.getFilter(), proposal);
- }
-
- protected static boolean matches(final String filter, final String proposal) {
- return (filter != null) ? proposal.startsWith(filter) : true;
- }
-
- protected static boolean matchesIgnoreCase(final String filter, final String proposal) {
- return (filter != null) ? proposal.toLowerCase().startsWith(filter.toLowerCase()) : true;
- }
-
- protected abstract void prepareProposals(ICompletionContext context);
-}
diff --git a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/BasicContext.java b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/BasicContext.java
new file mode 100644
index 0000000..63a1f47
--- /dev/null
+++ b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/BasicContext.java
@@ -0,0 +1,170 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Christian Pontesegger and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License_Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian Pontesegger - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.ui.completion;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.ease.ICompletionContext;
+import org.eclipse.ease.IScriptEngine;
+import org.eclipse.ease.modules.EnvironmentModule;
+import org.eclipse.ease.modules.ModuleDefinition;
+import org.eclipse.ease.modules.ModuleHelper;
+import org.eclipse.ease.service.ScriptType;
+import org.eclipse.ease.ui.completion.tokenizer.InputTokenizer;
+import org.eclipse.ease.ui.completion.tokenizer.TokenList;
+
+public class BasicContext implements ICompletionContext {
+
+ private final String fContent;
+ private final int fCursorPosition;
+ private final IScriptEngine fScriptEngine;
+ private final ScriptType fScriptType;
+ private final Object fResource;
+
+ public BasicContext(IScriptEngine scriptEngine, String content, int cursorPosition) {
+ fScriptEngine = scriptEngine;
+ fScriptType = scriptEngine.getDescription().getSupportedScriptTypes().get(0);
+ fResource = null;
+ fContent = content;
+ fCursorPosition = cursorPosition;
+ }
+
+ public BasicContext(ScriptType scriptType, Object resource, String content, int cursorPosition) {
+ fScriptEngine = null;
+ fScriptType = scriptType;
+ fResource = resource;
+ fContent = content;
+ fCursorPosition = cursorPosition;
+ }
+
+ @Override
+ public List<Object> getTokens() {
+ return getInputTokenizer().getTokens(getRelevantText());
+ }
+
+ protected InputTokenizer getInputTokenizer() {
+ if (getScriptEngine() != null)
+ return new InputTokenizer(v -> {
+ if (getScriptEngine().hasVariable(v)) {
+ final Object variable = getScriptEngine().getVariable(v);
+ return variable == null ? null : variable.getClass();
+ }
+
+ return null;
+ });
+
+ return new InputTokenizer();
+ }
+
+ @Override
+ public String getText() {
+ return fContent;
+ }
+
+ private String getRelevantText() {
+ return getText().substring(0, getReplaceOffset());
+ }
+
+ @Override
+ public int getReplaceOffset() {
+ return fCursorPosition;
+ }
+
+ @Override
+ public int getReplaceLength() {
+ return 0;
+ }
+
+ @Override
+ public IScriptEngine getScriptEngine() {
+ return fScriptEngine;
+ }
+
+ @Override
+ public List<ModuleDefinition> getLoadedModules() {
+ final List<ModuleDefinition> modules = new ArrayList<>();
+
+ if (getScriptEngine() != null) {
+ modules.addAll(ModuleHelper.getLoadedModules(getScriptEngine()));
+
+ } else {
+ modules.addAll(getLoadedModules(getRelevantText()));
+
+ if (modules.stream().filter(m -> EnvironmentModule.MODULE_NAME.equals(m.getName())).count() == 0)
+ modules.add(ModuleHelper.resolveModuleName(EnvironmentModule.MODULE_NAME));
+ }
+
+ return modules;
+ }
+
+ private static final Pattern LOAD_MODULE_PATTERN = Pattern.compile(EnvironmentModule.LOAD_MODULE_METHOD + "\\([\\\"\\'](.*?)[\\\"\\']");
+
+ private Collection<? extends ModuleDefinition> getLoadedModules(String content) {
+ final List<ModuleDefinition> modules = new ArrayList<>();
+
+ final Matcher matcher = LOAD_MODULE_PATTERN.matcher(content);
+ while (matcher.find()) {
+ final String moduleId = matcher.group(1);
+ final ModuleDefinition moduleDefinition = ModuleHelper.resolveModuleName(moduleId);
+ if (moduleDefinition != null) {
+ if (modules.stream().filter(m -> moduleId.equals(m.getName())).count() == 0)
+ modules.add(moduleDefinition);
+ }
+ }
+
+ return modules;
+ }
+
+ private Map<Object, String> getIncludes() {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public String getFilterToken() {
+ final Object lastToken = new TokenList(getTokens()).getLastToken();
+ return (isFilter(lastToken)) ? lastToken.toString() : "";
+ }
+
+ @Override
+ public String getFilter() {
+ final String filter = getFilterToken();
+
+ return isStringLiteral(filter) ? filter.substring(1) : filter;
+ }
+
+ private boolean isFilter(final Object lastToken) {
+ return (lastToken instanceof String) && (!InputTokenizer.isDelimiter(lastToken));
+ }
+
+ @Override
+ public boolean isStringLiteral(String input) {
+ return input.startsWith("\"");
+ }
+
+ @Override
+ public ScriptType getScriptType() {
+ return fScriptType;
+ }
+
+ @Override
+ public Object getResource() {
+ return fResource;
+ }
+}
diff --git a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/CodeCompletionAggregator.java b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/CodeCompletionAggregator.java
index ce40ac4..7f67a76 100644
--- a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/CodeCompletionAggregator.java
+++ b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/CodeCompletionAggregator.java
@@ -13,234 +13,115 @@
package org.eclipse.ease.ui.completion;
+import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
+import java.util.stream.Collectors;
import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Platform;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.core.runtime.jobs.Job;
-import org.eclipse.ease.ICodeParser;
+import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.ease.ICompletionContext;
import org.eclipse.ease.IScriptEngine;
import org.eclipse.ease.Logger;
import org.eclipse.ease.service.ScriptType;
+import org.eclipse.ease.tools.PlatformExtension;
import org.eclipse.ease.ui.Activator;
+import org.eclipse.ease.ui.completion.provider.ICompletionProvider;
import org.eclipse.jface.fieldassist.IContentProposal;
import org.eclipse.jface.fieldassist.IContentProposalProvider;
-import org.eclipse.jface.text.contentassist.ICompletionProposal;
-/**
- * Dispatcher class create code completion proposals.
- *
- * First checks all registered {@link ICompletionProvider} objects to get the {@link ICompletionContext} for the desired line.
- *
- * Then uses all registered {@link ICompletionProvider} objects to calculate the {@link IContentProposal} array for {@link #getProposals(String, int)}.
- *
- * TODO: Refactor to use multi-threading.
- *
- * @author Martin Kloesch
- *
- */
public class CodeCompletionAggregator implements IContentProposalProvider {
- /**
- * String constant for codeCompletionProvider extension point.
- */
- public static final String COMPLETION_PROCESSOR = "org.eclipse.ease.ui.codeCompletionProvider";
+ private static final String SCRIPT_COMPLETION_EXTENSION_POINT = "org.eclipse.ease.ui.codeCompletionProvider";
- /**
- * String constant for script type attribute of codeCompletionProvider extension.
- */
- public static final String ATTRIBUTE_SCRIPT_TYPE = "scriptType";
+ private final IScriptEngine fScriptEngine;
+ private ScriptType fScriptType;
+ private final Object fResource;
- /**
- * String constant for class attribute of codeCompletionProvider extension.
- */
- public static final String ATTRIBUTE_CLASS = "class";
+ private final List<ICompletionProvider> fStaticCompletionProviders = new ArrayList<>();
- /** Timeout for completion processor. */
- private static final long COMPLETION_TIMEOUT = 500;
+ public CodeCompletionAggregator(IScriptEngine scriptEngine) {
+ if (scriptEngine == null)
+ throw new IllegalArgumentException("scriptEngine cannot be null");
- /**
- * Retrieve all {@link ICompletionProvider}s matching a given script type.
- *
- * @param scriptType
- * script type filter for code completion proposal providers. May be <code>null</code> to get all providers.
- *
- * @return list of all matching {@link ICompletionProvider}s.
- */
- private static Collection<ICompletionProvider> getProviders(final String scriptType) {
- final Collection<ICompletionProvider> providers = new HashSet<>();
-
- final IConfigurationElement[] elements = Platform.getExtensionRegistry().getConfigurationElementsFor(COMPLETION_PROCESSOR);
- for (final IConfigurationElement element : elements) {
-
- if (scriptType != null) {
- final String registeredType = element.getAttribute(ATTRIBUTE_SCRIPT_TYPE);
- if ((registeredType != null) && (!registeredType.isEmpty()) && (!scriptType.equals(registeredType)))
- // ignore as script type does not match
- continue;
- }
-
- try {
- final Object candidate = element.createExecutableExtension(ATTRIBUTE_CLASS);
- if (candidate instanceof ICompletionProvider)
- // register provider
- providers.add((ICompletionProvider) candidate);
-
- } catch (final CoreException e) {
- Logger.error(Activator.PLUGIN_ID, "Invalid completion provider detected in " + element.getContributor().getName(), e);
- }
- }
-
- return providers;
- }
-
- /**
- * Static code analyzer to split given line of code to base {@link ICompletionContext} for {@link ICompletionProvider#refineContext(ICompletionContext)}.
- */
- private ICodeParser fCodeParser;
-
- /** All registered {@link ICompletionProvider}s. */
- private Collection<ICompletionProvider> fCompletionProviders = Collections.emptySet();
-
- /** Manually added {@link ICompletionProvider}s. */
- private final Collection<ICompletionProvider> fAddedCompletionProviders = new HashSet<>();
-
- /** Registered script engine. */
- private IScriptEngine fScriptEngine;
-
- /**
- * Setter method for ICompletionAnalyzer.
- *
- * @param codeParser
- * {@link ICodeParser} for completion calculation.
- */
- public void setCodeParser(final ICodeParser codeParser) {
- fCodeParser = codeParser;
- }
-
- public char[] getActivationChars() {
- return new char[] { '.' };
- }
-
- /**
- * Sets the given script engine for all registered completion providers.
- *
- * @param scriptEngine
- * {@link IScriptEngine} to be set.
- */
- public void setScriptEngine(final IScriptEngine scriptEngine) {
fScriptEngine = scriptEngine;
-
- if (fScriptEngine != null) {
- final List<ScriptType> supportedScriptTypes = fScriptEngine.getDescription().getSupportedScriptTypes();
- if (supportedScriptTypes.size() > 0) {
- setScriptType(supportedScriptTypes.get(0));
- }
- }
+ setScriptType(fScriptEngine.getDescription().getSupportedScriptTypes().stream().findAny().orElse(null));
+ fResource = null;
}
- public void setScriptType(final ScriptType scriptType) {
- setCodeParser(scriptType.getCodeParser());
- fCompletionProviders = getProviders(scriptType.getName());
- fCompletionProviders.addAll(fAddedCompletionProviders);
+ public CodeCompletionAggregator(Object resource, ScriptType scriptType) {
+ fScriptEngine = null;
+ setScriptType(scriptType);
+ fResource = resource;
}
- public void addCompletionProvider(ICompletionProvider completionProvider) {
- fAddedCompletionProviders.add(completionProvider);
+ private void setScriptType(ScriptType scriptType) {
+ if (scriptType == null)
+ throw new IllegalArgumentException("scriptType cannot be detected");
+
+ fScriptType = scriptType;
}
- /**
- * Calculate relevant completion proposals.
- *
- * @param resource
- * resource that contains relevantText. May be <code>null</code>
- * @param relevantText
- * text that is relevant for completion calculation
- * @param insertOffset
- * cursor position within relevatText
- * @param selectionRange
- * @param monitor
- * job monitor for calculation termination
- * @return
- */
- public List<ICompletionProposal> getCompletionProposals(final Object resource, final String relevantText, final int insertOffset, final int selectionRange,
- final IProgressMonitor monitor) {
+ @Override
+ public IContentProposal[] getProposals(String contents, int position) {
+ return getProposals(contents, position, new NullProgressMonitor()).toArray(new IContentProposal[0]);
+ }
- final LinkedList<ICompletionProposal> proposals = new LinkedList<>();
- final Job completionProcessorJob = new Job("Calculate EASE code completions") {
+ public List<ScriptCompletionProposal> getProposals(String content, int cursorPosition, IProgressMonitor monitor) {
+ final List<ScriptCompletionProposal> proposals = new LinkedList<>();
- @Override
- protected IStatus run(IProgressMonitor monitor) {
- try {
- if (monitor.isCanceled())
- return Status.CANCEL_STATUS;
+ final ICompletionContext context = createContext(content, cursorPosition);
- final ICompletionContext context = createContext(resource, relevantText, insertOffset, selectionRange);
-
- if (context != null) {
- for (final ICompletionProvider provider : fCompletionProviders) {
- try {
- if (monitor.isCanceled())
- return Status.CANCEL_STATUS;
-
- if (provider.isActive(context))
- proposals.addAll(provider.getProposals(context));
-
- } catch (final Throwable ex) {
- Logger.error(Activator.PLUGIN_ID, "Could not get proposals from ICompletionProvider <" + provider.getClass().getName() + ">",
- ex);
- }
- }
- }
-
- } finally {
- synchronized (this) {
- notifyAll();
- }
- }
-
- return Status.OK_STATUS;
- }
- };
-
- completionProcessorJob.schedule();
-
- synchronized (completionProcessorJob) {
+ for (final ICompletionProvider provider : getProposalProviders()) {
try {
- completionProcessorJob.wait(COMPLETION_TIMEOUT);
- } catch (final InterruptedException e) {
+ if (provider.isActive(context))
+ proposals.addAll(provider.getProposals(context));
+
+ } catch (final Throwable e) {
+ Logger.error(Activator.PLUGIN_ID, "Code completion provider failed", e);
}
}
return proposals;
}
- private ICompletionContext createContext(final Object resource, final String relevantText, final int insertOffset, final int selectionRange) {
- if (fCodeParser != null)
- return fCodeParser.getContext(fScriptEngine, resource, relevantText, insertOffset, selectionRange);
+ private ICompletionContext createContext(String content, int cursorPosition) {
+ if (fScriptEngine == null)
+ return new BasicContext(fScriptType, null, content, cursorPosition);
- return null;
+ return new BasicContext(fScriptEngine, content, cursorPosition);
}
- @Override
- public IContentProposal[] getProposals(final String contents, final int position) {
- final List<ICompletionProposal> proposals = getCompletionProposals(null, contents, position, 0, null);
- Collections.sort(proposals, (o1, o2) -> {
- if ((o1 instanceof ScriptCompletionProposal) && (o2 instanceof ScriptCompletionProposal))
- return ((ScriptCompletionProposal) o1).compareTo((ScriptCompletionProposal) o2);
+ private List<ICompletionProvider> getProposalProviders() {
+ final List<ICompletionProvider> providers = new ArrayList<>();
+ providers.addAll(getExtensionProposalProviders());
+ providers.addAll(getLocalProposalProviders());
+ return providers;
+ }
- return o1.getDisplayString().compareTo(o2.getDisplayString());
- });
+ private List<ICompletionProvider> getLocalProposalProviders() {
+ return fStaticCompletionProviders;
+ }
- return proposals.toArray(new IContentProposal[proposals.size()]);
+ private List<ICompletionProvider> getExtensionProposalProviders() {
+ final Collection<PlatformExtension> extensions = PlatformExtension.createForName(SCRIPT_COMPLETION_EXTENSION_POINT, "codeCompletionProvider");
+
+ return extensions.stream().filter(e -> matchesScriptType(e.getAttribute("scriptType"))).map(e -> {
+ try {
+ return e.createInstance("class", ICompletionProvider.class);
+ } catch (CoreException | ClassCastException ex) {
+ return null;
+ }
+ }).filter(p -> p != null).collect(Collectors.toList());
+ }
+
+ private boolean matchesScriptType(String extensionScriptType) {
+ return (extensionScriptType == null) || extensionScriptType.isEmpty() || extensionScriptType.equals(fScriptType.getName());
+ }
+
+ public void addCompletionProvider(ICompletionProvider completionProvider) {
+ fStaticCompletionProviders.add(completionProvider);
}
}
diff --git a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/CompletionContext.java b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/CompletionContext.java
deleted file mode 100644
index d56ecbc..0000000
--- a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/CompletionContext.java
+++ /dev/null
@@ -1,723 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Martin Kloesch and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v2.0
- * which accompanies this distribution, and is available at
- * https://www.eclipse.org/legal/epl-2.0/
- *
- * SPDX-License_Identifier: EPL-2.0
- *
- * Contributors:
- * Martin Kloesch - initial API and implementation
- * Christian Pontesegger - rewrite of implementation
- *******************************************************************************/
-
-package org.eclipse.ease.ui.completion;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-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.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.eclipse.ease.ICompletionContext;
-import org.eclipse.ease.IScriptEngine;
-import org.eclipse.ease.classloader.EaseClassLoader;
-import org.eclipse.ease.modules.EnvironmentModule;
-import org.eclipse.ease.modules.ModuleDefinition;
-import org.eclipse.ease.modules.ModuleHelper;
-import org.eclipse.ease.service.ScriptType;
-import org.eclipse.ease.tools.ResourceTools;
-import org.eclipse.jface.text.Position;
-
-/**
- * The context evaluates and stores information on the code fragment at a given cursor position.
- */
-public abstract class CompletionContext implements ICompletionContext {
-
- public static class Bracket {
-
- private int fStart = -1;
- private int fEnd = -1;
-
- public Bracket(final int start, final int end) {
- fStart = start;
- fEnd = end;
- }
- }
-
- private static final Pattern JAVA_PACKAGE_PATTERN = Pattern.compile("([A-Za-z]+\\.?)+");
-
- private final IScriptEngine fScriptEngine;
- private Object fResource;
- private ScriptType fScriptType;
- private String fOriginalCode = "";
-
- private final Map<Object, String> fIncludes = new HashMap<>();
- private Collection<ModuleDefinition> fLoadedModules = null;
- private Class<? extends Object> fReferredClazz;
- private String fFilter = "";
- private Type fType = Type.UNKNOWN;
- private String fPackage;
- private String fCaller = "";
- private int fParameterOffset = -1;
-
- private int fOffset;
- private int fSelectionRange;
-
- /** Global classloader to resolve unknown java classes (lazily loaded). */
- private EaseClassLoader fGlobalClassLoader = null;
-
- /**
- * Context constructor. A context is bound to a given script engine or script type.
- *
- * @param scriptEngine
- * script engine to evaluate
- * @param scriptType
- * script type to evaluate
- */
- public CompletionContext(final IScriptEngine scriptEngine, final ScriptType scriptType) {
- fScriptEngine = scriptEngine;
- fScriptType = scriptType;
-
- if ((fScriptType == null) && (fScriptEngine != null))
- fScriptType = fScriptEngine.getDescription().getSupportedScriptTypes().get(0);
- }
-
- @Override
- public Type getType() {
- return fType;
- }
-
- @Override
- public Class<? extends Object> getReferredClazz() {
- return fReferredClazz;
- }
-
- /**
- * Calculate a context over a given code fragment.
- *
- * @param resource
- * base resource (eg. edited file)
- * @param code
- * code fragment to evaluate
- * @param offset
- * the offset within the provided document (usually code.length())
- * @param selectionRange
- * amount of selected characters
- */
- public void calculateContext(final Object resource, String code, final int offset, final int selectionRange) {
- fOffset = offset;
- fSelectionRange = selectionRange;
- fIncludes.clear();
- fLoadedModules = null;
-
- fResource = resource;
- fOriginalCode = code;
- fReferredClazz = null;
- fFilter = "";
-
- // process include() calls
- addInclude(getOriginalCode());
-
- // remove irrelevant parts
- code = simplifyCode();
-
- parseCode(code);
- }
-
- /**
- * Try to evaluate the calling method or class.
- *
- * @param code
- * code fragment to parse
- */
- protected void parseCode(final String code) {
-
- // sometimes simplifyCode() already detects the type correctly, no need for further parsing
- if (getType() == Type.UNKNOWN) {
- final int dotDelimiter = code.lastIndexOf('.');
- if (dotDelimiter == -1) {
- fReferredClazz = null;
- fType = code.endsWith(")") ? Type.UNKNOWN : Type.NONE;
- fFilter = code;
-
- } else {
- fFilter = code.substring(dotDelimiter + 1);
- fReferredClazz = getClazz(code.substring(0, dotDelimiter).trim());
-
- if (fReferredClazz == null) {
- // maybe we have a package
- if (JAVA_PACKAGE_PATTERN.matcher(code.subSequence(0, dotDelimiter)).matches()) {
- fType = Type.PACKAGE;
- fPackage = code.subSequence(0, dotDelimiter).toString();
- }
- }
- }
- }
- }
-
- /**
- * Try to remove unnecessary information from code fragment to simplify parsing.
- *
- * @return simplified code fragment
- */
- protected String simplifyCode() {
- // only operate on last line
- final int lineFeedPosition = getOriginalCode().lastIndexOf('\n');
- String code = (lineFeedPosition > 0) ? getOriginalCode().substring(lineFeedPosition) : getOriginalCode();
- code = code.trim();
-
- // remove all literals with dummies for simpler parsing: "some 'literal'" -> ""
- code = replaceStringLiterals(code);
- if (fType == Type.STRING_LITERAL) {
- // we are within a string literal, cannot simplify further
-
- // try to detect calling method
- if (!code.isEmpty()) {
- final int openingBracket = findMatchingBracket(code + ")", code.length());
- if (openingBracket != -1) {
- // caller found
- fCaller = code.substring(0, openingBracket);
-
- String callerParameters = code.substring(openingBracket + 1);
- callerParameters = removeMethodCalls(callerParameters);
- fParameterOffset = callerParameters.split(",").length - 1;
- }
- }
-
- return code;
- }
-
- // if we find an opening bracket with no closing bracket, we can forget about everything left from it
- final Collection<Bracket> brackets = matchBrackets(code, '(', ')');
-
- int truncatePosition = -1;
- for (final Bracket bracket : brackets) {
- if ((bracket.fStart >= 0) && (bracket.fEnd == -1)) {
- // found an open bracket
- truncatePosition = Math.max(truncatePosition, bracket.fStart + 1);
- }
- }
-
- // try to truncate parameters
- for (int pos = code.length() - 1; pos >= 0; pos--) {
- final char c = code.charAt(pos);
- if ((c == ' ') || (c == '\t') || (c == ',') || (c == '!') || (c == '=') || (c == '<') || (c == '>') || (c == '+') || (c == '-') || (c == '*')
- || (c == '/') || (c == '%') || (c == '&') || (c == '|') || (c == '^')) {
-
- // we have a separation character (operator, comma)
- if (getBracket(brackets, pos) == null) {
- // outside of a closed bracket, therefore we can truncate here
- truncatePosition = Math.max(truncatePosition, pos + 1);
-
- // parsing further to the left is pointless as truncatePosition cannot get bigger anymore
- break;
- }
- }
- }
-
- if (truncatePosition != -1)
- code = code.substring(truncatePosition);
-
- return code;
- }
-
- private static int countOccurrence(final String string, final char character) {
- int count = 0;
- for (final char c : string.toCharArray()) {
- if (c == character)
- count++;
- }
-
- return count;
- }
-
- /**
- * Remove all brackets from method calls along with their content. Eg. transforms "some(call() + 3, test()), another(4)" to "some, another".
- *
- * @param code
- * string to parse
- * @return transformed string
- */
- private static String removeMethodCalls(String code) {
- int closingBracket = code.lastIndexOf(')');
- while (closingBracket != -1) {
- final int openingBracket = findMatchingBracket(code, closingBracket);
- if (openingBracket != -1)
- code = code.substring(0, openingBracket) + code.substring(closingBracket + 1);
- else
- // error, no opening bracket, giving up
- return code;
-
- // find next location
- closingBracket = code.lastIndexOf(')');
- }
-
- return code;
- }
-
- /**
- * Try to evaluate the class returned from a function or an object.
- *
- * @param code
- * code to evaluate
- * @return class or <code>null</code>
- */
- private Class<? extends Object> getClazz(String code) {
- code = code.trim();
- String parameters = null;
- if (code.endsWith(")")) {
- final int bracketOpenPosition = findMatchingBracket(code, code.length() - 1);
-
- // extract parameters in case we have multiple candidates
- parameters = code.substring(bracketOpenPosition + 1, code.length() - 1);
- code = code.substring(0, bracketOpenPosition);
- }
-
- // lets try: invoke class
- try {
- final Class<?> clazz = CompletionContext.class.getClassLoader().loadClass(code);
- fType = (parameters != null) ? Type.CLASS_INSTANCE : Type.STATIC_CLASS;
- return clazz;
-
- } catch (final ClassNotFoundException e) {
- // did not work, we need to dig deeper
- }
-
- final int dotDelimiter = code.lastIndexOf('.');
- if (dotDelimiter == -1) {
-
- if (parameters != null) {
- // maybe a function call
- final Method method = getMethodDefinition(code);
- if (method != null) {
- fType = Type.CLASS_INSTANCE;
- return method.getReturnType();
- }
-
- // giving up
- return null;
-
- } else {
- // maybe a field
- final Field field = getFieldDefinition(code);
- if (field != null) {
- fType = Type.CLASS_INSTANCE;
- return field.getType();
- }
-
- // must be a script variable
- Class<? extends Object> clazz = getVariableClazz(code);
- if (clazz != null) {
- fType = Type.CLASS_INSTANCE;
- return clazz;
- }
-
- // maybe a variable and we find a definition somewhere in the previous code
- clazz = parseVariableType(code);
- if (clazz != null) {
- fType = Type.CLASS_INSTANCE;
- return clazz;
- }
-
- // giving up
- return null;
- }
- }
-
- final String keyWord = code.substring(dotDelimiter + 1);
- code = code.substring(0, dotDelimiter).trim();
-
- if (!code.isEmpty()) {
- final Class<? extends Object> clazz = getClazz(code);
- if (clazz != null) {
- if (parameters != null) {
- // searching for a method
- for (final Method method : clazz.getMethods()) {
- if (method.getName().matches(keyWord)) {
- fType = Type.CLASS_INSTANCE;
- return method.getReturnType();
- }
- }
-
- } else {
- // searching for a field
- for (final Field field : clazz.getFields()) {
- if (field.getName().matches(keyWord)) {
- fType = Type.CLASS_INSTANCE;
- return field.getType();
- }
- }
- }
- }
- }
-
- return null;
- }
-
- /**
- * Parse source code for a variable type definition. Type definitions are comments right before a variable definition in the form: // @type java.lang.String
- *
- * @param name
- * variable name to look up
- * @return variable class type
- */
- protected Class<? extends Object> parseVariableType(final String name) {
-
- final List<String> sources = new ArrayList<>();
- sources.add(getOriginalCode());
- sources.addAll(getIncludedResources().values());
-
- final Pattern pattern = Pattern.compile("@type\\s([a-zA-Z0-9_\\.]+)\\s*$\\s*.*?" + Pattern.quote(name) + "\\s*=", Pattern.MULTILINE);
-
- for (final String source : sources) {
- final Matcher matcher = pattern.matcher(source);
- if (matcher.find()) {
- try {
- return getGlobalClassLoader().loadClass(matcher.group(1));
- } catch (final ClassNotFoundException e) {
- // did not work, invalid definition, giving up
- return null;
- }
- }
- }
-
- return null;
- }
-
- /**
- * Return a classloader that can access all files avaliable in the RCP application.
- *
- * @return global classloader
- */
- private EaseClassLoader getGlobalClassLoader() {
- if (fGlobalClassLoader == null)
- fGlobalClassLoader = new EaseClassLoader();
-
- return fGlobalClassLoader;
- }
-
- /**
- * Retrieve a method definition from loaded modules.
- *
- * @param code
- * method call to look up
- * @return method definition or <code>null</code>
- */
- private Method getMethodDefinition(final String code) {
- for (final ModuleDefinition definition : getLoadedModules()) {
- for (final Method method : definition.getMethods()) {
- if (method.getName().equals(code))
- return method;
- }
- }
-
- return null;
- }
-
- /**
- * Retrieve a field definition from loaded modules.
- *
- * @param code
- * field to look up
- * @return field definition or <code>null</code>
- */
- private Field getFieldDefinition(final String code) {
- for (final ModuleDefinition definition : getLoadedModules()) {
- for (final Field field : definition.getFields()) {
- if (field.getName().equals(code))
- return field;
- }
- }
-
- return null;
- }
-
- /**
- * Retrieve a variable from a running script engine.
- *
- * @param name
- * variable to look up
- * @return variable class or <code>null</code>
- */
- protected Class<? extends Object> getVariableClazz(final String name) {
- if (getScriptEngine() != null) {
- final Object variable = getScriptEngine().getVariable(name);
- if (variable != null)
- return variable.getClass();
- }
-
- return null;
- }
-
- /**
- * Find the corresponding opening bracket to a closing bracket. Therefore we search the string to the left.
- *
- * @param code
- * code fragment to parse
- * @param offset
- * offset position of the closing bracket
- * @return offset of the corresponding opening bracket or -1
- */
- private static int findMatchingBracket(final String string, int offset) {
- int openBrackets = 0;
- do {
- if (string.charAt(offset) == ')')
- openBrackets++;
- else if (string.charAt(offset) == '(')
- openBrackets--;
-
- offset--;
-
- } while ((openBrackets > 0) && (offset >= 0));
-
- return (openBrackets > 0) ? -1 : offset + 1;
- }
-
- /**
- * Remove all string literal content and keep empty literals.
- *
- * @param code
- * code fragment to parse
- * @return code fragment with empty string literals
- */
- public String replaceStringLiterals(final String code) {
- final StringBuilder simplifiedString = new StringBuilder();
- final StringBuilder literalContent = new StringBuilder();
-
- Character currentLiteral = null;
- for (int index = 0; index < code.length(); index++) {
- if (isLiteral(code.charAt(index))) {
- if ((index == 0) || (code.charAt(index - 1) != '\\')) {
- // not escaped
-
- if (currentLiteral == null) {
- // start new literal
- currentLiteral = code.charAt(index);
-
- } else if (currentLiteral == code.charAt(index)) {
- // close literal
- literalContent.delete(0, literalContent.length());
-
- simplifiedString.append(currentLiteral);
- simplifiedString.append(currentLiteral);
-
- currentLiteral = null;
- }
-
- continue;
- }
- }
-
- // process character
- if (currentLiteral == null)
- simplifiedString.append(code.charAt(index));
- else
- literalContent.append(code.charAt(index));
- }
-
- if (currentLiteral != null) {
- fFilter = literalContent.toString();
- fType = Type.STRING_LITERAL;
- }
-
- return simplifiedString.toString();
- }
-
- /**
- * See if a character matches a string literal token.
- *
- * @param candidate
- * character to test
- * @return <code>true</code> when character is a string literal token
- */
- protected abstract boolean isLiteral(final char candidate);
-
- private void addLoadedModules(final String code) {
- final List<Position> modulePositions = AbstractCompletionParser.findInvocations("loadModule(java.lang.String, boolean)", code);
-
- for (final Position position : modulePositions) {
- final String call = code.substring(position.getOffset(), position.getOffset() + position.getLength());
- final String[] parameters = AbstractCompletionParser.getParameters(call);
- if (parameters.length > 0) {
- final String candidate = parameters[0].trim();
-
- if (candidate.charAt(0) == candidate.charAt(candidate.length() - 1)) {
- // TODO add string literal characters lookup method
- if ((candidate.charAt(0) == '"') || (candidate.charAt(0) == '\'')) {
- // found loadModule, try to resolve
- final ModuleDefinition moduleDefinition = ModuleHelper.resolveModuleName(candidate.substring(1, candidate.length() - 1));
- if (moduleDefinition != null)
- fLoadedModules.add(moduleDefinition);
- }
- }
- }
- }
- }
-
- /**
- * @param originalCode
- */
- private void addInclude(final String code) {
- final List<Position> includePositions = AbstractCompletionParser.findInvocations("include(java.lang.String)", code);
-
- for (final Position position : includePositions) {
- try {
- final String call = code.substring(position.getOffset(), position.getOffset() + position.getLength());
- final String[] parameters = AbstractCompletionParser.getParameters(call);
- if (parameters.length > 0) {
- final String candidate = parameters[0].trim();
-
- if (candidate.charAt(0) == candidate.charAt(candidate.length() - 1)) {
- // TODO add string literal characters lookup method
- if ((candidate.charAt(0) == '"') || (candidate.charAt(0) == '\'')) {
- // found resource, try to resolve
- final Object includeResource = ResourceTools.resolve(candidate.substring(1, candidate.length() - 1), getResource());
- if (includeResource != null) {
- if (!fIncludes.containsKey(includeResource)) {
- // store object & content, as we need to parse this content multiple times
- fIncludes.put(includeResource, ResourceTools.toString(includeResource));
-
- // recursively process include files
- addInclude(fIncludes.get(includeResource));
- }
- }
- }
- }
- }
- } catch (final Exception e) {
- // ignore invalid include locations
- }
- }
- }
-
- @Override
- public String getOriginalCode() {
- return fOriginalCode;
- }
-
- @Override
- public String getProcessedCode() {
- return getOriginalCode();
- }
-
- @Override
- public Object getResource() {
- return fResource;
- }
-
- @Override
- public IScriptEngine getScriptEngine() {
- return fScriptEngine;
- }
-
- @Override
- public ScriptType getScriptType() {
- return fScriptType;
- }
-
- @Override
- public Collection<ModuleDefinition> getLoadedModules() {
- if (fLoadedModules == null) {
- // lazy loading of modules
- fLoadedModules = new HashSet<>();
-
- // add default environment module
- fLoadedModules.add(ModuleHelper.resolveModuleName(EnvironmentModule.MODULE_NAME));
-
- // process loadModule() calls
- addLoadedModules(getOriginalCode());
-
- for (final String includeContent : fIncludes.values()) {
- // recursively process include files for loadModule() calls
- if (includeContent != null)
- addLoadedModules(includeContent);
- }
-
- // add loaded modules from script engine
- if (getScriptEngine() != null) {
- for (final ModuleDefinition definition : ModuleHelper.getLoadedModules(getScriptEngine()))
- fLoadedModules.add(definition);
- }
- }
-
- return fLoadedModules;
- }
-
- @Override
- public Map<Object, String> getIncludedResources() {
- return fIncludes;
- }
-
- @Override
- public String getFilter() {
- return fFilter;
- }
-
- @Override
- public int getOffset() {
- return fOffset;
- }
-
- @Override
- public int getSelectionRange() {
- return fSelectionRange;
- }
-
- @Override
- public String getPackage() {
- return fPackage;
- }
-
- @Override
- public String getCaller() {
- return fCaller;
- }
-
- @Override
- public int getParameterOffset() {
- return fParameterOffset;
- }
-
- private static Collection<Bracket> matchBrackets(final String code, final char openChar, final char closeChar) {
- final List<Bracket> brackets = new ArrayList<>();
-
- for (int pos = 0; pos < code.length(); pos++) {
- final char c = code.charAt(pos);
- if (c == openChar) {
- // push new Bracket
- brackets.add(0, new Bracket(pos, -1));
-
- } else if (c == closeChar) {
- boolean found = false;
- for (final Bracket bracket : brackets) {
- if (bracket.fEnd == -1) {
- bracket.fEnd = pos;
- found = true;
- break;
- }
- }
-
- if (!found)
- brackets.add(0, new Bracket(-1, pos));
- }
- }
-
- return brackets;
- }
-
- private static Bracket getBracket(final Collection<Bracket> brackets, final int pos) {
- for (final Bracket bracket : brackets) {
- if ((bracket.fStart != -1) && (bracket.fStart <= pos) && (bracket.fEnd != -1) && (bracket.fEnd > pos))
- return bracket;
- }
-
- return null;
- }
-}
\ No newline at end of file
diff --git a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/IImageResolver.java b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/IImageResolver.java
index 472d010..fb5bce2 100644
--- a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/IImageResolver.java
+++ b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/IImageResolver.java
@@ -19,7 +19,7 @@
/**
* Returns an image instance. Only called when the actual image gets displayed.
- *
+ *
* @return image to be displayed in proposal
*/
Image getImage();
diff --git a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/ScriptCompletionProposal.java b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/ScriptCompletionProposal.java
index 0bb22d4..e3f4073 100644
--- a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/ScriptCompletionProposal.java
+++ b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/ScriptCompletionProposal.java
@@ -68,6 +68,7 @@
public ScriptCompletionProposal(final ICompletionContext context, final StyledString styledString, final String replacementString,
final IImageResolver imageResolver, final int sortOrder, final IHelpResolver helpResolver) {
this(context, styledString.getString(), replacementString, imageResolver, sortOrder, helpResolver);
+
fStyledString = styledString;
}
@@ -101,11 +102,7 @@
@Override
public void apply(final IDocument document) {
try {
- if (fContext.getFilter() != null)
- document.replace(fContext.getOffset() - fContext.getFilter().length(), fContext.getFilter().length(), fReplacementString);
-
- else
- document.replace(fContext.getOffset(), 0, fReplacementString);
+ document.replace(fContext.getReplaceOffset(), fContext.getReplaceLength(), fReplacementString);
} catch (final BadLocationException e) {
Logger.error(Activator.PLUGIN_ID, "Could not insert completion proposal into document", e);
@@ -114,11 +111,7 @@
@Override
public Point getSelection(final IDocument document) {
- if (fContext.getFilter() != null)
- return new Point((fContext.getOffset() - fContext.getFilter().length()) + fReplacementString.length(), 0);
-
- else
- return new Point(fContext.getOffset() + fReplacementString.length(), 0);
+ return new Point(fContext.getReplaceOffset() + fReplacementString.length(), 0);
}
@Override
@@ -159,33 +152,26 @@
// ------------------------------------------------------------------
@Override
public String getContent() {
- final String original = fContext.getOriginalCode();
- return original.substring(0, original.length() - fContext.getFilter().length()) + fReplacementString;
+ final String prefix = fContext.getText().substring(0, fContext.getReplaceOffset() - fContext.getFilter().length());
+ final String suffix = fContext.getText().substring(fContext.getReplaceOffset());
+
+ return prefix + fReplacementString + suffix;
}
@Override
public int getCursorPosition() {
- return getContent().length();
+ final String prefix = fContext.getText().substring(0, fContext.getReplaceOffset() - fContext.getFilter().length());
+
+ return (prefix + fReplacementString).length();
}
@Override
public String getLabel() {
- return getDisplayString() + "x";
+ return getDisplayString();
}
@Override
public String getDescription() {
return getAdditionalProposalInfo();
}
-
- // ------------------------------------------------------------------
- // Custom methods for script completion in EASE
- // ------------------------------------------------------------------
- public String getReplacementString() {
- return fReplacementString;
- }
-
- public int getCursorStartPosition() {
- return fContext.getOriginalCode().length() - fContext.getFilter().length();
- }
}
diff --git a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/AbstractCompletionProvider.java b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/AbstractCompletionProvider.java
new file mode 100644
index 0000000..a22a825
--- /dev/null
+++ b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/AbstractCompletionProvider.java
@@ -0,0 +1,187 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Christian Pontesegger and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License_Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian Pontesegger - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.ui.completion.provider;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.ease.ICompletionContext;
+import org.eclipse.ease.modules.ModuleDefinition;
+import org.eclipse.ease.service.IScriptService;
+import org.eclipse.ease.ui.completion.IHelpResolver;
+import org.eclipse.ease.ui.completion.IImageResolver;
+import org.eclipse.ease.ui.completion.ScriptCompletionProposal;
+import org.eclipse.ease.ui.completion.tokenizer.InputTokenizer;
+import org.eclipse.ease.ui.completion.tokenizer.TokenList;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.StyledString;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.PlatformUI;
+
+public abstract class AbstractCompletionProvider implements ICompletionProvider {
+
+ public static class DescriptorImageResolver implements IImageResolver {
+ private final ImageDescriptor fDescriptor;
+
+ public DescriptorImageResolver() {
+ fDescriptor = null;
+ }
+
+ public DescriptorImageResolver(ImageDescriptor descriptor) {
+ fDescriptor = descriptor;
+ }
+
+ @Override
+ public Image getImage() {
+ return (getDescriptor() != null) ? getDescriptor().createImage() : null;
+ }
+
+ protected ImageDescriptor getDescriptor() {
+ return fDescriptor;
+ }
+ }
+
+ public static class WorkbenchDescriptorImageResolver extends DescriptorImageResolver {
+ private final String fIdentifier;
+
+ public WorkbenchDescriptorImageResolver(String identifier) {
+ super();
+
+ fIdentifier = identifier;
+ }
+
+ @Override
+ protected ImageDescriptor getDescriptor() {
+ return PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(fIdentifier);
+ }
+ }
+
+ protected static ModuleDefinition getModuleDefinition(final String identifier) {
+ final IScriptService scriptService = PlatformUI.getWorkbench().getService(IScriptService.class);
+ return scriptService.getModuleDefinition(identifier);
+ }
+
+ private Collection<ScriptCompletionProposal> fProposals = null;
+ private ICompletionContext fContext;
+
+ @Override
+ public boolean isActive(final ICompletionContext context) {
+ return true;
+ }
+
+ @Override
+ public Collection<ScriptCompletionProposal> getProposals(final ICompletionContext context) {
+ fContext = context;
+ fProposals = new ArrayList<>();
+
+ prepareProposals(context);
+
+ final Collection<ScriptCompletionProposal> result = fProposals;
+ fProposals = null;
+ fContext = null;
+ return result;
+ }
+
+ /**
+ * Get the current context. Only valid during proposal evaluation. Clients may retrieve the content when {@link #prepareProposals(ICompletionContext)} is
+ * called.
+ *
+ * @return the current context or <code>null</code> when proposals are not evaluated
+ */
+ public ICompletionContext getContext() {
+ return fContext;
+ }
+
+ protected void addProposal(final ScriptCompletionProposal proposal) {
+ fProposals.add(proposal);
+ }
+
+ protected void addProposal(final StyledString displayString, final String replacementString, final IImageResolver imageResolver, final int priority,
+ final IHelpResolver helpResolver) {
+
+ fProposals.add(new ScriptCompletionProposal(fContext, displayString, replacementString, imageResolver, priority, helpResolver));
+ }
+
+ protected void addProposal(final String displayString, final String replacementString, final IImageResolver imageResolver, final int priority,
+ final IHelpResolver helpResolver) {
+
+ fProposals.add(new ScriptCompletionProposal(fContext, displayString, replacementString, imageResolver, priority, helpResolver));
+ }
+
+ protected boolean matchesFilter(final String proposal) {
+ return matches(fContext.getFilter(), proposal);
+ }
+
+ protected boolean matchesFilterIgnoreCase(final String proposal) {
+ return matchesIgnoreCase(fContext.getFilter(), proposal);
+ }
+
+ protected boolean isMethodParameter(ICompletionContext context, Method calledMethod, int parameterIndex) {
+ return isMethodParameter(context, calledMethod.getName(), parameterIndex);
+ }
+
+ protected boolean isMethodParameter(ICompletionContext context, String calledMethod, int parameterIndex) {
+ return isMethodCall(context) && matchesMethodName(context, calledMethod) && isParameterIndex(context, parameterIndex);
+ }
+
+ protected boolean isStringParameter(ICompletionContext context) {
+ return isMethodCall(context) && context.isStringLiteral(context.getFilterToken());
+ }
+
+ private boolean matchesMethodName(ICompletionContext context, String name) {
+ final List<Object> tokens = context.getTokens();
+ final TokenList candidates = new TokenList(tokens).getFromLast("(");
+
+ if (!candidates.isEmpty())
+ return name.equals(tokens.get(tokens.size() - 1 - candidates.size()));
+
+ return false;
+ }
+
+ private boolean isMethodCall(ICompletionContext context) {
+ final TokenList candidates = new TokenList(context.getTokens()).getFromLast("(");
+
+ if (!candidates.isEmpty()) {
+ candidates.removeIfMatches(0, "(");
+ candidates.removeAny(",");
+
+ return candidates.isEmpty() || ((candidates.size() == 1) && (InputTokenizer.isTextFilter(candidates.get(0))));
+ }
+
+ return false;
+ }
+
+ private boolean isParameterIndex(ICompletionContext context, int parameterIndex) {
+ final TokenList candidates = new TokenList(context.getTokens()).getFromLast("(");
+
+ if (!candidates.isEmpty()) {
+ candidates.removeIfMatches(0, "(");
+ return parameterIndex == candidates.stream().filter(t -> ",".equals(t)).count();
+ }
+
+ return false;
+ }
+
+ protected static boolean matches(final String filter, final String proposal) {
+ return (filter != null) ? proposal.startsWith(filter) : true;
+ }
+
+ protected static boolean matchesIgnoreCase(final String filter, final String proposal) {
+ return (filter != null) ? proposal.toLowerCase().startsWith(filter.toLowerCase()) : true;
+ }
+
+ protected abstract void prepareProposals(ICompletionContext context);
+}
diff --git a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/AbstractFileLocationCompletionProvider.java b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/AbstractFileLocationCompletionProvider.java
index 920a6a2..6115dc1 100644
--- a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/AbstractFileLocationCompletionProvider.java
+++ b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/AbstractFileLocationCompletionProvider.java
@@ -10,6 +10,7 @@
* Contributors:
* Christian Pontesegger - initial API and implementation
*******************************************************************************/
+
package org.eclipse.ease.ui.completion.provider;
import java.io.File;
@@ -20,71 +21,26 @@
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.Platform;
import org.eclipse.ease.ICompletionContext;
-import org.eclipse.ease.ICompletionContext.Type;
import org.eclipse.ease.tools.ResourceTools;
-import org.eclipse.ease.ui.completion.AbstractCompletionProvider;
import org.eclipse.ease.ui.completion.IImageResolver;
import org.eclipse.ease.ui.completion.ScriptCompletionProposal;
-import org.eclipse.jface.resource.ImageDescriptor;
-import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.model.IWorkbenchAdapter;
-import org.eclipse.ui.model.WorkbenchLabelProvider;
public abstract class AbstractFileLocationCompletionProvider extends AbstractCompletionProvider {
- private static class ResourceImageResolver implements IImageResolver {
-
- private final Object fFile;
-
- public ResourceImageResolver(Object file) {
- fFile = file;
- }
-
- @Override
- public Image getImage() {
- if (fFile instanceof IResource) {
- final IWorkbenchAdapter adapter = Platform.getAdapterManager().getAdapter(fFile, IWorkbenchAdapter.class);
- return (adapter != null) ? adapter.getImageDescriptor(fFile).createImage() : null;
-
- } else if (fFile instanceof File) {
-
- if (isRootFile((File) fFile))
- return PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_OBJ_FOLDER).createImage();
-
- if (((File) fFile).isFile())
- return PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_OBJ_FILE).createImage();
-
- if (((File) fFile).isDirectory())
- return PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_OBJ_FOLDER).createImage();
-
- } else if (fFile instanceof ImageDescriptor)
- return ((ImageDescriptor) fFile).createImage();
-
- return null;
- }
- }
-
private static final int ORDER_URI_SCHEME = ScriptCompletionProposal.ORDER_DEFAULT;
private static final int ORDER_PROJECT = ScriptCompletionProposal.ORDER_DEFAULT + 1;
private static final int ORDER_FOLDER = ScriptCompletionProposal.ORDER_DEFAULT + 2;
private static final int ORDER_FILE = ScriptCompletionProposal.ORDER_DEFAULT + 3;
- private final ILabelProvider fLabelProvider = new WorkbenchLabelProvider();
-
- public AbstractFileLocationCompletionProvider() {
- Display.getDefault().syncExec(() -> fLabelProvider.getImage(ResourcesPlugin.getWorkspace().getRoot()));
- }
-
@Override
public boolean isActive(final ICompletionContext context) {
- return (context.getType() == Type.STRING_LITERAL);
+ return super.isActive(context) && isStringParameter(context);
}
@Override
@@ -95,7 +51,7 @@
if ((matches(context.getFilter(), "workspace:/")) && (showCandidate("workspace://")))
addProposal("workspace://", "workspace://", null, ORDER_URI_SCHEME, null);
- if ((matches(context.getFilter(), "project:/")) && (getContext().getResource() instanceof IResource) && (showCandidate("project://")))
+ if ((matches(context.getFilter(), "project:/")) && (showCandidate("project://")) && (getContext().getResource() instanceof IResource))
addProposal("project://", "project://", null, ORDER_URI_SCHEME, null);
if ((matches(context.getFilter(), "file://")) && (showCandidate("file:///")))
@@ -143,14 +99,10 @@
final Object parentFolder = resolver.getParentFolder();
if ((parentFolder instanceof IResource) && !(parentFolder instanceof IWorkspaceRoot)) {
- addProposal("..", resolver.getParentString() + "../",
- new ResourceImageResolver(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_OBJ_FOLDER)), ORDER_FOLDER,
- null);
+ addProposal("..", resolver.getParentString() + "../", new WorkbenchDescriptorImageResolver(ISharedImages.IMG_OBJ_FOLDER), ORDER_FOLDER, null);
} else if ((parentFolder instanceof File) && !(isRootFile((File) parentFolder)) && !(ResourceTools.VIRTUAL_WINDOWS_ROOT.equals(parentFolder))) {
- addProposal("..", resolver.getParentString() + "/../",
- new ResourceImageResolver(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_OBJ_FOLDER)), ORDER_FOLDER,
- null);
+ addProposal("..", resolver.getParentString() + "/../", new WorkbenchDescriptorImageResolver(ISharedImages.IMG_OBJ_FOLDER), ORDER_FOLDER, null);
}
}
}
@@ -210,4 +162,35 @@
protected static boolean isFolder(final Object candidate) {
return ((candidate instanceof File) && (((File) candidate).isDirectory())) || (candidate instanceof IContainer);
}
-}
\ No newline at end of file
+
+ private static final class ResourceImageResolver implements IImageResolver {
+
+ private final Object fFile;
+
+ private ResourceImageResolver(Object file) {
+ fFile = file;
+ }
+
+ @Override
+ public Image getImage() {
+ if (fFile instanceof IResource) {
+ final IWorkbenchAdapter adapter = Platform.getAdapterManager().getAdapter(fFile, IWorkbenchAdapter.class);
+ return (adapter == null) ? null : adapter.getImageDescriptor(fFile).createImage();
+
+ } else if (fFile instanceof File) {
+
+ if (isRootFile((File) fFile))
+ return PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_OBJ_FOLDER).createImage();
+
+ if (((File) fFile).isFile())
+ return PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_OBJ_FILE).createImage();
+
+ if (((File) fFile).isDirectory())
+ return PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_OBJ_FOLDER).createImage();
+
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/AbstractPathCompletionProvider.java b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/AbstractPathCompletionProvider.java
new file mode 100644
index 0000000..743aeb8
--- /dev/null
+++ b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/AbstractPathCompletionProvider.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Christian Pontesegger and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License_Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian Pontesegger - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.ui.completion.provider;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.ease.ICompletionContext;
+
+public abstract class AbstractPathCompletionProvider extends AbstractCompletionProvider {
+
+ protected <T> Collection<T> filter(Collection<T> elements, ICompletionContext context) {
+ final Collection<T> filteredElements = new ArrayList<>();
+
+ final String filter = getFilter(context);
+ for (final T element : elements) {
+ final IPath path = convertToPath(element).makeAbsolute();
+ if (path.toString().startsWith(filter)) {
+ if ((new Path(filter).segmentCount() + (filter.endsWith("/") ? 1 : 0)) == path.segmentCount())
+ filteredElements.add(element);
+ }
+ }
+
+ return filteredElements;
+ }
+
+ private String getFilter(ICompletionContext context) {
+ return (context.getFilter().startsWith("/")) ? context.getFilter() : "/" + context.getFilter();
+ }
+
+ protected Collection<IPath> getPathsFromElements(Collection<?> elements) {
+ final Collection<IPath> paths = new LinkedHashSet<>();
+
+ final List<IPath> pathsFromElements = elements.stream().map(e -> convertToPath(e)).filter(p -> p.segmentCount() > 0)
+ .map(p -> p.removeLastSegments(1).makeAbsolute()).collect(Collectors.toList());
+ for (final IPath path : pathsFromElements)
+ addPath(path, paths);
+
+ return paths;
+ }
+
+ private void addPath(IPath path, Collection<IPath> paths) {
+ if (!Path.ROOT.equals(path)) {
+ addPath(path.removeLastSegments(1), paths);
+ paths.add(path);
+ }
+ }
+
+ private IPath convertToPath(Object element) {
+ if (element instanceof IPath)
+ return (IPath) element;
+
+ return toPath(element);
+ }
+
+ protected abstract IPath toPath(Object element);
+
+}
diff --git a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/EnvironmentLocationCompletionProvider.java b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/EnvironmentLocationCompletionProvider.java
index 0b888ad..6aa7d70 100644
--- a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/EnvironmentLocationCompletionProvider.java
+++ b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/EnvironmentLocationCompletionProvider.java
@@ -14,22 +14,23 @@
package org.eclipse.ease.ui.completion.provider;
import org.eclipse.ease.ICompletionContext;
+import org.eclipse.ease.modules.EnvironmentModule;
public class EnvironmentLocationCompletionProvider extends AbstractFileLocationCompletionProvider {
@Override
public boolean isActive(final ICompletionContext context) {
- return super.isActive(context) && ((context.getCaller().endsWith("include")) || (context.getCaller().endsWith("loadJar")))
- && (context.getParameterOffset() == 0);
+ return super.isActive(context)
+ && (isMethodParameter(context, EnvironmentModule.INCLUDE_METHOD, 0) || isMethodParameter(context, EnvironmentModule.LOAD_JAR_METHOD, 0));
}
@Override
protected boolean showCandidate(final Object candidate) {
if (isFile(candidate)) {
- if (getContext().getCaller().endsWith("include"))
+ if (isMethodParameter(getContext(), EnvironmentModule.INCLUDE_METHOD, 0))
return hasFileExtension(candidate, getContext().getScriptType().getDefaultExtension());
- else if (getContext().getCaller().endsWith("loadJar"))
+ else if (isMethodParameter(getContext(), EnvironmentModule.LOAD_JAR_METHOD, 0))
return hasFileExtension(candidate, "jar");
}
diff --git a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/ICompletionProvider.java b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/ICompletionProvider.java
similarity index 60%
rename from plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/ICompletionProvider.java
rename to plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/ICompletionProvider.java
index addcb75..8509c70 100644
--- a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/ICompletionProvider.java
+++ b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/ICompletionProvider.java
@@ -12,35 +12,30 @@
* Christian Pontesegger - rewrite of this interface
*******************************************************************************/
-package org.eclipse.ease.ui.completion;
+package org.eclipse.ease.ui.completion.provider;
import java.util.Collection;
-import org.eclipse.core.runtime.Platform;
import org.eclipse.ease.ICompletionContext;
-import org.eclipse.ease.ui.Activator;
+import org.eclipse.ease.ui.completion.ScriptCompletionProposal;
public interface ICompletionProvider {
- /** Trace enablement for code completion. */
- boolean TRACE_CODE_COMPLETION = Activator.getDefault().isDebugging()
- && "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.ease.ui/debug/codeCompletion"));
-
/**
- * Calculate all matching proposals for given {@link ICompletionContext}.
+ * Calculate all matching proposals.
*
* @param context
- * {@link ICompletionContext} with necessary information to calculate proposals.
+ * with necessary information to calculate proposals.
* @return Collection of matching proposals.
*/
- Collection<? extends ScriptCompletionProposal> getProposals(ICompletionContext context);
+ Collection<ScriptCompletionProposal> getProposals(ICompletionContext context);
/**
* Query indicating that this providers completion proposals should be taken into account.
*
* @param context
- * {@link ICompletionContext} with necessary information to calculate proposals.
+ * with necessary information to calculate proposals.
* @return <code>true</code> when active
*/
boolean isActive(ICompletionContext context);
-}
\ No newline at end of file
+}
diff --git a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/LoadModuleCompletionProvider.java b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/LoadModuleCompletionProvider.java
index caf8e34..22a532e 100644
--- a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/LoadModuleCompletionProvider.java
+++ b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/LoadModuleCompletionProvider.java
@@ -13,78 +13,52 @@
package org.eclipse.ease.ui.completion.provider;
import java.util.Collection;
-import java.util.HashSet;
import org.eclipse.core.runtime.IPath;
-import org.eclipse.core.runtime.Path;
import org.eclipse.ease.ICompletionContext;
-import org.eclipse.ease.ICompletionContext.Type;
+import org.eclipse.ease.modules.EnvironmentModule;
import org.eclipse.ease.modules.ModuleDefinition;
import org.eclipse.ease.service.IScriptService;
+import org.eclipse.ease.service.ScriptService;
import org.eclipse.ease.ui.Activator;
-import org.eclipse.ease.ui.completion.AbstractCompletionProvider;
import org.eclipse.jface.viewers.StyledString;
import org.eclipse.ui.ISharedImages;
-import org.eclipse.ui.PlatformUI;
-public class LoadModuleCompletionProvider extends AbstractCompletionProvider {
+public class LoadModuleCompletionProvider extends AbstractPathCompletionProvider {
@Override
public boolean isActive(final ICompletionContext context) {
- return (context.getType() == Type.STRING_LITERAL) && (context.getCaller().endsWith("loadModule"));
+ return (super.isActive(context)) && isMethodParameter(context, EnvironmentModule.LOAD_MODULE_METHOD, 0);
}
@Override
protected void prepareProposals(final ICompletionContext context) {
- // create a path to search for
- final IPath filterPath = new Path(context.getFilter());
- final IPath searchPath;
-
- if (filterPath.segmentCount() > 1)
- searchPath = filterPath.makeAbsolute().removeLastSegments(1);
-
- else if (filterPath.hasTrailingSeparator())
- searchPath = filterPath.makeAbsolute();
-
- else
- searchPath = new Path("/");
-
- final Collection<String> pathProposals = new HashSet<>();
-
- final IScriptService scriptService = PlatformUI.getWorkbench().getService(IScriptService.class);
+ final IScriptService scriptService = ScriptService.getInstance();
final Collection<ModuleDefinition> availableModules = scriptService.getAvailableModules();
- for (final ModuleDefinition definition : availableModules) {
- final IPath modulePath = definition.getPath();
- if (searchPath.isPrefixOf(modulePath)) {
- // this is a valid candidate
+ final Collection<IPath> paths = filter(getPathsFromElements(availableModules), context);
- if ((searchPath.segmentCount() + 1) == modulePath.segmentCount()) {
+ paths.stream().forEach(p -> {
+ addProposal(p.toString(), p.toString() + "/", new WorkbenchDescriptorImageResolver(ISharedImages.IMG_OBJ_FOLDER), 10, null);
+ });
- if (matchesFilterIgnoreCase(definition.getName())) {
+ final Collection<ModuleDefinition> modules = filter(availableModules, context);
+ modules.stream().forEach(m -> {
+ final StyledString displayString = new StyledString(m.getPath().lastSegment());
+ if (!m.isVisible())
+ displayString.append(" (hidden)", StyledString.DECORATIONS_STYLER);
- // add module proposal
- final StyledString displayString = new StyledString(modulePath.lastSegment());
- if (!definition.isVisible())
- displayString.append(" (hidden)", StyledString.DECORATIONS_STYLER);
+ addProposal(displayString, m.getName(), new DescriptorImageResolver(Activator.getImageDescriptor(Activator.PLUGIN_ID, "/icons/eobj16/module.png")),
+ 0, null);
+ });
+ }
- addProposal(displayString, definition.getName(),
- new DescriptorImageResolver(Activator.getImageDescriptor(Activator.PLUGIN_ID, "/icons/eobj16/module.png")), 0, null);
- }
+ @Override
+ protected IPath toPath(Object element) {
+ if (element instanceof ModuleDefinition)
+ return ((ModuleDefinition) element).getPath();
- } else {
- // add path proposal; collect them first to avoid duplicates
- pathProposals.add(modulePath.removeLastSegments(1).toString());
- }
- }
- }
-
- // add path proposals
- for (final String pathProposal : pathProposals) {
- if (matchesFilterIgnoreCase(pathProposal))
- addProposal(pathProposal, pathProposal + "/",
- new DescriptorImageResolver(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_OBJ_FOLDER)), 10, null);
- }
+ throw new IllegalArgumentException("element is not of type ModuleDefinition");
}
}
\ No newline at end of file
diff --git a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/LoadedModuleCompletionProvider.java b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/LoadedModuleCompletionProvider.java
index 8ea1d6c..15cc847 100644
--- a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/LoadedModuleCompletionProvider.java
+++ b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/LoadedModuleCompletionProvider.java
@@ -10,17 +10,14 @@
* Contributors:
* Christian Pontesegger - initial API and implementation
*******************************************************************************/
+
package org.eclipse.ease.ui.completion.provider;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-
import org.eclipse.ease.ICompletionContext;
-import org.eclipse.ease.ICompletionContext.Type;
import org.eclipse.ease.modules.ModuleDefinition;
import org.eclipse.ease.ui.Activator;
-import org.eclipse.ease.ui.completion.AbstractCompletionProvider;
import org.eclipse.ease.ui.completion.ScriptCompletionProposal;
+import org.eclipse.ease.ui.completion.tokenizer.TokenList;
import org.eclipse.ease.ui.modules.ui.ModulesTools;
import org.eclipse.jface.viewers.StyledString;
@@ -28,42 +25,60 @@
@Override
public boolean isActive(final ICompletionContext context) {
- return context.getType() == Type.NONE;
+ return super.isActive(context) && isModuleContext(context);
+ }
+
+ private boolean isModuleContext(ICompletionContext context) {
+ TokenList tokenList = new TokenList(context.getTokens());
+
+ final TokenList methodCall = tokenList.getFromLast("(");
+ if (!methodCall.isEmpty()) {
+ methodCall.remove(0);
+ while (methodCall.removeIfMatches(0, ",")) {
+ // repeat
+ }
+
+ tokenList = methodCall;
+ }
+
+ if (tokenList.isEmpty())
+ return true;
+
+ if (tokenList.size() == 1) {
+ return (tokenList.get(0) instanceof String) && (!context.isStringLiteral(tokenList.get(0).toString()));
+ }
+
+ return false;
}
@Override
protected void prepareProposals(final ICompletionContext context) {
for (final ModuleDefinition definition : context.getLoadedModules()) {
// field proposals
- for (final Field field : definition.getFields()) {
- if (matchesFilterIgnoreCase(field.getName())) {
- final StyledString styledString = new StyledString(field.getName());
- styledString.append(" : " + field.getType().getSimpleName(), StyledString.DECORATIONS_STYLER);
- styledString.append(" - " + definition.getName(), StyledString.QUALIFIER_STYLER);
+ definition.getFields().stream().filter(f -> f.getName().startsWith(context.getFilter())).forEach(field -> {
+ final StyledString styledString = new StyledString(field.getName());
+ styledString.append(" : " + field.getType().getSimpleName(), StyledString.DECORATIONS_STYLER);
+ styledString.append(" - " + definition.getName(), StyledString.QUALIFIER_STYLER);
- addProposal(styledString, field.getName(),
- new DescriptorImageResolver(Activator.getLocalImageDescriptor("/icons/eobj16/field_public_obj.png")),
- ScriptCompletionProposal.ORDER_FIELD, null);
- }
- }
+ addProposal(styledString, field.getName(), new DescriptorImageResolver(Activator.getLocalImageDescriptor("/icons/eobj16/field_public_obj.png")),
+ ScriptCompletionProposal.ORDER_FIELD, null);
+ });
// method proposals
- for (final Method method : definition.getMethods()) {
- if (matchesFilterIgnoreCase(method.getName())) {
- final StyledString styledString = ModulesTools.getSignature(method, true);
- styledString.append(" - " + definition.getName(), StyledString.QUALIFIER_STYLER);
+ definition.getMethods().stream().filter(m -> m.getName().startsWith(context.getFilter())).forEach(method -> {
+ final StyledString styledString = ModulesTools.getSignature(method, true);
+ styledString.append(" - " + definition.getName(), StyledString.QUALIFIER_STYLER);
- if ((method.getParameterTypes().length - ModulesTools.getOptionalParameterCount(method)) > 0) {
- addProposal(styledString, method.getName() + "(",
- new DescriptorImageResolver(Activator.getLocalImageDescriptor("/icons/eobj16/field_public_obj.png")),
- ScriptCompletionProposal.ORDER_METHOD, null);
- } else {
- addProposal(styledString, method.getName() + "()",
- new DescriptorImageResolver(Activator.getLocalImageDescriptor("/icons/eobj16/field_public_obj.png")),
- ScriptCompletionProposal.ORDER_METHOD, null);
- }
+ if ((method.getParameterTypes().length - ModulesTools.getOptionalParameterCount(method)) > 0) {
+ addProposal(styledString, method.getName() + "(",
+ new DescriptorImageResolver(Activator.getLocalImageDescriptor("/icons/eobj16/field_public_obj.png")),
+ ScriptCompletionProposal.ORDER_METHOD, null);
+ } else {
+ addProposal(styledString, method.getName() + "()",
+ new DescriptorImageResolver(Activator.getLocalImageDescriptor("/icons/eobj16/field_public_obj.png")),
+ ScriptCompletionProposal.ORDER_METHOD, null);
}
- }
+ });
}
}
}
diff --git a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/VariablesCompletionProvider.java b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/VariablesCompletionProvider.java
index 82dbf30..fc41436 100644
--- a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/VariablesCompletionProvider.java
+++ b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/provider/VariablesCompletionProvider.java
@@ -12,14 +12,17 @@
*******************************************************************************/
package org.eclipse.ease.ui.completion.provider;
+import java.util.Collection;
+import java.util.List;
import java.util.Map.Entry;
+import java.util.stream.Collectors;
import org.eclipse.ease.ICompletionContext;
-import org.eclipse.ease.ICompletionContext.Type;
import org.eclipse.ease.modules.IEnvironment;
import org.eclipse.ease.ui.Activator;
-import org.eclipse.ease.ui.completion.AbstractCompletionProvider;
import org.eclipse.ease.ui.completion.ScriptCompletionProposal;
+import org.eclipse.ease.ui.completion.tokenizer.InputTokenizer;
+import org.eclipse.ease.ui.completion.tokenizer.TokenList;
import org.eclipse.jface.viewers.StyledString;
/**
@@ -29,25 +32,40 @@
@Override
public boolean isActive(final ICompletionContext context) {
- return super.isActive(context) && (context.getScriptEngine() != null) && (context.getType() == Type.NONE);
+ return super.isActive(context) && (context.getScriptEngine() != null) && ((context.getTokens().size() <= 1) || (isParameter(context)));
+ }
+
+ private boolean isParameter(ICompletionContext context) {
+ final TokenList candidates = new TokenList(context.getTokens()).getFromLast("(");
+
+ if (!candidates.isEmpty()) {
+ candidates.removeIfMatches(0, "(");
+ candidates.removeAny(",");
+
+ return candidates.isEmpty() || ((candidates.size() == 1) && (InputTokenizer.isTextFilter(candidates.get(0))));
+ }
+
+ return false;
}
@Override
protected void prepareProposals(final ICompletionContext context) {
- for (final Entry<String, Object> variable : context.getScriptEngine().getVariables().entrySet()) {
- // ignore mapped modules
- if (!variable.getKey().startsWith(IEnvironment.MODULE_PREFIX)) {
- if (matchesFilterIgnoreCase(variable.getKey())) {
- final String type = (variable.getValue() != null) ? variable.getValue().getClass().getSimpleName() : "null";
- final StyledString styledString = new StyledString(variable.getKey());
- styledString.append(" : " + type, StyledString.DECORATIONS_STYLER);
- styledString.append(" - " + "Variable", StyledString.QUALIFIER_STYLER);
+ final Collection<Entry<String, Object>> elements = context.getScriptEngine().getVariables().entrySet();
- addProposal(styledString, variable.getKey(),
- new DescriptorImageResolver(Activator.getLocalImageDescriptor("/icons/eobj16/debug_local_variable.png")),
- ScriptCompletionProposal.ORDER_FIELD, null);
- }
- }
+ final List<Entry<String, Object>> filteredEntries = elements.stream().filter(e -> !e.getKey().startsWith(IEnvironment.MODULE_PREFIX))
+ .filter(e -> matchesFilterIgnoreCase(e.getKey())).collect(Collectors.toList());
+
+ for (final Entry<String, Object> entry : filteredEntries) {
+ final StyledString styledString = new StyledString(entry.getKey());
+ styledString.append(String.format(" : %s", getClassName(entry.getValue())), StyledString.DECORATIONS_STYLER);
+ styledString.append(" - Variable", StyledString.QUALIFIER_STYLER);
+
+ addProposal(styledString, entry.getKey(), new DescriptorImageResolver(Activator.getLocalImageDescriptor("/icons/eobj16/debug_local_variable.png")),
+ ScriptCompletionProposal.ORDER_FIELD, null);
}
}
+
+ private String getClassName(Object entry) {
+ return (entry == null) ? "null" : entry.getClass().getSimpleName();
+ }
}
diff --git a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/tokenizer/Bracket.java b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/tokenizer/Bracket.java
new file mode 100644
index 0000000..9f06f98
--- /dev/null
+++ b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/tokenizer/Bracket.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Christian Pontesegger and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License_Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian Pontesegger - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.ui.completion.tokenizer;
+
+import java.util.Objects;
+
+public class Bracket {
+ private final int fStart;
+ private int fEnd;
+
+ public Bracket(final int start, final int end) {
+ fStart = start;
+ fEnd = end;
+ }
+
+ public int getStart() {
+ return fStart;
+ }
+
+ public int getEnd() {
+ return fEnd;
+ }
+
+ public void setEnd(int end) {
+ fEnd = end;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(fEnd, fStart);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final Bracket other = (Bracket) obj;
+ return (fEnd == other.fEnd) && (fStart == other.fStart);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("start: %d, end: %d", getStart(), getEnd());
+ }
+}
diff --git a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/tokenizer/BracketMatcher.java b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/tokenizer/BracketMatcher.java
new file mode 100644
index 0000000..1a58edd
--- /dev/null
+++ b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/tokenizer/BracketMatcher.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Christian Pontesegger and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License_Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian Pontesegger - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.ui.completion.tokenizer;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class BracketMatcher {
+
+ private static final char OPEN = '(';
+ private static final char CLOSE = ')';
+
+ private final List<Bracket> fBrackets;
+
+ public BracketMatcher(String input) {
+ fBrackets = new ArrayList<>();
+
+ for (int pos = 0; pos < input.length(); pos++) {
+ final char c = input.charAt(pos);
+ if (c == OPEN) {
+ fBrackets.add(0, new Bracket(pos, -1));
+
+ } else if (c == CLOSE) {
+ for (final Bracket bracket : fBrackets) {
+ if (bracket.getEnd() == -1) {
+ bracket.setEnd(pos);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ public List<Bracket> getBrackets() {
+ return fBrackets;
+ }
+
+ public boolean hasOpenBrackets() {
+ return getBrackets().stream().anyMatch(b -> b.getEnd() == -1);
+ }
+
+ public List<Bracket> getOpenBrackets() {
+ return getBrackets().stream().filter(b -> b.getEnd() == -1).collect(Collectors.toList());
+ }
+}
diff --git a/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/modules/ModulesToolsTest.java b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/tokenizer/IVariablesResolver.java
similarity index 78%
copy from tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/modules/ModulesToolsTest.java
copy to plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/tokenizer/IVariablesResolver.java
index d20563c..2aa0315 100644
--- a/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/modules/ModulesToolsTest.java
+++ b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/tokenizer/IVariablesResolver.java
@@ -11,8 +11,10 @@
* Christian Pontesegger - initial API and implementation
*******************************************************************************/
-package org.eclipse.ease.ui.modules;
+package org.eclipse.ease.ui.completion.tokenizer;
-public class ModulesToolsTest {
+@FunctionalInterface
+public interface IVariablesResolver {
+ Class<?> resolveClass(String variableName);
}
diff --git a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/tokenizer/InputTokenizer.java b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/tokenizer/InputTokenizer.java
new file mode 100644
index 0000000..2687793
--- /dev/null
+++ b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/tokenizer/InputTokenizer.java
@@ -0,0 +1,311 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Christian Pontesegger and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License_Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian Pontesegger - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.ui.completion.tokenizer;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class InputTokenizer {
+
+ private static final Pattern PACKAGE_PATTERN = Pattern.compile("(java|com|org)\\.([\\p{Lower}\\d]+\\.?)*");
+ private static final Pattern CLASS_PATTERN = Pattern.compile("(java|com|org)\\.([\\p{Lower}\\d]+\\.?)\\.\\p{Upper}(\\w)*");
+ private static final Pattern VARIABLES_PATTERN = Pattern.compile("\\p{Alpha}\\w*");
+
+ private static final char[] DELIMITERS = { '.', '(', ',' };
+
+ public static boolean isDelimiter(Object element) {
+ for (final char c : DELIMITERS) {
+ if (new String(new char[] { c }).equals(element))
+ return true;
+ }
+
+ return "()".equals(element) || ")".equals(element);
+ }
+
+ public static boolean isTextFilter(Object element) {
+ return (element instanceof String) && (!isDelimiter(element));
+ }
+
+ private final IVariablesResolver fVariablesResolver;
+
+ public InputTokenizer() {
+ this(v -> null);
+ }
+
+ public InputTokenizer(IVariablesResolver variablesResolver) {
+ fVariablesResolver = variablesResolver;
+ }
+
+ public List<Object> getTokens(String input) {
+ return getTokensFromSimplifiedInput(getSimplifiedInput(input));
+ }
+
+ private List<Object> getTokensFromSimplifiedInput(String simpleInput) {
+ final List<Object> simpleToken = getSimpleToken(simpleInput);
+ if (simpleToken != null)
+ return simpleToken;
+
+ final int delimiterPosition = findLastDelimiter(simpleInput);
+ if (delimiterPosition > 0)
+ return divideAndConquerTokens(simpleInput, delimiterPosition);
+ else
+ return Arrays.asList(simpleInput);
+ }
+
+ private List<Object> divideAndConquerTokens(String simpleInput, final int delimiterPosition) {
+ final List<Object> tokens = new ArrayList<>();
+ final String beforeDelimiter = simpleInput.substring(0, delimiterPosition);
+ final String delimiterAndRest = simpleInput.substring(delimiterPosition).trim();
+
+ tokens.addAll(getTokensFromSimplifiedInput(beforeDelimiter));
+
+ final Class<?> lastClass = getTrailingClassToken(tokens);
+ final Method method = (lastClass != null) ? detectMethod(lastClass, delimiterAndRest.substring(1)) : null;
+
+ if (method != null)
+ tokens.add(method);
+
+ else if ("()".equals(delimiterAndRest))
+ tokens.add(delimiterAndRest);
+
+ else if (delimiterAndRest.startsWith("(") && (delimiterAndRest.length() > 1)) {
+ tokens.add("(");
+ tokens.add(delimiterAndRest.substring(1).trim());
+
+ } else if (delimiterAndRest.startsWith(".") && (delimiterAndRest.length() > 1)) {
+ tokens.add(".");
+ tokens.add(delimiterAndRest.substring(1).trim());
+
+ } else if (delimiterAndRest.startsWith(",") && (delimiterAndRest.length() > 1)) {
+ tokens.add(",");
+ tokens.add(delimiterAndRest.substring(1).trim());
+
+ } else
+ tokens.add(delimiterAndRest);
+
+ return tokens;
+ }
+
+ private Method detectMethod(Class<?> clazz, String methodName) {
+ return Arrays.asList(clazz.getMethods()).stream().filter(m -> methodName.equals(m.getName())).findFirst().orElse(null);
+ }
+
+ private Class<?> getTrailingClassToken(List<Object> tokens) {
+ Object checkToken = null;
+ if ((tokens.size() >= 2) && ("()".equals(tokens.get(tokens.size() - 1)))) {
+ checkToken = tokens.get(tokens.size() - 2);
+
+ if (checkToken instanceof Method)
+ return ((Method) checkToken).getReturnType();
+
+ } else if (!tokens.isEmpty()) {
+ checkToken = tokens.get(tokens.size() - 1);
+ }
+
+ if (checkToken instanceof Class<?>)
+ return (Class<?>) checkToken;
+
+ return null;
+ }
+
+ private int findLastDelimiter(String input) {
+ int position = -1;
+ for (final char delimiter : DELIMITERS)
+ position = Math.max(position, input.lastIndexOf(delimiter));
+
+ return position;
+ }
+
+ private List<Object> getSimpleToken(String input) {
+ if (input.isEmpty())
+ return Collections.emptyList();
+
+ final Matcher variablesMatcher = VARIABLES_PATTERN.matcher(input);
+ if (variablesMatcher.matches()) {
+ final Class<?> candidate = fVariablesResolver.resolveClass(input);
+ if ((candidate != null) && (!isBlacklisted(candidate)))
+ return Arrays.asList(candidate, "()");
+ }
+
+ final Package packageInstance = getPackage(input);
+ if (packageInstance != null)
+ return Arrays.asList(packageInstance);
+
+ final Class<?> clazz = getClass(input);
+ if (clazz != null)
+ return Arrays.asList(clazz);
+
+ return null;
+ }
+
+ private boolean isBlacklisted(Class<?> candidate) {
+ return candidate.getName().startsWith("org.mozilla.javascript");
+ }
+
+ protected Package getPackage(String input) {
+ final Matcher packageMatcher = PACKAGE_PATTERN.matcher(input);
+ if (packageMatcher.matches()) {
+ return Package.getPackage(input);
+ }
+
+ return null;
+ }
+
+ protected Class<?> getClass(String input) {
+ final Matcher classMatcher = CLASS_PATTERN.matcher(input);
+ if (classMatcher.matches()) {
+ try {
+ return getClass().getClassLoader().loadClass(input);
+ } catch (final ClassNotFoundException e) {
+ // class does not exist
+ }
+ }
+
+ return null;
+ }
+
+ private String getSimplifiedInput(String input) {
+ String simplifiedInput = input.trim();
+ simplifiedInput = simplifyLiterals(simplifiedInput);
+ final String trailingLiteral = getTrailingLiteral(simplifiedInput);
+ simplifiedInput = simplifiedInput.substring(0, simplifiedInput.length() - trailingLiteral.length());
+
+ simplifiedInput = simplifyBrackets(simplifiedInput);
+ simplifiedInput = simplifyParameters(simplifiedInput);
+ simplifiedInput = clipIrrelevantStuff(simplifiedInput);
+
+ return simplifiedInput + trailingLiteral;
+ }
+
+ private String getTrailingLiteral(String input) {
+ final int literalStart = input.indexOf('"');
+
+ return (literalStart >= 0) ? input.substring(literalStart) : "";
+ }
+
+ /**
+ * Remove unused tokens. Removes stuff left of an assignment or left of whitespace.
+ *
+ * @param input
+ * text to simplify
+ * @return simplified string, 'foo = new File' ... 'File'
+ */
+ private String clipIrrelevantStuff(String input) {
+ String simplifiedInput = input;
+
+ final int locationOfEquals = simplifiedInput.lastIndexOf('=');
+ if (locationOfEquals >= 0)
+ simplifiedInput = simplifiedInput.substring(locationOfEquals + 1).trim();
+
+ final int locationOfSpace = simplifiedInput.lastIndexOf(' ');
+ if (locationOfSpace >= 0)
+ simplifiedInput = simplifiedInput.substring(locationOfSpace + 1).trim();
+
+ final int locationOfTab = simplifiedInput.lastIndexOf('\t');
+ if (locationOfTab >= 0)
+ simplifiedInput = simplifiedInput.substring(locationOfTab + 1).trim();
+
+ return simplifiedInput;
+ }
+
+ /**
+ * Remove parameters in an open bracket when they are not relevant.
+ *
+ * @param input
+ * text to simplify
+ * @return simplified string, 'foo(42, bar(), another' ... 'foo(,,another'
+ */
+ private String simplifyParameters(String input) {
+ final BracketMatcher bracketMatcher = new BracketMatcher(input);
+ if (bracketMatcher.hasOpenBrackets()) {
+ final Bracket openBracket = bracketMatcher.getOpenBrackets().get(0);
+ final int lastCommaPosition = input.lastIndexOf(',');
+
+ if (lastCommaPosition > openBracket.getStart()) {
+ final StringBuilder simplifiedText = new StringBuilder(input.substring(0, openBracket.getStart() + 1));
+ simplifiedText.append(getCommas(input.substring(openBracket.getStart())));
+ simplifiedText.append(input.substring(lastCommaPosition + 1).trim());
+ return simplifiedText.toString();
+ }
+ }
+
+ return input;
+ }
+
+ private String getCommas(String input) {
+ final int amountOfNeededCommas = (int) input.chars().filter(c -> c == ',').count();
+ return ",".repeat(amountOfNeededCommas);
+ }
+
+ /**
+ * Remove contents within brackets.
+ *
+ * @param input
+ * text to simplify
+ * @return simplified string, 'foo(42, 12, bar())' ... 'foo()'
+ */
+ private String simplifyBrackets(String input) {
+ final StringBuilder simplifiedText = new StringBuilder(input);
+
+ while (true) {
+ final BracketMatcher bracketMatcher = new BracketMatcher(simplifiedText.toString());
+ final Optional<Bracket> bracket = bracketMatcher.getBrackets().stream().filter(b -> b.getStart() < (b.getEnd() - 1)).findFirst();
+ if (bracket.isPresent()) {
+ simplifiedText.delete(bracket.get().getStart() + 1, bracket.get().getEnd());
+ } else
+ break;
+ }
+
+ return simplifiedText.toString();
+ }
+
+ /**
+ * Remove content within String literals.
+ *
+ * @param input
+ * text to simplify
+ * @return simplified string
+ */
+ private String simplifyLiterals(String input) {
+ final StringBuilder simplified = new StringBuilder(input);
+
+ int startIndex;
+ int endIndex = 0;
+ do {
+ startIndex = simplified.indexOf("\"");
+ if (startIndex >= 0) {
+ endIndex = simplified.indexOf("\"", startIndex + 1);
+
+ while ((endIndex > startIndex) && (simplified.charAt(endIndex - 1) == '\\')) {
+ endIndex = simplified.indexOf("\"", endIndex + 1);
+ }
+
+ if (endIndex > startIndex)
+ simplified.delete(startIndex, endIndex + 1);
+ }
+ } while ((startIndex >= 0) && (endIndex > startIndex));
+
+ return simplified.toString();
+ }
+
+ protected boolean isLiteral(final char candidate) {
+ return ('"' == candidate);
+ }
+}
diff --git a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/tokenizer/TokenList.java b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/tokenizer/TokenList.java
new file mode 100644
index 0000000..df8d128
--- /dev/null
+++ b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/completion/tokenizer/TokenList.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Christian Pontesegger and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License_Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian Pontesegger - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.ui.completion.tokenizer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TokenList extends ArrayList<Object> {
+
+ private static final long serialVersionUID = -6713581488474706366L;
+
+ public TokenList(List<Object> baseList) {
+ super(baseList);
+ }
+
+ public Object getLastToken() {
+ return getFromTail(0);
+ }
+
+ public Object getFromTail(int index) {
+ if (size() > index)
+ return get(size() - index - 1);
+
+ return null;
+ }
+
+ public TokenList getFromLast(Class<?> clazz) {
+ int startIndex = size();
+ for (int index = 0; index < size(); index++) {
+ if (clazz.isAssignableFrom(get(index).getClass()))
+ startIndex = index;
+ }
+
+ return new TokenList(subList(startIndex, size()));
+ }
+
+ public TokenList getFromLast(String needle) {
+ int startIndex = size();
+ for (int index = 0; index < size(); index++) {
+ if (needle.equals(get(index)))
+ startIndex = index;
+ }
+
+ return new TokenList(subList(startIndex, size()));
+ }
+
+ public <T> T getLast(Class<T> clazz) {
+ final TokenList remainingTokens = getFromLast(clazz);
+ return remainingTokens.isEmpty() ? null : (T) getFromLast(clazz).get(0);
+ }
+
+ public boolean removeIfMatches(int index, String expected) {
+ if ((size() > index) && (expected.equals(get(index)))) {
+ remove(index);
+ return true;
+ }
+
+ return false;
+ }
+
+ public void removeAny(String needle) {
+ for (final Object element : new ArrayList<>(this)) {
+ if (needle.equals(element))
+ remove(element);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/modules/ui/ModulesTools.java b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/modules/ui/ModulesTools.java
index a23a4d8..8bbe3f4 100644
--- a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/modules/ui/ModulesTools.java
+++ b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/modules/ui/ModulesTools.java
@@ -27,7 +27,6 @@
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.StyledString;
import org.eclipse.jface.viewers.StyledString.Styler;
-import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.TextStyle;
import org.eclipse.ui.PlatformUI;
@@ -65,12 +64,10 @@
}
}
- private static Styler OPTIONAL_PARAMETER_STYLE = new Styler() {
- private final Font italic = JFaceResources.getFontRegistry().getItalic(JFaceResources.DEFAULT_FONT);
-
+ private static final Styler OPTIONAL_PARAMETER_STYLE = new Styler() {
@Override
public void applyStyles(TextStyle textStyle) {
- textStyle.font = italic;
+ textStyle.font = JFaceResources.getFontRegistry().getItalic(JFaceResources.DEFAULT_FONT);
textStyle.foreground = JFaceResources.getColorRegistry().get("QUALIFIER_COLOR");
}
};
diff --git a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/view/ScriptShell.java b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/view/ScriptShell.java
index 6d03225..a699db7 100644
--- a/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/view/ScriptShell.java
+++ b/plugins/org.eclipse.ease.ui/src/org/eclipse/ease/ui/view/ScriptShell.java
@@ -14,10 +14,11 @@
package org.eclipse.ease.ui.view;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
-import java.util.HashSet;
import java.util.List;
+import java.util.stream.Collectors;
import org.eclipse.core.commands.Command;
import org.eclipse.core.commands.State;
@@ -40,12 +41,12 @@
import org.eclipse.ease.service.ScriptService;
import org.eclipse.ease.service.ScriptType;
import org.eclipse.ease.ui.Activator;
-import org.eclipse.ease.ui.completion.AbstractCompletionProvider.DescriptorImageResolver;
import org.eclipse.ease.ui.completion.CodeCompletionAggregator;
import org.eclipse.ease.ui.completion.CompletionLabelProvider;
-import org.eclipse.ease.ui.completion.ICompletionProvider;
import org.eclipse.ease.ui.completion.IImageResolver;
import org.eclipse.ease.ui.completion.ScriptCompletionProposal;
+import org.eclipse.ease.ui.completion.provider.AbstractCompletionProvider.DescriptorImageResolver;
+import org.eclipse.ease.ui.completion.provider.ICompletionProvider;
import org.eclipse.ease.ui.console.ScriptConsole;
import org.eclipse.ease.ui.dnd.ShellDropTarget;
import org.eclipse.ease.ui.handler.ToggleDropinsSection;
@@ -139,7 +140,7 @@
private AutoFocus fAutoFocusListener = null;
- private final CodeCompletionAggregator fCompletionDispatcher = new CodeCompletionAggregator();
+ private CodeCompletionAggregator fCompletionDispatcher = null;
private Collection<IShellDropin> fDropins = Collections.emptySet();
@@ -239,8 +240,6 @@
}
fHistory = fInputCombo.getItems().clone();
- addAutoCompletion();
-
// clear reference as we are done with initialization
fInitMemento = null;
@@ -319,26 +318,15 @@
}
@Override
- public Collection<? extends ScriptCompletionProposal> getProposals(ICompletionContext context) {
- final Collection<ScriptCompletionProposal> proposals = new HashSet<>();
-
- for (final String history : fHistory) {
- if (history.startsWith(context.getOriginalCode())) {
- proposals.add(new ScriptCompletionProposal(context, history, history, fImageResolver, ScriptCompletionProposal.ORDER_HISTORY, null) {
- @Override
- public String getContent() {
- return getReplacementString();
- }
- });
- }
- }
-
- return proposals;
+ public Collection<ScriptCompletionProposal> getProposals(ICompletionContext context) {
+ return Arrays.asList(fHistory).stream().filter(t -> t.startsWith(context.getText()))
+ .map(t -> new ScriptCompletionProposal(context, t, t, fImageResolver, ScriptCompletionProposal.ORDER_HISTORY, null))
+ .collect(Collectors.toList());
}
});
final ContentProposalModifier contentAssistAdapter = new ContentProposalModifier(fInputCombo, new ComboContentAdapter(), fCompletionDispatcher,
- KeyStroke.getInstance(SWT.CTRL, ' '), fCompletionDispatcher.getActivationChars());
+ KeyStroke.getInstance(SWT.CTRL, ' '), new char[] { '.' });
contentAssistAdapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);
contentAssistAdapter.setLabelProvider(new CompletionLabelProvider());
@@ -539,7 +527,8 @@
dropin.setScriptEngine(fScriptEngine);
// set script engine
- fCompletionDispatcher.setScriptEngine(fScriptEngine);
+ fCompletionDispatcher = new CodeCompletionAggregator(fScriptEngine);
+ addAutoCompletion();
}
}
diff --git a/plugins/org.eclipse.ease/src/org/eclipse/ease/AbstractCodeParser.java b/plugins/org.eclipse.ease/src/org/eclipse/ease/AbstractCodeParser.java
index 6a65852..fbaa273 100644
--- a/plugins/org.eclipse.ease/src/org/eclipse/ease/AbstractCodeParser.java
+++ b/plugins/org.eclipse.ease/src/org/eclipse/ease/AbstractCodeParser.java
@@ -142,12 +142,6 @@
}
@Override
- public ICompletionContext getContext(final IScriptEngine scriptEngine, final Object resource, final String contents, final int position,
- final int selectionRange) {
- return null;
- }
-
- @Override
public SignatureInfo getSignatureInfo(final InputStream stream) throws ScriptSignatureException {
final BufferedReader bReader = new BufferedReader(new InputStreamReader(stream));
try {
diff --git a/plugins/org.eclipse.ease/src/org/eclipse/ease/ICompletionContext.java b/plugins/org.eclipse.ease/src/org/eclipse/ease/ICompletionContext.java
index 3e12710..f512fcd 100644
--- a/plugins/org.eclipse.ease/src/org/eclipse/ease/ICompletionContext.java
+++ b/plugins/org.eclipse.ease/src/org/eclipse/ease/ICompletionContext.java
@@ -13,89 +13,47 @@
package org.eclipse.ease;
-import java.util.Collection;
-import java.util.Map;
+import java.util.List;
import org.eclipse.ease.modules.ModuleDefinition;
import org.eclipse.ease.service.ScriptType;
-/**
- * Interface for completion context. This context helps ICompletionProvider to simplify completion proposal calculation. Stores information about given input,
- * filter for part of interest, and Source stack for part of interest.
- *
- * @author Martin Kloesch
- */
public interface ICompletionContext {
- enum Type {
- UNKNOWN, NONE, STATIC_CLASS, CLASS_INSTANCE, PACKAGE, STRING_LITERAL
- };
+ List<Object> getTokens();
- String getOriginalCode();
+ String getText();
- String getProcessedCode();
+ int getReplaceOffset();
- String getFilter();
-
- Class<? extends Object> getReferredClazz();
+ int getReplaceLength();
/**
- * Get the base resource of the context. Typically holds a reference to the file open in an editor
- *
- * @return base resource or <code>null</code>
- */
- Object getResource();
-
- /**
- * Get the running script engine. Only works for live engines like a shell.
+ * Get active script engine.
*
* @return script engine or <code>null</code>
*/
IScriptEngine getScriptEngine();
- ScriptType getScriptType();
-
/**
- * Get a list of loaded modules.
+ * Get all loaded modules.
*
* @return loaded modules
*/
- Collection<ModuleDefinition> getLoadedModules();
+ List<ModuleDefinition> getLoadedModules();
/**
- * Get a list of included resource. Returns a map of resource objects -> resource content.
+ * Get a text filter to be applied for the current input. This is the prefix of the expected completion proposals.
*
- * @return map of included resources
+ * @return filter text or empty string
*/
- Map<Object, String> getIncludedResources();
+ String getFilter();
- public Type getType();
+ String getFilterToken();
- int getOffset();
+ boolean isStringLiteral(String input);
- int getSelectionRange();
+ ScriptType getScriptType();
- /**
- * Returns the package for PACKAGE types.
- *
- * @return package name
- */
- String getPackage();
-
- /**
- * Get the caller method for string literals. On STRING_LITERAL types this value denotes the calling method. The whole context of the caller is passed as a
- * value. Eg. "new java.lang.String". May not return <code>null</code>.
- *
- * @return calling method or empty string
- */
- String getCaller();
-
- /**
- * Get the index of the parameter for string literals. On STRING_LITERAL types this value indicates which parameter we are looking at: 0 for the first, 1
- * for the second, ...
- *
- * @return parameter offset for string literals
- */
- int getParameterOffset();
-
+ Object getResource();
}
\ No newline at end of file
diff --git a/plugins/org.eclipse.ease/src/org/eclipse/ease/modules/EnvironmentModule.java b/plugins/org.eclipse.ease/src/org/eclipse/ease/modules/EnvironmentModule.java
index 2ae5a33..d0013d8 100644
--- a/plugins/org.eclipse.ease/src/org/eclipse/ease/modules/EnvironmentModule.java
+++ b/plugins/org.eclipse.ease/src/org/eclipse/ease/modules/EnvironmentModule.java
@@ -57,6 +57,15 @@
public static final String MODULE_NAME = "/System/Environment";
+ /** Used by code completion. Keep in sync with method name in this class. */
+ public static final String INCLUDE_METHOD = "include";
+
+ /** Used by code completion. Keep in sync with method name in this class. */
+ public static final String LOAD_JAR_METHOD = "loadJar";
+
+ /** Used by code completion. Keep in sync with method name in this class. */
+ public static final String LOAD_MODULE_METHOD = "loadModule";
+
private static final Pattern VALID_TOPICS_PATTERN = Pattern.compile("[\\w ]+(?:\\(\\))?");
public static void bootstrap() throws ExecutionException {
diff --git a/plugins/org.eclipse.ease/src/org/eclipse/ease/modules/ModuleDefinition.java b/plugins/org.eclipse.ease/src/org/eclipse/ease/modules/ModuleDefinition.java
index 26eb337..925fe99 100644
--- a/plugins/org.eclipse.ease/src/org/eclipse/ease/modules/ModuleDefinition.java
+++ b/plugins/org.eclipse.ease/src/org/eclipse/ease/modules/ModuleDefinition.java
@@ -185,7 +185,7 @@
}
/**
- * Sets visibility status of module in preferences
+ * Sets visibility status of module in preferences.
*
* @param visible
* <code>true</code> to make visible
diff --git a/plugins/org.eclipse.ease/src/org/eclipse/ease/service/ScriptService.java b/plugins/org.eclipse.ease/src/org/eclipse/ease/service/ScriptService.java
index 29301ee..d2a6419 100644
--- a/plugins/org.eclipse.ease/src/org/eclipse/ease/service/ScriptService.java
+++ b/plugins/org.eclipse.ease/src/org/eclipse/ease/service/ScriptService.java
@@ -315,7 +315,8 @@
@Override
public ModuleDefinition getModuleDefinition(final String moduleId) {
for (final ModuleDefinition definition : getAvailableModules()) {
- if (definition.getId().equals(moduleId))
+
+ if ((definition.getId().equals(moduleId)) || (definition.getPath().toString().equals(moduleId)))
return definition;
}
diff --git a/plugins/org.eclipse.ease/src/org/eclipse/ease/tools/PlatformExtension.java b/plugins/org.eclipse.ease/src/org/eclipse/ease/tools/PlatformExtension.java
new file mode 100644
index 0000000..691c8cb
--- /dev/null
+++ b/plugins/org.eclipse.ease/src/org/eclipse/ease/tools/PlatformExtension.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Christian Pontesegger and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License_Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian Pontesegger - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.tools;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.Platform;
+
+public class PlatformExtension {
+
+ public static Collection<PlatformExtension> createFor(String extensionPoint) {
+ final IConfigurationElement[] config = Platform.getExtensionRegistry().getConfigurationElementsFor(extensionPoint);
+
+ return Arrays.asList(config).stream().map(e -> new PlatformExtension(e)).collect(Collectors.toSet());
+ }
+
+ public static Collection<PlatformExtension> createForName(String extensionPoint, String name) {
+ final Collection<PlatformExtension> extensions = createFor(extensionPoint);
+
+ return extensions.stream().filter(e -> Objects.equals(name, e.getConfigurationElement().getName())).collect(Collectors.toSet());
+ }
+
+ private final IConfigurationElement fConfigurationElement;
+
+ public PlatformExtension(IConfigurationElement configurationElement) {
+ fConfigurationElement = configurationElement;
+ }
+
+ public <T> T createInstance(String name, Class<T> clazz) throws CoreException {
+ final Object instance = getConfigurationElement().createExecutableExtension(name);
+ if (clazz.isAssignableFrom(instance.getClass()))
+ return (T) instance;
+
+ throw new ClassCastException(String.format("Could not cast class '%s' to '%s'", instance.getClass().getName(), clazz.getName()));
+ }
+
+ public IConfigurationElement getConfigurationElement() {
+ return fConfigurationElement;
+ }
+
+ public String getAttribute(String name) {
+ return getConfigurationElement().getAttribute(name);
+ }
+}
diff --git a/releng/org.eclipse.ease.releng.coverage/pom.xml b/releng/org.eclipse.ease.releng.coverage/pom.xml
index 08ba9cf..81fc87b 100644
--- a/releng/org.eclipse.ease.releng.coverage/pom.xml
+++ b/releng/org.eclipse.ease.releng.coverage/pom.xml
@@ -226,6 +226,12 @@
<version>0.9.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.eclipse.ease</groupId>
+ <artifactId>org.eclipse.ease.ui.completions.java.test</artifactId>
+ <version>0.9.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
<!-- test insertion point -->
</dependencies>
</project>
diff --git a/releng/org.eclipse.ease.releng/pmd/pmd_rules_unittest.xml b/releng/org.eclipse.ease.releng/pmd/pmd_rules_unittest.xml
index 8a63d7e..c3e829a 100644
--- a/releng/org.eclipse.ease.releng/pmd/pmd_rules_unittest.xml
+++ b/releng/org.eclipse.ease.releng/pmd/pmd_rules_unittest.xml
@@ -24,6 +24,9 @@
<!-- More than 1 assert allowed in tests -->
<exclude name="JUnitTestContainsTooManyAsserts" />
+
+ <!-- JUnit 5 tests should be package private -->
+ <exclude name="JUnit5TestShouldBePackagePrivate" />
</rule>
<rule ref="category/java/codestyle.xml">
diff --git a/releng/org.eclipse.ease.releng/pom.xml b/releng/org.eclipse.ease.releng/pom.xml
index baa299e..f69b4ce 100644
--- a/releng/org.eclipse.ease.releng/pom.xml
+++ b/releng/org.eclipse.ease.releng/pom.xml
@@ -198,6 +198,7 @@
<module>../../tests/org.eclipse.ease.ui.scripts.test</module>
<module>../../tests/org.eclipse.ease.ui.test</module>
+ <module>../../tests/org.eclipse.ease.ui.completions.java.test</module>
<!-- test insertion point -->
</modules>
diff --git a/releng/org.eclipse.ease.releng/scripts/Setup.js b/releng/org.eclipse.ease.releng/scripts/Setup.js
index 2a44db7..499e73d 100644
--- a/releng/org.eclipse.ease.releng/scripts/Setup.js
+++ b/releng/org.eclipse.ease.releng/scripts/Setup.js
@@ -83,7 +83,7 @@
this.internalCreatePlugin(pluginId, pluginName, "workspace://${releng.project}/templates/plugin-test");
// add to master pom
- this.replaceInFile("workspace://${releng.project}/pom.xml", "<!-- test insertion point -->", "<module>../../tests/${bundle.id}</module>\n\t\t\t\t<!-- test insertion point -->");
+ this.replaceInFile("workspace://${releng.project}/pom.xml", "<!-- test insertion point -->", "<module>../../tests/${bundle.id}</module>\n\t\t<!-- test insertion point -->");
this.replaceInFile("workspace://${releng.project}.coverage/pom.xml", "<!-- test insertion point -->", "<dependency>\n\t\t\t<groupId>${project.root.id}</groupId>\n\t\t\t<artifactId>${bundle.id}</artifactId>\n\t\t\t<version>${bundle.version}-SNAPSHOT</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<!-- test insertion point -->");
}
@@ -146,14 +146,14 @@
Setup.prototype.replaceInFile = function(file, search, replacement) {
var resolvedFile = this.replaceText(file)
var content = readFile(resolvedFile);
- var handle = writeFile(resolvedFile, content.replace(search, replacement));
+ var handle = writeFile(resolvedFile, content.replace(search, this.replaceText(replacement)));
closeFile(handle);
}
Setup.prototype.appendToFile = function(file, text) {
var resolvedFile = this.replaceText(file)
var content = readFile(resolvedFile);
- var handle = writeFile(resolvedFile, content + text);
+ var handle = writeFile(resolvedFile, content + this.replaceText(text));
closeFile(handle);
}
diff --git a/releng/org.eclipse.ease.releng/spotbugs/spotbugs_filter_unittest.xml b/releng/org.eclipse.ease.releng/spotbugs/spotbugs_filter_unittest.xml
index b230cbb..8f19bb7 100644
--- a/releng/org.eclipse.ease.releng/spotbugs/spotbugs_filter_unittest.xml
+++ b/releng/org.eclipse.ease.releng/spotbugs/spotbugs_filter_unittest.xml
@@ -19,4 +19,9 @@
<Match>
<Bug pattern="UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR"/>
</Match>
+
+ <!-- Ignore default encoding when converting byte[] / String -->
+ <Match>
+ <Bug pattern="DM_DEFAULT_ENCODING"/>
+ </Match>
</FindBugsFilter>
\ No newline at end of file
diff --git a/releng/org.eclipse.ease.releng/templates/plugin-test/META-INF/MANIFEST.MF b/releng/org.eclipse.ease.releng/templates/plugin-test/META-INF/MANIFEST.MF
index ec16d27..dd9564b 100644
--- a/releng/org.eclipse.ease.releng/templates/plugin-test/META-INF/MANIFEST.MF
+++ b/releng/org.eclipse.ease.releng/templates/plugin-test/META-INF/MANIFEST.MF
@@ -6,6 +6,7 @@
Bundle-Version: ${bundle.version}.qualifier
Bundle-Vendor: ${bundle.vendor}
Bundle-RequiredExecutionEnvironment: ${java.version}
-Fragment-Host: ${bundle.host.id};bundle-version="${bundle.version}"
+Fragment-Host: ${bundle.host.id}
Require-Bundle: org.junit.jupiter.api,
- org.mockito
+ org.mockito,
+ org.junit.jupiter.params
diff --git a/releng/org.eclipse.ease.releng/templates/plugin-test/pom.xml b/releng/org.eclipse.ease.releng/templates/plugin-test/pom.xml
index c5fa761..df8f6ff 100644
--- a/releng/org.eclipse.ease.releng/templates/plugin-test/pom.xml
+++ b/releng/org.eclipse.ease.releng/templates/plugin-test/pom.xml
@@ -8,7 +8,7 @@
<parent>
<groupId>${project.root.id}</groupId>
- <artifactId>${project.root.id}.unittests</artifactId>
+ <artifactId>${project.root.id}.core.tests</artifactId>
<version>${bundle.version}-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
diff --git a/tests/org.eclipse.ease.lang.javascript.test/src/org/eclipse/ease/lang/javascript/JavaScriptCompletionContextTest.java b/tests/org.eclipse.ease.lang.javascript.test/src/org/eclipse/ease/lang/javascript/JavaScriptCompletionContextTest.java
deleted file mode 100644
index d2cedf9..0000000
--- a/tests/org.eclipse.ease.lang.javascript.test/src/org/eclipse/ease/lang/javascript/JavaScriptCompletionContextTest.java
+++ /dev/null
@@ -1,113 +0,0 @@
-package org.eclipse.ease.lang.javascript;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-
-import org.eclipse.ease.IScriptEngine;
-import org.eclipse.ease.service.EngineDescription;
-import org.eclipse.ease.service.IScriptService;
-import org.eclipse.ease.service.ScriptService;
-import org.eclipse.ease.ui.completion.CompletionContext;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-public class JavaScriptCompletionContextTest {
-
- private static JavaScriptCompletionContext fContext;
-
- @BeforeEach
- public void setup() {
- fContext = new JavaScriptCompletionContext(null);
- }
-
- @Test
- public void verifyUnknownTypes() {
- fContext.calculateContext(null, "getScriptEngine()", 0, 0);
- assertEquals(CompletionContext.Type.UNKNOWN, fContext.getType());
- }
-
- @Test
- public void verifyNoneTypes() {
- fContext.calculateContext(null, "", 0, 0);
- assertEquals(CompletionContext.Type.NONE, fContext.getType());
-
- fContext.calculateContext(null, "get", 0, 0);
- assertEquals(CompletionContext.Type.NONE, fContext.getType());
- }
-
- @Test
- public void verifyStaticClassTypes() {
- fContext.calculateContext(null, "java.lang.String.", 0, 0);
- assertEquals(CompletionContext.Type.STATIC_CLASS, fContext.getType());
-
- fContext.calculateContext(null, "Packages.java.lang.String.", 0, 0);
- assertEquals(CompletionContext.Type.STATIC_CLASS, fContext.getType());
- }
-
- @Test
- public void verifyStringLiteralTypes() {
- fContext.calculateContext(null, "'Hello", 0, 0);
- assertEquals(CompletionContext.Type.STRING_LITERAL, fContext.getType());
- assertEquals("Hello", fContext.getFilter());
- assertEquals("", fContext.getCaller());
-
- fContext.calculateContext(null, "print('Hello", 0, 0);
- assertEquals(CompletionContext.Type.STRING_LITERAL, fContext.getType());
- assertEquals("Hello", fContext.getFilter());
- assertEquals("print", fContext.getCaller());
-
- fContext.calculateContext(null, "new java.lang.String('", 0, 0);
- assertEquals(CompletionContext.Type.STRING_LITERAL, fContext.getType());
- assertEquals("", fContext.getFilter());
- assertEquals("new java.lang.String", fContext.getCaller());
- }
-
- @Test
- public void verifyClassInstanceTypes() {
- fContext.calculateContext(null, "getScriptEngine().", 0, 0);
- assertEquals(CompletionContext.Type.CLASS_INSTANCE, fContext.getType());
-
- fContext.calculateContext(null, "getScriptEngine().getInputStream().", 0, 0);
- assertEquals(CompletionContext.Type.CLASS_INSTANCE, fContext.getType());
- }
-
- @Test
- public void verifyPackageTypes() {
- fContext.calculateContext(null, "java.lang.String", 0, 0);
- assertEquals(CompletionContext.Type.PACKAGE, fContext.getType());
-
- fContext.calculateContext(null, "Packages.java.lang.String", 0, 0);
- assertEquals(CompletionContext.Type.PACKAGE, fContext.getType());
- }
-
- @Test
- public void verifyTypesForScriptEngine() {
- // we need to retrieve the service singleton as the workspace is not available in headless tests
- final IScriptService scriptService = ScriptService.getService();
- final EngineDescription engineDescription = scriptService.getEngine(JavaScriptHelper.SCRIPT_TYPE_JAVASCRIPT);
- assertNotNull(engineDescription, "No JavaScript engine available");
-
- final IScriptEngine engine = engineDescription.createEngine();
- engine.setVariable("test", "Hello world");
-
- fContext = new JavaScriptCompletionContext(engine);
-
- fContext.calculateContext(null, "test.", 0, 0);
- assertEquals(CompletionContext.Type.CLASS_INSTANCE, fContext.getType());
-
- fContext.calculateContext(null, "test.getByt", 0, 0);
- assertEquals(CompletionContext.Type.CLASS_INSTANCE, fContext.getType());
-
- fContext.calculateContext(null, "test.toString().", 0, 0);
- assertEquals(CompletionContext.Type.CLASS_INSTANCE, fContext.getType());
- }
-
- @Test
- public void definedVariableTypes() {
- fContext.calculateContext(null, " // @type java.lang.String\n" + " var a = \"foo\";\n" + " a.", 0, 0);
- assertEquals(CompletionContext.Type.CLASS_INSTANCE, fContext.getType());
-
- fContext.calculateContext(null, " // @type java.lang.String\n" + " var a = \"foo\";\n" + " a.toString().", 0, 0);
- assertEquals(CompletionContext.Type.CLASS_INSTANCE, fContext.getType());
- }
-}
diff --git a/tests/org.eclipse.ease.test/.classpath b/tests/org.eclipse.ease.test/.classpath
index f193818..a621c21 100644
--- a/tests/org.eclipse.ease.test/.classpath
+++ b/tests/org.eclipse.ease.test/.classpath
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src">
<attributes>
diff --git a/tests/org.eclipse.ease.test/.settings/org.eclipse.jdt.core.prefs b/tests/org.eclipse.ease.test/.settings/org.eclipse.jdt.core.prefs
index 64e8545..7004b85 100644
--- a/tests/org.eclipse.ease.test/.settings/org.eclipse.jdt.core.prefs
+++ b/tests/org.eclipse.ease.test/.settings/org.eclipse.jdt.core.prefs
@@ -11,17 +11,21 @@
org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.compliance=11
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=11
org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
@@ -29,19 +33,22 @@
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_assignment=0
-org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16
org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16
org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
@@ -130,11 +137,12 @@
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
@@ -165,6 +173,8 @@
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
@@ -189,13 +199,17 @@
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
@@ -243,6 +257,8 @@
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
@@ -279,9 +295,12 @@
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
@@ -317,9 +336,13 @@
org.eclipse.jdt.core.formatter.tabulation.size=4
org.eclipse.jdt.core.formatter.use_on_off_tags=true
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true
org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
-org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true
org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true
org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/tests/org.eclipse.ease.test/META-INF/MANIFEST.MF b/tests/org.eclipse.ease.test/META-INF/MANIFEST.MF
index 7c262d9..6d1316b 100644
--- a/tests/org.eclipse.ease.test/META-INF/MANIFEST.MF
+++ b/tests/org.eclipse.ease.test/META-INF/MANIFEST.MF
@@ -4,7 +4,7 @@
Bundle-SymbolicName: org.eclipse.ease.test;singleton:=true
Bundle-Version: 0.9.0.qualifier
Fragment-Host: org.eclipse.ease
-Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Bundle-RequiredExecutionEnvironment: JavaSE-11
Require-Bundle: org.junit.jupiter.api;bundle-version="5.5.0",
org.mockito,
org.eclipse.ease.ui.scripts,
diff --git a/tests/org.eclipse.ease.test/build.properties b/tests/org.eclipse.ease.test/build.properties
index 34d2e4d..e3023e1 100644
--- a/tests/org.eclipse.ease.test/build.properties
+++ b/tests/org.eclipse.ease.test/build.properties
@@ -1,4 +1,5 @@
source.. = src/
output.. = bin/
bin.includes = META-INF/,\
- .
+ .,\
+ fragment.xml
diff --git a/tests/org.eclipse.ease.test/fragment.xml b/tests/org.eclipse.ease.test/fragment.xml
new file mode 100644
index 0000000..2a96bb0
--- /dev/null
+++ b/tests/org.eclipse.ease.test/fragment.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<fragment>
+ <extension-point id="test" name="Test" schema="schema/test.exsd"/>
+ <extension
+ point="org.eclipse.ease.test">
+ <entry
+ ID="stringEntry"
+ class="java.lang.String">
+ </entry>
+ <entry
+ ID="stringbuilderEntry"
+ class="java.lang.StringBuilder">
+ </entry>
+ </extension>
+
+</fragment>
diff --git a/tests/org.eclipse.ease.test/schema/test.exsd b/tests/org.eclipse.ease.test/schema/test.exsd
new file mode 100644
index 0000000..02ac772
--- /dev/null
+++ b/tests/org.eclipse.ease.test/schema/test.exsd
@@ -0,0 +1,109 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.ease.test" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appinfo>
+ <meta.schema plugin="org.eclipse.ease.test" id="test" name="Test"/>
+ </appinfo>
+ <documentation>
+ [Enter description of this extension point.]
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <annotation>
+ <appinfo>
+ <meta.element />
+ </appinfo>
+ </annotation>
+ <complexType>
+ <choice minOccurs="1" maxOccurs="unbounded">
+ <element ref="entry"/>
+ </choice>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appinfo>
+ <meta.attribute translatable="true"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="entry">
+ <complexType>
+ <attribute name="ID" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="class" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="java" basedOn="java.lang.String:"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="since"/>
+ </appinfo>
+ <documentation>
+ [Enter the first release in which this extension point appears.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="examples"/>
+ </appinfo>
+ <documentation>
+ [Enter extension point usage example here.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="apiinfo"/>
+ </appinfo>
+ <documentation>
+ [Enter API information here.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="implementation"/>
+ </appinfo>
+ <documentation>
+ [Enter information about supplied implementation of this extension point.]
+ </documentation>
+ </annotation>
+
+
+</schema>
diff --git a/tests/org.eclipse.ease.test/src/org/eclipse/ease/AbstractCodeParserTest.java b/tests/org.eclipse.ease.test/src/org/eclipse/ease/AbstractCodeParserTest.java
index b29636b..9e08e09 100644
--- a/tests/org.eclipse.ease.test/src/org/eclipse/ease/AbstractCodeParserTest.java
+++ b/tests/org.eclipse.ease.test/src/org/eclipse/ease/AbstractCodeParserTest.java
@@ -25,7 +25,7 @@
public class AbstractCodeParserTest {
// classic implementation of a HeaderParser
- private class HeaderParser extends AbstractCodeParser {
+ private static class HeaderParser extends AbstractCodeParser {
@Override
protected boolean hasBlockComment() {
@@ -54,38 +54,43 @@
return super.stripCommentLine(commentLine);
}
+
+ @Override
+ public ICompletionContext getContext(IScriptEngine scriptEngine, Object resource, String contents, int position, int selectionRange) {
+ return null;
+ }
}
// @formatter:off
- private static final String TEMPLATE_BLOCK_HEADER =
- "/**\n"
+ private static final String TEMPLATE_BLOCK_HEADER =
+ "/**\n"
+ " * This is a block comment with a keyword.\n"
+ " * \n"
+ " * key: word\n"
+ " * menu: no menu selected\n"
+ " * multi: this is a multi\n"
- + " * line keyword\n"
+ + " * line keyword\n"
+ " **/\n";
private static final String TEMPLATE_LINE_HEADER =
"//\n"
+ "// This is a block comment with a keyword.\n"
- + "// \n"
+ + "// \n"
+ " // key: word\n"
- + "// menu: no menu selected\n"
- + "// multi: this is a multi\n"
- + "// line keyword\n"
+ + "// menu: no menu selected\n"
+ + "// multi: this is a multi\n"
+ + "// line keyword\n"
+ "//\n";
private static final String TEMPLATE_NO_COMMENT =
"var a = 13;\n"
+ TEMPLATE_BLOCK_HEADER;
-
+
private static final String TEMPLATE_WHITESPACE_BEFORE_BLOCK_HEADER =
"\n"
+ "\t\t\n"
+ " \n"
- + " "
+ + " "
+ TEMPLATE_BLOCK_HEADER;
// @formatter:on
@@ -133,7 +138,7 @@
assertEquals("this is a multi line keyword", keywords.get("multi"));
}
- private static final InputStream toStream(String data) {
+ private static InputStream toStream(String data) {
return new ByteArrayInputStream(data.getBytes());
}
}
diff --git a/tests/org.eclipse.ease.test/src/org/eclipse/ease/tools/PlatformExtensionTest.java b/tests/org.eclipse.ease.test/src/org/eclipse/ease/tools/PlatformExtensionTest.java
new file mode 100644
index 0000000..b7baa97
--- /dev/null
+++ b/tests/org.eclipse.ease.test/src/org/eclipse/ease/tools/PlatformExtensionTest.java
@@ -0,0 +1,86 @@
+package org.eclipse.ease.tools;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Collection;
+import java.util.Objects;
+
+import org.eclipse.core.runtime.CoreException;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+public class PlatformExtensionTest {
+
+ private static final String EXTENSION_POINT = "org.eclipse.ease.test";
+
+ @Test
+ @DisplayName("createFor('{ease}.notThere') returns empty collection")
+ public void createFor_returns_empty_collection() {
+ final Collection<PlatformExtension> extensions = PlatformExtension.createFor("org.eclipse.ease.notthere");
+ assertNotNull(extensions);
+ assertTrue(extensions.isEmpty());
+ }
+
+ @Test
+ @DisplayName("createFor('{ease}.test') returns populated collection")
+ public void createFor_returns_non_empty_collection() {
+ final Collection<PlatformExtension> extensions = PlatformExtension.createFor(EXTENSION_POINT);
+ assertEquals(2, extensions.size());
+ }
+
+ @Test
+ @DisplayName("createForName('{ease}.test', 'entry') returns populated collection")
+ public void createForName_returns_non_empty_collection() {
+ final Collection<PlatformExtension> extensions = PlatformExtension.createForName(EXTENSION_POINT, "entry");
+ assertEquals(2, extensions.size());
+ }
+
+ @Test
+ @DisplayName("getConfigurationElement() != null")
+ public void getConfigurationElement_is_not_null() {
+ final Collection<PlatformExtension> extensions = PlatformExtension.createFor(EXTENSION_POINT);
+
+ for (final PlatformExtension extension : extensions)
+ assertNotNull(extension.getConfigurationElement());
+ }
+
+ @Test
+ @DisplayName("getAttribute() != null for known attribute")
+ public void getAttribute_is_not_null_for_known_attribute() {
+ final Collection<PlatformExtension> extensions = PlatformExtension.createFor(EXTENSION_POINT);
+ final PlatformExtension extension = extensions.iterator().next();
+
+ assertNotNull(extension.getAttribute("ID"));
+ }
+
+ @Test
+ @DisplayName("getAttribute() == null for unknown attribute")
+ public void getAttribute_is_null_for_unknown_attribute() {
+ final Collection<PlatformExtension> extensions = PlatformExtension.createFor(EXTENSION_POINT);
+ final PlatformExtension extension = extensions.iterator().next();
+
+ assertNull(extension.getAttribute("unknown"));
+ }
+
+ @Test
+ @DisplayName("createInstance() != null for valid type")
+ public void createInstance_returns_class_instance() throws CoreException {
+ final Collection<PlatformExtension> extensions = PlatformExtension.createFor(EXTENSION_POINT);
+ final PlatformExtension extension = extensions.stream().filter(e -> Objects.equals("stringEntry", e.getAttribute("ID"))).findAny().orElseThrow();
+
+ assertNotNull(extension.createInstance("class", String.class));
+ }
+
+ @Test
+ @DisplayName("createInstance() throws ClassCastException for invalid type")
+ public void createInstance_throws_for_invalid_type() throws CoreException {
+ final Collection<PlatformExtension> extensions = PlatformExtension.createFor(EXTENSION_POINT);
+ final PlatformExtension extension = extensions.stream().filter(e -> Objects.equals("stringEntry", e.getAttribute("ID"))).findAny().orElseThrow();
+
+ assertThrows(ClassCastException.class, () -> extension.createInstance("class", StringBuilder.class));
+ }
+}
diff --git a/tests/org.eclipse.ease.ui.completions.java.test/.checkstyle b/tests/org.eclipse.ease.ui.completions.java.test/.checkstyle
new file mode 100644
index 0000000..83a40d4
--- /dev/null
+++ b/tests/org.eclipse.ease.ui.completions.java.test/.checkstyle
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<fileset-config file-format-version="1.2.0" simple-config="false" sync-formatter="false">
+ <local-check-config name="Eclipse.org Checkstyle" location="/org.eclipse.ease.releng/checkstyle/checkstyle_rules_unittest.xml" type="project" description="">
+ <additional-data name="protect-config-file" value="false"/>
+ </local-check-config>
+ <fileset name="All files" enabled="true" check-config-name="Eclipse.org Checkstyle" local="true">
+ <file-match-pattern match-pattern=".java$" include-pattern="true"/>
+ </fileset>
+</fileset-config>
diff --git a/tests/org.eclipse.ease.ui.completions.java.test/.classpath b/tests/org.eclipse.ease.ui.completions.java.test/.classpath
new file mode 100644
index 0000000..856ddfc
--- /dev/null
+++ b/tests/org.eclipse.ease.ui.completions.java.test/.classpath
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8" />
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins" />
+ <classpathentry kind="src" path="src">
+ <attributes>
+ <attribute name="test" value="true" />
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="output" path="target/classes"/>
+</classpath>
diff --git a/tests/org.eclipse.ease.ui.completions.java.test/.eclipse-pmd b/tests/org.eclipse.ease.ui.completions.java.test/.eclipse-pmd
new file mode 100644
index 0000000..00a904c
--- /dev/null
+++ b/tests/org.eclipse.ease.ui.completions.java.test/.eclipse-pmd
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<eclipse-pmd xmlns="http://acanda.ch/eclipse-pmd/0.8" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://acanda.ch/eclipse-pmd/0.8 http://acanda.ch/eclipse-pmd/eclipse-pmd-0.8.xsd">
+ <analysis enabled="true" />
+ <rulesets>
+ <ruleset name="Eclipse EASE Unittest PMD Rules" ref="$org.eclipse.ease.releng/pmd/pmd_rules_unittest.xml" refcontext="workspace" />
+ </rulesets>
+</eclipse-pmd>
\ No newline at end of file
diff --git a/tests/org.eclipse.ease.ui.completions.java.test/.project b/tests/org.eclipse.ease.ui.completions.java.test/.project
new file mode 100644
index 0000000..0f147ec
--- /dev/null
+++ b/tests/org.eclipse.ease.ui.completions.java.test/.project
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.ease.ui.completions.java.test</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>ch.acanda.eclipse.pmd.builder.PMDBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>edu.umd.cs.findbugs.plugin.eclipse.findbugsBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>ch.acanda.eclipse.pmd.builder.PMDNature</nature>
+ <nature>edu.umd.cs.findbugs.plugin.eclipse.findbugsNature</nature>
+ <nature>net.sf.eclipsecs.core.CheckstyleNature</nature>
+ </natures>
+</projectDescription>
diff --git a/tests/org.eclipse.ease.ui.completions.java.test/.settings/com.github.spotbugs.plugin.eclipse.prefs b/tests/org.eclipse.ease.ui.completions.java.test/.settings/com.github.spotbugs.plugin.eclipse.prefs
new file mode 100644
index 0000000..53e9365
--- /dev/null
+++ b/tests/org.eclipse.ease.ui.completions.java.test/.settings/com.github.spotbugs.plugin.eclipse.prefs
@@ -0,0 +1,2 @@
+dontRemindAboutFullBuild=true
+eclipse.preferences.version=1
diff --git a/tests/org.eclipse.ease.ui.completions.java.test/.settings/edu.umd.cs.findbugs.core.prefs b/tests/org.eclipse.ease.ui.completions.java.test/.settings/edu.umd.cs.findbugs.core.prefs
new file mode 100644
index 0000000..bf5403e
--- /dev/null
+++ b/tests/org.eclipse.ease.ui.completions.java.test/.settings/edu.umd.cs.findbugs.core.prefs
@@ -0,0 +1,145 @@
+#SpotBugs User Preferences
+#Thu Mar 11 18:38:53 CET 2021
+detectorExplicitSerialization=ExplicitSerialization|true
+detectorMultithreadedInstanceAccess=MultithreadedInstanceAccess|true
+detectorConfusionBetweenInheritedAndOuterMethod=ConfusionBetweenInheritedAndOuterMethod|true
+detectorWrongMapIterator=WrongMapIterator|true
+detectorUnnecessaryMath=UnnecessaryMath|true
+detectorUselessSubclassMethod=UselessSubclassMethod|false
+filter_settings=Low|BAD_PRACTICE,CORRECTNESS,EXPERIMENTAL,I18N,MALICIOUS_CODE,MT_CORRECTNESS,PERFORMANCE,SECURITY,STYLE|false|20
+detectorURLProblems=URLProblems|true
+detectorIteratorIdioms=IteratorIdioms|true
+detectorMutableEnum=MutableEnum|true
+detectorFindNonShortCircuit=FindNonShortCircuit|true
+detectorSynchronizeAndNullCheckField=SynchronizeAndNullCheckField|true
+detectorVolatileUsage=VolatileUsage|true
+detectorFindNakedNotify=FindNakedNotify|true
+detectorFindUninitializedGet=FindUninitializedGet|true
+detectorFindUseOfNonSerializableValue=FindUseOfNonSerializableValue|true
+detectorFindJSR166LockMonitorenter=FindJSR166LockMonitorenter|true
+detectorQuestionableBooleanAssignment=QuestionableBooleanAssignment|true
+detectorSwitchFallthrough=SwitchFallthrough|true
+detectorFindLocalSelfAssignment2=FindLocalSelfAssignment2|true
+detectorConfusedInheritance=ConfusedInheritance|true
+detectorSynchronizationOnSharedBuiltinConstant=SynchronizationOnSharedBuiltinConstant|true
+detectorMutableStaticFields=MutableStaticFields|true
+detectorInvalidJUnitTest=InvalidJUnitTest|true
+detectorInfiniteLoop=InfiniteLoop|true
+detectorFindRunInvocations=FindRunInvocations|true
+detectorBadSyntaxForRegularExpression=BadSyntaxForRegularExpression|true
+detectorXMLFactoryBypass=XMLFactoryBypass|true
+detectorFindOpenStream=FindOpenStream|true
+detectorCheckExpectedWarnings=CheckExpectedWarnings|false
+detectorHugeSharedStringConstants=HugeSharedStringConstants|true
+detectorLostLoggerDueToWeakReference=LostLoggerDueToWeakReference|true
+detectorStringConcatenation=StringConcatenation|true
+detectorLoadOfKnownNullValue=LoadOfKnownNullValue|true
+detectorFinalizerNullsFields=FinalizerNullsFields|true
+detectorFindFieldSelfAssignment=FindFieldSelfAssignment|true
+detectorInefficientToArray=InefficientToArray|false
+detectorDontCatchIllegalMonitorStateException=DontCatchIllegalMonitorStateException|true
+detectorInconsistentAnnotations=InconsistentAnnotations|true
+detectorBadlyOverriddenAdapter=BadlyOverriddenAdapter|true
+detectorInstantiateStaticClass=InstantiateStaticClass|true
+detectorCheckRelaxingNullnessAnnotation=CheckRelaxingNullnessAnnotation|true
+detectorMethodReturnCheck=MethodReturnCheck|true
+detectorEqualsOperandShouldHaveClassCompatibleWithThis=EqualsOperandShouldHaveClassCompatibleWithThis|true
+detectorFindDoubleCheck=FindDoubleCheck|true
+detectorFindBadForLoop=FindBadForLoop|true
+detectorDefaultEncodingDetector=DefaultEncodingDetector|true
+detectorFindInconsistentSync2=FindInconsistentSync2|true
+detectorFindSpinLoop=FindSpinLoop|true
+detectorFindMaskedFields=FindMaskedFields|true
+detectorBooleanReturnNull=BooleanReturnNull|true
+detectorFindUnsyncGet=FindUnsyncGet|true
+detectorCrossSiteScripting=CrossSiteScripting|true
+detectorDroppedException=DroppedException|true
+detectorFindDeadLocalStores=FindDeadLocalStores|true
+detectorCheckImmutableAnnotation=CheckImmutableAnnotation|true
+detectorInfiniteRecursiveLoop=InfiniteRecursiveLoop|true
+detectorFindRefComparison=FindRefComparison|true
+detectorFindRoughConstants=FindRoughConstants|true
+detectorMutableLock=MutableLock|true
+detectorFindNullDeref=FindNullDeref|true
+detectorFindReturnRef=FindReturnRef|true
+detectorSynchronizeOnClassLiteralNotGetClass=SynchronizeOnClassLiteralNotGetClass|true
+detectorFindUselessControlFlow=FindUselessControlFlow|true
+detectorOverridingEqualsNotSymmetrical=OverridingEqualsNotSymmetrical|true
+detectorIDivResultCastToDouble=IDivResultCastToDouble|true
+detectorReadOfInstanceFieldInMethodInvokedByConstructorInSuperclass=ReadOfInstanceFieldInMethodInvokedByConstructorInSuperclass|true
+detectorFindSelfComparison=FindSelfComparison|true
+detectorFindFloatEquality=FindFloatEquality|true
+detectorFindComparatorProblems=FindComparatorProblems|true
+detectorRepeatedConditionals=RepeatedConditionals|true
+filter_settings_neg=NOISE|
+detectorInefficientMemberAccess=InefficientMemberAccess|false
+detectorFindUncalledPrivateMethods=FindUncalledPrivateMethods|true
+detectorNumberConstructor=NumberConstructor|true
+detectorDontAssertInstanceofInTests=DontAssertInstanceofInTests|true
+detectorFindFinalizeInvocations=FindFinalizeInvocations|true
+detectorFindNullDerefsInvolvingNonShortCircuitEvaluation=FindNullDerefsInvolvingNonShortCircuitEvaluation|true
+detectorDontIgnoreResultOfPutIfAbsent=DontIgnoreResultOfPutIfAbsent|true
+detectorFindUnconditionalWait=FindUnconditionalWait|true
+detectorFindTwoLockWait=FindTwoLockWait|true
+detectorFindSleepWithLockHeld=FindSleepWithLockHeld|true
+detectorFindUnreleasedLock=FindUnreleasedLock|true
+detectorInefficientIndexOf=InefficientIndexOf|false
+detectorDoInsideDoPrivileged=DoInsideDoPrivileged|true
+detectorFindEmptySynchronizedBlock=FindEmptySynchronizedBlock|true
+detectorOverridingMethodsMustInvokeSuperDetector=OverridingMethodsMustInvokeSuperDetector|true
+detectorWaitInLoop=WaitInLoop|true
+detectorIntCast2LongAsInstant=IntCast2LongAsInstant|true
+detectorBadUseOfReturnValue=BadUseOfReturnValue|true
+detectorFindSqlInjection=FindSqlInjection|true
+detectorUnreadFields=UnreadFields|true
+detectorSynchronizingOnContentsOfFieldToProtectField=SynchronizingOnContentsOfFieldToProtectField|true
+detectorFindUselessObjects=FindUselessObjects|true
+detectorBadAppletConstructor=BadAppletConstructor|false
+detectorInheritanceUnsafeGetResource=InheritanceUnsafeGetResource|true
+detectorSerializableIdiom=SerializableIdiom|true
+detectorNaming=Naming|true
+detectorNoteUnconditionalParamDerefs=NoteUnconditionalParamDerefs|true
+detectorFormatStringChecker=FormatStringChecker|true
+detectorSuspiciousThreadInterrupted=SuspiciousThreadInterrupted|true
+detectorEmptyZipFileEntry=EmptyZipFileEntry|false
+detectorFindCircularDependencies=FindCircularDependencies|false
+detectorPreferZeroLengthArrays=PreferZeroLengthArrays|true
+detectorAtomicityProblem=AtomicityProblem|true
+detectorRuntimeExceptionCapture=RuntimeExceptionCapture|true
+detectorInitializationChain=InitializationChain|true
+detectorInitializeNonnullFieldsInConstructor=InitializeNonnullFieldsInConstructor|true
+detectorOptionalReturnNull=OptionalReturnNull|true
+detectorStartInConstructor=StartInConstructor|true
+detectorFindUnsatisfiedObligation=FindUnsatisfiedObligation|true
+detectorRedundantConditions=RedundantConditions|true
+effort=max
+detectorRedundantInterfaces=RedundantInterfaces|true
+detectorDuplicateBranches=DuplicateBranches|true
+detectorCheckTypeQualifiers=CheckTypeQualifiers|true
+detectorComparatorIdiom=ComparatorIdiom|true
+detectorFindBadCast2=FindBadCast2|true
+detectorFindMismatchedWaitOrNotify=FindMismatchedWaitOrNotify|true
+excludefilter0=../../releng/org.eclipse.ease.releng/spotbugs/spotbugs_filter_unittest.xml|true
+detectorBadResultSetAccess=BadResultSetAccess|true
+detectorIncompatMask=IncompatMask|true
+detectorCovariantArrayAssignment=CovariantArrayAssignment|false
+detectorDumbMethodInvocations=DumbMethodInvocations|true
+run_at_full_build=true
+detectorStaticCalendarDetector=StaticCalendarDetector|true
+detectorUncallableMethodOfAnonymousClass=UncallableMethodOfAnonymousClass|true
+detectorVarArgsProblems=VarArgsProblems|true
+detectorInefficientInitializationInsideLoop=InefficientInitializationInsideLoop|false
+detectorCloneIdiom=CloneIdiom|true
+detectorFindHEmismatch=FindHEmismatch|true
+detectorAppendingToAnObjectOutputStream=AppendingToAnObjectOutputStream|true
+detectorFindSelfComparison2=FindSelfComparison2|true
+detectorLazyInit=LazyInit|true
+detectorFindUnrelatedTypesInGenericContainer=FindUnrelatedTypesInGenericContainer|true
+detectorDontUseEnum=DontUseEnum|true
+detectorFindPuzzlers=FindPuzzlers|true
+detectorCallToUnsupportedMethod=CallToUnsupportedMethod|false
+detectorSuperfluousInstanceOf=SuperfluousInstanceOf|true
+detectorReadReturnShouldBeChecked=ReadReturnShouldBeChecked|true
+detector_threshold=3
+detectorPublicSemaphores=PublicSemaphores|false
+detectorDumbMethods=DumbMethods|true
diff --git a/tests/org.eclipse.ease.ui.completions.java.test/.settings/org.eclipse.core.resources.prefs b/tests/org.eclipse.ease.ui.completions.java.test/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..4824b80
--- /dev/null
+++ b/tests/org.eclipse.ease.ui.completions.java.test/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/tests/org.eclipse.ease.ui.completions.java.test/.settings/org.eclipse.jdt.core.prefs b/tests/org.eclipse.ease.ui.completions.java.test/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ac87d4f
--- /dev/null
+++ b/tests/org.eclipse.ease.ui.completions.java.test/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,325 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=f
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
+org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
+org.eclipse.jdt.core.formatter.comment.line_length=160
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=160
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=true
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/tests/org.eclipse.ease.ui.completions.java.test/.settings/org.eclipse.jdt.ui.prefs b/tests/org.eclipse.ease.ui.completions.java.test/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..4a6e7c5
--- /dev/null
+++ b/tests/org.eclipse.ease.ui.completions.java.test/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,130 @@
+cleanup.add_default_serial_version_id=false
+cleanup.add_generated_serial_version_id=true
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=true
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=false
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=true
+cleanup.format_source_code=true
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=false
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=true
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=false
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=false
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=true
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_EASE Development
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_Eclipse EASE Development
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=java;javax;org;com;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=false
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*******************************************************************************\n * Copyright (c) ${year} ${user} and others.\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v2.0\n * which accompanies this distribution, and is available at\n * https\://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License_Identifier\: EPL-2.0\n *\n * Contributors\:\n * ${user} - initial API and implementation\n *******************************************************************************/\n</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="true" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="false" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} handle this exception (but for now, at least know it happened)\nthrow new RuntimeException(${exception_var});\n</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template><template autoinsert\="true" context\="modulecomment_context" deleted\="false" description\="Comment for modules" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.modulecomment" name\="modulecomment">/**\n * @author ${user}\n *\n * ${tags}\n */</template><template autoinsert\="true" context\="recordbody_context" deleted\="false" description\="Code in new record type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.recordbody" name\="recordbody">\n</template></templates>
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=true
+sp_cleanup.always_use_this_for_non_static_field_access=false
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=true
+sp_cleanup.convert_to_enhanced_for_loop=true
+sp_cleanup.correct_indentation=true
+sp_cleanup.format_source_code=true
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=false
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=true
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=true
+sp_cleanup.remove_trailing_whitespaces_all=true
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=true
+sp_cleanup.remove_unused_imports=true
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=true
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=true
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=false
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=true
+sp_cleanup.use_parentheses_in_expressions=true
+sp_cleanup.use_this_for_non_static_field_access=false
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+sp_cleanup.use_this_for_non_static_method_access=false
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
diff --git a/tests/org.eclipse.ease.ui.completions.java.test/META-INF/MANIFEST.MF b/tests/org.eclipse.ease.ui.completions.java.test/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..f5cf2d3
--- /dev/null
+++ b/tests/org.eclipse.ease.ui.completions.java.test/META-INF/MANIFEST.MF
@@ -0,0 +1,12 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Java Code Completion Support Unit Tests
+Bundle-SymbolicName: org.eclipse.ease.ui.completions.java.test
+Automatic-Module-Name: org.eclipse.ease.ui.completions.java.test
+Bundle-Version: 0.9.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Fragment-Host: org.eclipse.ease.ui.completions.java
+Require-Bundle: org.junit.jupiter.api,
+ org.mockito,
+ org.junit.jupiter.params
diff --git a/tests/org.eclipse.ease.ui.completions.java.test/build.properties b/tests/org.eclipse.ease.ui.completions.java.test/build.properties
new file mode 100644
index 0000000..3f1d08a
--- /dev/null
+++ b/tests/org.eclipse.ease.ui.completions.java.test/build.properties
@@ -0,0 +1,3 @@
+source.. = src/
+bin.includes = .,\
+ META-INF/
\ No newline at end of file
diff --git a/tests/org.eclipse.ease.ui.completions.java.test/pom.xml b/tests/org.eclipse.ease.ui.completions.java.test/pom.xml
new file mode 100644
index 0000000..bfc8c47
--- /dev/null
+++ b/tests/org.eclipse.ease.ui.completions.java.test/pom.xml
@@ -0,0 +1,15 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>org.eclipse.ease.ui.completions.java.test</artifactId>
+ <packaging>eclipse-test-plugin</packaging>
+
+ <parent>
+ <groupId>org.eclipse.ease</groupId>
+ <artifactId>org.eclipse.ease.core.tests</artifactId>
+ <version>0.9.0-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+</project>
diff --git a/tests/org.eclipse.ease.ui.completions.java.test/src/org/eclipse/ease/ui/completions/java/provider/JavaClassCompletionProviderTest.java b/tests/org.eclipse.ease.ui.completions.java.test/src/org/eclipse/ease/ui/completions/java/provider/JavaClassCompletionProviderTest.java
new file mode 100644
index 0000000..4b55dee
--- /dev/null
+++ b/tests/org.eclipse.ease.ui.completions.java.test/src/org/eclipse/ease/ui/completions/java/provider/JavaClassCompletionProviderTest.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Christian Pontesegger and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License_Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian Pontesegger - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.ui.completions.java.provider;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Collection;
+
+import org.eclipse.ease.ui.completion.BasicContext;
+import org.eclipse.ease.ui.completion.ScriptCompletionProposal;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+public class JavaClassCompletionProviderTest {
+
+ @BeforeAll
+ public static void beforeAll() {
+ // preload java packages
+
+ while (!JavaResources.getInstance().getPackages().contains("java.io")) {
+ try {
+ Thread.sleep(300);
+ } catch (final InterruptedException e) {
+ }
+ }
+ }
+
+ private JavaClassCompletionProvider fProvider;
+
+ @BeforeEach
+ public void beforeEach() {
+ fProvider = new JavaClassCompletionProvider();
+ }
+
+ @ParameterizedTest(name = "for context ''{0}''")
+ @DisplayName("isActive() = true")
+ @ValueSource(strings = { "Fil", "Foo", "java.io", "java.io.", "java.io.F", "java.io.File" })
+ public void isActive_equals_true(String input) {
+ assertTrue(fProvider.isActive(createContext(input)));
+ }
+
+ @ParameterizedTest(name = "for context ''{0}''")
+ @DisplayName("isActive() = false")
+ @ValueSource(strings = { "Fi", "java." })
+ public void isActive_equals_false(String input) {
+ assertFalse(fProvider.isActive(createContext(input)));
+ }
+
+ @Test
+ @DisplayName("prepareProposals() contains 'FileReader' for package context")
+ public void prepareProposals_instance_contains_class_for_package_context() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext("java.io."));
+
+ final ScriptCompletionProposal proposal = findProposal(proposals, "FileReader");
+ assertNotNull(proposal);
+ }
+
+ @Test
+ @DisplayName("prepareProposals() contains 'FileReader' for global context")
+ public void prepareProposals_instance_contains_class_for_global_context() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext("File"));
+
+ final ScriptCompletionProposal proposal = findProposal(proposals, "FileReader");
+ assertNotNull(proposal);
+ }
+
+ private ScriptCompletionProposal findProposal(Collection<ScriptCompletionProposal> proposals, String displayString) {
+ return proposals.stream().filter(p -> p.getDisplayString().startsWith(displayString)).findFirst().orElseGet(() -> null);
+ }
+
+ private BasicContext createContext(String input) {
+ return new BasicContext(null, null, input, input.length());
+ }
+}
diff --git a/tests/org.eclipse.ease.ui.completions.java.test/src/org/eclipse/ease/ui/completions/java/provider/JavaMethodCompletionProviderTest.java b/tests/org.eclipse.ease.ui.completions.java.test/src/org/eclipse/ease/ui/completions/java/provider/JavaMethodCompletionProviderTest.java
new file mode 100644
index 0000000..e7488ea
--- /dev/null
+++ b/tests/org.eclipse.ease.ui.completions.java.test/src/org/eclipse/ease/ui/completions/java/provider/JavaMethodCompletionProviderTest.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Christian Pontesegger and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License_Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian Pontesegger - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.ui.completions.java.provider;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Collection;
+
+import org.eclipse.ease.ui.completion.BasicContext;
+import org.eclipse.ease.ui.completion.ScriptCompletionProposal;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+public class JavaMethodCompletionProviderTest {
+
+ @ParameterizedTest(name = "for context ''{0}''")
+ @DisplayName("isActive() = true")
+ @ValueSource(strings = { "java.io.File()", "java.io.File().", "java.io.File().exis", "java.io.File", "java.io.File.", "java.io.File.exis" })
+ public void isActive_equals_true(String input) {
+ assertTrue(new JavaMethodCompletionProvider().isActive(createContext(input)));
+ }
+
+ @ParameterizedTest(name = "for context ''{0}''")
+ @DisplayName("isActive() = false")
+ @ValueSource(strings = { "java.io", "java.io.File(", "File()" })
+ public void isActive_equals_false(String input) {
+ assertFalse(new JavaMethodCompletionProvider().isActive(createContext(input)));
+ }
+
+ @Test
+ @DisplayName("prepareProposals() instance contains instance methods")
+ public void prepareProposals_instance_contains_instance_methods() {
+ final Collection<ScriptCompletionProposal> proposals = new JavaMethodCompletionProvider().getProposals(createContext("java.io.File()."));
+
+ final ScriptCompletionProposal proposal = findProposal(proposals, "exists()");
+ assertNotNull(proposal);
+ }
+
+ @Test
+ @DisplayName("prepareProposals() instance does not contain static methods")
+ public void prepareProposals_instance_does_not_contain_static_methods() {
+ final Collection<ScriptCompletionProposal> proposals = new JavaMethodCompletionProvider().getProposals(createContext("java.io.File()."));
+
+ final ScriptCompletionProposal proposal = findProposal(proposals, "createTempFile(");
+ assertNull(proposal);
+ }
+
+ @Test
+ @DisplayName("prepareProposals() class contains static methods")
+ public void prepareProposals_class_contains_static_methods() {
+ final Collection<ScriptCompletionProposal> proposals = new JavaMethodCompletionProvider().getProposals(createContext("java.io.File."));
+
+ final ScriptCompletionProposal proposal = findProposal(proposals, "createTempFile(");
+ assertNotNull(proposal);
+ }
+
+ @Test
+ @DisplayName("prepareProposals() class does not contain instance methods")
+ public void prepareProposals_class_does_not_contain_isntance_methods() {
+ final Collection<ScriptCompletionProposal> proposals = new JavaMethodCompletionProvider().getProposals(createContext("java.io.File."));
+
+ final ScriptCompletionProposal proposal = findProposal(proposals, "exists()");
+ assertNull(proposal);
+ }
+
+ @Test
+ @DisplayName("prepareProposals() instance does not contain static fields")
+ public void prepareProposals_instance_does_not_contain_static_fields() {
+ final Collection<ScriptCompletionProposal> proposals = new JavaMethodCompletionProvider().getProposals(createContext("java.io.File()."));
+
+ final ScriptCompletionProposal proposal = findProposal(proposals, "pathSeparator");
+ assertNull(proposal);
+ }
+
+ @Test
+ @DisplayName("prepareProposals() class contains static fields")
+ public void prepareProposals_class_contains_static_fields() {
+ final Collection<ScriptCompletionProposal> proposals = new JavaMethodCompletionProvider().getProposals(createContext("java.io.File."));
+
+ final ScriptCompletionProposal proposal = findProposal(proposals, "pathSeparator");
+ assertNotNull(proposal);
+ }
+
+ @Test
+ @DisplayName("prepareProposals() instance contains method with filter")
+ public void prepareProposals_instance_contains_method_with_filter() {
+ final Collection<ScriptCompletionProposal> proposals = new JavaMethodCompletionProvider().getProposals(createContext("java.io.File().exi"));
+
+ final ScriptCompletionProposal proposal = findProposal(proposals, "exists()");
+ assertNotNull(proposal);
+ }
+
+ private ScriptCompletionProposal findProposal(Collection<ScriptCompletionProposal> proposals, String displayString) {
+ return proposals.stream().filter(p -> p.getDisplayString().startsWith(displayString)).findFirst().orElseGet(() -> null);
+ }
+
+ private BasicContext createContext(String input) {
+ return new BasicContext(null, null, input, input.length());
+ }
+}
diff --git a/tests/org.eclipse.ease.ui.completions.java.test/src/org/eclipse/ease/ui/completions/java/provider/JavaPackagesCompletionProviderTest.java b/tests/org.eclipse.ease.ui.completions.java.test/src/org/eclipse/ease/ui/completions/java/provider/JavaPackagesCompletionProviderTest.java
new file mode 100644
index 0000000..3fb0137
--- /dev/null
+++ b/tests/org.eclipse.ease.ui.completions.java.test/src/org/eclipse/ease/ui/completions/java/provider/JavaPackagesCompletionProviderTest.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Christian Pontesegger and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License_Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian Pontesegger - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.ui.completions.java.provider;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Collection;
+
+import org.eclipse.ease.ui.completion.BasicContext;
+import org.eclipse.ease.ui.completion.ScriptCompletionProposal;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+public class JavaPackagesCompletionProviderTest {
+
+ @BeforeAll
+ public static void beforeAll() {
+ // preload java packages
+
+ while (!JavaResources.getInstance().getPackages().contains("java.io")) {
+ try {
+ Thread.sleep(300);
+ } catch (final InterruptedException e) {
+ }
+ }
+ }
+
+ private JavaPackagesCompletionProvider fProvider;
+
+ @BeforeEach
+ public void beforeEach() {
+ fProvider = new JavaPackagesCompletionProvider();
+ }
+
+ @ParameterizedTest(name = "for context ''{0}''")
+ @DisplayName("isActive() = true")
+ @ValueSource(strings = { "", "j", "java", "java.", "java.i", "java.lang.ref", "foo(", "foo(co", "java.io.File(", "java.io.File(jav",
+ "java.io.File().exists(", "java.io.File().exists(org", "new java", "f=java" })
+ public void isActive_equals_true(String input) {
+ assertTrue(fProvider.isActive(createContext(input)));
+ }
+
+ @ParameterizedTest(name = "for context ''{0}''")
+ @DisplayName("isActive() = false")
+ @ValueSource(strings = { "foo()", "foo().bar" })
+ public void isActive_equals_false(String input) {
+ assertFalse(fProvider.isActive(createContext(input)));
+ }
+
+ @ParameterizedTest(name = "''{0}''")
+ @DisplayName("prepareProposals() contains root package")
+ @ValueSource(strings = { "java", "com", "org" })
+ public void prepareProposals_contains_root_package(String rootPackage) {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext(""));
+
+ final ScriptCompletionProposal proposal = findProposal(proposals, rootPackage);
+ assertNotNull(proposal);
+ }
+
+ @Test
+ @DisplayName("prepareProposals() contains 'java.io'")
+ public void prepareProposals_instance_contains_sub_package() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext("java."));
+
+ final ScriptCompletionProposal proposal = findProposal(proposals, "java.io");
+ assertNotNull(proposal);
+ }
+
+ @Test
+ @DisplayName("prepareProposals() contains 'java.lang.reflect'")
+ public void prepareProposals_instance_contains_3rd_level() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext("java.lang."));
+
+ final ScriptCompletionProposal proposal = findProposal(proposals, "java.lang.reflect");
+ assertNotNull(proposal);
+ }
+
+ @Test
+ @DisplayName("prepareProposals() contains 'java' after 'new' keyword")
+ public void prepareProposals_instance_contains_root_package_after_new_keyword() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext("new java"));
+
+ final ScriptCompletionProposal proposal = findProposal(proposals, "java");
+ assertNotNull(proposal);
+ }
+
+ @Test
+ @DisplayName("proposal 'java' replaces filter")
+ public void proposal_java_replaces_filter() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext("ja"));
+
+ final ScriptCompletionProposal proposal = findProposal(proposals, "java");
+ assertEquals("java.", proposal.getContent());
+ assertEquals(5, proposal.getCursorPosition());
+ }
+
+ @Test
+ @DisplayName("proposal 'java' appends to prefix")
+ public void proposal_java_appends_to_prefix() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext("new ja"));
+
+ final ScriptCompletionProposal proposal = findProposal(proposals, "java");
+ assertEquals("new java.", proposal.getContent());
+ assertEquals(9, proposal.getCursorPosition());
+ }
+
+ @Test
+ @DisplayName("proposal 'java' preserves suffix")
+ public void proposal_java_preserves_suffix() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(new BasicContext(null, null, "jaio.File", 2));
+
+ final ScriptCompletionProposal proposal = findProposal(proposals, "java");
+ assertEquals("java.io.File", proposal.getContent());
+ assertEquals(5, proposal.getCursorPosition());
+ }
+
+ private ScriptCompletionProposal findProposal(Collection<ScriptCompletionProposal> proposals, String displayString) {
+ return proposals.stream().filter(p -> p.getDisplayString().startsWith(displayString)).findFirst().orElseGet(() -> null);
+ }
+
+ private BasicContext createContext(String input) {
+ return new BasicContext(null, null, input, input.length());
+ }
+}
diff --git a/tests/org.eclipse.ease.ui.completions.java.test/src/org/eclipse/ease/ui/completions/java/provider/JavaResourcesTest.java b/tests/org.eclipse.ease.ui.completions.java.test/src/org/eclipse/ease/ui/completions/java/provider/JavaResourcesTest.java
new file mode 100644
index 0000000..faab457
--- /dev/null
+++ b/tests/org.eclipse.ease.ui.completions.java.test/src/org/eclipse/ease/ui/completions/java/provider/JavaResourcesTest.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Christian Pontesegger and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License_Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian Pontesegger - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.ui.completions.java.provider;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+public class JavaResourcesTest {
+
+ @BeforeAll
+ public static void beforeAll() {
+ // preload java packages
+
+ while (!JavaResources.getInstance().getPackages().contains("java.io")) {
+ try {
+ Thread.sleep(300);
+ } catch (final InterruptedException e) {
+ }
+ }
+ }
+
+ @Test
+ @DisplayName("singleton exists")
+ public void singleton_exists() {
+ assertNotNull(JavaResources.getInstance());
+ }
+
+ @Test
+ @DisplayName("getClasses() is populated")
+ public void getClasses_is_populated() {
+ assertFalse(JavaResources.getInstance().getClasses().isEmpty());
+ }
+
+ @Test
+ @DisplayName("getPackages() is populated")
+ public void getPackages_is_populated() {
+ assertFalse(JavaResources.getInstance().getPackages().isEmpty());
+ }
+
+ @Test
+ @DisplayName("getClasses(<filter>) is populated")
+ public void getClasses_with_filter_is_populated() {
+ assertFalse(JavaResources.getInstance().getClasses("java.io").isEmpty());
+ }
+
+ @Test
+ @DisplayName("getClasses(java.io) contains File class")
+ public void getClasses_with_filter_contains_File_class() {
+ assertTrue(JavaResources.getInstance().getClasses("java.io").contains("File"));
+ }
+}
diff --git a/tests/org.eclipse.ease.ui.test/.classpath b/tests/org.eclipse.ease.ui.test/.classpath
index f193818..a621c21 100644
--- a/tests/org.eclipse.ease.ui.test/.classpath
+++ b/tests/org.eclipse.ease.ui.test/.classpath
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src">
<attributes>
diff --git a/tests/org.eclipse.ease.ui.test/.settings/org.eclipse.jdt.core.prefs b/tests/org.eclipse.ease.ui.test/.settings/org.eclipse.jdt.core.prefs
index 64e8545..7004b85 100644
--- a/tests/org.eclipse.ease.ui.test/.settings/org.eclipse.jdt.core.prefs
+++ b/tests/org.eclipse.ease.ui.test/.settings/org.eclipse.jdt.core.prefs
@@ -11,17 +11,21 @@
org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.compliance=11
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=11
org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
@@ -29,19 +33,22 @@
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_assignment=0
-org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16
org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16
org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
@@ -130,11 +137,12 @@
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
@@ -165,6 +173,8 @@
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
@@ -189,13 +199,17 @@
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
@@ -243,6 +257,8 @@
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
@@ -279,9 +295,12 @@
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
@@ -317,9 +336,13 @@
org.eclipse.jdt.core.formatter.tabulation.size=4
org.eclipse.jdt.core.formatter.use_on_off_tags=true
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true
org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
-org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true
org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true
org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/tests/org.eclipse.ease.ui.test/META-INF/MANIFEST.MF b/tests/org.eclipse.ease.ui.test/META-INF/MANIFEST.MF
index 48ec14d..989f8d4 100644
--- a/tests/org.eclipse.ease.ui.test/META-INF/MANIFEST.MF
+++ b/tests/org.eclipse.ease.ui.test/META-INF/MANIFEST.MF
@@ -4,12 +4,13 @@
Bundle-SymbolicName: org.eclipse.ease.ui.test;singleton:=true
Bundle-Version: 0.9.0.qualifier
Fragment-Host: org.eclipse.ease.ui
-Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Require-Bundle: org.junit.jupiter.api;bundle-version="5.5.0",
+Bundle-RequiredExecutionEnvironment: JavaSE-11
+Require-Bundle: org.junit.jupiter.api,
org.eclipse.help,
org.eclipse.help.ui,
org.eclipse.help.webapp,
org.eclipse.equinox.http.jetty,
org.eclipse.ui.browser,
- org.mockito
+ org.mockito,
+ org.junit.jupiter.params
Automatic-Module-Name: org.eclipse.ease.ui.test
diff --git a/tests/org.eclipse.ease.ui.test/fragment.xml b/tests/org.eclipse.ease.ui.test/fragment.xml
index 97f910b..cdd3fe4 100644
--- a/tests/org.eclipse.ease.ui.test/fragment.xml
+++ b/tests/org.eclipse.ease.ui.test/fragment.xml
@@ -9,6 +9,23 @@
name="Sample"
visible="true">
</module>
+ <module
+ class="org.eclipse.ease.ui.test.RootModule"
+ id="org.eclipse.ease.ui.test.rootModule"
+ name="Test Root"
+ visible="true">
+ </module>
+ <category
+ id="org.eclipse.ease.ui.test.category"
+ name="Testing">
+ </category>
+ <module
+ category="org.eclipse.ease.ui.test.category"
+ class="org.eclipse.ease.ui.test.SubModule"
+ id="org.eclipse.ease.ui.test.subModule"
+ name="Test Sub"
+ visible="true">
+ </module>
</extension>
<extension
point="org.eclipse.help.toc">
diff --git a/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/BasicContextTest.java b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/BasicContextTest.java
new file mode 100644
index 0000000..6d3f713
--- /dev/null
+++ b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/BasicContextTest.java
@@ -0,0 +1,175 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Christian Pontesegger and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License_Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian Pontesegger - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.ui.completion;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.ease.IScriptEngine;
+import org.eclipse.ease.modules.EnvironmentModule;
+import org.eclipse.ease.modules.IEnvironment;
+import org.eclipse.ease.modules.ModuleDefinition;
+import org.eclipse.ease.service.EngineDescription;
+import org.eclipse.ease.service.ScriptType;
+import org.eclipse.ease.ui.test.SubModule;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+public class BasicContextTest {
+
+ @Test
+ @DisplayName("getFilter() is empty for 'java.io.File()'")
+ public void getFilter_is_empty() {
+ final BasicContext context = createContext("java.io.File()");
+
+ assertEquals("", context.getFilter());
+ }
+
+ @Test
+ @DisplayName("getFilter() is empty for ''")
+ public void getFilter_is_empty_for_empty_input() {
+ final BasicContext context = createContext("");
+
+ assertEquals("", context.getFilter());
+ }
+
+ @Test
+ @DisplayName("getFilter() = 12 for 'java.io.File().exists(12'")
+ public void getFilter_contains_parameter_prefix() {
+ final BasicContext context = createContext("java.io.File().exists(12");
+
+ assertEquals("12", context.getFilter());
+ }
+
+ @Test
+ @DisplayName("getFilter() = 123 for 'java.io.File().exists(\"123'")
+ public void getFilter_removes_string_literal_start() {
+ final BasicContext context = createContext("java.io.File().exists(\"123");
+
+ assertEquals("123", context.getFilter());
+ }
+
+ @Test
+ @DisplayName("getFilter() = 123 abc for 'java.io.File().exists(\"123 abc'")
+ public void getFilter_keeps_spaces_in_string_literal() {
+ final BasicContext context = createContext("java.io.File().exists(\"123 abc");
+
+ assertEquals("123 abc", context.getFilter());
+ }
+
+ @Test
+ @DisplayName("getFilterToken() is empty for ''")
+ public void getFilterToken_is_empty_for_empty_input() {
+ final BasicContext context = createContext("");
+
+ assertEquals("", context.getFilterToken());
+ }
+
+ @Test
+ @DisplayName("getFilterToken() = 12 for 'java.io.File().exists(12'")
+ public void getFilterToken_contains_parameter_prefix() {
+ final BasicContext context = createContext("java.io.File().exists(12");
+
+ assertEquals("12", context.getFilterToken());
+ }
+
+ @Test
+ @DisplayName("getFilterToken() = \"123 for 'java.io.File().exists(\"123'")
+ public void getFilterToken_removes_string_literal_start() {
+ final BasicContext context = createContext("java.io.File().exists(\"123");
+
+ assertEquals("\"123", context.getFilterToken());
+ }
+
+ @Test
+ @DisplayName("getScriptEngine() returns engine")
+ public void getScriptEngine_returns_engine() {
+ final IScriptEngine scriptEngine = createEngine();
+
+ assertEquals(scriptEngine, new BasicContext(scriptEngine, "", 0).getScriptEngine());
+ }
+
+ @Test
+ @DisplayName("getLoadedModules() contains environment on resource")
+ public void getLoadedModules_contains_environment_on_resource() {
+
+ final IScriptEngine scriptEngine = createEngine();
+ when(scriptEngine.getVariables()).thenReturn(Collections.emptyMap());
+
+ final List<ModuleDefinition> modules = createContext("").getLoadedModules();
+ assertEquals(1, modules.size());
+ assertEquals(EnvironmentModule.MODULE_NAME, modules.get(0).getPath().toString());
+ }
+
+ @Test
+ @DisplayName("getLoadedModules() does not load environment twice on resource")
+ public void getLoadedModules_does_not_contain_environment_twice_on_resource() {
+
+ final IScriptEngine scriptEngine = createEngine();
+ when(scriptEngine.getVariables()).thenReturn(Collections.emptyMap());
+
+ final List<ModuleDefinition> modules = createContext("loadModule(\"/Environment\")\n").getLoadedModules();
+ assertEquals(1, modules.size());
+ assertEquals(EnvironmentModule.MODULE_NAME, modules.get(0).getPath().toString());
+ }
+
+ @Test
+ @DisplayName("getLoadedModules() detects loadModule() commands")
+ public void getLoadedModules_detects_loadModule_commands() {
+
+ final IScriptEngine scriptEngine = createEngine();
+ when(scriptEngine.getVariables()).thenReturn(Collections.emptyMap());
+
+ final List<ModuleDefinition> modules = createContext("loadModule(\"/Testing/Test Sub\")\n").getLoadedModules();
+ assertEquals(2, modules.size());
+ assertEquals("/Testing/Test Sub", modules.get(0).getPath().toString());
+ assertEquals(EnvironmentModule.MODULE_NAME, modules.get(1).getPath().toString());
+ }
+
+ @Test
+ @DisplayName("getLoadedModules() detects modules from ScriptEngine")
+ public void getLoadedModules_detects_modules_from_ScriptEngine() {
+
+ final Map<String, Object> variables = new HashMap<>();
+ variables.put(IEnvironment.MODULE_PREFIX + "_one", new SubModule());
+
+ final IScriptEngine scriptEngine = createEngine();
+ when(scriptEngine.getVariables()).thenReturn(variables);
+
+ final List<ModuleDefinition> modules = new BasicContext(scriptEngine, "", 0).getLoadedModules();
+ assertEquals(1, modules.size());
+ assertEquals("/Testing/Test Sub", modules.get(0).getPath().toString());
+ }
+
+ private IScriptEngine createEngine() {
+ final EngineDescription engineDescription = mock(EngineDescription.class);
+ when(engineDescription.getSupportedScriptTypes()).thenReturn(Arrays.asList(new ScriptType(null)));
+
+ final IScriptEngine engine = mock(IScriptEngine.class);
+ when(engine.getDescription()).thenReturn(engineDescription);
+
+ return engine;
+ }
+
+ private BasicContext createContext(String input) {
+ return new BasicContext(null, null, input, input.length());
+ }
+}
diff --git a/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/CodeCompletionAggregatorTest.java b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/CodeCompletionAggregatorTest.java
new file mode 100644
index 0000000..c8f756f
--- /dev/null
+++ b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/CodeCompletionAggregatorTest.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Christian Pontesegger and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License_Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian Pontesegger - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.ui.completion;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.ease.ICompletionContext;
+import org.eclipse.ease.service.ScriptType;
+import org.eclipse.ease.ui.completion.provider.ICompletionProvider;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatchers;
+
+public class CodeCompletionAggregatorTest {
+
+ private static List<ScriptCompletionProposal> createProposal(String displayString) {
+ return Arrays.asList(new ScriptCompletionProposal(null, displayString, null, null, 0, null));
+ }
+
+ private ScriptType fScriptType;
+ private CodeCompletionAggregator fAggregator;
+
+ @BeforeEach
+ public void beforeEach() {
+ fScriptType = mock(ScriptType.class);
+ when(fScriptType.getName()).thenReturn("TestEngine");
+
+ fAggregator = new CodeCompletionAggregator(null, fScriptType);
+ }
+
+ @Test
+ @DisplayName("getProposals() contains proposal from local provider")
+ public void getProposals_contains_proposal_from_local_provider() {
+ final ICompletionProvider localProvider = mock(ICompletionProvider.class);
+ when(localProvider.getProposals(ArgumentMatchers.any())).thenReturn(createProposal("test1"));
+ when(localProvider.isActive(ArgumentMatchers.any())).thenReturn(true);
+
+ fAggregator.addCompletionProvider(localProvider);
+
+ final List<ScriptCompletionProposal> proposals = fAggregator.getProposals("foo", 0, null);
+ assertTrue(proposals.stream().filter(p -> "test1".equals(p.getDisplayString())).findAny().isPresent());
+ }
+
+ @Test
+ @DisplayName("context for '|'")
+ public void context_for_empty_input() {
+ final ICompletionContext context = captureContext("");
+
+ assertTrue(context.getTokens().isEmpty());
+ }
+
+ @Test
+ @DisplayName("context for 'java.|'")
+ public void context_for_root_package() {
+ final ICompletionContext context = captureContext("java.");
+
+ assertArrayEquals(new Object[] { "java", "." }, context.getTokens().toArray());
+ }
+
+ @Test
+ @DisplayName("context for 'java.|another'")
+ public void context_for_root_package_with_suffix() {
+ final ICompletionContext context = captureContext("java.another", 5);
+
+ assertArrayEquals(new Object[] { "java", "." }, context.getTokens().toArray());
+ }
+
+ private ICompletionContext captureContext(String input) {
+ return captureContext(input, input.length());
+ }
+
+ private ICompletionContext captureContext(String input, int offset) {
+ final ICompletionProvider localProvider = mock(ICompletionProvider.class);
+
+ final ArgumentCaptor<ICompletionContext> contextCaptor = ArgumentCaptor.forClass(ICompletionContext.class);
+ fAggregator.addCompletionProvider(localProvider);
+
+ fAggregator.getProposals(input, offset, null);
+
+ verify(localProvider).isActive(contextCaptor.capture());
+
+ return contextCaptor.getValue();
+ }
+}
diff --git a/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/CompletionContextTest.java b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/CompletionContextTest.java
deleted file mode 100644
index d4fa0b7..0000000
--- a/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/CompletionContextTest.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Christian Pontesegger and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v2.0
- * which accompanies this distribution, and is available at
- * https://www.eclipse.org/legal/epl-2.0/
- *
- * SPDX-License_Identifier: EPL-2.0
- *
- * Contributors:
- * Christian Pontesegger - initial API and implementation
- *******************************************************************************/
-
-package org.eclipse.ease.ui.completion;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-import java.io.File;
-
-import org.eclipse.ease.ICompletionContext.Type;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-public class CompletionContextTest {
-
- private CompletionContext fContext;
-
- @BeforeEach
- public void setUp() throws Exception {
- fContext = new CompletionContext(null, null) {
-
- @Override
- protected boolean isLiteral(final char candidate) {
- return (candidate == '"') || (candidate == '\'');
- }
- };
- }
-
- @Test
- public void replaceSimpleStringLiterals() {
- assertEquals("print('')", fContext.replaceStringLiterals("print('')"));
- assertEquals("print('')", fContext.replaceStringLiterals("print('Hello world')"));
- assertEquals("print('')", fContext.replaceStringLiterals("print('Hello \" world')"));
-
- assertEquals("print(\"\")", fContext.replaceStringLiterals("print(\"\")"));
- assertEquals("print(\"\")", fContext.replaceStringLiterals("print(\"Hello world\")"));
- assertEquals("print(\"\")", fContext.replaceStringLiterals("print(\"Hello ' world\")"));
- }
-
- @Test
- public void replaceEscapedStringLiterals() {
- assertEquals("print('')", fContext.replaceStringLiterals("print('Hello \\'world')"));
- assertEquals("print(\"\")", fContext.replaceStringLiterals("print(\"Hello \\\"world\")"));
- }
-
- @Test
- public void replaceMultipleStringLiterals() {
- assertEquals("print('', \"\")", fContext.replaceStringLiterals("print('', \"\")"));
- assertEquals("print('', \"\")", fContext.replaceStringLiterals("print('Hello world', \"Hello world\")"));
- }
-
- @Test
- public void simplifyCalls() {
- fContext.calculateContext(null, "create(java.lang.String('').is", 22, 0);
- assertEquals("is", fContext.getFilter());
- }
-
- @Test
- public void resolveStaticClass() {
- fContext.calculateContext(null, "java.io.File.", 0, 0);
- assertEquals("", fContext.getFilter());
- assertEquals(File.class, fContext.getReferredClazz());
- assertEquals(Type.STATIC_CLASS, fContext.getType());
- }
-
- @Test
- public void resolveStaticClassWithFilter() {
- fContext.calculateContext(null, "java.io.File.exi", 0, 0);
- assertEquals("exi", fContext.getFilter());
- assertEquals(File.class, fContext.getReferredClazz());
- assertEquals(Type.STATIC_CLASS, fContext.getType());
- }
-
- @Test
- public void resolveClass() {
- fContext.calculateContext(null, "new java.io.File().", 0, 0);
- assertEquals("", fContext.getFilter());
- assertEquals(File.class, fContext.getReferredClazz());
- assertEquals(Type.CLASS_INSTANCE, fContext.getType());
- }
-
- @Test
- public void resolveClassWithParameters() {
- fContext.calculateContext(null, "new java.io.File(\"/some/path\").", 0, 0);
- assertEquals("", fContext.getFilter());
- assertEquals(File.class, fContext.getReferredClazz());
- assertEquals(Type.CLASS_INSTANCE, fContext.getType());
- }
-
- @Test
- public void resolveClassWithFilter() {
- fContext.calculateContext(null, "new java.io.File(\"/some/path\").exi", 0, 0);
- assertEquals("exi", fContext.getFilter());
- assertEquals(File.class, fContext.getReferredClazz());
- assertEquals(Type.CLASS_INSTANCE, fContext.getType());
- }
-}
diff --git a/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/ScriptCompletionProposalTest.java b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/ScriptCompletionProposalTest.java
new file mode 100644
index 0000000..4c11fcc
--- /dev/null
+++ b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/ScriptCompletionProposalTest.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Christian Pontesegger and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License_Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian Pontesegger - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.ui.completion;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.eclipse.ease.ICompletionContext;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+public class ScriptCompletionProposalTest {
+
+ @Test
+ @DisplayName("getContent() sets replacement text")
+ public void getContent_sets_replacement_text() {
+ final ScriptCompletionProposal proposal = new ScriptCompletionProposal(createContext(""), "foo", "foo()", null, 0, null);
+
+ assertEquals("foo()", proposal.getContent());
+ }
+
+ @Test
+ @DisplayName("getContent() appends replacement text")
+ public void getContent_appends_replacement_text() {
+ final ScriptCompletionProposal proposal = new ScriptCompletionProposal(createContext("bar."), "foo", "foo()", null, 0, null);
+
+ assertEquals("bar.foo()", proposal.getContent());
+ }
+
+ @Test
+ @DisplayName("getContent() inserts replacement text")
+ public void getContent_inserts_replacement_text() {
+ final ScriptCompletionProposal proposal = new ScriptCompletionProposal(new BasicContext(null, null, "AAA.BBB", 4), "foo", "foo()", null, 0, null);
+
+ assertEquals("AAA.foo()BBB", proposal.getContent());
+ }
+
+ @Test
+ @DisplayName("getCursorPosition() = end of set text")
+ public void getCursorPosition_equals_end_of_set_text() {
+ final ScriptCompletionProposal proposal = new ScriptCompletionProposal(createContext(""), "foo", "foo()", null, 0, null);
+
+ assertEquals(5, proposal.getCursorPosition());
+ }
+
+ @Test
+ @DisplayName("getCursorPosition() = end of appended text")
+ public void getCursorPosition_equals_end_of_appended_text() {
+ final ScriptCompletionProposal proposal = new ScriptCompletionProposal(createContext("bar."), "foo", "foo()", null, 0, null);
+
+ assertEquals(9, proposal.getCursorPosition());
+ }
+
+ @Test
+ @DisplayName("getCursorPosition() = end of inserted text")
+ public void getCursorPosition_equals_end_of_inserted_text() {
+ final ScriptCompletionProposal proposal = new ScriptCompletionProposal(new BasicContext(null, null, "AAA.BBB", 4), "foo", "foo()", null, 0, null);
+
+ assertEquals(9, proposal.getCursorPosition());
+ }
+
+ private ICompletionContext createContext(String input) {
+ return new BasicContext(null, null, input, input.length());
+ }
+}
diff --git a/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/provider/AbstractCompletionProviderTest.java b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/provider/AbstractCompletionProviderTest.java
new file mode 100644
index 0000000..fe1d28d
--- /dev/null
+++ b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/provider/AbstractCompletionProviderTest.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Christian Pontesegger and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License_Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian Pontesegger - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.ui.completion.provider;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.eclipse.ease.ICompletionContext;
+import org.eclipse.ease.ui.completion.BasicContext;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+public class AbstractCompletionProviderTest {
+
+ @ParameterizedTest(name = "for ''{0}''")
+ @DisplayName("isMethodParameter(foo, 0) = true")
+ @ValueSource(strings = { "foo(", "com.test.foo(" })
+ public void isMethodParameter_equals_true(String input) {
+ assertTrue(new TestCompletionProvider("foo", 0).isActive(new BasicContext(null, null, input, input.length())));
+ }
+
+ @ParameterizedTest(name = "for ''{0}''")
+ @DisplayName("isMethodParameter(foo, 0) = false")
+ @ValueSource(strings = { "bar(", "foo", "foo(," })
+ public void isMethodParameter_equals_false(String input) {
+ assertFalse(new TestCompletionProvider("foo", 0).isActive(new BasicContext(null, null, input, input.length())));
+ }
+
+ @ParameterizedTest(name = "for ''{0}''")
+ @DisplayName("isMethodParameter(foo, 2) = true")
+ @ValueSource(strings = { "foo(a, b, ", "foo(a, b, cpart", "com.test.foo(1,2,", "com.test.foo(1,bar(1,2,3)," })
+ public void isMethodParameter_equals_true_for_parameter_index(String input) {
+ assertTrue(new TestCompletionProvider("foo", 2).isActive(new BasicContext(null, null, input, input.length())));
+ }
+
+ @ParameterizedTest(name = "for ''{0}''")
+ @DisplayName("isMethodParameter(foo, 2) = false")
+ @ValueSource(strings = { "bar(1,2,", "foo", "foo(1,", "foo(1,2,3," })
+ public void isMethodParameter_equals_false_for_parameter_index(String input) {
+ assertFalse(new TestCompletionProvider("foo", 2).isActive(new BasicContext(null, null, input, input.length())));
+ }
+
+ private static final class TestCompletionProvider extends AbstractCompletionProvider {
+
+ private final String fMethodName;
+ private final int fParameterIndex;
+
+ private TestCompletionProvider(String methodName, int parameterIndex) {
+ fMethodName = methodName;
+ fParameterIndex = parameterIndex;
+ }
+
+ @Override
+ public boolean isActive(ICompletionContext context) {
+ return super.isActive(context) && isMethodParameter(context, fMethodName, fParameterIndex);
+ }
+
+ @Override
+ protected void prepareProposals(ICompletionContext context) {
+ // nothing to do
+ }
+ }
+}
diff --git a/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/provider/AbstractFileLocationCompletionProviderTest.java b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/provider/AbstractFileLocationCompletionProviderTest.java
index 1a197c5..5a78724 100644
--- a/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/provider/AbstractFileLocationCompletionProviderTest.java
+++ b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/provider/AbstractFileLocationCompletionProviderTest.java
@@ -13,16 +13,12 @@
package org.eclipse.ease.ui.completion.provider;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.util.Collection;
-import java.util.HashSet;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
@@ -31,10 +27,11 @@
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.ease.ICompletionContext;
+import org.eclipse.ease.ui.completion.BasicContext;
import org.eclipse.ease.ui.completion.ScriptCompletionProposal;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
public class AbstractFileLocationCompletionProviderTest {
@@ -89,7 +86,7 @@
if (!fFolder.exists())
fFolder.create(0, true, null);
- fFile1 = fFolder.getFile(FILE1_NAME);
+ fFile1 = fProject.getFile(FILE1_NAME);
if (!fFile1.exists())
fFile1.create(new ByteArrayInputStream(FILE1_CONTENT.getBytes("UTF-8")), false, null);
@@ -117,140 +114,157 @@
}
}
- @Disabled
@Test
- public void checkOperatingSystem() {
- assertTrue(isLinux() || isWindows(), "Operating system is: " + System.getProperty("os.name"));
+ @DisplayName("getProposals('') contains 'workspace://'")
+ public void getProposals_contains_workspace_root() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext(""));
+ assertNotNull(findProposal(proposals, "workspace://"));
}
- @Disabled
@Test
- public void absoluteRootWorkspaceProposals() {
-
- final ICompletionContext context = mock(ICompletionContext.class);
- when(context.getOriginalCode()).thenReturn("");
- when(context.getFilter()).thenReturn("");
- when(context.getResource()).thenReturn(null);
-
- final Collection<? extends ScriptCompletionProposal> proposals = fProvider.getProposals(context);
- final Collection<String> content = extractDisplayedContent(proposals);
-
- assertTrue(content.contains("workspace://"), "<workspace://> proposal missing");
- assertTrue(content.contains("file:///"), "<file:///> proposal missing");
- assertEquals(2, proposals.size());
+ @DisplayName("getProposals('') contains 'file://'")
+ public void getProposals_contains_filesystem_root() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext(""));
+ assertNotNull(findProposal(proposals, "file://"));
}
- @Disabled
@Test
- public void workspaceProposals() {
-
- final ICompletionContext context = mock(ICompletionContext.class);
- when(context.getOriginalCode()).thenReturn("workspace://");
- when(context.getFilter()).thenReturn("workspace://");
- when(context.getResource()).thenReturn(null);
-
- final Collection<? extends ScriptCompletionProposal> proposals = fProvider.getProposals(context);
- final Collection<String> content = extractDisplayedContent(proposals);
-
- assertTrue(content.contains(PROJECT_NAME), "<" + PROJECT_NAME + "> proposal missing");
- assertEquals(1, proposals.size());
+ @DisplayName("getProposals('') does not contain 'project://' without resource")
+ public void getProposals_does_not_contain_project_root_without_resource() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext(""));
+ assertNull(findProposal(proposals, "project://"));
}
- @Disabled
@Test
- public void workspaceProjectProposals() {
-
- final ICompletionContext context = mock(ICompletionContext.class);
- when(context.getOriginalCode()).thenReturn("workspace://" + PROJECT_NAME + "/");
- when(context.getFilter()).thenReturn("workspace://" + PROJECT_NAME + "/");
- when(context.getResource()).thenReturn(null);
-
- final Collection<? extends ScriptCompletionProposal> proposals = fProvider.getProposals(context);
- final Collection<String> content = extractDisplayedContent(proposals);
-
- assertTrue(content.contains(".."), "<..> proposal missing");
- assertTrue(content.contains(FOLDER_NAME), "<" + FOLDER_NAME + "> proposal missing");
- assertTrue(content.contains(".project"), "<.project> proposal missing");
- assertEquals(3, proposals.size());
+ @DisplayName("getProposals('') does not contain 'project://' with file resource")
+ public void getProposals_does_not_contain_project_root_with_file_resource() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext("", fFsFile1));
+ assertNull(findProposal(proposals, "project://"));
}
- @Disabled
@Test
- public void workspaceFolderProposals() {
-
- final ICompletionContext context = mock(ICompletionContext.class);
- when(context.getOriginalCode()).thenReturn("workspace://" + PROJECT_NAME + "/" + FOLDER_NAME + "/");
- when(context.getFilter()).thenReturn("workspace://" + PROJECT_NAME + "/" + FOLDER_NAME + "/");
- when(context.getResource()).thenReturn(null);
-
- final Collection<? extends ScriptCompletionProposal> proposals = fProvider.getProposals(context);
- final Collection<String> content = extractDisplayedContent(proposals);
-
- assertTrue(content.contains(".."), "<..> proposal missing");
- assertTrue(content.contains(FILE1_NAME), "<" + FILE1_NAME + "> proposal missing");
- assertTrue(content.contains(FILE2_NAME), "<" + FILE2_NAME + "> proposal missing");
- assertEquals(3, proposals.size());
+ @DisplayName("getProposals('') contains 'project://' with workspace resource")
+ public void getProposals_contains_project_root_with_workspace_resource() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext("", fFile1));
+ assertNotNull(findProposal(proposals, "project://"));
}
- @Disabled
@Test
- public void relativeRootWorkspaceProposals() {
-
- final ICompletionContext context = mock(ICompletionContext.class);
- when(context.getOriginalCode()).thenReturn("");
- when(context.getFilter()).thenReturn("");
- when(context.getResource()).thenReturn(fFile1);
-
- final Collection<? extends ScriptCompletionProposal> proposals = fProvider.getProposals(context);
- final Collection<String> content = extractDisplayedContent(proposals);
-
- assertTrue(content.contains("workspace://"), "<workspace://> proposal missing");
- assertTrue(content.contains("file:///"), "<file:///> proposal missing");
- assertTrue(content.contains("project://"), "<project://> proposal missing");
- assertTrue(content.contains(".."), "<..> proposal missing");
- assertTrue(content.contains(FILE1_NAME), "<" + FILE1_NAME + "> proposal missing");
- assertTrue(content.contains(FILE2_NAME), "<" + FILE2_NAME + "> proposal missing");
- assertEquals(6, proposals.size());
+ @DisplayName("getProposals('workspace://') contains projects")
+ public void getProposals_contains_projects_for_workspace_root() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext("workspace://"));
+ assertNotNull(findProposal(proposals, fProject.getName()));
}
- @Disabled
@Test
- public void fileSystemRootProposals() {
- final ICompletionContext context = mock(ICompletionContext.class);
- when(context.getOriginalCode()).thenReturn("file:///");
- when(context.getFilter()).thenReturn("file:///");
- when(context.getResource()).thenReturn(null);
-
- final Collection<? extends ScriptCompletionProposal> proposals = fProvider.getProposals(context);
- final Collection<String> content = extractDisplayedContent(proposals);
-
- assertFalse(content.contains(".."), "<..> proposal exists");
- assertFalse(proposals.isEmpty());
+ @DisplayName("getProposals('workspace://') does not contain contains '..'")
+ public void getProposals_doe_not_contain_back_proposal() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext("workspace://"));
+ assertNull(findProposal(proposals, ".."));
}
- @Disabled
@Test
- public void fileSystemFolderProposals() {
- final ICompletionContext context = mock(ICompletionContext.class);
- when(context.getOriginalCode()).thenReturn(fFsFolder.getAbsolutePath());
- when(context.getFilter()).thenReturn(fFsFolder.getAbsolutePath());
- when(context.getResource()).thenReturn(null);
-
- final Collection<? extends ScriptCompletionProposal> proposals = fProvider.getProposals(context);
- final Collection<String> content = extractDisplayedContent(proposals);
-
- assertTrue(content.contains(".."), "<..> proposal missing");
- assertTrue(content.contains(FILE1_NAME), "<" + FILE1_NAME + "> proposal missing");
- assertTrue(content.contains(FILE2_NAME), "<" + FILE2_NAME + "> proposal missing");
- assertEquals(3, proposals.size());
+ @DisplayName("getProposals('workspace://<project>') contains project root folders")
+ public void getProposals_contains_project_root_folders_for_workspace_project() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext("workspace://" + fProject.getName() + "/"));
+ assertNotNull(findProposal(proposals, fFolder.getName()));
}
- private static Collection<String> extractDisplayedContent(Collection<? extends ScriptCompletionProposal> proposals) {
- final Collection<String> content = new HashSet<>();
+ @Test
+ @DisplayName("getProposals('workspace://<project>') contains project root files")
+ public void getProposals_contains_project_root_files_for_workspace_project() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext("workspace://" + fProject.getName() + "/"));
+ assertNotNull(findProposal(proposals, fFile1.getName()));
+ }
- for (final ScriptCompletionProposal proposal : proposals)
- content.add(proposal.getDisplayString());
+ @Test
+ @DisplayName("getProposals('workspace://<project>/<folder>') contains folder files")
+ public void getProposals_contains_files_for_workspace_folder() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider
+ .getProposals(createContext("workspace://" + fProject.getName() + "/" + fFolder.getName() + "/"));
+ assertNotNull(findProposal(proposals, fFile2.getName()));
+ }
- return content;
+ @Test
+ @DisplayName("getProposals('workspace://<project>/<folder>') contains '..' proposal")
+ public void getProposals_contains_back_for_workspace_folder() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider
+ .getProposals(createContext("workspace://" + fProject.getName() + "/" + fFolder.getName() + "/"));
+ assertNotNull(findProposal(proposals, ".."));
+ }
+
+ @DisplayName("getProposals('project://') contains project root folders")
+ public void getProposals_contains_project_root_folders_for_project_root() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext("project://", fFile2));
+ assertNotNull(findProposal(proposals, fFolder.getName()));
+ }
+
+ @Test
+ @DisplayName("getProposals('project://') contains project root files")
+ public void getProposals_contains_project_root_files_for_project_root() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext("project://", fFile2));
+ assertNotNull(findProposal(proposals, fFile1.getName()));
+ }
+
+ @Test
+ @DisplayName("getProposals('project://<folder>') contains folder files")
+ public void getProposals_contains_files_for_project_folder() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext("project://" + fFolder.getName() + "/", fFile2));
+ assertNotNull(findProposal(proposals, fFile2.getName()));
+ }
+
+ @Test
+ @DisplayName("getProposals('project://<folder>') contains '..' proposal")
+ public void getProposals_contains_back_for_project_folder() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext("project://" + fFolder.getName() + "/", fFile2));
+ assertNotNull(findProposal(proposals, ".."));
+ }
+
+ @Test
+ @DisplayName("getProposals('file://') contains root file systems")
+ public void getProposals_contains_root_file_systems() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext("file://"));
+ for (final File root : File.listRoots())
+ assertNotNull(findProposal(proposals, root.getName()), String.format("Root entry not found for %s", root.getName()));
+ }
+
+ @Test
+ @DisplayName("getProposals('') contains files for project")
+ public void getProposals_contains_files_for_project() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext("", fProject));
+ assertNotNull(findProposal(proposals, fFile1.getName()));
+ }
+
+ @Test
+ @DisplayName("getProposals('') contains '..' for project")
+ public void getProposals_contains_back_for_project() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext("", fProject));
+ assertNotNull(findProposal(proposals, ".."));
+ }
+
+ @Test
+ @DisplayName("getProposals('') contains files for filesystem")
+ public void getProposals_contains_files_for_filesystem() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext("", fFsFile1));
+ assertNotNull(findProposal(proposals, fFsFile1.getName()));
+ }
+
+ @Test
+ @DisplayName("getProposals('') contains '..' for filesystem")
+ public void getProposals_contains_back_for_filesystem() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext("", fFsFile1));
+ assertNotNull(findProposal(proposals, ".."));
+ }
+
+ private ScriptCompletionProposal findProposal(Collection<ScriptCompletionProposal> proposals, String displayString) {
+ return proposals.stream().filter(p -> p.getDisplayString().startsWith(displayString)).findFirst().orElseGet(() -> null);
+ }
+
+ private ICompletionContext createContext(String input) {
+ return createContext(input, null);
+ }
+
+ private ICompletionContext createContext(String input, Object resource) {
+ return new BasicContext(null, resource, "\"" + input, input.length() + 1);
}
}
diff --git a/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/provider/AbstractPathCompletionProviderTest.java b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/provider/AbstractPathCompletionProviderTest.java
new file mode 100644
index 0000000..bc84f73
--- /dev/null
+++ b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/provider/AbstractPathCompletionProviderTest.java
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Christian Pontesegger and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License_Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian Pontesegger - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.ui.completion.provider;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.ease.ICompletionContext;
+import org.eclipse.ease.ui.completion.BasicContext;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+public class AbstractPathCompletionProviderTest {
+
+ @Test
+ @DisplayName("getPathsFromElements() is empty for no elements")
+ public void getPathsFromElements_is_empty_for_empty_element() {
+ assertTrue(new Provider().getPaths().isEmpty());
+ }
+
+ @Test
+ @DisplayName("getPathsFromElements() is empty for root elements only")
+ public void getPathsFromElements_is_empty_for_root_elements_only() {
+ assertTrue(new Provider().getPaths("foo", "bar").isEmpty());
+ }
+
+ @Test
+ @DisplayName("getPathsFromElements() contains parent paths")
+ public void getPathsFromElements_contains_parent_paths() {
+ final Collection<IPath> paths = new Provider().getPaths("foo/bar", "foo/another", "/2nd/path");
+
+ assertEquals(2, paths.size());
+ assertEquals(new Path("/foo"), new ArrayList<>(paths).get(0));
+ assertEquals(new Path("/2nd"), new ArrayList<>(paths).get(1));
+ }
+
+ @Test
+ @DisplayName("getPathsFromElements() contains all hierarchies")
+ public void getPathsFromElements_contains_all_hierarchies() {
+ final Collection<IPath> paths = new Provider().getPaths("first/second/third/fourth");
+
+ assertEquals(3, paths.size());
+ assertEquals(new Path("/first"), new ArrayList<>(paths).get(0));
+ assertEquals(new Path("/first/second"), new ArrayList<>(paths).get(1));
+ assertEquals(new Path("/first/second/third"), new ArrayList<>(paths).get(2));
+ }
+
+ @Test
+ @DisplayName("filter() removes nothing if context is empty")
+ public void filter_removes_nothing_if_context_is_empty() {
+
+ final Collection<String> elements = new Provider().filter(createContext(""), "a", "b", "c");
+
+ assertEquals(3, elements.size());
+ assertEquals("a", new ArrayList<>(elements).get(0));
+ assertEquals("b", new ArrayList<>(elements).get(1));
+ assertEquals("c", new ArrayList<>(elements).get(2));
+ }
+
+ @Test
+ @DisplayName("filter() removes mismatches on same level")
+ public void filter_removes_mismatches_on_same_level() {
+
+ final Collection<String> elements = new Provider().filter(createContext("a"), "a", "b", "c", "alpha");
+
+ assertEquals(2, elements.size());
+ assertEquals("a", new ArrayList<>(elements).get(0));
+ assertEquals("alpha", new ArrayList<>(elements).get(1));
+ }
+
+ @Test
+ @DisplayName("filter('') keeps only 1st level")
+ public void filter_keeps_only_1st_level_on_empty_filter() {
+
+ final Collection<String> elements = new Provider().filter(createContext(""), "first/second/third", "foo/bar", "root");
+
+ assertEquals(1, elements.size());
+ assertEquals("root", new ArrayList<>(elements).get(0));
+ }
+
+ @Test
+ @DisplayName("filter() keeps only 1st level on matching filter")
+ public void filter_keeps_only_1st_level_on_matching_filter() {
+
+ final Collection<String> elements = new Provider().filter(createContext("r"), "first/second/third", "foo/bar", "root");
+
+ assertEquals(1, elements.size());
+ assertEquals("root", new ArrayList<>(elements).get(0));
+ }
+
+ @Test
+ @DisplayName("filter() keeps only matching level on filter")
+ public void filter_keeps_only_lower_level_on_matching_filter() {
+
+ final Collection<String> elements = new Provider().filter(createContext("first/b"), "first", "first/bar", "first/mismatch", "first/bar/another");
+
+ assertEquals(1, elements.size());
+ assertEquals("first/bar", new ArrayList<>(elements).get(0));
+ }
+
+ @Test
+ @DisplayName("filter('foo') matches absolute paths")
+ public void filter_matches_relative_paths() {
+
+ final Collection<String> elements = new Provider().filter(createContext("foo"), "/fooBar", "/foo", "/foo/none", "/bar");
+
+ assertEquals(2, elements.size());
+ assertEquals("/fooBar", new ArrayList<>(elements).get(0));
+ assertEquals("/foo", new ArrayList<>(elements).get(1));
+ }
+
+ @Test
+ @DisplayName("filter('/first/') matches next level")
+ public void filter_matches_next_level() {
+
+ final Collection<String> elements = new Provider().filter(createContext("/first/"), "/first", "/first/second", "/first/second/third");
+
+ assertEquals(1, elements.size());
+ assertEquals("/first/second", new ArrayList<>(elements).get(0));
+ }
+
+ private ICompletionContext createContext(String input) {
+ return new BasicContext(null, null, input, input.length());
+ }
+
+ private class Provider extends AbstractPathCompletionProvider {
+
+ public Collection<IPath> getPaths(String... elements) {
+ return getPathsFromElements(Arrays.asList(elements));
+ }
+
+ public Collection<String> filter(ICompletionContext context, String... elements) {
+ return filter(Arrays.asList(elements), context);
+ }
+
+ @Override
+ protected IPath toPath(Object element) {
+ return new Path(String.valueOf(element));
+ }
+
+ @Override
+ protected void prepareProposals(ICompletionContext context) {
+ // nothing to do
+ }
+ }
+}
diff --git a/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/provider/LoadModuleCompletionProviderTest.java b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/provider/LoadModuleCompletionProviderTest.java
new file mode 100644
index 0000000..50ee3cc
--- /dev/null
+++ b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/provider/LoadModuleCompletionProviderTest.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Christian Pontesegger and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License_Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian Pontesegger - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.ui.completion.provider;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Collection;
+
+import org.eclipse.ease.ICompletionContext;
+import org.eclipse.ease.ui.completion.BasicContext;
+import org.eclipse.ease.ui.completion.ScriptCompletionProposal;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+public class LoadModuleCompletionProviderTest {
+
+ @Test
+ @DisplayName("isActive() = true for loadModule(|")
+ public void isActive_equals_true_for_method() {
+ assertTrue(new LoadModuleCompletionProvider().isActive(getContext("loadModule(")));
+ }
+
+ @Test
+ @DisplayName("isActive() = true for loadModule(\"Plat|")
+ public void isActive_equals_true_for_partial_module_name() {
+ assertTrue(new LoadModuleCompletionProvider().isActive(getContext("loadModule(\"Plat")));
+ }
+
+ @Test
+ @DisplayName("isActive() = false for loadModul(|")
+ public void isActive_equals_true_for_wrong_method_name() {
+ assertFalse(new LoadModuleCompletionProvider().isActive(getContext("loadModul(")));
+ }
+
+ @Test
+ @DisplayName("isActive() = false for loadModule(\"\", |")
+ public void isActive_equals_true_for_wrong_method_parameter() {
+ assertFalse(new LoadModuleCompletionProvider().isActive(getContext("loadModule(\"\",")));
+ }
+
+ @Test
+ @DisplayName("getProposals() contains root entry for loadModule(")
+ public void getProposals_contains_root_entry() {
+ final Collection<ScriptCompletionProposal> proposals = new LoadModuleCompletionProvider().getProposals(getContext("loadModule("));
+ assertNotNull(findProposal(proposals, "Test Root"));
+ }
+
+ @Test
+ @DisplayName("getProposals() contains root entry for loadModule(\"Te")
+ public void getProposals_contains_root_entry_with_relative_filter() {
+ final Collection<ScriptCompletionProposal> proposals = new LoadModuleCompletionProvider().getProposals(getContext("loadModule(\"Te"));
+ assertNotNull(findProposal(proposals, "Test Root"));
+ }
+
+ @Test
+ @DisplayName("getProposals() contains root entry for loadModule(\"/Te")
+ public void getProposals_contains_root_entry_with_absolute_filter() {
+ final Collection<ScriptCompletionProposal> proposals = new LoadModuleCompletionProvider().getProposals(getContext("loadModule(\"/Te"));
+ assertNotNull(findProposal(proposals, "Test Root"));
+ }
+
+ @Test
+ @DisplayName("getProposals() does not contain root entry for loadModule(\"/Foo")
+ public void getProposals_does_not_contain_root_entry_on_filter_mismatch() {
+ final Collection<ScriptCompletionProposal> proposals = new LoadModuleCompletionProvider().getProposals(getContext("loadModule(\"/foo"));
+ assertNull(findProposal(proposals, "Test Root"));
+ }
+
+ private ScriptCompletionProposal findProposal(Collection<ScriptCompletionProposal> proposals, String displayString) {
+ return proposals.stream().filter(p -> p.getDisplayString().startsWith(displayString)).findFirst().orElseGet(() -> null);
+ }
+
+ private ICompletionContext getContext(String input) {
+ return new BasicContext(null, null, input, input.length());
+ }
+}
diff --git a/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/provider/LoadedModuleCompletionProviderTest.java b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/provider/LoadedModuleCompletionProviderTest.java
new file mode 100644
index 0000000..24465dc
--- /dev/null
+++ b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/provider/LoadedModuleCompletionProviderTest.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Christian Pontesegger and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License_Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian Pontesegger - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.ui.completion.provider;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Collection;
+
+import org.eclipse.ease.ICompletionContext;
+import org.eclipse.ease.ui.completion.BasicContext;
+import org.eclipse.ease.ui.completion.ScriptCompletionProposal;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+public class LoadedModuleCompletionProviderTest {
+
+ @ParameterizedTest(name = "for ''{0}''")
+ @DisplayName("isActive() = true")
+ @ValueSource(strings = { "", "myMethod", "call(", "call(myMethod", "call(param, ", "call(param, myMe" })
+ public void isActive_equals_true(String input) {
+ assertTrue(new LoadedModuleCompletionProvider().isActive(createContext(input)));
+ }
+
+ @ParameterizedTest(name = "for ''{0}''")
+ @DisplayName("isActive() = false")
+ @ValueSource(strings = { "java.", "java.io", "call(java.io", "call(\"myMethod" })
+ public void isActive_equals_false(String input) {
+ assertFalse(new LoadedModuleCompletionProvider().isActive(createContext(input)));
+ }
+
+ @Test
+ @DisplayName("getProposals() contains method proposals")
+ public void getProposals_contains_module_methods() {
+ final Collection<ScriptCompletionProposal> proposals = new LoadedModuleCompletionProvider().getProposals(createContext("loadModule(\"/Test Root\")\n"));
+ assertNotNull(findProposal(proposals, "testMethod"));
+ }
+
+ @Test
+ @DisplayName("getProposals() contains constant proposals")
+ public void getProposals_contains_constant_methods() {
+ final Collection<ScriptCompletionProposal> proposals = new LoadedModuleCompletionProvider().getProposals(createContext("loadModule(\"/Test Root\")\n"));
+ assertNotNull(findProposal(proposals, "TEST_CONSTANT"));
+ }
+
+ private ScriptCompletionProposal findProposal(Collection<ScriptCompletionProposal> proposals, String displayString) {
+ return proposals.stream().filter(p -> p.getDisplayString().startsWith(displayString)).findFirst().orElseGet(() -> null);
+ }
+
+ private ICompletionContext createContext(String input) {
+ return new BasicContext(null, null, input, input.length());
+ }
+}
diff --git a/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/provider/VariablesCompletionProviderTest.java b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/provider/VariablesCompletionProviderTest.java
new file mode 100644
index 0000000..6c71b92
--- /dev/null
+++ b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/provider/VariablesCompletionProviderTest.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Christian Pontesegger and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License_Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian Pontesegger - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.ui.completion.provider;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.ease.IScriptEngine;
+import org.eclipse.ease.modules.IEnvironment;
+import org.eclipse.ease.service.EngineDescription;
+import org.eclipse.ease.ui.completion.BasicContext;
+import org.eclipse.ease.ui.completion.ScriptCompletionProposal;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+public class VariablesCompletionProviderTest {
+
+ private VariablesCompletionProvider fProvider;
+
+ @BeforeEach
+ public void beforeEach() {
+ fProvider = new VariablesCompletionProvider();
+ }
+
+ @ParameterizedTest(name = "for context ''{0}''")
+ @DisplayName("isActive() = true")
+ @ValueSource(strings = { "", "foo", "Foo", "method(", "method(45,", "method(45, foo", "java.io.File(", "java.io.File().exists(" })
+ public void isActive_equals_true(String input) {
+ assertTrue(fProvider.isActive(createContext(input)));
+ }
+
+ @ParameterizedTest(name = "for context ''{0}''")
+ @DisplayName("isActive() = false")
+ @ValueSource(strings = { "com.", "method()" })
+ public void isActive_equals_false(String input) {
+ assertFalse(fProvider.isActive(createContext(input)));
+ }
+
+ @Test
+ @DisplayName("prepareProposals() contains string variable")
+ public void prepareProposals_instance_contains_string_variable() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext(""));
+
+ final ScriptCompletionProposal proposal = findProposal(proposals, "myString");
+ assertNotNull(proposal);
+ }
+
+ @Test
+ @DisplayName("prepareProposals() contains string variable for filter input")
+ public void prepareProposals_instance_contains_string_variable_for_filter_input() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext("myStr"));
+
+ final ScriptCompletionProposal proposal = findProposal(proposals, "myString");
+ assertNotNull(proposal);
+ }
+
+ @Test
+ @DisplayName("prepareProposals() contains string variable for filter input (case insensitive))")
+ public void prepareProposals_instance_contains_string_variable_for_filter_input_case_insensitive() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext("MYSTR"));
+
+ final ScriptCompletionProposal proposal = findProposal(proposals, "myString");
+ assertNotNull(proposal);
+ }
+
+ @Test
+ @DisplayName("prepareProposals() contains integer variable")
+ public void prepareProposals_instance_contains_integer_variable() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext(""));
+
+ final ScriptCompletionProposal proposal = findProposal(proposals, "myNumber");
+ assertNotNull(proposal);
+ }
+
+ @Test
+ @DisplayName("prepareProposals() does not contain internal variable")
+ public void prepareProposals_does_not_contain_internal_variable() {
+ final Collection<ScriptCompletionProposal> proposals = fProvider.getProposals(createContext(""));
+
+ final ScriptCompletionProposal proposal = findProposal(proposals, IEnvironment.MODULE_PREFIX + "SOMETHING");
+ assertNull(proposal);
+ }
+
+ private ScriptCompletionProposal findProposal(Collection<ScriptCompletionProposal> proposals, String displayString) {
+ return proposals.stream().filter(p -> p.getDisplayString().startsWith(displayString)).findFirst().orElseGet(() -> null);
+ }
+
+ private BasicContext createContext(String input) {
+ final Map<String, Object> variables = new HashMap<>();
+ variables.put("myString", "Hello world");
+ variables.put("myNumber", 42);
+ variables.put(IEnvironment.MODULE_PREFIX + "SOMETHING", "not visible");
+
+ final EngineDescription description = mock(EngineDescription.class);
+ when(description.getSupportedScriptTypes()).thenReturn(Collections.singletonList(null));
+
+ final IScriptEngine scriptEngine = mock(IScriptEngine.class);
+ when(scriptEngine.getVariables()).thenReturn(variables);
+ when(scriptEngine.getDescription()).thenReturn(description);
+
+ return new BasicContext(scriptEngine, input, input.length());
+ }
+}
diff --git a/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/tokenizer/BracketMatcherTest.java b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/tokenizer/BracketMatcherTest.java
new file mode 100644
index 0000000..db06caf
--- /dev/null
+++ b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/tokenizer/BracketMatcherTest.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Christian Pontesegger and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License_Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian Pontesegger - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.ui.completion.tokenizer;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+public class BracketMatcherTest {
+
+ @Test
+ @DisplayName("getBrackets() is empty for 'some text'")
+ public void getBrackets_is_empty() {
+ assertTrue(new BracketMatcher("some text").getBrackets().isEmpty());
+ }
+
+ @Test
+ @DisplayName("getBrackets() detects 'single()'")
+ public void getBrackets_detects_1() {
+ assertArrayEquals(new Object[] { new Bracket(6, 7) }, new BracketMatcher("single()").getBrackets().toArray());
+ }
+
+ @Test
+ @DisplayName("getBrackets() detects 'single().inText'")
+ public void getBrackets_detects_2() {
+ assertArrayEquals(new Object[] { new Bracket(6, 7) }, new BracketMatcher("single().inText").getBrackets().toArray());
+ }
+
+ @Test
+ @DisplayName("getBrackets() detects 'one().two().three'")
+ public void getBrackets_detects_3() {
+ assertArrayEquals(new Object[] { new Bracket(9, 10), new Bracket(3, 4) }, new BracketMatcher("one().two().three").getBrackets().toArray());
+ }
+
+ @Test
+ @DisplayName("getBrackets() detects 'outer(inner())'")
+ public void getBrackets_detects_nested() {
+ assertArrayEquals(new Object[] { new Bracket(11, 12), new Bracket(5, 13) }, new BracketMatcher("outer(inner())").getBrackets().toArray());
+ }
+
+ @Test
+ @DisplayName("getBrackets() detects 'outer(inner('")
+ public void getBrackets_detects_open_brackets() {
+ assertArrayEquals(new Object[] { new Bracket(11, -1), new Bracket(5, -1) }, new BracketMatcher("outer(inner(").getBrackets().toArray());
+ }
+
+ @Test
+ @DisplayName("hasOpenBrackets() = false for 'outer(inner())'")
+ public void hasOpenBrackets_equals_false() {
+ assertFalse(new BracketMatcher("outer(inner())").hasOpenBrackets());
+ }
+
+ @Test
+ @DisplayName("hasOpenBrackets() = true for 'outer(inner(), text()'")
+ public void hasOpenBrackets_equals_true() {
+ assertTrue(new BracketMatcher("outer(inner(), text()").hasOpenBrackets());
+ }
+
+ @Test
+ @DisplayName("getOpenBrackets() detects 'outer(inner(), text('")
+ public void getOpenBrackets_returns_open_brackets_only() {
+ assertArrayEquals(new Object[] { new Bracket(19, -1), new Bracket(5, -1) }, new BracketMatcher("outer(inner(), text(").getOpenBrackets().toArray());
+ }
+}
diff --git a/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/tokenizer/InputTokenizerTest.java b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/tokenizer/InputTokenizerTest.java
new file mode 100644
index 0000000..957cd2c
--- /dev/null
+++ b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/completion/tokenizer/InputTokenizerTest.java
@@ -0,0 +1,289 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Christian Pontesegger and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License_Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian Pontesegger - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.ui.completion.tokenizer;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+import org.eclipse.ease.ui.completion.tokenizer.InputTokenizer;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+public class InputTokenizerTest {
+
+ @ParameterizedTest(name = "for ''{0}''")
+ @DisplayName("isDelimiter() = true")
+ @ValueSource(strings = { ".", ",", "(", "()", ")" })
+ public void isDelimiter_equals_true(String input) {
+ assertTrue(InputTokenizer.isDelimiter(input));
+ }
+
+ @ParameterizedTest(name = "for ''{0}''")
+ @DisplayName("isDelimiter() = false")
+ @ValueSource(strings = { ". ", "test", "123" })
+ public void isDelimiter_equals_false(String input) {
+ assertFalse(InputTokenizer.isDelimiter(input));
+ }
+
+ @ParameterizedTest(name = "for ''{0}''")
+ @DisplayName("isTextFilter() = true")
+ @ValueSource(strings = { "foo", "bar" })
+ public void isTextFilter_equals_true(String input) {
+ assertTrue(InputTokenizer.isTextFilter(input));
+ }
+
+ @ParameterizedTest(name = "for ''{0}''")
+ @DisplayName("isTextFilter() = false")
+ @ValueSource(strings = { ".", "(", "()", ")", "," })
+ public void isTextFilter_equals_false(String input) {
+ assertFalse(InputTokenizer.isTextFilter(input));
+ }
+
+ @Test
+ @DisplayName("'' => {}")
+ public void getTokens_for_empty_input() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+
+ assertArrayEquals(new Object[] {}, tokenizer.getTokens("").toArray());
+ }
+
+ @Test
+ @DisplayName("'foo' => 'foo'")
+ public void getTokens_1() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+
+ assertArrayEquals(new Object[] { "foo" }, tokenizer.getTokens("foo").toArray());
+ }
+
+ @Test
+ @DisplayName("'java.i' => 'java', '.', 'i')")
+ public void getTokens_detects_package_fragments() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+ assertArrayEquals(new Object[] { "java", ".", "i" }, tokenizer.getTokens("java.i").toArray());
+ }
+
+ @Test
+ @DisplayName("'java.io' => P(java.io)")
+ public void getTokens_detects_package() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+ assertArrayEquals(new Object[] { Package.getPackage("java.io") }, tokenizer.getTokens("java.io").toArray());
+ }
+
+ @Test
+ @DisplayName("'java.io.' => P(java.io), '.'")
+ public void getTokens_detects_incomplete_package() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+ assertArrayEquals(new Object[] { Package.getPackage("java.io"), "." }, tokenizer.getTokens("java.io.").toArray());
+ }
+
+ @Test
+ @DisplayName("'java.io.foo' => P(java.io), '.', 'foo'")
+ public void getTokens_detects_partial_package() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+ assertArrayEquals(new Object[] { Package.getPackage("java.io"), ".", "foo" }, tokenizer.getTokens("java.io.foo").toArray());
+ }
+
+ @Test
+ @DisplayName("'java.io.File' => C(java.io.File)")
+ public void getTokens_detects_class() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+ assertArrayEquals(new Object[] { File.class }, tokenizer.getTokens("java.io.File").toArray());
+ }
+
+ @Test
+ @DisplayName("'java.io.File.' => C(java.io.File), '.'")
+ public void getTokens_detects_class_2() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+ assertArrayEquals(new Object[] { File.class, "." }, tokenizer.getTokens("java.io.File.").toArray());
+ }
+
+ @Test
+ @DisplayName("'java.io.File()' => C(java.io.File), '()'")
+ public void getTokens_detects_class_instantiation() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+ assertArrayEquals(new Object[] { File.class, "()" }, tokenizer.getTokens("java.io.File()").toArray());
+ }
+
+ @Test
+ @DisplayName("'java.io.File(42, 23)' => C(java.io.File), '()'")
+ public void getTokens_detects_class_instantiation_2() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+ assertArrayEquals(new Object[] { File.class, "()" }, tokenizer.getTokens("java.io.File(42, 23)").toArray());
+ }
+
+ @Test
+ @DisplayName("'java.io.File().' => C(java.io.File), '()', '.'")
+ public void getTokens_detects_class_instantiation_3() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+ assertArrayEquals(new Object[] { File.class, "()", "." }, tokenizer.getTokens("java.io.File().").toArray());
+ }
+
+ @Test
+ @DisplayName("'java.io.Fi' => P(java.io), '.', 'Fi'")
+ public void getTokens_detects_package_with_class_prefix() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+ assertArrayEquals(new Object[] { Package.getPackage("java.io"), ".", "Fi" }, tokenizer.getTokens("java.io.Fi").toArray());
+ }
+
+ @Test
+ @DisplayName("'java.io.File.createTempFile()' => C(java.io.File), M(createTempFile), '()'")
+ public void getTokens_detects_static_method_call() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+ assertArrayEquals(new Object[] { File.class, getMethod(File.class, "createTempFile"), "()" },
+ tokenizer.getTokens("java.io.File.createTempFile()").toArray());
+ }
+
+ @Test
+ @DisplayName("'java.io.File.createTempFile().getName()' => C(java.io.File), M(createTempFile), '()', M(getName), '()'")
+ public void getTokens_detects_static_method_call_chain() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+ assertArrayEquals(new Object[] { File.class, getMethod(File.class, "createTempFile"), "()", getMethod(File.class, "getName"), "()" },
+ tokenizer.getTokens("java.io.File.createTempFile().getName()").toArray());
+ }
+
+ @Test
+ @DisplayName("'java.io.File().getName()' => C(java.io.File), '()', M(getName), '()'")
+ public void getTokens_detects_method_call() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+ assertArrayEquals(new Object[] { File.class, "()", getMethod(File.class, "getName"), "()" }, tokenizer.getTokens("java.io.File().getName()").toArray());
+ }
+
+ @Test
+ @DisplayName("'java.io.File.getName().getBytes()' => C(java.io.File), '()', M(getName), '()', M(getBytes), '()'")
+ public void getTokens_detects_method_call_chain() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+ assertArrayEquals(new Object[] { File.class, getMethod(File.class, "getName"), "()", getMethod(String.class, "getBytes"), "()" },
+ tokenizer.getTokens("java.io.File.getName().getBytes()").toArray());
+ }
+
+ @Test
+ @DisplayName("'java.io.File().getName(' => C(java.io.File), '()', M(getName), '('")
+ public void getTokens_detects_method_call_parameter() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+ assertArrayEquals(new Object[] { File.class, "()", getMethod(File.class, "getName"), "(" }, tokenizer.getTokens("java.io.File().getName(").toArray());
+ }
+
+ @Test
+ @DisplayName("'java.io.File().getName(1, 2,' => C(java.io.File), '()', M(getName), '(', ',', ','")
+ public void getTokens_detects_method_call_parameters() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+ assertArrayEquals(new Object[] { File.class, "()", getMethod(File.class, "getName"), "(", ",", "," },
+ tokenizer.getTokens("java.io.File().getName(1, 2,").toArray());
+ }
+
+ @Test
+ @DisplayName("'new java' => 'java'")
+ public void getTokens_removes_new_operator() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+ assertArrayEquals(new Object[] { "java" }, tokenizer.getTokens("new java").toArray());
+ }
+
+ @Test
+ @DisplayName("'foo=java' => 'java'")
+ public void getTokens_removes_left_hand_side_of_assignment() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+ assertArrayEquals(new Object[] { "java" }, tokenizer.getTokens("foo=java").toArray());
+ }
+
+ @Test
+ @DisplayName("'java.io.File().' => C(java.io.File), '()', '.'")
+ public void getTokens_detects_method_call_request() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+ assertArrayEquals(new Object[] { File.class, "()", "." }, tokenizer.getTokens("java.io.File().").toArray());
+ }
+
+ @Test
+ @DisplayName("'java.io.File().get' => C(java.io.File), '()', '.', 'get'")
+ public void getTokens_detects_method_call_request_with_filter() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+ assertArrayEquals(new Object[] { File.class, "()", ".", "get" }, tokenizer.getTokens("java.io.File().get").toArray());
+ }
+
+ @Test
+ @DisplayName("'java.io.File().getName(1, 2, 3' => C(java.io.File), '()', M(getName), '(', ',', ',', '3'")
+ public void getTokens_detects_method_call_parameters_with_prefix() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+ assertArrayEquals(new Object[] { File.class, "()", getMethod(File.class, "getName"), "(", ",", ",", "3" },
+ tokenizer.getTokens("java.io.File().getName(1, 2, 3").toArray());
+ }
+
+ @Test
+ @DisplayName("'java.io.File().getName(foo' => C(java.io.File), '()', M(getName), '(', 'foo'")
+ public void getTokens_detects_method_call_parameter_prefix() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+ assertArrayEquals(new Object[] { File.class, "()", getMethod(File.class, "getName"), "(", "foo" },
+ tokenizer.getTokens("java.io.File().getName(foo").toArray());
+ }
+
+ @Test
+ @DisplayName("'foo()' => 'foo', '()'")
+ public void getTokens_detects_javascript_method_call() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+ assertArrayEquals(new Object[] { "foo", "()" }, tokenizer.getTokens("foo()").toArray());
+ }
+
+ @Test
+ @DisplayName("'JavaScript()' => 'JavaScript', '()'")
+ public void getTokens_detects_javascript_class_instantiation() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+ assertArrayEquals(new Object[] { "JavaScript", "()" }, tokenizer.getTokens("JavaScript()").toArray());
+ }
+
+ @Test
+ @DisplayName("'myVar' => 'myVar'")
+ public void getTokens_detects_javascript_variable() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+ assertArrayEquals(new Object[] { "myVar" }, tokenizer.getTokens("myVar").toArray());
+ }
+
+ @Test
+ @DisplayName("'myVar.foo()' => 'myVar', '.', 'foo', '()'")
+ public void getTokens_detects_javascript_object_call() {
+ final InputTokenizer tokenizer = new InputTokenizer();
+ assertArrayEquals(new Object[] { "myVar", ".", "foo", "()" }, tokenizer.getTokens("myVar.foo()").toArray());
+ }
+
+ @Test
+ @DisplayName("'myVar' => C(java.lang.String), '()'")
+ public void getTokens_detects_resolved_javascript_variable() {
+ final InputTokenizer tokenizer = new InputTokenizer(v -> "myVar".equals(v) ? String.class : null);
+ assertArrayEquals(new Object[] { String.class, "()" }, tokenizer.getTokens("myVar").toArray());
+ }
+
+ @Test
+ @DisplayName("'myVar.' => C(java.lang.String), '()', '.'")
+ public void getTokens_detects_resolved_javascript_variable_2() {
+ final InputTokenizer tokenizer = new InputTokenizer(v -> "myVar".equals(v) ? String.class : null);
+ assertArrayEquals(new Object[] { String.class, "()", "." }, tokenizer.getTokens("myVar.").toArray());
+ }
+
+ @Test
+ @DisplayName("'myVar.startsWith(x)' => C(java.lang.String), '()', M(startsWith), '()'")
+ public void getTokens_detects_resolved_javascript_variable_with_method() {
+ final InputTokenizer tokenizer = new InputTokenizer(v -> "myVar".equals(v) ? String.class : null);
+ assertArrayEquals(new Object[] { String.class, "()", getMethod(String.class, "startsWith"), "()" },
+ tokenizer.getTokens("myVar.startsWith(x)").toArray());
+ }
+
+ private static Method getMethod(Class<?> clazz, String methodName) {
+ return Arrays.asList(clazz.getMethods()).stream().filter(m -> methodName.equals(m.getName())).findFirst().get();
+ }
+}
diff --git a/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/modules/ModulesToolsTest.java b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/test/RootModule.java
similarity index 70%
copy from tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/modules/ModulesToolsTest.java
copy to tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/test/RootModule.java
index d20563c..f8ec394 100644
--- a/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/modules/ModulesToolsTest.java
+++ b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/test/RootModule.java
@@ -11,8 +11,17 @@
* Christian Pontesegger - initial API and implementation
*******************************************************************************/
-package org.eclipse.ease.ui.modules;
+package org.eclipse.ease.ui.test;
-public class ModulesToolsTest {
+import org.eclipse.ease.modules.WrapToScript;
+public class RootModule {
+
+ @WrapToScript
+ public static final String TEST_CONSTANT = "";
+
+ @WrapToScript
+ public void testMethod() {
+ // nothing to do
+ }
}
diff --git a/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/modules/ModulesToolsTest.java b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/test/SubModule.java
similarity index 88%
rename from tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/modules/ModulesToolsTest.java
rename to tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/test/SubModule.java
index d20563c..c818d61 100644
--- a/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/modules/ModulesToolsTest.java
+++ b/tests/org.eclipse.ease.ui.test/src/org/eclipse/ease/ui/test/SubModule.java
@@ -11,8 +11,8 @@
* Christian Pontesegger - initial API and implementation
*******************************************************************************/
-package org.eclipse.ease.ui.modules;
+package org.eclipse.ease.ui.test;
-public class ModulesToolsTest {
+public class SubModule {
}
diff --git a/tests/pom.xml b/tests/pom.xml
index e037d0a..7765cac 100644
--- a/tests/pom.xml
+++ b/tests/pom.xml
@@ -24,8 +24,17 @@
<artifactId>tycho-surefire-plugin</artifactId>
<version>${tycho.version}</version>
<configuration>
- <providerHint>junit5</providerHint>
+ <providerHint>junit57</providerHint>
+
+ <dependencies>
+ <!-- avoid CNFE in Surefire when looking for JUnitPlatformProvider -->
+ <dependency>
+ <artifactId>org.junit</artifactId>
+ <type>eclipse-plugin</type>
+ </dependency>
+ </dependencies>
</configuration>
+
</plugin>
<!-- enable JaCoCo code coverage -->