diff --git a/vscode-extensions/commons/application-properties-metadata/lib/org.springframework.ide.eclipse.org.json-20140107-repackaged-sources.jar b/vscode-extensions/commons/application-properties-metadata/lib/org.springframework.ide.eclipse.org.json-20140107-repackaged-sources.jar deleted file mode 100644 index a1226d8e7..000000000 Binary files a/vscode-extensions/commons/application-properties-metadata/lib/org.springframework.ide.eclipse.org.json-20140107-repackaged-sources.jar and /dev/null differ diff --git a/vscode-extensions/commons/application-properties-metadata/lib/org.springframework.ide.eclipse.org.json-20140107-repackaged.jar b/vscode-extensions/commons/application-properties-metadata/lib/org.springframework.ide.eclipse.org.json-20140107-repackaged.jar deleted file mode 100644 index 04feaa8cc..000000000 Binary files a/vscode-extensions/commons/application-properties-metadata/lib/org.springframework.ide.eclipse.org.json-20140107-repackaged.jar and /dev/null differ diff --git a/vscode-extensions/commons/application-properties-metadata/pom.xml b/vscode-extensions/commons/application-properties-metadata/pom.xml index 14ec55193..d9ed5f0d6 100644 --- a/vscode-extensions/commons/application-properties-metadata/pom.xml +++ b/vscode-extensions/commons/application-properties-metadata/pom.xml @@ -10,14 +10,19 @@ application-properties-metadata Builds metadata for boot application properties based on project's classpath contents + + + project-repo + file://${project.basedir}/repo + + + - libs - json + org.springframework.ide.eclipse + org.json 1.0 - system - ${project.basedir}/lib/org.springframework.ide.eclipse.org.json-20140107-repackaged.jar @@ -44,6 +49,16 @@ commons-util ${project.version} + + org.springframework.ide.vscode + commons-yaml + ${project.version} + + + org.springframework.ide.vscode + commons-java + ${project.version} + org.springframework.ide.vscode commons-language-server diff --git a/vscode-extensions/commons/application-properties-metadata/repo/org/springframework/ide/eclipse/org.json/1.0/org.json-1.0.pom b/vscode-extensions/commons/application-properties-metadata/repo/org/springframework/ide/eclipse/org.json/1.0/org.json-1.0.pom new file mode 100644 index 000000000..5bee0835b --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/repo/org/springframework/ide/eclipse/org.json/1.0/org.json-1.0.pom @@ -0,0 +1,9 @@ + + + 4.0.0 + org.springframework.ide.eclipse + org.json + 1.0 + POM was created from install:install-file + diff --git a/vscode-extensions/commons/application-properties-metadata/repo/org/springframework/ide/eclipse/org.json/maven-metadata-local.xml b/vscode-extensions/commons/application-properties-metadata/repo/org/springframework/ide/eclipse/org.json/maven-metadata-local.xml new file mode 100644 index 000000000..ad72ce3cb --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/repo/org/springframework/ide/eclipse/org.json/maven-metadata-local.xml @@ -0,0 +1,12 @@ + + + org.springframework.ide.eclipse + org.json + + 1.0 + + 1.0 + + 20161019231202 + + diff --git a/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/IndexNavigator.java b/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/IndexNavigator.java new file mode 100644 index 000000000..bc0d24c09 --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/IndexNavigator.java @@ -0,0 +1,133 @@ +/******************************************************************************* + * Copyright (c) 2015 Pivotal, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.boot.properties.metadata; + +import static org.springframework.ide.vscode.util.StringUtil.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.springframework.ide.vscode.boot.properties.util.FuzzyMap; +import org.springframework.ide.vscode.boot.properties.util.FuzzyMap.Match; +import org.springframework.ide.vscode.util.StringUtil; + +/** + * An index navigator allows selecting subset of a property index as if + * navigating the index by selecting on a property + * + * @author Kris De Volder + */ +public class IndexNavigator { + + //Possible opitmization: we could cache prefix match candidate and extended match candidate + // since it is assumed that the index is immutable for the lifetime of + // the index navigator. + + private static final char NAV_CHAR = '.'; + + /** + * Property access in this navigator are interpreted relative + * to this prefix + */ + private String prefix = null; + private FuzzyMap index; + + private IndexNavigator(FuzzyMap index) { + this.index = index; + } + + private IndexNavigator(FuzzyMap index, String prefix) { + this.index = index; + this.prefix = prefix; + } + + public static IndexNavigator with(FuzzyMap index) { + return new IndexNavigator(index); + } + + public IndexNavigator selectSubProperty(String name) { + return new IndexNavigator(index, join(prefix, name)); + } + + protected String join(String prefix, String postfix) { + if (!hasText(prefix)) { + return postfix; + } else { + return prefix + NAV_CHAR + postfix; + } + } + + /** + * @return property info that is an exact match with the current prefix or + * null if there's no exact match + */ + public PropertyInfo getExactMatch() { + if (prefix!=null) { + PropertyInfo candidate = index.findLongestCommonPrefixEntry(prefix); + if (candidate.getId().equals(prefix)) { + return candidate; + } + } + return null; + } + + /** + * Get a property that has the current prefix as a 'true' prefix. A true prefix + * is a String that has the current prefix as a prefix and continues onward with + * a navigation operation. + */ + public PropertyInfo getExtensionCandidate() { + //If current prefix is null then all entries in the index are candidates since + // the index is at the 'root' of the tree and we don't need a '.' to navigate + String extendedPrefix = prefix==null?"":prefix + NAV_CHAR; + PropertyInfo candidate = index.findLongestCommonPrefixEntry(extendedPrefix); + if (candidate.getId().startsWith(extendedPrefix)) { + return candidate; + } + return null; + } + + public String getPrefix() { + return prefix; + } + + public List> findMatching(String query) { + if (!StringUtil.hasText(prefix)) { + return index.find(query); + } else { + String dottedPrefix = prefix +"."; + List> candidates = index.find(dottedPrefix + query); + if (!candidates.isEmpty()) { + //TODO: we can do better than this using treemap to narrow based on + // prefix + List> matches = new ArrayList>(candidates.size()); + for (Match match : candidates) { + if (match.data.getId().startsWith(dottedPrefix)){ + matches.add(match); + } + } + return matches; + } + } + return Collections.emptyList(); + } + + @Override + public String toString() { + return "IndexNavigator("+prefix+")"; + } + + public boolean isEmpty() { + return getExactMatch()==null && getExtensionCandidate()==null; + } + +} diff --git a/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/SpringPropertyIndexProvider.java b/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/SpringPropertyIndexProvider.java index 6229380ca..73b8e88d2 100644 --- a/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/SpringPropertyIndexProvider.java +++ b/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/SpringPropertyIndexProvider.java @@ -10,12 +10,11 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.properties.metadata; -import org.springframework.ide.vscode.util.IDocument; import org.springframework.ide.vscode.boot.properties.util.FuzzyMap; +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; -public abstract class SpringPropertyIndexProvider { - - public abstract FuzzyMap getIndex(IDocument doc); - +@FunctionalInterface +public interface SpringPropertyIndexProvider { + FuzzyMap getIndex(IDocument doc); } diff --git a/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/ValueProviderRegistry.java b/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/ValueProviderRegistry.java index 28ddac0da..6f3d7a708 100644 --- a/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/ValueProviderRegistry.java +++ b/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/ValueProviderRegistry.java @@ -10,13 +10,18 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.properties.metadata; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Function; import org.springframework.boot.configurationmetadata.ValueProvider; -import org.springframework.ide.vscode.boot.properties.util.CollectionUtil; +import org.springframework.ide.vscode.boot.properties.metadata.types.StsValueHint; +import org.springframework.ide.vscode.java.IJavaProject; +import org.springframework.ide.vscode.util.CollectionUtil; + +import reactor.core.publisher.Flux; /** * An instance of this class serves as a 'registry' that associates known @@ -50,14 +55,14 @@ public class ValueProviderRegistry { private Map, ValueProviderStrategy>> registry = new HashMap<>(); public interface ValueProviderStrategy { -// Flux getValues(IJavaProject javaProject, String query); -// -// default Collection getValuesNow(IJavaProject javaProject, String query) { -// return this.getValues(javaProject, query) -// .take(CachingValueProvider.TIMEOUT) -// .collectList() -// .block(); -// } + Flux getValues(IJavaProject javaProject, String query); + + default Collection getValuesNow(IJavaProject javaProject, String query) { + return this.getValues(javaProject, query) + .take(CachingValueProvider.TIMEOUT) + .collectList() + .block(); + } } /** diff --git a/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/types/StsValueHint.java b/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/types/StsValueHint.java new file mode 100644 index 000000000..8ab138fb6 --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/types/StsValueHint.java @@ -0,0 +1,154 @@ +package org.springframework.ide.vscode.boot.properties.metadata.types; + +import static org.springframework.ide.vscode.boot.properties.util.DeprecationUtil.*; + +import javax.inject.Provider; + +import org.springframework.boot.configurationmetadata.Deprecation; +import org.springframework.boot.configurationmetadata.ValueHint; +import org.springframework.ide.vscode.boot.properties.util.DeprecationUtil; +import org.springframework.ide.vscode.java.IJavaElement; +import org.springframework.ide.vscode.java.IJavaProject; +import org.springframework.ide.vscode.java.IType; +import org.springframework.ide.vscode.util.Assert; +import org.springframework.ide.vscode.util.HtmlSnippet; +import org.springframework.ide.vscode.util.Log; +import org.springframework.ide.vscode.util.StringUtil; + +/** + * Sts version of {@link ValueHint} contains similar data, but accomoates + * a html snippet to be computed lazyly for the description. + *

+ * This is meant to support using data pulled from JavaDoc in enums as description. + * This data is a html snippet, whereas the data derived from spring-boot metadata is + * just plain text. + * + * @author Kris De Volder + */ +public class StsValueHint { + + private static final HtmlSnippet EMPTY_DESCRIPTION = HtmlSnippet.italic("No description"); + + private static final Provider EMPTY_DESCRIPTION_PROVIDER = () -> EMPTY_DESCRIPTION; + + private final String value; + private final Provider description; + private final Deprecation deprecation; + + /** + * Create a hint with a textual description. + *

+ * This constructor is private. Use one of the provided + * static 'create' methods instead. + */ + private StsValueHint(String value, Provider description, Deprecation deprecation) { + this.value = value==null?"null":value.toString(); + Assert.isLegal(!this.value.startsWith("StsValueHint")); + this.description = description; + this.deprecation = deprecation; + } + + /** + * Creates a hint out of an IJavaElement. + */ + public static StsValueHint create(String value, IJavaElement javaElement) { + return new StsValueHint(value, javaDocSnippet(javaElement), DeprecationUtil.extract(javaElement)) { + @Override + public IJavaElement getJavaElement() { + return javaElement; + } + }; + } + + public static StsValueHint create(String value) { + return new StsValueHint(value, EMPTY_DESCRIPTION_PROVIDER, null); + } + + public static StsValueHint create(ValueHint hint) { + return new StsValueHint(""+hint.getValue(), textSnippet(hint.getDescription()), null); + } + + public static StsValueHint className(String fqName, TypeUtil typeUtil) { + try { + IJavaProject jp = typeUtil.getJavaProject(); + if (jp!=null) { + IType type = jp.findType(fqName); + if (type!=null) { + return create(type); + } + } + } catch (Exception e) { + Log.log(e); + } + return null; + } + + public static StsValueHint create(IType klass) { + return new StsValueHint(klass.getFullyQualifiedName(), javaDocSnippet(klass), DeprecationUtil.extract(klass)) { + @Override + public IJavaElement getJavaElement() { + return klass; + } + }; + } + + /** + * Create a html snippet from a text snippet. + */ + private static Provider textSnippet(String description) { + if (StringUtil.hasText(description)) { + return () -> HtmlSnippet.text(description); + } + return EMPTY_DESCRIPTION_PROVIDER; + } + + public String getValue() { + return value; + } + + public HtmlSnippet getDescription() { + return description.get(); + } + public Provider getDescriptionProvider() { + return description; + } + + public static Provider javaDocSnippet(IJavaElement je) { + return () -> { + try { + HtmlSnippet jdoc = je.getJavaDoc(); + if (jdoc!=null) { + return jdoc; + } + } catch (Exception e) { + Log.log(e); + } + return EMPTY_DESCRIPTION; + }; + } + + @Override + public String toString() { + return "StsValueHint("+value+")"; + } + + public Deprecation getDeprecation() { + return deprecation; + } + + public IJavaElement getJavaElement() { + return null; + } + + public StsValueHint prefixWith(String prefix) { + StsValueHint it = this; + return new StsValueHint(prefix+getValue(), description, deprecation) { + @Override + public IJavaElement getJavaElement() { + return it.getJavaElement(); + } + }; + } + + +} diff --git a/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/types/Type.java b/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/types/Type.java new file mode 100644 index 000000000..377ade78a --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/types/Type.java @@ -0,0 +1,209 @@ +/******************************************************************************* + * Copyright (c) 2015 Pivotal, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.boot.properties.metadata.types; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.springframework.ide.vscode.java.IType; +import org.springframework.ide.vscode.util.ArrayUtils; +import org.springframework.ide.vscode.util.Assert; +import org.springframework.ide.vscode.util.Log; +import org.springframework.ide.vscode.util.StringUtil; +import org.springframework.ide.vscode.yaml.schema.YType; + +/** + * @author Kris De Volder + */ +public class Type implements YType { + + private final String erasure; + private final Type[] params; + + public Type(String erasure, Type[] params) { + this.erasure = erasure; + this.params = params; + } + + + public boolean isGeneric() { + return params!=null; + } + + public String getErasure() { + return erasure; + } + public Type[] getParams() { + return params; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + toString(buf); + return buf.toString(); + } + + private void toString(StringBuilder buf) { + buf.append(getErasure()); + if (isGeneric()) { + buf.append("<"); + boolean first = true; + for (Type param : getParams()) { + if (!first) { + buf.append(","); + } + param.toString(buf); + first = false; + } + buf.append(">"); + } + } + + /** + * Attempt to convert given typeSignature to a corresponding Type object. + *

+ * Not all valid typeSig have a representation as a Type object. This may + * return null if no corresponding representation can be constructed. + */ + public static Type fromSignature(String typeSig, IType context) { + //TODO: does this work correctly with nested types (i.e like Map$Entry) + Type type = TYPE_FROM_SIG.get(typeSig); + if (type!=null) { + return type; + } + int kind = Signature.getTypeSignatureKind(typeSig); + //Essentially, Type object only able to represent class types with with generic parameters + // as long as these generic parameters are fully concrete (i.e. do not contain unbound type + // variables. For now only support the simplest case (no generics) and bail out returning null if we + // see something we don't understand. + if (kind==Signature.CLASS_TYPE_SIGNATURE) { + boolean shouldResolve = typeSig.charAt(0)==Signature.C_UNRESOLVED; + String erasure = Signature.getTypeErasure(typeSig); + String pkg = Signature.getSignatureQualifier(erasure); + String nam = Signature.getSignatureSimpleName(erasure); + String[] params = Signature.getTypeParameters(typeSig); + String[] args = Signature.getTypeArguments(typeSig); + if (shouldResolve) { + erasure = tryToResolve(qualifiedName(pkg, nam), context); + } else { + erasure = qualifiedName(pkg, nam); + } + if (ArrayUtils.hasElements(params)) { + //TODO: handle this case + return null; + } else if (ArrayUtils.hasElements(args)) { + Type[] argTypes = new Type[args.length]; + for (int i = 0; i < argTypes.length; i++) { + argTypes[i] = fromSignature(args[i], context); + } + return new Type(erasure, argTypes); + } else { + return new Type(erasure, null); + } + } else if (kind==Signature.ARRAY_TYPE_SIGNATURE) { + Type elementType = fromSignature(Signature.getElementType(typeSig), context); + if (elementType!=null) { + int arrayCount = Signature.getArrayCount(typeSig); + return elementType.asArray(arrayCount); + } + } + return null; + } + + public Type asArray(int arrayCount) { + Assert.isLegal(arrayCount>0); + StringBuilder arrayErasure = new StringBuilder(erasure); + for (int i = 0; i < arrayCount; i++) { + arrayErasure.append("[]"); + } + return new Type(arrayErasure.toString(), params); + } + + private static String qualifiedName(String pkg, String nam) { + if (StringUtil.hasText(pkg)) { + return pkg + "." + nam; + } else { + return nam; + } + } + + private static String tryToResolve(String typeName, IType context) { + try { + String[][] resolved = context.resolveType(typeName); + if (ArrayUtils.hasElements(resolved)) { + String pkg = resolved[0][0]; + String nam = resolved[0][1]; + if (StringUtil.hasText(pkg)) { + return pkg+"."+nam; + } else { + //No . in front of default package + return nam; + } + } + } catch (Exception e) { + Log.log(e); + } + return typeName; + } + + ////////////////////////////////////////////////// + + /** + * Map of some known / common type signatures and their corresponding 'Type' representation. + * Note that springboot metadata 'normalizes' all primitive types to their corresponding box + * types. So we do the same here. + */ + private static final Map TYPE_FROM_SIG = new HashMap(); + static { + sig2type("B", Byte.class); + sig2type("C", Character.class); + sig2type("D", Double.class); + sig2type("F", Float.class); + sig2type("I", Integer.class); + sig2type("J", Long.class); + sig2type("S", Short.class); + sig2type("V", Void.class); + sig2type("Z", Boolean.class); + } + private static void sig2type(String sig, Class cls) { + TYPE_FROM_SIG.put(sig, TypeParser.parse(cls.getName())); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((erasure == null) ? 0 : erasure.hashCode()); + result = prime * result + Arrays.hashCode(params); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Type other = (Type) obj; + if (erasure == null) { + if (other.erasure != null) + return false; + } else if (!erasure.equals(other.erasure)) + return false; + if (!Arrays.equals(params, other.params)) + return false; + return true; + } +} \ No newline at end of file diff --git a/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/types/TypeParser.java b/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/types/TypeParser.java new file mode 100644 index 000000000..d2b2bd744 --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/types/TypeParser.java @@ -0,0 +1,134 @@ +package org.springframework.ide.vscode.boot.properties.metadata.types; + +import java.util.ArrayList; +import java.util.StringTokenizer; + +import org.springframework.ide.vscode.util.StringUtil; + +/** + * Converts types in notation used by spring properties metadata into a 'Structured' form + * + * @author Kris De Volder + */ +public class TypeParser { + + private static final String DELIM = "<>,"; + + /** + * Wrapper around StringTokenizer that manages a single lookahead token. + * So it can implement 'peekToken()' method. + */ + private static class Tokener { + private String lookahead; + private StringTokenizer tokens; + public Tokener(String input) { + this.tokens = new StringTokenizer(input, DELIM, true); + } + + /** + * Fetch next token. Returns null if there are no more tokens. + */ + public String nextToken() { + if (lookahead!=null) { + try { + return lookahead; + } finally { + lookahead = null; + } + } else if (tokens.hasMoreTokens()) { + return tokens.nextToken(); + } + return null; + } + /** + * Fetch the next token without consuming it. + * Returns null if there are no more tokens. + */ + public String peekToken() { + if (lookahead!=null) { + return lookahead; + } else if (tokens.hasMoreTokens()) { + lookahead = tokens.nextToken(); + return lookahead; + } + return null; + } + } + + private Tokener input; + + private TypeParser(String input) { + this.input = new Tokener(input); + } + + public static Type parse(String str) { + if (StringUtil.hasText(str)) { + return new TypeParser(str).parseType(); + } + return null; + } + + private Type parseType() { + String ident = input.nextToken(); + String token = input.peekToken(); + if ("<".equals(token)) { + ArrayList params = parseParams(); + return new Type(ident, params.toArray(new Type[params.size()])); + } else { + return new Type(ident, null); + } + } + + private ArrayList parseParams() { + skip("<"); + try { + return parseParamList(new ArrayList()); + } finally { + skip(">"); + } + } + + private ArrayList parseParamList(ArrayList params) { + //parse params separate by ",' + String tok = input.peekToken(); + if (isIdent(tok)) { + params.add(parseType()); + if (skip(",")) { + return parseParamList(params); + } + } + return params; + } + + /** + * Skip an expected token, or do nothing if the next token is + * something unexpected. + * @return whether token was skipped. + */ + private boolean skip(String expected) { + String t = input.peekToken(); + if (expected.equals(t)) { + input.nextToken(); + return true; + } + return false; + } + + public boolean isIdent(String token) { + return token!=null && !isSeparator(token); + } + + private boolean isSeparator(String token) { + if (token!=null && token.length()==1) { + int len = DELIM.length(); + char c = token.charAt(0); + for (int i = 0; i < len; i++) { + if (DELIM.charAt(i)==c) { + return true; + } + } + } + return false; + } + +} diff --git a/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/types/TypeUtil.java b/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/types/TypeUtil.java new file mode 100644 index 000000000..a66b3ff85 --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/types/TypeUtil.java @@ -0,0 +1,976 @@ +package org.springframework.ide.vscode.boot.properties.metadata.types; + +import static org.springframework.ide.vscode.util.ArrayUtils.firstElement; +import static org.springframework.ide.vscode.util.ArrayUtils.lastElement; + +import java.lang.reflect.Field; +import java.net.InetAddress; +import java.nio.charset.Charset; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.TreeSet; +import java.util.stream.Collectors; + +import javax.inject.Provider; + +import org.springframework.boot.configurationmetadata.Deprecation; +import org.springframework.ide.vscode.boot.properties.metadata.ValueProviderRegistry.ValueProviderStrategy; +import org.springframework.ide.vscode.boot.properties.util.DeprecationUtil; +import org.springframework.ide.vscode.java.Flags; +import org.springframework.ide.vscode.java.IField; +import org.springframework.ide.vscode.java.IJavaElement; +import org.springframework.ide.vscode.java.IJavaProject; +import org.springframework.ide.vscode.java.IMethod; +import org.springframework.ide.vscode.java.IType; +import org.springframework.ide.vscode.util.AlwaysFailingParser; +import org.springframework.ide.vscode.util.ArrayUtils; +import org.springframework.ide.vscode.util.Assert; +import org.springframework.ide.vscode.util.CollectionUtil; +import org.springframework.ide.vscode.util.EnumValueParser; +import org.springframework.ide.vscode.util.HtmlSnippet; +import org.springframework.ide.vscode.util.LazyProvider; +import org.springframework.ide.vscode.util.Log; +import org.springframework.ide.vscode.util.StringUtil; +import org.springframework.ide.vscode.util.ValueParser; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.net.MediaType; + +import reactor.core.publisher.Flux; + +/** + * Utilities to work with types represented as Strings as returned by + * Spring config metadata apis. + * + * @author Kris De Volder + */ +public class TypeUtil { + + private static abstract class RadixableParser implements ValueParser { + protected abstract Object parse(String str, int radix); + + @Override + public Object parse(String str) { + if (str.startsWith("0")) { + if (str.startsWith("0x")||str.startsWith("0X")) { + return parse(str.substring(2), 16); + } else if (str.startsWith("0b") || str.startsWith("0B")) { + return parse(str.substring(2), 2); + } else { + return parse(str, 8); + } + } + return parse(str, 10); + } + + } + + private static final Object OBJECT_TYPE_NAME = Object.class.getName(); + private static final String STRING_TYPE_NAME = String.class.getName(); + private static final String INET_ADDRESS_TYPE_NAME = InetAddress.class.getName(); + private static final String CLASS_TYPE_NAME = Class.class.getName(); + + public enum BeanPropertyNameMode { + HYPHENATED(true,false), //bean property name in hyphenated form. E.g 'some-property-name' + CAMEL_CASE(false,true), //bean property name in camelCase. E.g. 'somePropertyName' + ALIASED(true,true); //use both as aliases of one another. + + private final boolean includesHyphenated; + private final boolean includesCamelCase; + + BeanPropertyNameMode(boolean hyphenated, boolean camelCase) { + this.includesCamelCase = camelCase; + this.includesHyphenated = hyphenated; + } + + public boolean includesHyphenated() { + return includesHyphenated; + } + + public boolean includesCamelCase() { + return includesCamelCase; + } + } + + public enum EnumCaseMode { + LOWER_CASE, //convert enum names to lower case + ORIGNAL, //keep orignal enum name + ALIASED //use both lower-cased and original names as aliases of one another + } + + private IJavaProject javaProject; + + public TypeUtil(IJavaProject jp) { + //Note javaProject is allowed to be null, but only in unit testing context + // (This is so some tests can be run without an explicit jp needing to be created) + this.javaProject = jp; + } + + + private static final Map PRIMITIVE_TYPE_NAMES = new HashMap<>(); + private static final Map PRIMITIVE_TO_BOX_TYPE = new HashMap<>(); + static { + PRIMITIVE_TYPE_NAMES.put("java.lang.Boolean", "boolean"); + + PRIMITIVE_TYPE_NAMES.put("java.lang.Byte", "byte"); + PRIMITIVE_TYPE_NAMES.put("java.lang.Short", "short"); + PRIMITIVE_TYPE_NAMES.put("java.lang.Integer","int"); + PRIMITIVE_TYPE_NAMES.put("java.lang.Long", "long"); + + PRIMITIVE_TYPE_NAMES.put("java.lang.Double", "double"); + PRIMITIVE_TYPE_NAMES.put("java.lang.Float", "float"); + + PRIMITIVE_TYPE_NAMES.put("java.lang.Character", "char"); + + for (Entry e : PRIMITIVE_TYPE_NAMES.entrySet()) { + PRIMITIVE_TO_BOX_TYPE.put(e.getValue(), new Type(e.getKey(), null)); + } + } + + public static final Type INTEGER_TYPE = new Type("java.lang.Integer", null); + + private static final Set ASSIGNABLE_TYPES = new HashSet<>(Arrays.asList( + "java.lang.Boolean", + "java.lang.String", + "java.lang.Short", + "java.lang.Integer", + "java.lang.Long", + "java.lang.Double", + "java.lang.Float", + "java.lang.Character", + "java.lang.Byte", + INET_ADDRESS_TYPE_NAME, + CLASS_TYPE_NAME, + "java.lang.String[]" + )); + + private static final Set ATOMIC_TYPES = new HashSet<>(PRIMITIVE_TYPE_NAMES.keySet()); + static { + ATOMIC_TYPES.add(INET_ADDRESS_TYPE_NAME); + ATOMIC_TYPES.add(STRING_TYPE_NAME); + ATOMIC_TYPES.add(CLASS_TYPE_NAME); + } + + private static final Map TYPE_VALUES = new HashMap<>(); + static { + TYPE_VALUES.put("java.lang.Boolean", new String[] { "true", "false" }); + } + + private static final Map VALUE_PARSERS = new HashMap<>(); + static { + VALUE_PARSERS.put(Byte.class.getName(), new RadixableParser() { + public Object parse(String str, int radix) { + return Byte.parseByte(str, radix); + } + }); + VALUE_PARSERS.put(Integer.class.getName(), new RadixableParser() { + public Object parse(String str, int radix) { + return Integer.parseInt(str, radix); + } + }); + VALUE_PARSERS.put(Long.class.getName(), new RadixableParser() { + public Object parse(String str, int radix) { + return Long.parseLong(str, radix); + } + }); + VALUE_PARSERS.put(Short.class.getName(), new RadixableParser() { + public Object parse(String str, int radix) { + return Short.parseShort(str, radix); + } + }); + VALUE_PARSERS.put(Double.class.getName(), new ValueParser() { + public Object parse(String str) { + return Double.parseDouble(str); + } + }); + VALUE_PARSERS.put(Float.class.getName(), new ValueParser() { + public Object parse(String str) { + return Float.parseFloat(str); + } + }); + VALUE_PARSERS.put(Boolean.class.getName(), new ValueParser() { + public Object parse(String str) { + //The 'more obvious' implementation is too liberal and accepts anything as okay. + //return Boolean.parseBoolean(str); + str = str.toLowerCase(); + if (str.equals("true")) { + return true; + } else if (str.equals("false")) { + return false; + } + throw new IllegalArgumentException("Value should be 'true' or 'false'"); + } + }); + } + + public ValueParser getValueParser(Type type) { + ValueParser simpleParser = VALUE_PARSERS.get(type.getErasure()); + if (simpleParser!=null) { + return simpleParser; + } + Collection enumValues = getAllowedValues(type, EnumCaseMode.ALIASED); + if (enumValues!=null) { + //Note, technically if 'enumValues is empty array' this means something different + // from when it is null. An empty array means a type that has no values, so + // assigning anything to it is an error. + return new EnumValueParser(niceTypeName(type), getBareValues(enumValues)); + } + if (isMap(type)) { + //Trying to parse map types from scalars is not possible. Thus we + // provide a parser that allows throws + return new AlwaysFailingParser(niceTypeName(type)); + } + return null; + } + + private String[] getBareValues(Collection hints) { + if (hints!=null) { + String[] values = new String[hints.size()]; + int i = 0; + for (StsValueHint h : hints) { + values[i++] = h.getValue(); + } + return values; + } + return null; + } + + /** + * @return An array of allowed values for a given type. If an array is returned then + * *only* values in the array are valid and using any other value constitutes an error. + * This may return null if allowedValues list is unknown or the type is not characterizable + * as a simple enumaration of allowed values. + * @param caseMode determines whether Enum values are returned in 'lower case form', 'orignal form', + * or 'aliased' (meaning both forms are returned). + */ + public Collection getAllowedValues(Type enumType, EnumCaseMode caseMode) { + if (enumType!=null) { + try { + String[] values = TYPE_VALUES.get(enumType.getErasure()); + if (values!=null) { + if (caseMode==EnumCaseMode.ALIASED) { + ImmutableSet.Builder aliased = ImmutableSet.builder(); + aliased.add(values); + for (int i = 0; i < values.length; i++) { + aliased.add(values[i].toUpperCase()); + } + return aliased.build().stream().map(StsValueHint::create).collect(Collectors.toList()); + } else { + return Arrays.stream(values).map(StsValueHint::create).collect(Collectors.toList()); + } + } + IType type = findType(enumType.getErasure()); + if (type!=null && type.isEnum()) { + IField[] fields = type.getFields(); + + if (fields!=null) { + ImmutableList.Builder enums = ImmutableList.builder(); + boolean addOriginal = caseMode==EnumCaseMode.ORIGNAL||caseMode==EnumCaseMode.ALIASED; + boolean addLowerCased = caseMode==EnumCaseMode.LOWER_CASE||caseMode==EnumCaseMode.ALIASED; + for (int i = 0; i < fields.length; i++) { + IField f = fields[i]; + Provider jdoc = StsValueHint.javaDocSnippet(f); + if (f.isEnumConstant()) { + String rawName = f.getElementName(); + if (addOriginal) { + enums.add(StsValueHint.create(rawName, f)); + } + if (addLowerCased) { + enums.add(StsValueHint.create(StringUtil.upperCaseToHyphens(rawName), f)); + } + } + } + return enums.build(); + } + } + } catch (Exception e) { + Log.log(e); + } + } + return null; + } + + public String niceTypeName(Type _type) { + StringBuilder buf = new StringBuilder(); + niceTypeName(_type, buf); + return buf.toString(); + } + + public void niceTypeName(Type type, StringBuilder buf) { + if (type==null) { + buf.append("null"); + return; + } + String typeStr = type.getErasure(); + String primTypeName = PRIMITIVE_TYPE_NAMES.get(typeStr); + if (primTypeName!=null) { + buf.append(primTypeName); + } else if (typeStr.startsWith("java.lang.")) { + buf.append(typeStr.substring("java.lang.".length())); + } else if (typeStr.startsWith("java.util.")) { + buf.append(typeStr.substring("java.util.".length())); + } else { + buf.append(typeStr); + } + if (isEnum(type)) { + Collection values = getAllowedValues(type, EnumCaseMode.ORIGNAL); + if (values!=null && !values.isEmpty()) { + buf.append("["); + int i = 0; + for (StsValueHint hint : values) { + if (i>0) { + buf.append(", "); + } + buf.append(hint.getValue()); + i++; + if (i>=4) { + break; + } + } + if (i0) { + buf.append(", "); + } + niceTypeName(params[i], buf); + } + buf.append(">"); + } + } + + + /** + * @return true if it is reasonable to navigate given type with '.' notation. This returns true + * by default except for some specific cases we assume are not 'dotable' such as Primitive types + * and String + */ + public boolean isDotable(Type type) { + String typeName = type.getErasure(); + if (typeName.equals("java.lang.Object")) { + //special case. Treat as 'non dotable' type. This mainly for stuff like logging.level + // declared as Map so it would 'eat' the dots into the key. + // also it makes sense to treat Object as 'non-dotable' since we cannot determine properties + // for such an abstract type (as Object itself has no setters). + return false; + } + return !isAtomic(type); + } + + public static boolean isObject(Type type) { + return type!=null && OBJECT_TYPE_NAME.equals(type.getErasure()); + } + + public static boolean isString(Type type) { + return type!=null && STRING_TYPE_NAME.equals(type.getErasure()); + } + + public boolean isAtomic(Type type) { + if (type!=null) { + String typeName = type.getErasure(); + return ATOMIC_TYPES.contains(typeName) || isEnum(type); + } + return false; + } + + /** + * Check if it is valid to + * use the notation []= in property file + * for properties of this type. + */ + public static boolean isBracketable(Type type) { + //Note array types where once not considered 'Bracketable' + //see: STS-4031 + + //However... + //Seems that in Boot 1.3 arrays are now 'Bracketable' and funcion much equivalnt to list (even including 'autogrowing' them). + //This is actually more logical too. + //So '[' notation in props file can be used for either list or arrays (at leats in recent versions of boot). + return isArray(type) || isList(type); + } + + public static boolean isList(Type type) { + //Note: to be really correct we should use JDT infrastructure to resolve + //type in project classpath instead of using Java reflection. + //However, use reflection here is okay assuming types we care about + //are part of JRE standard libraries. Using eclipse 'type hirearchy' would + //also potentialy be very slow. + if (type!=null) { + String erasure = type.getErasure(); + try { + Class erasureClass = Class.forName(erasure); + return List.class.isAssignableFrom(erasureClass); + } catch (Exception e) { + //type not resolveable assume its not 'array like' + } + } + return false; + } + + /** + * Check if type can be treated / represented as a sequence node in .yml file + */ + public static boolean isSequencable(Type type) { + return isList(type) || isArray(type); + } + + public static boolean isArray(Type type) { + return type!=null && type.getErasure().endsWith("[]"); + } + + public static boolean isMap(Type type) { + //Note: to be really correct we should use JDT infrastructure to resolve + //type in project classpath instead of using Java reflection. + //However, use reflection here is okay assuming types we care about + //are part of JRE standard libraries. Using eclipse 'type hirearchy' would + //also potentialy be very slow. + if (type!=null) { + String erasure = type.getErasure(); + try { + Class erasureClass = Class.forName(erasure); + return Map.class.isAssignableFrom(erasureClass); + } catch (Exception e) { + //type not resolveable + } + } + return false; + } + + /** + * Get domain type for a map or list generic type. + */ + public static Type getDomainType(Type type) { + if (isArray(type)) { + return getArrayDomainType(type); + } else { + return lastElement(type.getParams()); + } + } + + private static Type getArrayDomainType(Type type) { + if (type!=null) { + String fullName = type.getErasure(); + Assert.isLegal(fullName.endsWith("[]")); + String elName = fullName.substring(0, fullName.length()-2); + return normalizePrimitiveType(new Type(elName, null)); + } + return null; + } + + /** + * Convert a type which is a 'primitive' type like 'int', 'long' etc. to its + * corresponding 'Boxed' type. If the type isn't a primitive type then + * just return it unchanged. + */ + private static Type normalizePrimitiveType(Type type) { + if (type!=null) { + String name = type.getErasure(); + Type boxType = PRIMITIVE_TO_BOX_TYPE.get(name); + if (boxType!=null) { + return boxType; + } + } + return type; + } + + public Type getKeyType(Type mapOrArrayType) { + if (isSequencable(mapOrArrayType)) { + return INTEGER_TYPE; + } else { + //assumed to be a map + return firstElement(mapOrArrayType.getParams()); + } + } + + public boolean isAssignableType(Type type) { + return ASSIGNABLE_TYPES.contains(type.getErasure()) + || isEnum(type) + || isAssignableList(type); + } + + private boolean isAssignableList(Type type) { + //TODO: isBracketable means 'isList' right now, but this may not be + // the case in the future. + if (isBracketable(type)) { + Type domainType = getDomainType(type); + return isAtomic(domainType); + } + return false; + } + + public boolean isEnum(Type type) { + try { + IType eclipseType = findType(type.getErasure()); + if (eclipseType!=null) { + return eclipseType.isEnum(); + } + } catch (Exception e) { + Log.log(e); + } + return false; + } + + private IType findType(String typeName) { + try { + if (javaProject!=null) { + return javaProject.findType(typeName); + } + } catch (Exception e) { + Log.log(e); + } + return null; + } + + private IType findType(Type beanType) { + return findType(beanType.getErasure()); + } + + private static final String[] NO_PARAMS = new String[0]; + private static final Map VALUE_HINTERS = new HashMap<>(); + static { + valueHints("java.nio.charset.Charset", new LazyProvider() { + @Override + protected String[] compute() { + Set charsets = Charset.availableCharsets().keySet(); + return charsets.toArray(new String[charsets.size()]); + } + }); + valueHints("java.util.Locale", new LazyProvider() { + @Override + protected String[] compute() { + Locale[] locales = SimpleDateFormat.getAvailableLocales(); + String[] names = new String[locales.length]; + for (int i = 0; i < names.length; i++) { + names[i] = locales[i].toString(); + } + return names; + } + }); + valueHints("org.springframework.util.MimeType", new LazyProvider() { + @Override + protected String[] compute() { + try { + Field f = MediaType.class.getDeclaredField("KNOWN_TYPES"); + f.setAccessible(true); + @SuppressWarnings("unchecked") + Map map = (Map) f.get(null); + TreeSet mediaTypes = new TreeSet<>(); + for (MediaType m : map.keySet()) { + mediaTypes.add(m.toString()); + } + return mediaTypes.toArray(new String[mediaTypes.size()]); + } catch (Exception e) { + Log.log(e); + } + return null; + } + }); +// valueHints("org.springframework.core.io.Resource", new ResourceHintProvider()); + } + + /** + * Determine properties that are setable on object of given type. + *

+ * Note that this may return both null or an empty list, but they mean + * different things. Null means that the properties on the object are not known, + * and therefore reconciling should not check property validity. On the other hand + * returning an empty list means that there are no properties. In this case, + * accessing properties is invalid and reconciler should show an error message + * for any property access. + * + * @return A list of known properties or null if the list of properties is unknown. + */ + public List getProperties(Type type, EnumCaseMode enumMode, BeanPropertyNameMode beanMode) { + if (type==null) { + return null; + } + if (!isDotable(type)) { + //If dot navigation is not valid then really this is just like saying the type has no properties. + return Collections.emptyList(); + } + if (isMap(type)) { + Type keyType = getKeyType(type); + if (keyType!=null) { + Collection keyHints = getAllowedValues(keyType, enumMode); + if (CollectionUtil.hasElements(keyHints)) { + Type valueType = getDomainType(type); + ArrayList properties = new ArrayList<>(keyHints.size()); + for (StsValueHint hint : keyHints) { + String propName = hint.getValue(); + properties.add(new TypedProperty(propName, valueType, hint.getDescriptionProvider(), hint.getDeprecation())); + } + return properties; + } + } + } else { + String typename = type.getErasure(); + IType eclipseType = findType(typename); + + //TODO: handle type parameters. + if (eclipseType!=null) { + List getters = getGetterMethods(eclipseType); + //TODO: getters inherited from super classes? + if (getters!=null && !getters.isEmpty()) { + ArrayList properties = new ArrayList<>(getters.size()); + for (IMethod m : getters) { + Deprecation deprecation = DeprecationUtil.extract(m); + Type propType = null; + try { + propType = Type.fromSignature(m.getReturnType(), eclipseType); + } catch (Exception e) { + Log.log(e); + } + if (beanMode.includesHyphenated()) { + properties.add(new TypedProperty(getterOrSetterNameToProperty(m.getElementName()), propType, deprecation)); + } + if (beanMode.includesCamelCase()) { + properties.add(new TypedProperty(getterOrSetterNameToCamelName(m.getElementName()), propType, deprecation)); + } + } + return properties; + } + } + } + return null; + } + + /** + * Registers a strategy for providing value hints with a given typeName. + */ + public static void valueHints(String typeName, ValueProviderStrategy provider) { + Assert.isLegal(!VALUE_HINTERS.containsKey(typeName)); //Only one value hinter per type is supported at the moment + ATOMIC_TYPES.add(typeName); //valueHints typically implies that the type should be treated as atomic as well. + ASSIGNABLE_TYPES.add(typeName); //valueHints typically implies that the type should be treated as atomic as well. + VALUE_HINTERS.put(typeName, provider); + } + + /** + * Registers a strategy for providing value hints with a given typeName. + */ + public static void valueHints(String typeName, Provider provider) { + valueHints(typeName, new ValueProviderStrategy() { + @Override + public Flux getValues(IJavaProject javaProject, String query) { + String[] values = provider.get(); + if (ArrayUtils.hasElements(values)) { + return Flux.fromArray(values) + .map(StsValueHint::create); + } + return Flux.empty(); + } + }); + } + + private String getterOrSetterNameToProperty(String name) { + String camelName = getterOrSetterNameToCamelName(name); + return StringUtil.camelCaseToHyphens(camelName); + } + + public String getterOrSetterNameToCamelName(String name) { + Assert.isLegal(name.startsWith("set") || name.startsWith("get") || name.startsWith("is")); + int prefixLen = name.startsWith("is") ? 2 : 3; + String camelName = Character.toLowerCase(name.charAt(prefixLen)) + name.substring(prefixLen+1); + return camelName; + } + + private List getGetterMethods(IType eclipseType) { + try { + if (eclipseType!=null && eclipseType.isClass()) { + IMethod[] allMethods = eclipseType.getMethods(); + if (ArrayUtils.hasElements(allMethods)) { + ArrayList getters = new ArrayList<>(); + for (IMethod m : allMethods) { + if (!isStatic(m) && isPublic(m)) { + String mname = m.getElementName(); + if ( + (mname.startsWith("get") && mname.length()>=4) || + (mname.startsWith("is") && mname.length()>=3) + ) { + //Need at least x chars or the property name will be empty. + String sig = m.getSignature(); + int numParams = Signature.getParameterCount(sig); + if (numParams==0) { + getters.add(m); + } + } + } + } + return getters; + } + } + } catch (Exception e) { + Log.log(e); + } + return null; + } + +// private List getSetterMethods(IType eclipseType) { +// try { +// if (eclipseType!=null && eclipseType.isClass()) { +// IMethod[] allMethods = eclipseType.getMethods(); +// if (ArrayUtils.hasElements(allMethods)) { +// ArrayList setters = new ArrayList(); +// for (IMethod m : allMethods) { +// String mname = m.getElementName(); +// if (mname.startsWith("set") && mname.length()>=4) { +// //Need at least 4 chars or the property name will be empty. +// String sig = m.getSignature(); +// int numParams = Signature.getParameterCount(sig); +// if (numParams==1) { +// setters.add(m); +// } +// } +// } +// return setters; +// } +// } +// } catch (Exception e) { +// BootActivator.log(e); +// } +// return null; +// } + + private boolean isStatic(IMethod m) { + try { + return Flags.isStatic(m.getFlags()); + } catch (Exception e) { + //Couldn't determine if it was public or not... let's assume it was NOT + // (will result in potentially more CA completions) + Log.log(e); + return false; + } + } + + private boolean isPublic(IMethod m) { + try { + return m.getDeclaringType().isInterface() + || Flags.isPublic(m.getFlags()); + } catch (Exception e) { + //Couldn't determine if it was public or not... let's assume it WAS + // (will result in potentially more CA completions) + Log.log(e); + return true; + } + } + + public Map getPropertiesMap(Type type, EnumCaseMode enumMode, BeanPropertyNameMode beanMode) { + //TODO: optimize, produce directly as a map instead of + // first creating list and then coverting it. + List list = getProperties(type, enumMode, beanMode); + if (list!=null) { + Map map = new HashMap<>(); + for (TypedProperty p : list) { + map.put(p.getName(), p); + } + return map; + } + return null; + } + + /** + * Maybe ne null in some contexts. In such context functionality will be limited because + * types can not be resolved. + */ + public IJavaProject getJavaProject() { + return javaProject; + } + + public IField getField(Type beanType, String propName) { + IType type = findType(beanType); + return getExactField(type, propName); + } + + protected IField getExactField(IType type, String fieldName) { + IField f = type.getField(StringUtil.hyphensToCamelCase(fieldName, false)); + if (f!=null && f.exists()) { + return f; + } + return null; + } + + public IField getEnumConstant(Type enumType, String propName) { + IType type = findType(enumType); + //1: if propname is already spelled exactly... + IField f = getExactField(type, propName); + if (f!=null) return f; + + //2: most likely enum constant is upper-case form of propname + String fieldName = StringUtil.hyphensToUpperCase(propName); + return getExactField(type, fieldName); + } + + + public IMethod getSetter(Type beanType, String propName) { + try { + String setterName = "set" + StringUtil.hyphensToCamelCase(propName, true); + IType type = findType(beanType); + for (IMethod m : type.getMethods()) { + if (setterName.equals(m.getElementName())) { + return m; + } + } + } catch (Exception e) { + Log.log(e); + } + return null; + } + + public IJavaElement getGetter(Type beanType, String propName) { + String getterName = "get" + StringUtil.hyphensToCamelCase(propName, true); + IType type = findType(beanType); + + IMethod m = type.getMethod(getterName, NO_PARAMS); + if (m.exists()) { + return m; + } + return null; + } + + public static String deprecatedPropertyMessage(String name, String contextType, String replace, String reason) { + StringBuilder msg = new StringBuilder("Property '"+name+"'"); + if (StringUtil.hasText(contextType)) { + msg.append(" of type '"+contextType+"'"); + } + boolean hasReplace = StringUtil.hasText(replace); + boolean hasReason = StringUtil.hasText(reason); + if (!hasReplace && !hasReason) { + msg.append(" is Deprecated!"); + } else { + msg.append(" is Deprecated: "); + if (hasReplace) { + msg.append("Use '"+ replace +"' instead."); + if (hasReason) { + msg.append(" Reason: "); + } + } + if (hasReason) { + msg.append(reason); + } + } + return msg.toString(); + } + + public Collection getHintValues(Type type, String query, EnumCaseMode enumCaseMode) { + if (type!=null) { + Collection allowed = getAllowedValues(type, enumCaseMode); + if (allowed!=null) { + return allowed; + } + ValueProviderStrategy valueHinter = VALUE_HINTERS.get(type.getErasure()); + if (valueHinter!=null) { + return valueHinter.getValuesNow(javaProject, query); + } + } + return null; + } + + /** + * Determine the dimensionality of a collection-like type (i.e. a Map or List). The dimensionality + * is essentialy how many succesive 'indexing' operations need to be applied before reasing the actual elements. + *

+ * For examle: + * List -> 1 + * List> -> 2 + * List>> -> 2 + * Map<*,List> -> 2 + */ + public static int getDimensionality(Type type) { + int dim = 0; + while (isSequencable(type) || isMap(type)) { + dim++; + type = getDomainType(type); + } + return dim; + } + + public static boolean isClass(Type type) { + if (type!=null) { + return CLASS_TYPE_NAME.equals(type.getErasure()); + } + return false; + } + + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // Addapting our interface so it is compatible with YTypeUtil + // + // This allows our types to be used by the more generic stuff from the 'editor.support' plugin. + // + // Note, it may be possible to avoid having these 'adaptor' methods by making YTypeUtil a paramerized + // type. I.e something like "interface YTypeUtil. + // Paramterizations like that tend to propagate fire and wide in the code and make for complicated + // signatures. For now using these bredging methods is simpler if perhaps a bit more error prone. + +// @Override +// public boolean isAtomic(YType type) { +// return isAtomic((Type)type); +// } +// +// @Override +// public boolean isMap(YType type) { +// return isMap((Type)type); +// } +// +// @Override +// public boolean isSequencable(YType type) { +// return isSequencable((Type)type); +// } +// +// @Override +// public YType getDomainType(YType type) { +// return getDomainType((Type)type); +// } +// +// @Override +// public String[] getHintValues(YType type) { +// return getAllowedValues((Type) type, EnumCaseMode.ALIASED); +// } +// +// @SuppressWarnings("unchecked") +// @Override +// public List getProperties(YType type) { +// //Dirty hack, passing this through a raw type to bypass the java type system +// //complaining the List is not compatible with List +// //This dirty and 'illegal' conversion is okay because the list is only used for reading. +// @SuppressWarnings("rawtypes") +// List props = getProperties((Type)type, EnumCaseMode.ALIASED, BeanPropertyNameMode.ALIASED); +// return Collections.unmodifiableList(props); +// } +// +// @SuppressWarnings("unchecked") +// @Override +// public Map getPropertiesMap(YType type) { +// //Dirty hack, see comment in getProperties(YType) +// @SuppressWarnings("rawtypes") +// Map map = getPropertiesMap((Type)type, EnumCaseMode.ALIASED, BeanPropertyNameMode.ALIASED); +// return Collections.unmodifiableMap(map); +// } +// +// @Override +// public String niceTypeName(YType type) { +// return niceTypeName((Type)type); +// } +// +// @Override +// public YType getKeyType(YType type) { +// return getKeyType((Type)type); +// } + +} \ No newline at end of file diff --git a/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/types/TypeUtilProvider.java b/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/types/TypeUtilProvider.java new file mode 100644 index 000000000..f1c2a4bd0 --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/types/TypeUtilProvider.java @@ -0,0 +1,8 @@ +package org.springframework.ide.vscode.boot.properties.metadata.types; + +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; + +@FunctionalInterface +public interface TypeUtilProvider { + TypeUtil getTypeUtil(IDocument doc); +} diff --git a/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/types/TypedProperty.java b/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/types/TypedProperty.java new file mode 100644 index 000000000..69356bda3 --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/types/TypedProperty.java @@ -0,0 +1,97 @@ +package org.springframework.ide.vscode.boot.properties.metadata.types; + +import javax.inject.Provider; + +import org.springframework.boot.configurationmetadata.Deprecation; +import org.springframework.ide.vscode.util.HtmlSnippet; +import org.springframework.ide.vscode.yaml.schema.YTypedProperty; +import org.springframework.ide.vscode.yaml.util.DescriptionProviders; + +/** + * Represents a property on a Type that can be accessed by name. + * + * @author Kris De Volder + */ +public class TypedProperty implements YTypedProperty { + + /** + * The name of the property + */ + private final String name; + + /** + * The type of value associated with the property. + */ + private final Type type; + + /** + * Provides a description for this property. + */ + private final Provider descriptionProvider; + + private final Deprecation deprecation; + + public TypedProperty(String name, Type type, Deprecation deprecation) { + this(name, type, DescriptionProviders.NO_DESCRIPTION, deprecation); + } + + public TypedProperty(String name, Type type, Provider descriptionProvider, Deprecation deprecation) { + this.name = name; + this.type = type; + this.descriptionProvider = descriptionProvider; + this.deprecation = deprecation; + } + + public String getName() { + return name; + } + + public Type getType() { + return type; + } + + @Override + public String toString() { + return name + "::" + type; + } + + @Override + public HtmlSnippet getDescription() { + //TODO: real implementation that somehow gets this from somewhere (i.e. the JavaDoc) + // Note that presently the application.yml and application.properties editor do not actually + // use this description provider but produce hover infos in a different way (so this is only + // used in Schema-based content assist, reconciling and hovering. + //So in that sense putting a good implementation here is kind of pointless right now. + //More refactoring needs to be done to also make use of this. + return descriptionProvider.get(); + } + + public static Type typeOf(TypedProperty typedProperty) { + if (typedProperty!=null) { + return typedProperty.getType(); + } + return null; + } + + public boolean isDeprecated() { + return deprecation!=null; + } + + public String getDeprecationReplacement() { + if (deprecation!=null) { + return deprecation.getReplacement(); + } + return null; + } + + public String getDeprecationReason() { + if (deprecation!=null) { + return deprecation.getReason(); + } + return null; + } + + public Deprecation getDeprecation() { + return deprecation; + } +} diff --git a/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/util/DeprecationUtil.java b/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/util/DeprecationUtil.java new file mode 100644 index 000000000..4f9e336d1 --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/util/DeprecationUtil.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2016 Pivotal, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.boot.properties.util; + +import org.springframework.boot.configurationmetadata.Deprecation; +import org.springframework.ide.vscode.java.IAnnotatable; +import org.springframework.ide.vscode.java.IAnnotation; +import org.springframework.ide.vscode.java.IJavaElement; +import org.springframework.ide.vscode.java.IMemberValuePair; +import org.springframework.ide.vscode.util.Log; + +import com.google.common.collect.ImmutableSet; + +public class DeprecationUtil { + + private static final ImmutableSet DEPRECATED_ANOT_NAMES = ImmutableSet.of( + "org.springframework.boot.context.properties.DeprecatedConfigurationProperty", + "DeprecatedConfigurationProperty", + "java.lang.Deprecated", + "Deprecated" + ); + + /** + * Extract {@link Deprecation} info from annotations on a {@link IJavaElement} + */ + public static Deprecation extract(IJavaElement je) { + if (je instanceof IAnnotatable) { + return extract((IAnnotatable)je); + } + return null; + } + + /** + * Extract {@link Deprecation} info from annotations on a {@link IJavaElement} + */ + private static Deprecation extract(IAnnotatable m) { + try { + for (IAnnotation a : m.getAnnotations()) { + if (DEPRECATED_ANOT_NAMES.contains(a.getElementName())) { + Deprecation d = new Deprecation(); + for (IMemberValuePair pair : a.getMemberValuePairs()) { + String name = pair.getMemberName(); + if (name.equals("reason")) { + d.setReason((String) pair.getValue()); + } else if (name.equals("replacement")) { + d.setReplacement((String) pair.getValue()); + } + } + return d; + } + } + } catch (Exception e) { + Log.log(e); + } + return null; + } + + +} diff --git a/vscode-extensions/commons/commons-java/.classpath b/vscode-extensions/commons/commons-java/.classpath new file mode 100644 index 000000000..fae1a2b37 --- /dev/null +++ b/vscode-extensions/commons/commons-java/.classpath @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vscode-extensions/commons/commons-java/.project b/vscode-extensions/commons/commons-java/.project new file mode 100644 index 000000000..bca620960 --- /dev/null +++ b/vscode-extensions/commons/commons-java/.project @@ -0,0 +1,23 @@ + + + commons-java + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/vscode-extensions/commons/commons-java/.settings/org.eclipse.jdt.core.prefs b/vscode-extensions/commons/commons-java/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..714351aec --- /dev/null +++ b/vscode-extensions/commons/commons-java/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/vscode-extensions/commons/commons-java/.settings/org.eclipse.m2e.core.prefs b/vscode-extensions/commons/commons-java/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 000000000..f897a7f1c --- /dev/null +++ b/vscode-extensions/commons/commons-java/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/vscode-extensions/commons/commons-java/pom.xml b/vscode-extensions/commons/commons-java/pom.xml new file mode 100644 index 000000000..4bac01ea8 --- /dev/null +++ b/vscode-extensions/commons/commons-java/pom.xml @@ -0,0 +1,22 @@ + + 4.0.0 + commons-java + commons-java + Common code related to 'accessing Java knowledge' + + + org.springframework.ide.vscode + commons-parent + 0.0.1-SNAPSHOT + ../pom.xml + + + + + org.springframework.ide.vscode + commons-util + ${project.version} + + + \ No newline at end of file diff --git a/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/types/Signature.java b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/types/Signature.java new file mode 100644 index 000000000..e5959cfc2 --- /dev/null +++ b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/boot/properties/metadata/types/Signature.java @@ -0,0 +1,195 @@ +package org.springframework.ide.vscode.boot.properties.metadata.types; + +public class Signature { + + //These are the bits of JDTs 'Signature' class. Only we copied the method decls + // of stuff we actually use + + //TODO: For performamce reason, JDT probably works with String or even naked char[] instead + // of wrapping these in a proper 'TypeSignature' or 'MethodSignature' object. But probably we should + // do the proper wrapping and abstract out a interface for these types. A 'client' + // using 'Java knowledge' should not have to directly be dealing with the JVM method and + // type signature strings. + + /** + * Kind constant for a class type signature. + * @see #getTypeSignatureKind(String) + * @since 3.0 + */ + public static final int CLASS_TYPE_SIGNATURE = 1; + + /** + * Kind constant for an array type signature. + * @see #getTypeSignatureKind(String) + * @since 3.0 + */ + public static final int ARRAY_TYPE_SIGNATURE = 4; + + /** + * Character constant indicating the start of an unresolved, named type in a + * signature. Value is 'Q'. + */ + public static final char C_UNRESOLVED = 'Q'; + //TODO: unless we use JDT to work with suource-types we probably don't see these? + + /** + * Returns the kind of type signature encoded by the given string. + * + * @param typeSignature the type signature string + * @return the kind of type signature; one of the kind constants: + * {@link #ARRAY_TYPE_SIGNATURE}, {@link #CLASS_TYPE_SIGNATURE}, + * {@link #BASE_TYPE_SIGNATURE}, or {@link #TYPE_VARIABLE_SIGNATURE}, + * or (since 3.1) {@link #WILDCARD_TYPE_SIGNATURE} or {@link #CAPTURE_TYPE_SIGNATURE} + * or (since 3.7) {@link #INTERSECTION_TYPE_SIGNATURE} + * @exception IllegalArgumentException if this is not a type signature + * @since 3.0 + */ + public static int getTypeSignatureKind(String typeSignature) { + return getTypeSignatureKind(typeSignature.toCharArray()); + } + + /** + * Returns the kind of type signature encoded by the given string. + * + * @param typeSignature the type signature string + * @return the kind of type signature; one of the kind constants: + * {@link #ARRAY_TYPE_SIGNATURE}, {@link #CLASS_TYPE_SIGNATURE}, + * {@link #BASE_TYPE_SIGNATURE}, or {@link #TYPE_VARIABLE_SIGNATURE}, + * or (since 3.1) {@link #WILDCARD_TYPE_SIGNATURE} or {@link #CAPTURE_TYPE_SIGNATURE}, + * or (since 3.7) {@link #INTERSECTION_TYPE_SIGNATURE} + * @exception IllegalArgumentException if this is not a type signature + * @since 3.0 + */ + public static int getTypeSignatureKind(char[] typeSignature) { + throw new UnsupportedOperationException("Not yet implemented"); + } + + /** + * Extracts the type erasure signature from the given parameterized type signature. + * Returns the given type signature if it is not parameterized. + * + * @param parameterizedTypeSignature the parameterized type signature + * @return the signature of the type erasure + * @exception IllegalArgumentException if the signature is syntactically + * incorrect + * + * @since 3.1 + */ + public static String getTypeErasure(String parameterizedTypeSignature) { + throw new UnsupportedOperationException("Not yet implemented"); + } + + /** + * Returns package fragment of a type signature. The package fragment separator must be '.' + * and the type fragment separator must be '$'. + *

+ * For example: + *

+	 * 
+	 * getSignatureQualifier("Ljava.util.Map$Entry") -> "java.util"
+	 * 
+	 * 
+ *

+ * + * @param typeSignature the type signature + * @return the package fragment (separators are '.') + * @since 3.1 + */ + public static String getSignatureQualifier(String typeSignature) { + throw new UnsupportedOperationException("Not yet implemented"); + } + + /** + * Returns type fragment of a type signature. The package fragment separator must be '.' + * and the type fragment separator must be '$'. + *

+ * For example: + *

+	 * 
+	 * getSignatureSimpleName("Ljava.util.Map$Entry") -> "Map.Entry"
+	 * 
+	 * 
+ *

+ * + * @param typeSignature the type signature + * @return the type fragment (separators are '.') + * @since 3.1 + */ + public static String getSignatureSimpleName(String typeSignature) { + throw new UnsupportedOperationException("Not yet implemented"); + } + + /** + * Extracts the type parameter signatures from the given method or type signature. + * The method or type signature is expected to be dot-based. + * + * @param methodOrTypeSignature the method or type signature + * @return the list of type parameter signatures + * @exception IllegalArgumentException if the signature is syntactically + * incorrect + * + * @since 3.1 + */ + public static String[] getTypeParameters(String methodOrTypeSignature) throws IllegalArgumentException { + throw new UnsupportedOperationException("Not yet implemented"); + } + + /** + * Extracts the type argument signatures from the given type signature. + * Returns an empty array if the type signature is not a parameterized type signature. + * + * @param parameterizedTypeSignature the parameterized type signature + * @return the signatures of the type arguments + * @exception IllegalArgumentException if the signature is syntactically incorrect + * + * @since 3.1 + */ + public static String[] getTypeArguments(String parameterizedTypeSignature) throws IllegalArgumentException { + throw new UnsupportedOperationException("Not yet implemented"); + } + + /** + * Returns the type signature without any array nesting. + *

+ * For example: + *

+	 * 
+	 * getElementType("[[I") --> "I".
+	 * 
+	 * 
+ *

+ * + * @param typeSignature the type signature + * @return the type signature without arrays + * @exception IllegalArgumentException if the signature is not syntactically + * correct + */ + public static String getElementType(String typeSignature) throws IllegalArgumentException { + throw new UnsupportedOperationException("Not yet implemented"); + } + + /** + * Returns the array count (array nesting depth) of the given type signature. + * + * @param typeSignature the type signature + * @return the array nesting depth, or 0 if not an array + * @exception IllegalArgumentException if the signature is not syntactically + * correct + */ + public static int getArrayCount(String typeSignature) throws IllegalArgumentException { + throw new UnsupportedOperationException("Not yet implemented"); + } + + /** + * Returns the number of parameter types in the given method signature. + * + * @param methodSignature the method signature + * @return the number of parameters + * @exception IllegalArgumentException if the signature is not syntactically + * correct + */ + public static int getParameterCount(String methodSignature) throws IllegalArgumentException { + throw new UnsupportedOperationException("Not yet implemented"); + } + +} diff --git a/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/ClassFileConstants.java b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/ClassFileConstants.java new file mode 100644 index 000000000..78412793e --- /dev/null +++ b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/ClassFileConstants.java @@ -0,0 +1,161 @@ +/******************************************************************************* + * Copyright (c) 2000, 2014 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jesper S Moller - Contributions for + * Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335 + * Bug 406982 - [1.8][compiler] Generation of MethodParameters Attribute in classfile + * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for + * Bug 405104 - [1.8][compiler][codegen] Implement support for serializeable lambdas + *******************************************************************************/ +package org.springframework.ide.vscode.java; + +public interface ClassFileConstants { + + int AccDefault = 0; + /* + * Modifiers + */ + int AccPublic = 0x0001; + int AccPrivate = 0x0002; + int AccProtected = 0x0004; + int AccStatic = 0x0008; + int AccFinal = 0x0010; + int AccSynchronized = 0x0020; + int AccVolatile = 0x0040; + int AccBridge = 0x0040; + int AccTransient = 0x0080; + int AccVarargs = 0x0080; + int AccNative = 0x0100; + int AccInterface = 0x0200; + int AccAbstract = 0x0400; + int AccStrictfp = 0x0800; + int AccSynthetic = 0x1000; + int AccAnnotation = 0x2000; + int AccEnum = 0x4000; + + /** + * From classfile version 52 (compliance 1.8 up), meaning that a formal parameter is mandated + * by a language specification, so all compilers for the language must emit it. + */ + int AccMandated = 0x8000; + + + /** + * Other VM flags. + */ + int AccSuper = 0x0020; + +// /** +// * Extra flags for types and members attributes (not from the JVMS, should have been defined in ExtraCompilerModifiers). +// */ +// int AccAnnotationDefault = ASTNode.Bit18; // indicate presence of an attribute "DefaultValue" (annotation method) +// int AccDeprecated = ASTNode.Bit21; // indicate presence of an attribute "Deprecated" + + int Utf8Tag = 1; + int IntegerTag = 3; + int FloatTag = 4; + int LongTag = 5; + int DoubleTag = 6; + int ClassTag = 7; + int StringTag = 8; + int FieldRefTag = 9; + int MethodRefTag = 10; + int InterfaceMethodRefTag = 11; + int NameAndTypeTag = 12; + int MethodHandleTag = 15; + int MethodTypeTag = 16; + int InvokeDynamicTag = 18; + + int ConstantMethodRefFixedSize = 5; + int ConstantClassFixedSize = 3; + int ConstantDoubleFixedSize = 9; + int ConstantFieldRefFixedSize = 5; + int ConstantFloatFixedSize = 5; + int ConstantIntegerFixedSize = 5; + int ConstantInterfaceMethodRefFixedSize = 5; + int ConstantLongFixedSize = 9; + int ConstantStringFixedSize = 3; + int ConstantUtf8FixedSize = 3; + int ConstantNameAndTypeFixedSize = 5; + int ConstantMethodHandleFixedSize = 4; + int ConstantMethodTypeFixedSize = 3; + int ConstantInvokeDynamicFixedSize = 5; + + // JVMS 4.4.8 + int MethodHandleRefKindGetField = 1; + int MethodHandleRefKindGetStatic = 2; + int MethodHandleRefKindPutField = 3; + int MethodHandleRefKindPutStatic = 4; + int MethodHandleRefKindInvokeVirtual = 5; + int MethodHandleRefKindInvokeStatic = 6; + int MethodHandleRefKindInvokeSpecial = 7; + int MethodHandleRefKindNewInvokeSpecial = 8; + int MethodHandleRefKindInvokeInterface = 9; + + int MAJOR_VERSION_1_1 = 45; + int MAJOR_VERSION_1_2 = 46; + int MAJOR_VERSION_1_3 = 47; + int MAJOR_VERSION_1_4 = 48; + int MAJOR_VERSION_1_5 = 49; + int MAJOR_VERSION_1_6 = 50; + int MAJOR_VERSION_1_7 = 51; + int MAJOR_VERSION_1_8 = 52; + int MAJOR_VERSION_1_9 = 53; // This might change + + int MINOR_VERSION_0 = 0; + int MINOR_VERSION_1 = 1; + int MINOR_VERSION_2 = 2; + int MINOR_VERSION_3 = 3; + int MINOR_VERSION_4 = 4; + + // JDK 1.1 -> 1.9, comparable value allowing to check both major/minor version at once 1.4.1 > 1.4.0 + // 16 unsigned bits for major, then 16 bits for minor + long JDK1_1 = ((long)ClassFileConstants.MAJOR_VERSION_1_1 << 16) + ClassFileConstants.MINOR_VERSION_3; // 1.1. is 45.3 + long JDK1_2 = ((long)ClassFileConstants.MAJOR_VERSION_1_2 << 16) + ClassFileConstants.MINOR_VERSION_0; + long JDK1_3 = ((long)ClassFileConstants.MAJOR_VERSION_1_3 << 16) + ClassFileConstants.MINOR_VERSION_0; + long JDK1_4 = ((long)ClassFileConstants.MAJOR_VERSION_1_4 << 16) + ClassFileConstants.MINOR_VERSION_0; + long JDK1_5 = ((long)ClassFileConstants.MAJOR_VERSION_1_5 << 16) + ClassFileConstants.MINOR_VERSION_0; + long JDK1_6 = ((long)ClassFileConstants.MAJOR_VERSION_1_6 << 16) + ClassFileConstants.MINOR_VERSION_0; + long JDK1_7 = ((long)ClassFileConstants.MAJOR_VERSION_1_7 << 16) + ClassFileConstants.MINOR_VERSION_0; + long JDK1_8 = ((long)ClassFileConstants.MAJOR_VERSION_1_8 << 16) + ClassFileConstants.MINOR_VERSION_0; + long JDK1_9 = ((long)ClassFileConstants.MAJOR_VERSION_1_9 << 16) + ClassFileConstants.MINOR_VERSION_0; + + /* + * cldc1.1 is 45.3, but we modify it to be different from JDK1_1. + * In the code gen, we will generate the same target value as JDK1_1 + */ + long CLDC_1_1 = ((long)ClassFileConstants.MAJOR_VERSION_1_1 << 16) + ClassFileConstants.MINOR_VERSION_4; + + // jdk level used to denote future releases: optional behavior is not enabled for now, but may become so. In order to enable these, + // search for references to this constant, and change it to one of the official JDT constants above. + long JDK_DEFERRED = Long.MAX_VALUE; + + int INT_ARRAY = 10; + int BYTE_ARRAY = 8; + int BOOLEAN_ARRAY = 4; + int SHORT_ARRAY = 9; + int CHAR_ARRAY = 5; + int LONG_ARRAY = 11; + int FLOAT_ARRAY = 6; + int DOUBLE_ARRAY = 7; + + // Debug attributes + int ATTR_SOURCE = 0x1; // SourceFileAttribute + int ATTR_LINES = 0x2; // LineNumberAttribute + int ATTR_VARS = 0x4; // LocalVariableTableAttribute + int ATTR_STACK_MAP_TABLE = 0x8; // Stack map table attribute + int ATTR_STACK_MAP = 0x10; // Stack map attribute: cldc + int ATTR_TYPE_ANNOTATION = 0x20; // type annotation attribute (jsr 308) + int ATTR_METHOD_PARAMETERS = 0x40; // method parameters attribute (jep 118) + + // See java.lang.invoke.LambdaMetafactory constants - option bitflags when calling altMetaFactory() + int FLAG_SERIALIZABLE = 0x01; + int FLAG_MARKERS = 0x02; + int FLAG_BRIDGES = 0x04; +} diff --git a/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/Flags.java b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/Flags.java new file mode 100644 index 000000000..486e59f3e --- /dev/null +++ b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/Flags.java @@ -0,0 +1,473 @@ +/******************************************************************************* + * Copyright (c) 2000, 2013 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * IBM Corporation - added constant AccDefault + * IBM Corporation - added constants AccBridge and AccVarargs for J2SE 1.5 + *******************************************************************************/ +package org.springframework.ide.vscode.java; + +/** + * Utility class for decoding modifier flags in Java elements. + *

+ * This class provides static methods only. + *

+ *

+ * Note that the numeric values of these flags match the ones for class files + * as described in the Java Virtual Machine Specification (except for + * {@link #AccDeprecated}, {@link #AccAnnotationDefault}, and {@link #AccDefaultMethod}). + *

+ *

+ * The AST class Modifier provides + * similar functionality as this class, only in the + * org.eclipse.jdt.core.dom package. + *

+ * + * @see IMember#getFlags() + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public final class Flags { + + /** + * Constant representing the absence of any flag. + * @since 3.0 + */ + public static final int AccDefault = ClassFileConstants.AccDefault; + /** + * Public access flag. See The Java Virtual Machine Specification for more details. + * @since 2.0 + */ + public static final int AccPublic = ClassFileConstants.AccPublic; + /** + * Private access flag. See The Java Virtual Machine Specification for more details. + * @since 2.0 + */ + public static final int AccPrivate = ClassFileConstants.AccPrivate; + /** + * Protected access flag. See The Java Virtual Machine Specification for more details. + * @since 2.0 + */ + public static final int AccProtected = ClassFileConstants.AccProtected; + /** + * Static access flag. See The Java Virtual Machine Specification for more details. + * @since 2.0 + */ + public static final int AccStatic = ClassFileConstants.AccStatic; + /** + * Final access flag. See The Java Virtual Machine Specification for more details. + * @since 2.0 + */ + public static final int AccFinal = ClassFileConstants.AccFinal; + /** + * Synchronized access flag. See The Java Virtual Machine Specification for more details. + * @since 2.0 + */ + public static final int AccSynchronized = ClassFileConstants.AccSynchronized; + /** + * Volatile property flag. See The Java Virtual Machine Specification for more details. + * @since 2.0 + */ + public static final int AccVolatile = ClassFileConstants.AccVolatile; + /** + * Transient property flag. See The Java Virtual Machine Specification for more details. + * @since 2.0 + */ + public static final int AccTransient = ClassFileConstants.AccTransient; + /** + * Native property flag. See The Java Virtual Machine Specification for more details. + * @since 2.0 + */ + public static final int AccNative = ClassFileConstants.AccNative; + /** + * Interface property flag. See The Java Virtual Machine Specification for more details. + * @since 2.0 + */ + public static final int AccInterface = ClassFileConstants.AccInterface; + /** + * Abstract property flag. See The Java Virtual Machine Specification for more details. + * @since 2.0 + */ + public static final int AccAbstract = ClassFileConstants.AccAbstract; + /** + * Strictfp property flag. See The Java Virtual Machine Specification for more details. + * @since 2.0 + */ + public static final int AccStrictfp = ClassFileConstants.AccStrictfp; + /** + * Super property flag. See The Java Virtual Machine Specification for more details. + * @since 2.0 + */ + public static final int AccSuper = ClassFileConstants.AccSuper; + /** + * Synthetic property flag. See The Java Virtual Machine Specification for more details. + * @since 2.0 + */ + public static final int AccSynthetic = ClassFileConstants.AccSynthetic; + +// /** +// * Deprecated property flag. +// *

+// * Note that this flag's value is internal and is not defined in the +// * Virtual Machine specification. +// *

+// * @since 2.0 +// */ +// public static final int AccDeprecated = ClassFileConstants.AccDeprecated; + + /** + * Bridge method property flag (added in J2SE 1.5). Used to flag a compiler-generated + * bridge methods. + * See The Java Virtual Machine Specification for more details. + * @since 3.0 + */ + public static final int AccBridge = ClassFileConstants.AccBridge; + + /** + * Varargs method property flag (added in J2SE 1.5). + * Used to flag variable arity method declarations. + * See The Java Virtual Machine Specification for more details. + * @since 3.0 + */ + public static final int AccVarargs = ClassFileConstants.AccVarargs; + + /** + * Enum property flag (added in J2SE 1.5). + * See The Java Virtual Machine Specification for more details. + * @since 3.0 + */ + public static final int AccEnum = ClassFileConstants.AccEnum; + + /** + * Annotation property flag (added in J2SE 1.5). + * See The Java Virtual Machine Specification for more details. + * @since 3.0 + */ + public static final int AccAnnotation = ClassFileConstants.AccAnnotation; + +// /** +// * Default method property flag. +// *

+// * Note that this flag's value is internal and is not defined in the +// * Virtual Machine specification. +// *

+// * @since 3.10 +// */ +// public static final int AccDefaultMethod = ExtraCompilerModifiers.AccDefaultMethod; +// +// /** +// * Annotation method default property flag. +// * Used to flag annotation type methods that declare a default value. +// *

+// * Note that this flag's value is internal and is not defined in the +// * Virtual Machine specification. +// *

+// * @since 3.10 +// */ +// public static final int AccAnnotationDefault = ClassFileConstants.AccAnnotationDefault; + + /** + * Not instantiable. + */ + private Flags() { + // Not instantiable + } + /** + * Returns whether the given integer includes the abstract modifier. + * + * @param flags the flags + * @return true if the abstract modifier is included + */ + public static boolean isAbstract(int flags) { + return (flags & AccAbstract) != 0; + } +// /** +// * Returns whether the given integer includes the indication that the +// * element is deprecated (@deprecated tag in Javadoc comment). +// * +// * @param flags the flags +// * @return true if the element is marked as deprecated +// */ +// public static boolean isDeprecated(int flags) { +// return (flags & AccDeprecated) != 0; +// } + + /** + * Returns whether the given integer includes the final modifier. + * + * @param flags the flags + * @return true if the final modifier is included + */ + public static boolean isFinal(int flags) { + return (flags & AccFinal) != 0; + } + /** + * Returns whether the given integer includes the interface modifier. + * + * @param flags the flags + * @return true if the interface modifier is included + * @since 2.0 + */ + public static boolean isInterface(int flags) { + return (flags & AccInterface) != 0; + } + /** + * Returns whether the given integer includes the native modifier. + * + * @param flags the flags + * @return true if the native modifier is included + */ + public static boolean isNative(int flags) { + return (flags & AccNative) != 0; + } + /** + * Returns whether the given integer does not include one of the + * public, private, or protected flags. + * + * @param flags the flags + * @return true if no visibility flag is set + * @since 3.2 + */ + public static boolean isPackageDefault(int flags) { + return (flags & (AccPublic | AccPrivate | AccProtected)) == 0; + } + /** + * Returns whether the given integer includes the private modifier. + * + * @param flags the flags + * @return true if the private modifier is included + */ + public static boolean isPrivate(int flags) { + return (flags & AccPrivate) != 0; + } + /** + * Returns whether the given integer includes the protected modifier. + * + * @param flags the flags + * @return true if the protected modifier is included + */ + public static boolean isProtected(int flags) { + return (flags & AccProtected) != 0; + } + /** + * Returns whether the given integer includes the public modifier. + * + * @param flags the flags + * @return true if the public modifier is included + */ + public static boolean isPublic(int flags) { + return (flags & AccPublic) != 0; + } + /** + * Returns whether the given integer includes the static modifier. + * + * @param flags the flags + * @return true if the static modifier is included + */ + public static boolean isStatic(int flags) { + return (flags & AccStatic) != 0; + } + /** + * Returns whether the given integer includes the super modifier. + * + * @param flags the flags + * @return true if the super modifier is included + * @since 3.2 + */ + public static boolean isSuper(int flags) { + return (flags & AccSuper) != 0; + } + /** + * Returns whether the given integer includes the strictfp modifier. + * + * @param flags the flags + * @return true if the strictfp modifier is included + */ + public static boolean isStrictfp(int flags) { + return (flags & AccStrictfp) != 0; + } + /** + * Returns whether the given integer includes the synchronized modifier. + * + * @param flags the flags + * @return true if the synchronized modifier is included + */ + public static boolean isSynchronized(int flags) { + return (flags & AccSynchronized) != 0; + } + /** + * Returns whether the given integer includes the indication that the + * element is synthetic. + * + * @param flags the flags + * @return true if the element is marked synthetic + */ + public static boolean isSynthetic(int flags) { + return (flags & AccSynthetic) != 0; + } + /** + * Returns whether the given integer includes the transient modifier. + * + * @param flags the flags + * @return true if the transient modifier is included + */ + public static boolean isTransient(int flags) { + return (flags & AccTransient) != 0; + } + /** + * Returns whether the given integer includes the volatile modifier. + * + * @param flags the flags + * @return true if the volatile modifier is included + */ + public static boolean isVolatile(int flags) { + return (flags & AccVolatile) != 0; + } + + /** + * Returns whether the given integer has the AccBridge + * bit set. + * + * @param flags the flags + * @return true if the AccBridge flag is included + * @see #AccBridge + * @since 3.0 + */ + public static boolean isBridge(int flags) { + return (flags & AccBridge) != 0; + } + + /** + * Returns whether the given integer has the AccVarargs + * bit set. + * + * @param flags the flags + * @return true if the AccVarargs flag is included + * @see #AccVarargs + * @since 3.0 + */ + public static boolean isVarargs(int flags) { + return (flags & AccVarargs) != 0; + } + + /** + * Returns whether the given integer has the AccEnum + * bit set. + * + * @param flags the flags + * @return true if the AccEnum flag is included + * @see #AccEnum + * @since 3.0 + */ + public static boolean isEnum(int flags) { + return (flags & AccEnum) != 0; + } + + /** + * Returns whether the given integer has the AccAnnotation + * bit set. + * + * @param flags the flags + * @return true if the AccAnnotation flag is included + * @see #AccAnnotation + * @since 3.0 + */ + public static boolean isAnnotation(int flags) { + return (flags & AccAnnotation) != 0; + } + +// /** +// * Returns whether the given integer has the AccDefaultMethod +// * bit set. Note that this flag represents the usage of the 'default' keyword +// * on a method and should not be confused with the 'package' access visibility (which used to be called 'default access'). +// * +// * @return true if the AccDefaultMethod flag is included +// * @see #AccDefaultMethod +// * @since 3.10 +// */ +// public static boolean isDefaultMethod(int flags) { +// return (flags & AccDefaultMethod) != 0; +// } + +// /** +// * Returns whether the given integer has the AccAnnnotationDefault +// * bit set. +// * +// * @return true if the AccAnnotationDefault flag is included +// * @see #AccAnnotationDefault +// * @since 3.10 +// */ +// public static boolean isAnnnotationDefault(int flags) { +// return (flags & AccAnnotationDefault) != 0; +// } + + /** + * Returns a standard string describing the given modifier flags. + * Only modifier flags are included in the output; deprecated, + * synthetic, bridge, etc. flags are ignored. + *

+ * The flags are output in the following order: + *

 public protected private
+	 * abstract default static final synchronized native strictfp transient volatile
+ *

+ * This order is consistent with the recommendations in JLS8 ("*Modifier:" rules in chapters 8 and 9). + *

+ *

+ * Note that the flags of a method can include the AccVarargs flag that has no standard description. Since the AccVarargs flag has the same value as + * the AccTransient flag (valid for fields only), attempting to get the description of method modifiers with the AccVarargs flag set would result in an + * unexpected description. Clients should ensure that the AccVarargs is not included in the flags of a method as follows: + *

+	 * IMethod method = ...
+	 * int flags = method.getFlags() & ~Flags.AccVarargs;
+	 * return Flags.toString(flags);
+	 * 
+ *

+ *

+ * Examples results: + *

+	 *	  "public static final"
+	 *	  "private native"
+	 * 
+ *

+ * + * @param flags the flags + * @return the standard string representation of the given flags + */ + public static String toString(int flags) { + StringBuffer sb = new StringBuffer(); + + if (isPublic(flags)) + sb.append("public "); //$NON-NLS-1$ + if (isProtected(flags)) + sb.append("protected "); //$NON-NLS-1$ + if (isPrivate(flags)) + sb.append("private "); //$NON-NLS-1$ + if (isAbstract(flags)) + sb.append("abstract "); //$NON-NLS-1$ +// if (isDefaultMethod(flags)) +// sb.append("default "); //$NON-NLS-1$ + if (isStatic(flags)) + sb.append("static "); //$NON-NLS-1$ + if (isFinal(flags)) + sb.append("final "); //$NON-NLS-1$ + if (isSynchronized(flags)) + sb.append("synchronized "); //$NON-NLS-1$ + if (isNative(flags)) + sb.append("native "); //$NON-NLS-1$ + if (isStrictfp(flags)) + sb.append("strictfp "); //$NON-NLS-1$ + if (isTransient(flags)) + sb.append("transient "); //$NON-NLS-1$ + if (isVolatile(flags)) + sb.append("volatile "); //$NON-NLS-1$ + int len = sb.length(); + if (len == 0) + return ""; //$NON-NLS-1$ + sb.setLength(len - 1); + return sb.toString(); + } +} diff --git a/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/IAnnotatable.java b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/IAnnotatable.java new file mode 100644 index 000000000..23d21283d --- /dev/null +++ b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/IAnnotatable.java @@ -0,0 +1,7 @@ +package org.springframework.ide.vscode.java; + +public interface IAnnotatable extends IJavaElement { + + IAnnotation[] getAnnotations(); + +} diff --git a/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/IAnnotation.java b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/IAnnotation.java new file mode 100644 index 000000000..60bdbb772 --- /dev/null +++ b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/IAnnotation.java @@ -0,0 +1,15 @@ +package org.springframework.ide.vscode.java; + +public interface IAnnotation extends IJavaElement { + + /** + * Returns the member-value pairs of this annotation. Returns an empty + * array if this annotation is a marker annotation. Returns a size-1 array if this + * annotation is a single member annotation. In this case, the member + * name is always "value". + * + * @return the member-value pairs of this annotation + */ + IMemberValuePair[] getMemberValuePairs(); + +} diff --git a/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/IField.java b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/IField.java new file mode 100644 index 000000000..84b6110f3 --- /dev/null +++ b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/IField.java @@ -0,0 +1,5 @@ +package org.springframework.ide.vscode.java; + +public interface IField extends IMember { + boolean isEnumConstant(); +} diff --git a/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/IJavaElement.java b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/IJavaElement.java new file mode 100644 index 000000000..04aec7bf2 --- /dev/null +++ b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/IJavaElement.java @@ -0,0 +1,9 @@ +package org.springframework.ide.vscode.java; + +import org.springframework.ide.vscode.util.HtmlSnippet; + +public interface IJavaElement { + String getElementName(); + HtmlSnippet getJavaDoc(); + boolean exists(); +} diff --git a/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/IJavaProject.java b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/IJavaProject.java new file mode 100644 index 000000000..fd02c0b71 --- /dev/null +++ b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/IJavaProject.java @@ -0,0 +1,8 @@ +package org.springframework.ide.vscode.java; + +import java.nio.file.Path; + +public interface IJavaProject extends IJavaElement { + IType findType(String fqName); + Path getPath(); +} diff --git a/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/IMember.java b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/IMember.java new file mode 100644 index 000000000..dd0860515 --- /dev/null +++ b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/IMember.java @@ -0,0 +1,35 @@ +package org.springframework.ide.vscode.java; + +public interface IMember extends IJavaElement, IAnnotatable { + + /** + * Returns the modifier flags for this member. The flags can be examined using class + * Flags. + *

+ * For {@linkplain #isBinary() binary} members, flags from the class file + * as well as derived flags {@link Flags#AccAnnotationDefault} and {@link Flags#AccDefaultMethod} are included. + *

+ *

+ * For source members, only flags as indicated in the source are returned. Thus if an interface + * defines a method void myMethod();, the flags don't include the + * 'public' flag. Source flags include {@link Flags#AccAnnotationDefault} as well. + *

+ * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @return the modifier flags for this member + * @see Flags + */ + int getFlags(); + + /** + * Returns the type in which this member is declared, or null + * if this member is not declared in a type (for example, a top-level type). + * This is a handle-only method. + * + * @return the type in which this member is declared, or null + * if this member is not declared in a type (for example, a top-level type) + */ + IType getDeclaringType(); + +} diff --git a/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/IMemberValuePair.java b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/IMemberValuePair.java new file mode 100644 index 000000000..fdd7b4030 --- /dev/null +++ b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/IMemberValuePair.java @@ -0,0 +1,28 @@ +package org.springframework.ide.vscode.java; + +public interface IMemberValuePair { + + /** + * Returns the member's name of this member-value pair. + * + * @return the member's name of this member-value pair. + */ + String getMemberName(); + + /** + * Returns the value of this member-value pair. The type of this value + * is function of this member-value pair's {@link #getValueKind() value kind}. It is an + * instance of {@link Object}[] if the value is an array. + *

+ * If the value kind is {@link #K_UNKNOWN} and the value is not an array, then the + * value is null. + * If the value kind is {@link #K_UNKNOWN} and the value is an array, then the + * value is an array containing {@link Object}s and/or nulls for + * unknown elements. + * See {@link #K_UNKNOWN} for more details. + *

+ * @return the value of this member-value pair. + */ + Object getValue(); + +} diff --git a/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/IMethod.java b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/IMethod.java new file mode 100644 index 000000000..758898feb --- /dev/null +++ b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/IMethod.java @@ -0,0 +1,49 @@ +package org.springframework.ide.vscode.java; + +import org.springframework.ide.vscode.boot.properties.metadata.types.Signature; + +public interface IMethod extends IMember { + + /** + * Returns the type signature of the return value of this method. + * For constructors, this returns the signature for void. + *

+ * For example, a source method declared as public String getName() + * would return "QString;". + *

+ *

+ * The type signature may be either unresolved (for source types) + * or resolved (for binary types), and either basic (for basic types) + * or rich (for parameterized types). See {@link Signature} for details. + *

+ * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @return the type signature of the return value of this method, void for constructors + * @see Signature + */ + String getReturnType(); + + /** + * Returns the signature of this method. This includes the signatures for the + * parameter types and return type, but does not include the method name, + * exception types, or type parameters. + *

+ * For example, a source method declared as public void foo(String text, int length) + * would return "(QString;I)V". + *

+ *

+ * The type signatures embedded in the method signature may be either unresolved + * (for source types) or resolved (for binary types), and either basic (for + * basic types) or rich (for parameterized types). See {@link Signature} for + * details. + *

+ * + * @return the signature of this method + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @see Signature + */ + String getSignature(); + +} diff --git a/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/IType.java b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/IType.java new file mode 100644 index 000000000..a1c821262 --- /dev/null +++ b/vscode-extensions/commons/commons-java/src/main/java/org/springframework/ide/vscode/java/IType.java @@ -0,0 +1,120 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * IBM Corporation - added J2SE 1.5 support + * Stephan Herrmann - Contribution for + * Bug 463533 - Signature.getSignatureSimpleName() returns different results for resolved and unresolved extends + *******************************************************************************/ +package org.springframework.ide.vscode.java; + +/** + * Replaces eclipse JDT IType. + */ +public interface IType extends IMember { + + boolean isClass(); + boolean isEnum(); + boolean isInterface(); + + /** + * Returns the fully qualified name of this type, + * including qualification for any containing types and packages. + * This is the name of the package, followed by '.', + * followed by the type-qualified name. + *

+ * Note: The enclosing type separator used in the type-qualified + * name is '$', not '.'. + *

+ * This method is fully equivalent to getFullyQualifiedName('$'). + * This is a handle-only method. + * + * @see IType#getTypeQualifiedName() + * @see IType#getFullyQualifiedName(char) + * @return the fully qualified name of this type + */ + String getFullyQualifiedName(); + + /** + * Returns the field with the specified name + * in this type (for example, "bar"). + * This is a handle-only method. The field may or may not exist. + * + * @param name the given name + * @return the field with the specified name in this type + */ + IField getField(String name); + + /** + * Returns the fields declared by this type in the order in which they appear + * in the source or class file. For binary types, this includes synthetic fields. + * + * @return the fields declared by this type + */ + IField[] getFields(); + + /** + * Returns the method with the specified name and parameter types + * in this type (for example, "foo", {"I", "QString;"}). + * To get the handle for a constructor, the name specified must be the + * simple name of the enclosing type. + * This is a handle-only method. The method may or may not be present. + *

+ * The type signatures may be either unresolved (for source types) + * or resolved (for binary types), and either basic (for basic types) + * or rich (for parameterized types). See {@link Signature} for details. + * Note that the parameter type signatures for binary methods are expected + * to be dot-based. + *

+ * + * @param name the given name + * @param parameterTypeSignatures the given parameter types + * @return the method with the specified name and parameter types in this type + */ + IMethod getMethod(String name, String[] parameterTypeSignatures); + + /** + * Returns the methods and constructors declared by this type. + * For binary types, this may include the special <clinit> method + * and synthetic methods. + *

+ * The results are listed in the order in which they appear in the source or class file. + *

+ * + * @return the methods and constructors declared by this type + */ + IMethod[] getMethods(); + + /** + * Resolves the given type name within the context of this type (depending on the type hierarchy + * and its imports). + *

+ * Multiple answers might be found in case there are ambiguous matches. + *

+ *

+ * Each matching type name is decomposed as an array of two strings, the first denoting the package + * name (dot-separated) and the second being the type name. The package name is empty if it is the + * default package. The type name is the type qualified name using a '.' enclosing type separator. + *

+ *

+ * Returns null if unable to find any matching type. + *

+ *

+ * For example, resolution of "Object" would typically return + * {{"java.lang", "Object"}}. Another resolution that returns + * {{"", "X.Inner"}} represents the inner type Inner defined in type X in the + * default package. + *

+ * + * @param typeName the given type name + * @return the resolved type names or null if unable to find any matching type + * @see #getTypeQualifiedName(char) + */ + String[][] resolveType(String typeName); + +} diff --git a/vscode-extensions/commons/commons-language-server/pom.xml b/vscode-extensions/commons/commons-language-server/pom.xml index 0376556b6..2c47c1de6 100644 --- a/vscode-extensions/commons/commons-language-server/pom.xml +++ b/vscode-extensions/commons/commons-language-server/pom.xml @@ -12,30 +12,16 @@ ../pom.xml - - - - oss-sonatype - oss-sonatype - https://oss.sonatype.org/content/repositories/snapshots/ - - true - - - - org.springframework.ide.vscode commons-util ${project.version} - org.springframework.ide.vscode - language-server-test-harness + commons-java ${project.version} - test @@ -79,5 +65,15 @@ jackson-datatype-jdk8 ${jackson-2-version} + + + + org.springframework.ide.vscode + language-server-test-harness + ${project.version} + test + + + diff --git a/vscode-extensions/commons/commons-language-server/pom.xml~ b/vscode-extensions/commons/commons-language-server/pom.xml~ deleted file mode 100644 index 9d6330f2c..000000000 --- a/vscode-extensions/commons/commons-language-server/pom.xml~ +++ /dev/null @@ -1,83 +0,0 @@ - - 4.0.0 - language-server-commons - language-server-commons - Shared utilities for building vscode language servers in Java - - - org.springframework.ide.vscode - commons-parent - 0.0.1-SNAPSHOT - ../pom.xml - - - - - - oss-sonatype - oss-sonatype - https://oss.sonatype.org/content/repositories/snapshots/ - - true - - - - - - - org.springframework.ide.vscode - commons-util - ${project.version} - - - - org.springframework.ide.vscode - language-server-test-harness - ${project.version} - test - - - - io.typefox.lsapi - io.typefox.lsapi - ${lsapi-version} - - - io.typefox.lsapi - io.typefox.lsapi.services - ${lsapi-version} - - - io.typefox.lsapi - io.typefox.lsapi.annotations - ${lsapi-version} - - - - com.fasterxml.jackson.core - jackson-core - ${jackson-2-version} - - - com.fasterxml.jackson.core - jackson-annotations - ${jackson-2-version} - - - com.fasterxml.jackson.core - jackson-databind - ${jackson-2-version} - - - com.fasterxml.jackson.datatype - jackson-datatype-jsr310 - ${jackson-2-version} - - - com.fasterxml.jackson.datatype - jackson-datatype-jdk8 - ${jackson-2-version} - - - \ No newline at end of file diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/completion/DocumentEdits.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/DocumentEdits.java similarity index 96% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/completion/DocumentEdits.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/DocumentEdits.java index adb277986..79540717e 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/completion/DocumentEdits.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/DocumentEdits.java @@ -8,15 +8,15 @@ * Contributors: * Pivotal, Inc. - initial API and implementation *******************************************************************************/ -package org.springframework.ide.vscode.commons.completion; +package org.springframework.ide.vscode.commons.languageserver.completion; import java.util.ArrayList; +import org.springframework.ide.vscode.commons.languageserver.util.BadLocationException; +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; +import org.springframework.ide.vscode.commons.languageserver.util.IRegion; +import org.springframework.ide.vscode.commons.languageserver.util.Region; import org.springframework.ide.vscode.util.Assert; -import org.springframework.ide.vscode.util.BadLocationException; -import org.springframework.ide.vscode.util.IDocument; -import org.springframework.ide.vscode.util.IRegion; -import org.springframework.ide.vscode.util.Region; import io.typefox.lsapi.TextEdit; diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/completion/ICompletionEngine.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/ICompletionEngine.java similarity index 82% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/completion/ICompletionEngine.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/ICompletionEngine.java index 2cadc73d5..d838e238f 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/completion/ICompletionEngine.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/ICompletionEngine.java @@ -8,11 +8,11 @@ * Contributors: * Pivotal, Inc. - initial API and implementation *******************************************************************************/ -package org.springframework.ide.vscode.commons.completion; +package org.springframework.ide.vscode.commons.languageserver.completion; import java.util.Collection; -import org.springframework.ide.vscode.util.IDocument; +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; /** * @author Kris De Volder diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/completion/ICompletionProposal.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/ICompletionProposal.java similarity index 81% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/completion/ICompletionProposal.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/ICompletionProposal.java index 60e9273b1..aa0f7e919 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/completion/ICompletionProposal.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/ICompletionProposal.java @@ -1,4 +1,4 @@ -package org.springframework.ide.vscode.commons.completion; +package org.springframework.ide.vscode.commons.languageserver.completion; import io.typefox.lsapi.CompletionItemKind; diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/completion/ProposalApplier.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/ProposalApplier.java similarity index 83% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/completion/ProposalApplier.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/ProposalApplier.java index 9a6b35425..85c20831e 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/completion/ProposalApplier.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/ProposalApplier.java @@ -8,10 +8,10 @@ * Contributors: * Pivotal, Inc. - initial API and implementation *******************************************************************************/ -package org.springframework.ide.vscode.commons.completion; +package org.springframework.ide.vscode.commons.languageserver.completion; -import org.springframework.ide.vscode.util.IDocument; -import org.springframework.ide.vscode.util.IRegion; +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; +import org.springframework.ide.vscode.commons.languageserver.util.IRegion; /** * Interface that represents the methods that one needs to implement in order diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/DefaultJavaProjectFinder.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/DefaultJavaProjectFinder.java new file mode 100644 index 000000000..e8e7339aa --- /dev/null +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/DefaultJavaProjectFinder.java @@ -0,0 +1,92 @@ +package org.springframework.ide.vscode.commons.languageserver.java; + +import java.io.File; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Path; + +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; +import org.springframework.ide.vscode.java.IJavaProject; +import org.springframework.ide.vscode.java.IType; +import org.springframework.ide.vscode.util.HtmlSnippet; +import org.springframework.ide.vscode.util.StringUtil; + +public class DefaultJavaProjectFinder implements JavaProjectFinder { + + private final String CLASSPATH_FILE_NAME; + + public DefaultJavaProjectFinder(String classpathFileName) { + this.CLASSPATH_FILE_NAME = classpathFileName; + } + + private File findClasspathFile(File file) { + if (file!=null && file.exists()) { + File cpFile = new File(file, CLASSPATH_FILE_NAME); + if (cpFile.isFile()) { + return cpFile; + } else { + return findClasspathFile(file.getParentFile()); + } + } + return null; + } + + @Override + public IJavaProject find(IDocument d) { + String uriStr = d.getUri(); + if (StringUtil.hasText(uriStr)) { + try { + URI uri = new URI(uriStr); + //TODO: This only work with File uri. Should it work with others too? + File file = new File(uri).getAbsoluteFile(); + File cpFile = findClasspathFile(file); + if (cpFile!=null) { + return new JavaProjectWithClasspathFile(cpFile); + } + } catch (URISyntaxException | IllegalArgumentException e) { + //garbage data. Ignore it. + } + } + return null; + }; + + private static class JavaProjectWithClasspathFile implements IJavaProject { + + private File cpFile; + + public JavaProjectWithClasspathFile(File cpFile) { + this.cpFile = cpFile; + } + + @Override + public String getElementName() { + return cpFile.getParentFile().getName(); + } + + @Override + public HtmlSnippet getJavaDoc() { + return null; + } + + @Override + public boolean exists() { + return cpFile.exists(); + } + + @Override + public IType findType(String fqName) { + //TODO: implement + return null; + } + + @Override + public Path getPath() { + return cpFile.getParentFile().toPath(); + } + + @Override + public String toString() { + return "JavaProjectWithClasspathFile("+cpFile+")"; + } + } +} diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/JavaProjectFinder.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/JavaProjectFinder.java new file mode 100644 index 000000000..40e27e65a --- /dev/null +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/JavaProjectFinder.java @@ -0,0 +1,10 @@ +package org.springframework.ide.vscode.commons.languageserver.java; + +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; +import org.springframework.ide.vscode.java.IJavaProject; + +@FunctionalInterface +public interface JavaProjectFinder { + JavaProjectFinder DEFAULT = new DefaultJavaProjectFinder("classpath.txt"); + IJavaProject find(IDocument doc); +} diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/quickfix/ProblemFixer.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/quickfix/ProblemFixer.java new file mode 100644 index 000000000..e5cf4b2a4 --- /dev/null +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/quickfix/ProblemFixer.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2016 Pivotal, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.commons.languageserver.quickfix; + +import java.util.List; + +import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal; +import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem; + +/** + * Represents a strategy for computing potential quickfixes for a given problem. + * + * @author Kris De Volder + */ +@FunctionalInterface +public interface ProblemFixer { + + /** + * Implementor can inspect the problem and quickfix context provided as parameters. + *

+ * If the problem is deemed fixable, the strategy can contribute one or more fixes by + * adding them to the list of proposals (provided as third parameter). + */ + void contributeFixes( + QuickfixContext context, ReconcileProblem problem, + List proposals + ); + +} diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/quickfix/QuickfixContext.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/quickfix/QuickfixContext.java new file mode 100644 index 000000000..cf62d2ae0 --- /dev/null +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/quickfix/QuickfixContext.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2015, 2016 Pivotal, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.commons.languageserver.quickfix; + +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; + +/** + * Provides access to additional context info and objects that quickfixes might + * need in order to be able to apply themselves. + * + * @author Kris De Volder + */ +public interface QuickfixContext { +// IProject getProject(); +// IPreferenceStore getWorkspacePreferences(); +// IPreferenceStore getProjectPreferences(); +// IJavaProject getJavaProject(); +// UserInteractions getUI(); + IDocument getDocument(); +} diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/BadWordReconcileEngine.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/BadWordReconcileEngine.java new file mode 100644 index 000000000..cccb9494b --- /dev/null +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/BadWordReconcileEngine.java @@ -0,0 +1,67 @@ +package org.springframework.ide.vscode.commons.languageserver.reconcile; + +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; + +/** + * A fake reconcule engine which is not useful except for quickly testing + * whether stuff is wired up correctly to the editor. + */ +public class BadWordReconcileEngine implements IReconcileEngine { + + static enum BWProblemType implements ProblemType { + VERY_BAD_WORD, + BAD_WORD; + + @Override + public ProblemSeverity getDefaultSeverity() { + if (this==VERY_BAD_WORD) { + return ProblemSeverity.ERROR; + } else { + return ProblemSeverity.WARNING; + } + } + + @Override + public String getCode() { + return this.name(); + } + } + + private final String[] BADWORDS = { + "bar", "foo" + }; + + public BadWordReconcileEngine() { + } + + @Override + public void reconcile(IDocument doc, IProblemCollector problemCollector) { + String text = doc.get(); + System.out.println(">>>> reconciling for bad words =========="); + System.out.println(text); + System.out.println("<<<< reconciling for bad words =========="); + + problemCollector.beginCollecting(); + try { + for (String badword : BADWORDS) { + int pos = 0; + while (pos>=0 && pos < text.length()) { + int badPos = text.indexOf(badword, pos); + if (badPos>=0) { + if (badword.equals(BADWORDS[0])) { + problemCollector.accept(new ReconcileProblemImpl(BWProblemType.VERY_BAD_WORD, "'"+badword+"' is a VERY bad word", badPos, badword.length())); + } else { + problemCollector.accept(new ReconcileProblemImpl(BWProblemType.BAD_WORD, "'"+badword+"' is a bad word", badPos, badword.length())); + } + pos = badPos+1; + } else { + pos = badPos; + } + } + } + } finally { + problemCollector.endCollecting(); + } + } + +} diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/reconcile/IProblemCollector.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/IProblemCollector.java similarity index 92% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/reconcile/IProblemCollector.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/IProblemCollector.java index 773f72b6d..6ac511745 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/reconcile/IProblemCollector.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/IProblemCollector.java @@ -8,7 +8,7 @@ * Contributors: * Pivotal, Inc. - initial API and implementation *******************************************************************************/ -package org.springframework.ide.vscode.commons.reconcile; +package org.springframework.ide.vscode.commons.languageserver.reconcile; public interface IProblemCollector { diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/reconcile/IReconcileEngine.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/IReconcileEngine.java similarity index 80% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/reconcile/IReconcileEngine.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/IReconcileEngine.java index ef9257a4b..381074245 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/reconcile/IReconcileEngine.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/IReconcileEngine.java @@ -8,9 +8,9 @@ * Contributors: * Pivotal, Inc. - initial API and implementation *******************************************************************************/ -package org.springframework.ide.vscode.commons.reconcile; +package org.springframework.ide.vscode.commons.languageserver.reconcile; -import org.springframework.ide.vscode.util.IDocument; +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; public interface IReconcileEngine { public void reconcile(IDocument doc, IProblemCollector problemCollector); diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/reconcile/ProblemSeverity.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/ProblemSeverity.java similarity index 56% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/reconcile/ProblemSeverity.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/ProblemSeverity.java index d215237eb..71dd16335 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/reconcile/ProblemSeverity.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/ProblemSeverity.java @@ -1,4 +1,4 @@ -package org.springframework.ide.vscode.commons.reconcile; +package org.springframework.ide.vscode.commons.languageserver.reconcile; /** * @author Kris De Volder diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/reconcile/ProblemType.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/ProblemType.java similarity index 87% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/reconcile/ProblemType.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/ProblemType.java index 45a6fdbe8..489ec4d65 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/reconcile/ProblemType.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/ProblemType.java @@ -1,4 +1,4 @@ -package org.springframework.ide.vscode.commons.reconcile; +package org.springframework.ide.vscode.commons.languageserver.reconcile; /** * Besides the methods below, the only hard requirement for a 'problem type' is diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/reconcile/ReconcileProblem.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/ReconcileProblem.java similarity index 78% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/reconcile/ReconcileProblem.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/ReconcileProblem.java index ee3d61b6e..066f9b127 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/reconcile/ReconcileProblem.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/ReconcileProblem.java @@ -1,4 +1,4 @@ -package org.springframework.ide.vscode.commons.reconcile; +package org.springframework.ide.vscode.commons.languageserver.reconcile; /** * Minamal interface that objects representing a reconciler problem must diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/reconcile/ReconcileProblemImpl.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/ReconcileProblemImpl.java similarity index 91% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/reconcile/ReconcileProblemImpl.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/ReconcileProblemImpl.java index f83d4468b..e7ff94aac 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/reconcile/ReconcileProblemImpl.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/ReconcileProblemImpl.java @@ -1,4 +1,4 @@ -package org.springframework.ide.vscode.commons.reconcile; +package org.springframework.ide.vscode.commons.languageserver.reconcile; /** * An implementation of {@link ReconcileProblem} that is just a simple data object. diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/BadLocationException.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/BadLocationException.java similarity index 81% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/BadLocationException.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/BadLocationException.java index f38145483..8c330fb23 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/BadLocationException.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/BadLocationException.java @@ -1,4 +1,4 @@ -package org.springframework.ide.vscode.util; +package org.springframework.ide.vscode.commons.languageserver.util; /** * Replacement for Eclipse's BadLocationException (so as ot make porting code easier) diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/CompletionHandler.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/CompletionHandler.java similarity index 80% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/CompletionHandler.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/CompletionHandler.java index 166764a0b..39e4d127a 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/CompletionHandler.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/CompletionHandler.java @@ -1,4 +1,4 @@ -package org.springframework.ide.vscode.util; +package org.springframework.ide.vscode.commons.languageserver.util; import java.util.concurrent.CompletableFuture; diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/CompletionResolveHandler.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/CompletionResolveHandler.java similarity index 76% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/CompletionResolveHandler.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/CompletionResolveHandler.java index 73d9d011a..50d0ef3d9 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/CompletionResolveHandler.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/CompletionResolveHandler.java @@ -1,4 +1,4 @@ -package org.springframework.ide.vscode.util; +package org.springframework.ide.vscode.commons.languageserver.util; import java.util.concurrent.CompletableFuture; diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/DocumentUtil.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/DocumentUtil.java similarity index 78% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/DocumentUtil.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/DocumentUtil.java index 7a0eeb983..fb9a6cd5b 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/DocumentUtil.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/DocumentUtil.java @@ -1,7 +1,11 @@ -package org.springframework.ide.vscode.util; +package org.springframework.ide.vscode.commons.languageserver.util; + +import org.springframework.ide.vscode.util.Assert; public class DocumentUtil { + //TODO: this stuff belongs in IDocument and its implementation, not here. This class should be removed. + /** * Fetch text between two offsets. Doesn't throw BadLocationException. * If either one or both of the offsets points outside the diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/IDocument.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/IDocument.java similarity index 85% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/IDocument.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/IDocument.java index 0d9367a67..b61707841 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/IDocument.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/IDocument.java @@ -1,7 +1,8 @@ -package org.springframework.ide.vscode.util; +package org.springframework.ide.vscode.commons.languageserver.util; public interface IDocument { + String getUri(); String get(); IRegion getLineInformationOfOffset(int offset); int getLength(); diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/IRegion.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/IRegion.java similarity index 67% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/IRegion.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/IRegion.java index 7eb255818..50eac8284 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/IRegion.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/IRegion.java @@ -1,4 +1,4 @@ -package org.springframework.ide.vscode.util; +package org.springframework.ide.vscode.commons.languageserver.util; /** * Mimicks eclipse IRegion (i.e. a region is a offset + length). diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/JSON.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/JSON.java similarity index 96% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/JSON.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/JSON.java index 32df4f379..f42f0c036 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/JSON.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/JSON.java @@ -1,4 +1,4 @@ -package org.springframework.ide.vscode.util; +package org.springframework.ide.vscode.commons.languageserver.util; import java.io.IOException; import java.nio.file.Path; diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/ListenerList.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/ListenerList.java similarity index 83% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/ListenerList.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/ListenerList.java index a8bb01e51..ac9a11fe8 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/ListenerList.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/ListenerList.java @@ -1,4 +1,4 @@ -package org.springframework.ide.vscode.util; +package org.springframework.ide.vscode.commons.languageserver.util; import java.util.ArrayList; import java.util.List; diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/LoggingFormat.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/LoggingFormat.java similarity index 96% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/LoggingFormat.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/LoggingFormat.java index 29bbff43e..6464c05f7 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/LoggingFormat.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/LoggingFormat.java @@ -1,4 +1,4 @@ -package org.springframework.ide.vscode.util; +package org.springframework.ide.vscode.commons.languageserver.util; import java.io.IOException; import java.io.PrintWriter; diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/PrefixFinder.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/PrefixFinder.java similarity index 94% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/PrefixFinder.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/PrefixFinder.java index 18b29753b..0b2c5dd54 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/PrefixFinder.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/PrefixFinder.java @@ -8,7 +8,7 @@ * Contributors: * Pivotal, Inc. - initial API and implementation *******************************************************************************/ -package org.springframework.ide.vscode.util; +package org.springframework.ide.vscode.commons.languageserver.util; public abstract class PrefixFinder { public String getPrefix(IDocument doc, int offset, int lowerBound) { diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/Region.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/Region.java similarity index 93% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/Region.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/Region.java index 2889ae76f..620e71c16 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/Region.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/Region.java @@ -1,4 +1,4 @@ -package org.springframework.ide.vscode.util; +package org.springframework.ide.vscode.commons.languageserver.util; /** * Trivial implementation of {@link IRegion} diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/Settings.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/Settings.java similarity index 92% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/Settings.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/Settings.java index 7ff3458ee..0c978a4a1 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/Settings.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/Settings.java @@ -1,4 +1,4 @@ -package org.springframework.ide.vscode.util; +package org.springframework.ide.vscode.commons.languageserver.util; import java.util.Map; diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/ShowMessageException.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/ShowMessageException.java similarity index 93% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/ShowMessageException.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/ShowMessageException.java index 585c0271a..d87572564 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/ShowMessageException.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/ShowMessageException.java @@ -1,4 +1,4 @@ -package org.springframework.ide.vscode.util; +package org.springframework.ide.vscode.commons.languageserver.util; import io.typefox.lsapi.MessageParams; import io.typefox.lsapi.impl.MessageParamsImpl; diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/SimpleLanguageServer.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleLanguageServer.java similarity index 64% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/SimpleLanguageServer.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleLanguageServer.java index 2db20cf38..72b011d1a 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/SimpleLanguageServer.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleLanguageServer.java @@ -1,17 +1,26 @@ -package org.springframework.ide.vscode.util; +package org.springframework.ide.vscode.commons.languageserver.util; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; import java.util.logging.Level; import java.util.logging.Logger; +import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector; +import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcileEngine; +import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemSeverity; +import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem; + +import io.typefox.lsapi.DiagnosticSeverity; import io.typefox.lsapi.InitializeParams; import io.typefox.lsapi.InitializeResult; import io.typefox.lsapi.MessageParams; import io.typefox.lsapi.MessageType; import io.typefox.lsapi.ShowMessageRequestParams; +import io.typefox.lsapi.impl.DiagnosticImpl; import io.typefox.lsapi.impl.InitializeResultImpl; import io.typefox.lsapi.impl.MessageParamsImpl; import io.typefox.lsapi.impl.ServerCapabilitiesImpl; @@ -134,5 +143,54 @@ public abstract class SimpleLanguageServer implements LanguageServer { //TODO: not sure what this is for exactly. We just stub it and do nothing for now. } + /** + * Convenience method. Subclasses can call this to use a {@link IReconcileEngine} ported + * from old STS codebase to validate a given {@link TextDocument} and publish Diagnostics. + */ + protected void validateWith(TextDocument doc, IReconcileEngine engine) { + SimpleTextDocumentService documents = getTextDocumentService(); + IProblemCollector problems = new IProblemCollector() { + + private List diagnostics = new ArrayList<>(); + + @Override + public void endCollecting() { + documents.publishDiagnostics(doc, diagnostics); + } + + @Override + public void beginCollecting() { + diagnostics.clear(); + } + + @Override + public void accept(ReconcileProblem problem) { + DiagnosticSeverity severity = getDiagnosticSeverity(problem); + if (severity!=null) { + DiagnosticImpl d = new DiagnosticImpl(); + d.setCode(problem.getCode()); + d.setMessage(problem.getMessage()); + d.setRange(doc.toRange(problem.getOffset(), problem.getLength())); + d.setSeverity(severity); + diagnostics.add(d); + } + } + + private DiagnosticSeverity getDiagnosticSeverity(ReconcileProblem problem) { + ProblemSeverity severity = problem.getType().getDefaultSeverity(); + switch (severity) { + case ERROR: + return DiagnosticSeverity.Error; + case WARNING: + return DiagnosticSeverity.Warning; + case IGNORE: + return null; + default: + throw new IllegalStateException("Bug! Missing switch case?"); + } + } + }; + engine.reconcile(doc, problems); + } } diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/SimpleTextDocumentService.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java similarity index 97% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/SimpleTextDocumentService.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java index 50317b2ea..e4519b924 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/SimpleTextDocumentService.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java @@ -1,4 +1,4 @@ -package org.springframework.ide.vscode.util; +package org.springframework.ide.vscode.commons.languageserver.util; import java.util.ArrayList; import java.util.Collection; @@ -10,6 +10,9 @@ import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; import java.util.logging.Logger; +import org.springframework.ide.vscode.util.Assert; +import org.springframework.ide.vscode.util.Futures; + import io.typefox.lsapi.CodeActionParams; import io.typefox.lsapi.CodeLens; import io.typefox.lsapi.CodeLensParams; @@ -44,16 +47,16 @@ import io.typefox.lsapi.impl.PublishDiagnosticsParamsImpl; import io.typefox.lsapi.services.TextDocumentService; public class SimpleTextDocumentService implements TextDocumentService { - + private static final Logger LOG = Logger.getLogger(SimpleTextDocumentService.class.getName()); - + private Consumer publishDiagnostics = (p) -> {}; - + private Map documents = new HashMap<>(); private ListenerList documentChangeListeners = new ListenerList<>(); private CompletionHandler completionHandler = null; private CompletionResolveHandler completionResolveHandler = null; - + public synchronized void onCompletion(CompletionHandler h) { Assert.isNull("A completion handler is already set, multiple handlers not supported yet", completionHandler); this.completionHandler = h; @@ -85,7 +88,7 @@ public class SimpleTextDocumentService implements TextDocumentService { } } } - + @Override public void didOpen(DidOpenTextDocumentParams params) { //LOG.info("didOpen: "+params); diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/SimpleWorkspaceService.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleWorkspaceService.java similarity index 93% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/SimpleWorkspaceService.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleWorkspaceService.java index d0df372c6..2de8347a8 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/SimpleWorkspaceService.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleWorkspaceService.java @@ -1,4 +1,4 @@ -package org.springframework.ide.vscode.util; +package org.springframework.ide.vscode.commons.languageserver.util; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -11,7 +11,7 @@ import io.typefox.lsapi.WorkspaceSymbolParams; import io.typefox.lsapi.services.WorkspaceService; public class SimpleWorkspaceService implements WorkspaceService { - + private ListenerList configurationListeners = new ListenerList<>(); @Override @@ -34,5 +34,5 @@ public class SimpleWorkspaceService implements WorkspaceService { public void onDidChangeConfiguraton(Consumer l) { configurationListeners.add(l); } - + } diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/TextDocument.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/TextDocument.java similarity index 98% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/TextDocument.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/TextDocument.java index f6c9cc397..5eaea2f9d 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/TextDocument.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/TextDocument.java @@ -1,4 +1,4 @@ -package org.springframework.ide.vscode.util; +package org.springframework.ide.vscode.commons.languageserver.util; import java.util.ArrayList; import java.util.List; diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/TextDocumentContentChange.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/TextDocumentContentChange.java similarity index 87% rename from vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/TextDocumentContentChange.java rename to vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/TextDocumentContentChange.java index ca82c08ef..f63515f55 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/util/TextDocumentContentChange.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/TextDocumentContentChange.java @@ -1,4 +1,4 @@ -package org.springframework.ide.vscode.util; +package org.springframework.ide.vscode.commons.languageserver.util; import io.typefox.lsapi.TextDocumentContentChangeEvent; diff --git a/vscode-extensions/commons/commons-language-server/src/test/java/org/springframework/ide/vscode/commons/completion/DocumentEditsTest.java b/vscode-extensions/commons/commons-language-server/src/test/java/org/springframework/ide/vscode/commons/completion/DocumentEditsTest.java index 843a9a33a..f7dd424b3 100644 --- a/vscode-extensions/commons/commons-language-server/src/test/java/org/springframework/ide/vscode/commons/completion/DocumentEditsTest.java +++ b/vscode-extensions/commons/commons-language-server/src/test/java/org/springframework/ide/vscode/commons/completion/DocumentEditsTest.java @@ -15,11 +15,12 @@ import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; +import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits; +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; +import org.springframework.ide.vscode.commons.languageserver.util.IRegion; +import org.springframework.ide.vscode.commons.languageserver.util.TextDocument; import org.springframework.ide.vscode.testharness.Editor; import org.springframework.ide.vscode.testharness.LanguageServerHarness; -import org.springframework.ide.vscode.util.IDocument; -import org.springframework.ide.vscode.util.IRegion; -import org.springframework.ide.vscode.util.TextDocument; /** * @author Kris De Volder */ diff --git a/vscode-extensions/commons/commons-util/pom.xml b/vscode-extensions/commons/commons-util/pom.xml index 904cf2425..0617ac842 100644 --- a/vscode-extensions/commons/commons-util/pom.xml +++ b/vscode-extensions/commons/commons-util/pom.xml @@ -10,4 +10,17 @@ ../pom.xml + + + com.google.guava + guava + 18.0 + + + javax.inject + javax.inject + 1 + + + diff --git a/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/util/CollectionUtil.java b/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/util/AlwaysFailingParser.java similarity index 50% rename from vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/util/CollectionUtil.java rename to vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/util/AlwaysFailingParser.java index 02a32792f..cee2ae16a 100644 --- a/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/util/CollectionUtil.java +++ b/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/util/AlwaysFailingParser.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015 Pivotal, Inc. + * Copyright (c) 2014-2015 Pivotal, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -8,17 +8,25 @@ * Contributors: * Pivotal, Inc. - initial API and implementation *******************************************************************************/ -package org.springframework.ide.vscode.boot.properties.util; - -import java.util.Collection; +package org.springframework.ide.vscode.util; /** + * Parser that always fails, regardless of the input. Used for types who's value cannot be + * expressed as a 'scalar' string value. + * * @author Kris De Volder */ -public class CollectionUtil { +public class AlwaysFailingParser implements ValueParser { - public static boolean hasElements(Collection c) { - return c!=null && !c.isEmpty(); + private String typeName; + + public AlwaysFailingParser(String typeName) { + this.typeName = typeName; + } + + @Override + public Object parse(String str) { + throw new IllegalArgumentException("'"+str+"' is not valid for type '"+typeName+"'"); } } diff --git a/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/util/ArrayUtils.java b/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/util/ArrayUtils.java similarity index 95% rename from vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/util/ArrayUtils.java rename to vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/util/ArrayUtils.java index b445b2aaa..e34e39f63 100644 --- a/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/boot/properties/util/ArrayUtils.java +++ b/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/util/ArrayUtils.java @@ -8,7 +8,7 @@ * Contributors: * Pivotal, Inc. - initial API and implementation *******************************************************************************/ -package org.springframework.ide.vscode.boot.properties.util; +package org.springframework.ide.vscode.util; import java.lang.reflect.Array; import java.util.ArrayList; diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/util/EnumValueParser.java b/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/util/EnumValueParser.java similarity index 96% rename from vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/util/EnumValueParser.java rename to vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/util/EnumValueParser.java index 1c373754b..ee1cc76ab 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/util/EnumValueParser.java +++ b/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/util/EnumValueParser.java @@ -8,7 +8,7 @@ * Contributors: * Pivotal, Inc. - initial API and implementation *******************************************************************************/ -package org.springframework.ide.vscode.yaml.util; +package org.springframework.ide.vscode.util; import java.util.Collection; import java.util.Set; diff --git a/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/util/HtmlBuffer.java b/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/util/HtmlBuffer.java new file mode 100644 index 000000000..8ac3f5a07 --- /dev/null +++ b/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/util/HtmlBuffer.java @@ -0,0 +1,171 @@ +/******************************************************************************* + * Copyright (c) 2014-2016 Pivotal, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.util; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + +/** + * Helper class to make it a little easier to create simple html page. + * + * @author Kris De Volder + */ +public class HtmlBuffer { + + private StringBuffer buffer = new StringBuffer(); + private boolean epilogAdded = false; //to ensure only added once. + + public HtmlBuffer() { + this.buffer = new StringBuffer(); + } + + /** + * Append text, applies escaping to the text as needed. + */ + public void text(String text) { + raw(convertToHTMLContent(text)); + } + + /** + * Append 'raw' text. Doesn't apply any escaping. + */ + public void raw(String rawText) { + if (epilogAdded) { + throw new IllegalStateException("Can not append more text after epilog was added"); + } + buffer.append(rawText); + } + + /** + * Append text, applies urlencoding to the text. + */ + public void url(String string) { + try { + raw(URLEncoder.encode(string, "utf8")); + } catch (UnsupportedEncodingException e) { + Log.log(e); + } + } + + + public String toString() { + if (!epilogAdded && buffer.length()>0) { + epilogAdded = true; + addPrologAndEpilog(); + } + return buffer.toString(); + } + + protected void addPrologAndEpilog() { +// HTMLPrinter.insertPageProlog(buffer, 0, getCSSStyles()); +// HTMLPrinter.addPageEpilog(buffer); + } + +// /** +// * Note: copied from org.eclipse.jdt.internal.ui.text.java.AbstractJavaCompletionProposal.getCSSStyles() +// * Returns the style information for displaying HTML (Javadoc) content. +// * +// * @return the CSS styles +// * @since 3.3 +// */ +// public static String getCSSStyles() { +// if (fgCSSStyles == null) { +// Bundle bundle= Platform.getBundle(JavaPlugin.getPluginId()); +// URL url= bundle.getEntry("/JavadocHoverStyleSheet.css"); //$NON-NLS-1$ +// if (url != null) { +// BufferedReader reader= null; +// try { +// url= FileLocator.toFileURL(url); +// reader= new BufferedReader(new InputStreamReader(url.openStream())); +// StringBuffer buffer= new StringBuffer(200); +// String line= reader.readLine(); +// while (line != null) { +// buffer.append(line); +// buffer.append('\n'); +// line= reader.readLine(); +// } +// fgCSSStyles= buffer.toString(); +// } catch (IOException ex) { +// JavaPlugin.log(ex); +// } finally { +// try { +// if (reader != null) +// reader.close(); +// } catch (IOException e) { +// } +// } +// +// } +// } +// String css= fgCSSStyles; +// if (css != null) { +// FontData fontData= JFaceResources.getFontRegistry().getFontData(PreferenceConstants.APPEARANCE_JAVADOC_FONT)[0]; +// css= HTMLPrinter.convertTopLevelFont(css, fontData); +// } +// return css; +// } + + public void hline() { + raw("


"); + } + + public void p(String string) { + raw("

"); + text(string); + raw("

"); + } + + public void snippet(HtmlSnippet snippet) { + snippet.render(this); + } + + public void bold(String string) { + raw(""); + text(string); + raw(""); + } + + /** + * Escapes reserved HTML characters in the given string. + *

+ * Warning: Does not preserve whitespace. + * + * @param content the input string + * @return the string with escaped characters + */ + public static String convertToHTMLContent(String content) { + content= replace(content, '&', "&"); //$NON-NLS-1$ + content= replace(content, '"', """); //$NON-NLS-1$ + content= replace(content, '<', "<"); //$NON-NLS-1$ + return replace(content, '>', ">"); //$NON-NLS-1$ + } + + private static String replace(String text, char c, String s) { + + int previous= 0; + int current= text.indexOf(c, previous); + + if (current == -1) + return text; + + StringBuffer buffer= new StringBuffer(); + while (current > -1) { + buffer.append(text.substring(previous, current)); + buffer.append(s); + previous= current + 1; + current= text.indexOf(c, previous); + } + buffer.append(text.substring(previous)); + + return buffer.toString(); + } + +} diff --git a/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/util/HtmlSnippet.java b/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/util/HtmlSnippet.java new file mode 100644 index 000000000..6c10308e5 --- /dev/null +++ b/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/util/HtmlSnippet.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2016 Pivotal, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.util; + +/** + * A snippet that can be rendered into html. + * + * @author Kris De Volder + */ +public abstract class HtmlSnippet { + public abstract void render(HtmlBuffer html); + + public String toHtml() { + HtmlBuffer buf = new HtmlBuffer(); + render(buf); + return buf.toString(); + } + + // Create snippets: + + public static HtmlSnippet text(final String text) { + return new HtmlSnippet() { + @Override + public void render(HtmlBuffer html) { + html.text(text); + } + }; + } + + public static HtmlSnippet raw(final String rawHtml) { + return new HtmlSnippet() { + @Override + public void render(HtmlBuffer html) { + html.raw(rawHtml); + } + }; + } + + public static HtmlSnippet italic(String text) { + return italic(text(text)); + } + + public static HtmlSnippet italic(final HtmlSnippet wrappee) { + return new HtmlSnippet() { + @Override + public void render(HtmlBuffer html) { + html.raw(""); + wrappee.render(html); + html.raw(""); + } + }; + } + + // add more as needed ... +} diff --git a/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/util/LazyProvider.java b/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/util/LazyProvider.java new file mode 100644 index 000000000..a77fcc6c3 --- /dev/null +++ b/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/util/LazyProvider.java @@ -0,0 +1,26 @@ +package org.springframework.ide.vscode.util; + +import javax.inject.Provider; + +/** + * An abstract class implementing {@link Provider}. The provided value + * is computed on demand and cached once computed. + *

+ * Subclass must implement the compute method. + */ +public abstract class LazyProvider implements Provider { + + private boolean computed = false; + private T cached = null; + + @Override + public synchronized final T get() { + if (!computed) { + cached = compute(); + } + return cached; + } + + protected abstract T compute(); + +} diff --git a/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/util/Log.java b/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/util/Log.java new file mode 100644 index 000000000..c5119fe30 --- /dev/null +++ b/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/util/Log.java @@ -0,0 +1,20 @@ +package org.springframework.ide.vscode.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Deprecated, this class is here to make porting old STS code easier. Code should + * avoid using this as much as possible and replaces calls to this by using Slf4J loggers + * directly. + */ +@Deprecated +public class Log { + + final static Logger logger = LoggerFactory.getLogger(Log.class); + + public static void log(Throwable e) { + logger.error("Error", e); + } + +} diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/util/ValueParser.java b/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/util/ValueParser.java similarity index 94% rename from vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/util/ValueParser.java rename to vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/util/ValueParser.java index 262052002..50806b806 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/util/ValueParser.java +++ b/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/util/ValueParser.java @@ -8,7 +8,7 @@ * Contributors: * Pivotal, Inc. - initial API and implementation *******************************************************************************/ -package org.springframework.ide.vscode.yaml.util; +package org.springframework.ide.vscode.util; /** * A ValueParser provides the means to Strings into some kind of diff --git a/vscode-extensions/commons/commons-yaml/pom.xml b/vscode-extensions/commons/commons-yaml/pom.xml index d7443a099..f28900823 100644 --- a/vscode-extensions/commons/commons-yaml/pom.xml +++ b/vscode-extensions/commons/commons-yaml/pom.xml @@ -26,12 +26,7 @@ org.yaml snakeyaml - 1.17 - - - org.yaml - snakeyaml - 1.17 + ${yaml-version} javax.inject diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/ast/YamlASTProvider.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/ast/YamlASTProvider.java index 43088c28d..abe0be822 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/ast/YamlASTProvider.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/ast/YamlASTProvider.java @@ -1,6 +1,6 @@ package org.springframework.ide.vscode.yaml.ast; -import org.springframework.ide.vscode.util.IDocument; +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; @FunctionalInterface public interface YamlASTProvider { diff --git a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/cloudfoundry/manifest/editor/YamlParser.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/ast/YamlParser.java similarity index 58% rename from vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/cloudfoundry/manifest/editor/YamlParser.java rename to vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/ast/YamlParser.java index 5a8454f68..fc4111372 100644 --- a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/cloudfoundry/manifest/editor/YamlParser.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/ast/YamlParser.java @@ -1,10 +1,8 @@ -package org.springframework.ide.vscode.cloudfoundry.manifest.editor; +package org.springframework.ide.vscode.yaml.ast; import java.io.StringReader; -import org.springframework.ide.vscode.util.IDocument; -import org.springframework.ide.vscode.yaml.ast.YamlASTProvider; -import org.springframework.ide.vscode.yaml.ast.YamlFileAST; +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; import org.yaml.snakeyaml.Yaml; public class YamlParser implements YamlASTProvider { diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/AbstractYamlAssistContext.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/AbstractYamlAssistContext.java index 3c8899d80..020e6e46a 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/AbstractYamlAssistContext.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/AbstractYamlAssistContext.java @@ -10,7 +10,7 @@ *******************************************************************************/ package org.springframework.ide.vscode.yaml.completion; -import org.springframework.ide.vscode.util.PrefixFinder; +import org.springframework.ide.vscode.commons.languageserver.util.PrefixFinder; import org.springframework.ide.vscode.yaml.path.YamlPath; import org.springframework.ide.vscode.yaml.structure.YamlDocument; import org.springframework.ide.vscode.yaml.structure.YamlStructureParser.SDocNode; diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/CompletionFactory.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/CompletionFactory.java index bd629d431..92a34505b 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/CompletionFactory.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/CompletionFactory.java @@ -1,8 +1,8 @@ package org.springframework.ide.vscode.yaml.completion; -import org.springframework.ide.vscode.commons.completion.DocumentEdits; -import org.springframework.ide.vscode.commons.completion.ICompletionProposal; -import org.springframework.ide.vscode.util.IDocument; +import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits; +import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal; +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; import org.springframework.ide.vscode.yaml.schema.YType; import org.springframework.ide.vscode.yaml.schema.YTypeUtil; import org.springframework.ide.vscode.yaml.schema.YTypedProperty; diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/DefaultCompletionFactory.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/DefaultCompletionFactory.java index ad2222161..bcf1705b4 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/DefaultCompletionFactory.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/DefaultCompletionFactory.java @@ -2,9 +2,9 @@ package org.springframework.ide.vscode.yaml.completion; import java.util.Comparator; -import org.springframework.ide.vscode.commons.completion.DocumentEdits; -import org.springframework.ide.vscode.commons.completion.ICompletionProposal; -import org.springframework.ide.vscode.util.IDocument; +import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits; +import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal; +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; import org.springframework.ide.vscode.yaml.schema.YType; import org.springframework.ide.vscode.yaml.schema.YTypeUtil; import org.springframework.ide.vscode.yaml.schema.YTypedProperty; diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/TopLevelAssistContext.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/TopLevelAssistContext.java index 35b8d9b6c..503ffdf64 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/TopLevelAssistContext.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/TopLevelAssistContext.java @@ -13,7 +13,7 @@ package org.springframework.ide.vscode.yaml.completion; import java.util.Collection; import java.util.Collections; -import org.springframework.ide.vscode.commons.completion.ICompletionProposal; +import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal; import org.springframework.ide.vscode.yaml.path.YamlPathSegment; import org.springframework.ide.vscode.yaml.structure.YamlDocument; import org.springframework.ide.vscode.yaml.structure.YamlStructureParser.SNode; diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/YTypeAssistContext.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/YTypeAssistContext.java index 521fdbe8d..5e42c2bef 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/YTypeAssistContext.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/YTypeAssistContext.java @@ -20,8 +20,8 @@ import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.ide.vscode.commons.completion.DocumentEdits; -import org.springframework.ide.vscode.commons.completion.ICompletionProposal; +import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits; +import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal; import org.springframework.ide.vscode.util.CollectionUtil; import org.springframework.ide.vscode.util.FuzzyMatcher; import org.springframework.ide.vscode.yaml.path.YamlPath; diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/YamlAssistContext.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/YamlAssistContext.java index f23550e75..9f3c2ee5d 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/YamlAssistContext.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/YamlAssistContext.java @@ -12,7 +12,7 @@ package org.springframework.ide.vscode.yaml.completion; import java.util.Collection; -import org.springframework.ide.vscode.commons.completion.ICompletionProposal; +import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal; import org.springframework.ide.vscode.yaml.path.YamlNavigable; import org.springframework.ide.vscode.yaml.structure.YamlDocument; import org.springframework.ide.vscode.yaml.structure.YamlStructureParser.SNode; diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/YamlCompletionEngine.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/YamlCompletionEngine.java index 88484ef68..bb3d77551 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/YamlCompletionEngine.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/YamlCompletionEngine.java @@ -15,10 +15,10 @@ import java.util.Collections; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.ide.vscode.commons.completion.ICompletionEngine; -import org.springframework.ide.vscode.commons.completion.ICompletionProposal; +import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine; +import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal; +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; import org.springframework.ide.vscode.util.Assert; -import org.springframework.ide.vscode.util.IDocument; import org.springframework.ide.vscode.yaml.path.YamlPath; import org.springframework.ide.vscode.yaml.structure.YamlDocument; import org.springframework.ide.vscode.yaml.structure.YamlStructureParser.SKeyNode; diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/YamlPathEdits.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/YamlPathEdits.java index 60bb4e483..341356e1b 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/YamlPathEdits.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/completion/YamlPathEdits.java @@ -10,9 +10,9 @@ *******************************************************************************/ package org.springframework.ide.vscode.yaml.completion; -import org.springframework.ide.vscode.commons.completion.DocumentEdits; +import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits; +import org.springframework.ide.vscode.commons.languageserver.util.IRegion; import org.springframework.ide.vscode.util.Assert; -import org.springframework.ide.vscode.util.IRegion; import org.springframework.ide.vscode.yaml.path.YamlPath; import org.springframework.ide.vscode.yaml.path.YamlPathSegment; import org.springframework.ide.vscode.yaml.path.YamlPathSegment.YamlPathSegmentType; diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/SchemaBasedYamlASTReconciler.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/SchemaBasedYamlASTReconciler.java index 7ea5f5ad0..8ae578f3d 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/SchemaBasedYamlASTReconciler.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/SchemaBasedYamlASTReconciler.java @@ -4,16 +4,16 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import org.springframework.ide.vscode.commons.reconcile.IProblemCollector; +import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector; import org.springframework.ide.vscode.util.ExceptionUtil; import org.springframework.ide.vscode.util.StringUtil; +import org.springframework.ide.vscode.util.ValueParser; import org.springframework.ide.vscode.yaml.ast.NodeUtil; import org.springframework.ide.vscode.yaml.ast.YamlFileAST; import org.springframework.ide.vscode.yaml.schema.YType; import org.springframework.ide.vscode.yaml.schema.YTypeUtil; import org.springframework.ide.vscode.yaml.schema.YTypedProperty; import org.springframework.ide.vscode.yaml.schema.YamlSchema; -import org.springframework.ide.vscode.yaml.util.ValueParser; import org.yaml.snakeyaml.nodes.MappingNode; import org.yaml.snakeyaml.nodes.Node; import org.yaml.snakeyaml.nodes.NodeTuple; diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/YamlReconcileEngine.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/YamlReconcileEngine.java index 792953ca1..51f9bb980 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/YamlReconcileEngine.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/YamlReconcileEngine.java @@ -2,10 +2,10 @@ package org.springframework.ide.vscode.yaml.reconcile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.ide.vscode.commons.reconcile.IProblemCollector; -import org.springframework.ide.vscode.commons.reconcile.IReconcileEngine; -import org.springframework.ide.vscode.commons.reconcile.ReconcileProblem; -import org.springframework.ide.vscode.util.IDocument; +import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector; +import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcileEngine; +import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem; +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; import org.springframework.ide.vscode.yaml.ast.YamlASTProvider; import org.springframework.ide.vscode.yaml.ast.YamlFileAST; import org.yaml.snakeyaml.error.Mark; diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/YamlSchemaBasedReconcileEngine.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/YamlSchemaBasedReconcileEngine.java index 2ec6a0887..76fbea103 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/YamlSchemaBasedReconcileEngine.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/YamlSchemaBasedReconcileEngine.java @@ -1,8 +1,8 @@ package org.springframework.ide.vscode.yaml.reconcile; -import org.springframework.ide.vscode.commons.reconcile.IProblemCollector; -import org.springframework.ide.vscode.commons.reconcile.ReconcileProblem; -import org.springframework.ide.vscode.util.IDocument; +import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector; +import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem; +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; import org.springframework.ide.vscode.yaml.ast.YamlASTProvider; import org.springframework.ide.vscode.yaml.schema.YamlSchema; diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/YamlSchemaProblems.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/YamlSchemaProblems.java index 7808d9425..dd95c339a 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/YamlSchemaProblems.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/YamlSchemaProblems.java @@ -1,9 +1,9 @@ package org.springframework.ide.vscode.yaml.reconcile; -import org.springframework.ide.vscode.commons.reconcile.ProblemSeverity; -import org.springframework.ide.vscode.commons.reconcile.ProblemType; -import org.springframework.ide.vscode.commons.reconcile.ReconcileProblem; -import org.springframework.ide.vscode.commons.reconcile.ReconcileProblemImpl; +import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemSeverity; +import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType; +import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem; +import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl; import org.yaml.snakeyaml.nodes.Node; /** diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/schema/YTypeFactory.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/schema/YTypeFactory.java index d9421c6db..a8ff3e14d 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/schema/YTypeFactory.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/schema/YTypeFactory.java @@ -21,10 +21,10 @@ import java.util.Set; import javax.inject.Provider; -import org.springframework.ide.vscode.yaml.util.Description; +import org.springframework.ide.vscode.util.EnumValueParser; +import org.springframework.ide.vscode.util.HtmlSnippet; +import org.springframework.ide.vscode.util.ValueParser; import org.springframework.ide.vscode.yaml.util.DescriptionProviders; -import org.springframework.ide.vscode.yaml.util.EnumValueParser; -import org.springframework.ide.vscode.yaml.util.ValueParser; /** * Static utility method for creating YType objects representing either @@ -193,7 +193,7 @@ public class YTypeFactory { propertyList.add(p); } - public void addProperty(String name, YType type, Provider description) { + public void addProperty(String name, YType type, Provider description) { YTypedPropertyImpl prop; addProperty(prop = new YTypedPropertyImpl(name, type)); prop.setDescriptionProvider(description); @@ -314,7 +314,7 @@ public class YTypeFactory { final private String name; final private YType type; - private Provider descriptionProvider = DescriptionProviders.NO_DESCRIPTION; + private Provider descriptionProvider = DescriptionProviders.NO_DESCRIPTION; private YTypedPropertyImpl(String name, YType type) { this.name = name; @@ -337,11 +337,11 @@ public class YTypeFactory { } @Override - public Description getDescription() { + public HtmlSnippet getDescription() { return descriptionProvider.get(); } - public void setDescriptionProvider(Provider descriptionProvider) { + public void setDescriptionProvider(Provider descriptionProvider) { this.descriptionProvider = descriptionProvider; } diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/schema/YTypeUtil.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/schema/YTypeUtil.java index a78d47cdc..1b922cce1 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/schema/YTypeUtil.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/schema/YTypeUtil.java @@ -13,7 +13,7 @@ package org.springframework.ide.vscode.yaml.schema; import java.util.List; import java.util.Map; -import org.springframework.ide.vscode.yaml.util.ValueParser; +import org.springframework.ide.vscode.util.ValueParser; /** * An implementation of YTypeUtil provides implementations of various diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/schema/YTypedProperty.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/schema/YTypedProperty.java index bbc64e41b..e8ffb0650 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/schema/YTypedProperty.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/schema/YTypedProperty.java @@ -10,7 +10,7 @@ *******************************************************************************/ package org.springframework.ide.vscode.yaml.schema; -import org.springframework.ide.vscode.yaml.util.Description; +import org.springframework.ide.vscode.util.HtmlSnippet; /** * @author Kris De Volder @@ -18,5 +18,5 @@ import org.springframework.ide.vscode.yaml.util.Description; public interface YTypedProperty { String getName(); YType getType(); - Description getDescription(); + HtmlSnippet getDescription(); } diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/structure/YamlDocument.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/structure/YamlDocument.java index 2b7104d84..7ce9c0d20 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/structure/YamlDocument.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/structure/YamlDocument.java @@ -10,10 +10,10 @@ *******************************************************************************/ package org.springframework.ide.vscode.yaml.structure; -import org.springframework.ide.vscode.util.BadLocationException; -import org.springframework.ide.vscode.util.DocumentUtil; -import org.springframework.ide.vscode.util.IDocument; -import org.springframework.ide.vscode.util.IRegion; +import org.springframework.ide.vscode.commons.languageserver.util.BadLocationException; +import org.springframework.ide.vscode.commons.languageserver.util.DocumentUtil; +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; +import org.springframework.ide.vscode.commons.languageserver.util.IRegion; import org.springframework.ide.vscode.yaml.structure.YamlStructureParser.SRootNode; /** diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/structure/YamlStructureParser.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/structure/YamlStructureParser.java index d78d63ba7..666f94fb8 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/structure/YamlStructureParser.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/structure/YamlStructureParser.java @@ -10,9 +10,9 @@ import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.springframework.ide.vscode.commons.languageserver.util.IRegion; import org.springframework.ide.vscode.util.Assert; import org.springframework.ide.vscode.util.CollectionUtil; -import org.springframework.ide.vscode.util.IRegion; import org.springframework.ide.vscode.util.StringUtil; import org.springframework.ide.vscode.yaml.path.KeyAliases; import org.springframework.ide.vscode.yaml.path.YamlNavigable; diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/util/Description.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/util/Description.java deleted file mode 100644 index 3caa74646..000000000 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/util/Description.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.springframework.ide.vscode.yaml.util; - -public abstract class Description { - - public abstract void renderAsText(StringBuilder buf); - - public void renderAsHtml(StringBuilder buf) { - throw new UnsupportedOperationException("Rendering as html not supported"); - } - - public static Description text(String text) { - return new Description() { - @Override - public void renderAsText(StringBuilder buf) { - buf.append(text); - } - }; - } - - public static Description italic(Description d) { - //Not really supported, we just ignore italic and display as is - return d; - } - - public String toText() { - StringBuilder buf = new StringBuilder(); - renderAsText(buf); - return buf.toString(); - } - -} diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/util/DescriptionProviders.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/util/DescriptionProviders.java index 09e1816be..30168713b 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/util/DescriptionProviders.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/yaml/util/DescriptionProviders.java @@ -16,8 +16,9 @@ import javax.inject.Provider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.ide.vscode.util.HtmlSnippet; -import static org.springframework.ide.vscode.yaml.util.Description.*; +import static org.springframework.ide.vscode.util.HtmlSnippet.*; /** * Static methods and convenience constants for creating some 'description providers'. @@ -28,33 +29,33 @@ public class DescriptionProviders { final static Logger logger = LoggerFactory.getLogger(DescriptionProviders.class); - public static final Provider NO_DESCRIPTION = () -> italic(text("no description")); + public static final Provider NO_DESCRIPTION = () -> italic(text("no description")); - public static Provider snippet(final Description snippet) { - return new Provider() { + public static Provider snippet(final HtmlSnippet snippet) { + return new Provider() { @Override public String toString() { return snippet.toString(); } @Override - public Description get() { + public HtmlSnippet get() { return snippet; } }; } - public static Provider fromClasspath(final Class klass, final String resourcePath) { - return new Provider() { + public static Provider fromClasspath(final Class klass, final String resourcePath) { + return new Provider() { @Override public String toString() { return "DescriptionFromClassPth(class="+klass.getSimpleName()+", "+resourcePath+")"; } @Override - public Description get() { + public HtmlSnippet get() { try { InputStream stream = klass.getResourceAsStream(resourcePath); if (stream!=null) { - return Description.text(IOUtil.toString(stream)); + return HtmlSnippet.text(IOUtil.toString(stream)); } } catch (Exception e) { logger.error("Error", e);; diff --git a/vscode-extensions/commons/commons-yaml/src/test/java/org/springframework/ide/vscode/yaml/structure/YamlStructureParserTest.java b/vscode-extensions/commons/commons-yaml/src/test/java/org/springframework/ide/vscode/yaml/structure/YamlStructureParserTest.java index 12a1789eb..5ac7a2b12 100644 --- a/vscode-extensions/commons/commons-yaml/src/test/java/org/springframework/ide/vscode/yaml/structure/YamlStructureParserTest.java +++ b/vscode-extensions/commons/commons-yaml/src/test/java/org/springframework/ide/vscode/yaml/structure/YamlStructureParserTest.java @@ -21,7 +21,7 @@ import java.util.ArrayList; import java.util.regex.Pattern; import org.junit.Test; -import org.springframework.ide.vscode.util.TextDocument; +import org.springframework.ide.vscode.commons.languageserver.util.TextDocument; import org.springframework.ide.vscode.yaml.path.YamlPath; import org.springframework.ide.vscode.yaml.path.YamlPathSegment; import org.springframework.ide.vscode.yaml.structure.YamlStructureParser.SChildBearingNode; diff --git a/vscode-extensions/commons/language-server-test-harness/pom.xml b/vscode-extensions/commons/language-server-test-harness/pom.xml index 8e33e6f6b..76b81e7c5 100644 --- a/vscode-extensions/commons/language-server-test-harness/pom.xml +++ b/vscode-extensions/commons/language-server-test-harness/pom.xml @@ -29,6 +29,11 @@ io.typefox.lsapi.annotations ${lsapi-version} + + org.springframework.ide.vscode + commons-java + ${project.version} + junit junit diff --git a/vscode-extensions/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/testharness/IType.java b/vscode-extensions/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/testharness/IType.java deleted file mode 100644 index 6ed7f2d34..000000000 --- a/vscode-extensions/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/testharness/IType.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.springframework.ide.vscode.testharness; - -/** - * Replaces eclipse JDT IType. Maybe we keep this maybe not, if keep, it should move to some - * other place, not stay here in the testharness. - */ -public interface IType { - -} diff --git a/vscode-extensions/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/testharness/TestProject.java b/vscode-extensions/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/testharness/TestProject.java deleted file mode 100644 index 1c06ceb61..000000000 --- a/vscode-extensions/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/testharness/TestProject.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.springframework.ide.vscode.testharness; - -import java.nio.file.Path; - -public interface TestProject { - - Path getPath(); - - IType findType(String string); - -} diff --git a/vscode-extensions/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/testharness/TestProjectHarness.java b/vscode-extensions/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/testharness/TestProjectHarness.java new file mode 100644 index 000000000..4593ca46f --- /dev/null +++ b/vscode-extensions/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/testharness/TestProjectHarness.java @@ -0,0 +1,66 @@ +package org.springframework.ide.vscode.testharness; + +import static org.junit.Assert.assertTrue; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.springframework.ide.vscode.java.IJavaProject; +import org.springframework.ide.vscode.java.IType; +import org.springframework.ide.vscode.util.ExternalCommand; +import org.springframework.ide.vscode.util.ExternalProcess; +import org.springframework.ide.vscode.util.HtmlSnippet; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; + +/** + * Class meant to be used in writing tests that require test projects to be populated + * from some data on the classpath. + */ +public class TestProjectHarness { + + public Cache cache = CacheBuilder.newBuilder().build(); + + public IJavaProject get(String name) throws Exception { + Path testProjectPath = Paths.get(TestProjectHarness.class.getResource("/demo-1").toURI()); + assertTrue(Files.exists(testProjectPath)); + if (!Files.exists(testProjectPath.resolve("classpath.txt"))) { + testProjectPath.resolve("mvnw").toFile().setExecutable(true); + ExternalProcess process = new ExternalProcess(testProjectPath.toFile(), new ExternalCommand("./mvnw", "clean", "package"), true); + if (process.getExitValue() != 0) { + throw new RuntimeException("Failed to build test project"); + } + } + return new IJavaProject() { + + @Override + public HtmlSnippet getJavaDoc() { + return null; + } + + @Override + public String getElementName() { + return name; + } + + @Override + public boolean exists() { + return true; + } + + @Override + public Path getPath() { + return testProjectPath; + } + + @Override + public IType findType(String string) { + //throw new UnsupportedOperationException("Not yet implemented"); + return null; + } + }; + } + +} diff --git a/vscode-extensions/commons/pom.xml b/vscode-extensions/commons/pom.xml index e41b048b6..5892de458 100644 --- a/vscode-extensions/commons/pom.xml +++ b/vscode-extensions/commons/pom.xml @@ -14,11 +14,13 @@ language-server-test-harness commons-yaml commons-util + commons-java java-properties application-properties-metadata + 1.17 4.11 3.5.2 1.7.21 diff --git a/vscode-extensions/vscode-application-properties/src/main/java/org/springframework/ide/vscode/boot/properties/ApplicationPropertiesLanguageServer.java b/vscode-extensions/vscode-application-properties/src/main/java/org/springframework/ide/vscode/boot/properties/ApplicationPropertiesLanguageServer.java index 304e3085a..dcefcbab6 100644 --- a/vscode-extensions/vscode-application-properties/src/main/java/org/springframework/ide/vscode/boot/properties/ApplicationPropertiesLanguageServer.java +++ b/vscode-extensions/vscode-application-properties/src/main/java/org/springframework/ide/vscode/boot/properties/ApplicationPropertiesLanguageServer.java @@ -12,12 +12,12 @@ package org.springframework.ide.vscode.boot.properties; import java.util.stream.Collectors; +import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; +import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService; +import org.springframework.ide.vscode.commons.languageserver.util.TextDocument; import org.springframework.ide.vscode.properties.antlr.parser.AntlrParser; import org.springframework.ide.vscode.properties.parser.ParseResults; import org.springframework.ide.vscode.properties.parser.Parser; -import org.springframework.ide.vscode.util.SimpleLanguageServer; -import org.springframework.ide.vscode.util.SimpleTextDocumentService; -import org.springframework.ide.vscode.util.TextDocument; import io.typefox.lsapi.Diagnostic; import io.typefox.lsapi.DiagnosticSeverity; diff --git a/vscode-extensions/vscode-application-properties/src/main/java/org/springframework/ide/vscode/boot/properties/Main.java b/vscode-extensions/vscode-application-properties/src/main/java/org/springframework/ide/vscode/boot/properties/Main.java index 4aee322ca..01b658605 100644 --- a/vscode-extensions/vscode-application-properties/src/main/java/org/springframework/ide/vscode/boot/properties/Main.java +++ b/vscode-extensions/vscode-application-properties/src/main/java/org/springframework/ide/vscode/boot/properties/Main.java @@ -20,7 +20,7 @@ import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.logging.Logger; -import org.springframework.ide.vscode.util.LoggingFormat; +import org.springframework.ide.vscode.commons.languageserver.util.LoggingFormat; import io.typefox.lsapi.services.json.LoggingJsonAdapter; diff --git a/vscode-extensions/vscode-application-yaml/pom.xml b/vscode-extensions/vscode-application-yaml/pom.xml index 65011bbe7..fbff35022 100644 --- a/vscode-extensions/vscode-application-yaml/pom.xml +++ b/vscode-extensions/vscode-application-yaml/pom.xml @@ -46,6 +46,12 @@ commons-language-server ${project.version} + + + org.springframework.ide.vscode + commons-java + ${project.version} + org.springframework.ide.vscode @@ -53,6 +59,11 @@ ${project.version} + + org.springframework.ide.vscode + commons-yaml + ${project.version} + org.yaml snakeyaml diff --git a/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/ApplicationYamlLanguageServer.java b/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/ApplicationYamlLanguageServer.java index 1172e25e7..88889cd53 100644 --- a/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/ApplicationYamlLanguageServer.java +++ b/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/ApplicationYamlLanguageServer.java @@ -1,45 +1,46 @@ package org.springframework.ide.vscode.yaml; -import java.io.StringReader; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.concurrent.CompletableFuture; +import org.springframework.ide.vscode.boot.properties.metadata.SpringPropertyIndexProvider; +import org.springframework.ide.vscode.boot.properties.metadata.types.TypeUtilProvider; +import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcileEngine; +import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; +import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService; +import org.springframework.ide.vscode.commons.languageserver.util.TextDocument; import org.springframework.ide.vscode.util.Futures; -import org.springframework.ide.vscode.util.SimpleLanguageServer; -import org.springframework.ide.vscode.util.SimpleTextDocumentService; -import org.springframework.ide.vscode.util.TextDocument; +import org.springframework.ide.vscode.yaml.ast.YamlASTProvider; +import org.springframework.ide.vscode.yaml.ast.YamlParser; +import org.springframework.ide.vscode.yaml.reconcile.ApplicationYamlReconcileEngine; import org.yaml.snakeyaml.Yaml; -import org.yaml.snakeyaml.error.MarkedYAMLException; -import org.yaml.snakeyaml.error.YAMLException; -import org.yaml.snakeyaml.nodes.Node; - -import com.google.common.collect.ImmutableList; import io.typefox.lsapi.CompletionItem; import io.typefox.lsapi.CompletionItemKind; import io.typefox.lsapi.CompletionList; -import io.typefox.lsapi.DiagnosticSeverity; import io.typefox.lsapi.TextDocumentSyncKind; import io.typefox.lsapi.impl.CompletionItemImpl; import io.typefox.lsapi.impl.CompletionListImpl; import io.typefox.lsapi.impl.CompletionOptionsImpl; -import io.typefox.lsapi.impl.DiagnosticImpl; -import io.typefox.lsapi.impl.PositionImpl; -import io.typefox.lsapi.impl.RangeImpl; import io.typefox.lsapi.impl.ServerCapabilitiesImpl; public class ApplicationYamlLanguageServer extends SimpleLanguageServer { private Yaml yaml = new Yaml(); + private YamlASTProvider parser = new YamlParser(yaml); + private SpringPropertyIndexProvider indexProvider; + private TypeUtilProvider typeUtilProvider; - public ApplicationYamlLanguageServer() { + public ApplicationYamlLanguageServer(SpringPropertyIndexProvider indexProvider, TypeUtilProvider typeUtilProvider) { + this.indexProvider = indexProvider; + this.typeUtilProvider = typeUtilProvider; SimpleTextDocumentService documents = getTextDocumentService(); // SimpleWorkspaceService workspace = getWorkspaceService(); + IReconcileEngine reconcileEngine = getReconcileEngine(); documents.onDidChangeContent(params -> { TextDocument doc = params.getDocument(); - validateDocument(documents, doc); + validateWith(doc, reconcileEngine); }); // workspace.onDidChangeConfiguraton(settings -> { @@ -103,54 +104,8 @@ public class ApplicationYamlLanguageServer extends SimpleLanguageServer { }); } - private void validateDocument(SimpleTextDocumentService documents, TextDocument doc) { - List diagnostics = reconcile(documents, doc); - documents.publishDiagnostics(doc, diagnostics); - } - - protected List reconcile(SimpleTextDocumentService documents, TextDocument doc) { - try { - Iterator asts = yaml.composeAll(new StringReader(doc.getText())).iterator(); - while (asts.hasNext()) { - asts.next(); - } - return ImmutableList.of(); - } catch (YAMLException e) { - return ImmutableList.of(parseError(e)); - } - } - - private DiagnosticImpl parseError(YAMLException e) { - DiagnosticImpl d = new DiagnosticImpl(); - d.setMessage(getMessage(e)); - d.setRange(getRange(e)); - d.setSeverity(DiagnosticSeverity.Error); - d.setCode(ErrorCodes.YAML_SYNTAX_ERROR); - d.setSource("yaml"); - return d; - } - - private String getMessage(YAMLException e) { - if (e instanceof MarkedYAMLException) { - return ((MarkedYAMLException) e).getProblem(); - } - return e.getMessage(); - } - - private RangeImpl getRange(YAMLException _e) { - if (_e instanceof MarkedYAMLException) { - MarkedYAMLException e = (MarkedYAMLException) _e; - - PositionImpl start = new PositionImpl(); - start.setLine(e.getProblemMark().getLine()); - start.setCharacter(e.getProblemMark().getColumn()); - - RangeImpl rng = new RangeImpl(); - rng.setStart(start); - rng.setEnd(start); - return rng; - } - return null; + protected IReconcileEngine getReconcileEngine() { + return new ApplicationYamlReconcileEngine(parser, indexProvider, typeUtilProvider); } @Override diff --git a/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/ApplicationYamlProblems.java b/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/ApplicationYamlProblems.java new file mode 100644 index 000000000..652fe71a2 --- /dev/null +++ b/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/ApplicationYamlProblems.java @@ -0,0 +1,43 @@ +package org.springframework.ide.vscode.yaml; + +import static org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemSeverity.ERROR; + +import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemSeverity; +import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType; +import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem; +import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl; + +public class ApplicationYamlProblems { + + public static enum Type implements ProblemType { + + YAML_SYNTAX_ERROR; + + Type() { + this(ERROR); + } + + Type(ProblemSeverity defaultSeverity) { + this.severity = defaultSeverity; + } + + private final ProblemSeverity severity; + + @Override + public ProblemSeverity getDefaultSeverity() { + return severity; + } + + @Override + public String getCode() { + return name(); + } + + } + + public static final String YAML_SYNTAX_ERROR = "YAML_SYNTAX_ERROR"; + + public static ReconcileProblem problem(Type type, String msg, int offset, int len) { + return new ReconcileProblemImpl(type, msg, offset, len); + } +} diff --git a/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/DefaultSpringPropertyIndexProvider.java b/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/DefaultSpringPropertyIndexProvider.java new file mode 100644 index 000000000..a001c9443 --- /dev/null +++ b/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/DefaultSpringPropertyIndexProvider.java @@ -0,0 +1,31 @@ +package org.springframework.ide.vscode.yaml; + +import java.nio.file.Path; + +import org.springframework.ide.vscode.boot.properties.metadata.PropertyInfo; +import org.springframework.ide.vscode.boot.properties.metadata.SpringPropertiesIndexManager; +import org.springframework.ide.vscode.boot.properties.metadata.SpringPropertyIndexProvider; +import org.springframework.ide.vscode.boot.properties.metadata.ValueProviderRegistry; +import org.springframework.ide.vscode.boot.properties.util.FuzzyMap; +import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; +import org.springframework.ide.vscode.java.IJavaProject; + +public class DefaultSpringPropertyIndexProvider implements SpringPropertyIndexProvider { + + private JavaProjectFinder javaProjectFinder = JavaProjectFinder.DEFAULT; + private SpringPropertiesIndexManager indexManager = new SpringPropertiesIndexManager(ValueProviderRegistry.getDefault()); + + @Override + public FuzzyMap getIndex(IDocument doc) { + IJavaProject jp = javaProjectFinder.find(doc); + if (jp!=null) { + Path projectFolder = jp.getPath(); + if (projectFolder!=null) { + return indexManager.get(projectFolder); + } + } + return null; + } + +} diff --git a/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/ErrorCodes.java b/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/ErrorCodes.java deleted file mode 100644 index fce1b8d27..000000000 --- a/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/ErrorCodes.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.springframework.ide.vscode.yaml; - -public class ErrorCodes { - public static final String YAML_SYNTAX_ERROR = "YAML_SYNTAX_ERROR"; -} diff --git a/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/Main.java b/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/Main.java index 90a575fd1..4c92da780 100644 --- a/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/Main.java +++ b/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/Main.java @@ -6,11 +6,14 @@ import java.io.OutputStream; import java.io.PrintStream; import java.io.PrintWriter; import java.net.Socket; -import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.logging.Logger; -import org.springframework.ide.vscode.util.LoggingFormat; +import org.springframework.ide.vscode.boot.properties.metadata.SpringPropertyIndexProvider; +import org.springframework.ide.vscode.boot.properties.metadata.types.TypeUtil; +import org.springframework.ide.vscode.boot.properties.metadata.types.TypeUtilProvider; +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; +import org.springframework.ide.vscode.commons.languageserver.util.LoggingFormat; import io.typefox.lsapi.services.json.LoggingJsonAdapter; @@ -79,7 +82,14 @@ public class Main { * When the request stream is closed, wait for 5s for all outstanding responses to compute, then return. */ public static void run(Connection connection) { - ApplicationYamlLanguageServer server = new ApplicationYamlLanguageServer(); + //TODO: proper TypeUtilProvider and IndexProvider that somehow determine classpath that should be + // in effect for given IDocument and provide TypeUtil or SpringPropertyIndex parsed from that classpath. + // Note that the provider is responsible for doing some kind of sensible caching so that indexes are not + // rebuilt every time the index is being used. + SpringPropertyIndexProvider indexProvider = new DefaultSpringPropertyIndexProvider(); + TypeUtil typeUtil = new TypeUtil(null); + TypeUtilProvider typeUtilProvider = (IDocument doc) -> typeUtil; + ApplicationYamlLanguageServer server = new ApplicationYamlLanguageServer(indexProvider, typeUtilProvider); LoggingJsonAdapter jsonServer = new LoggingJsonAdapter(server); jsonServer.setMessageLog(new PrintWriter(System.out)); diff --git a/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/quickfix/ReplaceDeprecatedYamlQuickfix.java b/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/quickfix/ReplaceDeprecatedYamlQuickfix.java new file mode 100644 index 000000000..5e60c2e4b --- /dev/null +++ b/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/quickfix/ReplaceDeprecatedYamlQuickfix.java @@ -0,0 +1,173 @@ +/******************************************************************************* + * Copyright (c) 2016 Pivotal, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.yaml.quickfix; + +import java.awt.Image; +import java.awt.Point; + +import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits; +import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal; +import org.springframework.ide.vscode.commons.languageserver.completion.ProposalApplier; +import org.springframework.ide.vscode.commons.languageserver.quickfix.ProblemFixer; +import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixContext; +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; +import org.springframework.ide.vscode.util.Log; +import org.springframework.ide.vscode.yaml.completion.YamlPathEdits; +import org.springframework.ide.vscode.yaml.path.YamlPath; +import org.springframework.ide.vscode.yaml.reconcile.SpringPropertyProblem; +import org.springframework.ide.vscode.yaml.structure.YamlDocument; +import org.springframework.ide.vscode.yaml.structure.YamlStructureParser.SChildBearingNode; +import org.springframework.ide.vscode.yaml.structure.YamlStructureParser.SDocNode; +import org.springframework.ide.vscode.yaml.structure.YamlStructureParser.SKeyNode; +import org.springframework.ide.vscode.yaml.structure.YamlStructureParser.SNode; +import org.springframework.ide.vscode.yaml.structure.YamlStructureParser.SNodeType; +import org.springframework.ide.vscode.yaml.structure.YamlStructureProvider; + +import io.typefox.lsapi.CompletionItemKind; + +@SuppressWarnings("restriction") +public class ReplaceDeprecatedYamlQuickfix implements ICompletionProposal { + + public static ProblemFixer FIXER = (context, problem, proposals) -> { + throw new UnsupportedOperationException("Not yet implemented"); +// PropertyInfo metadata = problem.getMetadata(); +// if (metadata!=null) { +// String replacement = metadata.getDeprecationReplacement(); +// if (replacement!=null) { +// //No need to check problem type... we only attach this fixer to problems of applicable type. +// proposals.add(new ReplaceDeprecatedYamlQuickfix(context, problem)); +// } +// } + }; + + @Override + public ICompletionProposal deemphasize() { + throw new UnsupportedOperationException("Not yet implemented"); + } + @Override + public String getLabel() { + throw new UnsupportedOperationException("Not yet implemented"); + } + @Override + public CompletionItemKind getKind() { + throw new UnsupportedOperationException("Not yet implemented"); + } + @Override + public DocumentEdits getTextEdit() { + throw new UnsupportedOperationException("Not yet implemented"); + } + +// private final QuickfixContext context; +// private final SpringPropertyProblem problem; +// +// private LazyProposalApplier applier = new LazyProposalApplier() { +// protected ProposalApplier create() throws Exception { +// String newName = problem.getMetadata().getDeprecationReplacement(); +// String oldName = problem.getPropertyName(); +// YamlPath newPath = YamlPath.fromProperty(newName); +// YamlPath oldPath = YamlPath.fromProperty(oldName); +// YamlPath prefix = newPath.commonPrefix(oldPath); +// if (prefix.size()==newPath.size()-1 && newPath.size()==oldPath.size()) { +// //only the last segment has changed. We can do a simple 'in-place' replace +// // of just the change segment. +// DocumentEdits edits = new DocumentEdits(context.getDocument()); +// edits.replace(problem.getOffset(), problem.getEnd(), newPath.getLastSegment().toPropString()); +// return edits; +// } +// YamlDocument doc = new YamlDocument(context.getDocument(), YamlStructureProvider.DEFAULT); +// SNode problemNode = doc.getStructure().find(problem.getOffset()); +// if (problemNode.getNodeType()==SNodeType.KEY) { +// SKeyNode problemKey = (SKeyNode) problemNode; +// if (problemKey.isInKey(problem.getOffset())) { +// YamlPathEdits edits = new YamlPathEdits(doc); +//// print(doc, edits); +// String valueText = problemKey.getValueWithRelativeIndent(); +// edits.deleteNode(problemKey); +// int maxParentDeletions = oldPath.size() - prefix.size() - 1; // don't delete bits of the common prefix! +// SChildBearingNode parent = problemNode.getParent(); +// while (maxParentDeletions>0 && parent!=null && parent.getChildren().size()==1) { +// edits.deleteNode(parent); +// parent = parent.getParent(); +// maxParentDeletions--; +// } +//// print(doc, edits); +// SDocNode docRoot = problemNode.getDocNode(); //edits should stay within the same 'document' for yaml file that has multiple documents inside of it. +// edits.createPath(docRoot, YamlPath.fromProperty(newName), valueText); +//// print(doc, edits); +// return edits; +// } +// } +// //Not sure what to do... case not covered... so do nothing but tell the user. +// context.getUI().error("Yaml file too complex", +// "Sorry, but the yaml file is too complex for this quickfix. " + +// "Please make the change manually." +// ); +// return ProposalApplier.NULL; +// } +// +//// private void print(YamlDocument doc, YamlPathEdits edits) throws Exception { +//// Document workingCopy = new Document(doc.getDocument().get()); +//// edits.apply(workingCopy); +//// System.out.println("=============="); +//// System.out.println(workingCopy.get()); +//// System.out.println("=============="); +//// } +// }; +// +// public ReplaceDeprecatedYamlQuickfix(QuickfixContext context, SpringPropertyProblem problem) { +// this.context = context; +// this.problem = problem; +// } +// +// @Override +// public void apply(IDocument doc) { +// try { +// applier.apply(doc); +// } catch (Exception e) { +// Log.log(e); +// } +// } +// +// private String getReplacementProperty() { +// return problem.getMetadata().getDeprecationReplacement(); +// } +// +// @Override +// public Point getSelection(IDocument doc) { +// try { +// return applier.getSelection(doc); +// } catch (Exception e) { +// Log.log(e); +// return null; +// } +// } +// +// @Override +// public String getAdditionalProposalInfo() { +// return null; +// } +// +// @Override +// public String getDisplayString() { +// return "Change to '"+getReplacementProperty()+"'"; +// } +// +// @Override +// public Image getImage() { +// return JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); +// } +// +// @Override +// public IContextInformation getContextInformation() { +// return null; +// } + +} diff --git a/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/ApplicationYamlASTReconciler.java b/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/ApplicationYamlASTReconciler.java new file mode 100644 index 000000000..a34f6213d --- /dev/null +++ b/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/ApplicationYamlASTReconciler.java @@ -0,0 +1,379 @@ +package org.springframework.ide.vscode.yaml.reconcile; + +import static org.springframework.ide.vscode.yaml.ast.NodeUtil.asScalar; +import static org.springframework.ide.vscode.yaml.ast.YamlFileAST.getChildren; +import static org.springframework.ide.vscode.yaml.reconcile.SpringPropertiesProblemType.YAML_DEPRECATED; +import static org.springframework.ide.vscode.yaml.reconcile.SpringPropertiesProblemType.YAML_DUPLICATE_KEY; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.springframework.ide.vscode.boot.properties.metadata.IndexNavigator; +import org.springframework.ide.vscode.boot.properties.metadata.PropertyInfo; +import org.springframework.ide.vscode.boot.properties.metadata.types.Type; +import org.springframework.ide.vscode.boot.properties.metadata.types.TypeParser; +import org.springframework.ide.vscode.boot.properties.metadata.types.TypeUtil; +import org.springframework.ide.vscode.boot.properties.metadata.types.TypeUtil.BeanPropertyNameMode; +import org.springframework.ide.vscode.boot.properties.metadata.types.TypeUtil.EnumCaseMode; +import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector; +import org.springframework.ide.vscode.boot.properties.metadata.types.TypedProperty; +import org.springframework.ide.vscode.util.StringUtil; +import org.springframework.ide.vscode.util.ValueParser; +import org.springframework.ide.vscode.yaml.ast.NodeRef; +import org.springframework.ide.vscode.yaml.ast.NodeRef.Kind; +import org.springframework.ide.vscode.yaml.ast.NodeRef.TupleValueRef; +import org.springframework.ide.vscode.yaml.ast.NodeUtil; +import org.springframework.ide.vscode.yaml.ast.YamlFileAST; +import org.springframework.ide.vscode.yaml.quickfix.ReplaceDeprecatedYamlQuickfix; +import org.yaml.snakeyaml.nodes.MappingNode; +import org.yaml.snakeyaml.nodes.Node; +import org.yaml.snakeyaml.nodes.NodeId; +import org.yaml.snakeyaml.nodes.NodeTuple; +import org.yaml.snakeyaml.nodes.ScalarNode; +import org.yaml.snakeyaml.nodes.SequenceNode; + +/** + * @author Kris De Volder + */ +public class ApplicationYamlASTReconciler implements YamlASTReconciler { + + private final IProblemCollector problems; + private final TypeUtil typeUtil; + private final IndexNavigator nav; + + public ApplicationYamlASTReconciler(IProblemCollector problems, IndexNavigator nav, TypeUtil typeUtil) { + this.problems = problems; + this.typeUtil = typeUtil; + this.nav = nav; + } + + @Override + public void reconcile(YamlFileAST ast) { + reconcile(ast, nav); + } + + protected void reconcile(YamlFileAST ast, IndexNavigator nav) { + List nodes = ast.getNodes(); + if (nodes!=null && !nodes.isEmpty()) { + for (Node node : nodes) { + reconcile(node, nav); + } + } + } + + protected void reconcile(Node node, IndexNavigator nav) { + switch (node.getNodeId()) { + case mapping: + checkForDuplicateKeys((MappingNode)node); + for (NodeTuple entry : ((MappingNode)node).getValue()) { + reconcile(entry, nav); + } + break; + case scalar: + if (!isIgnoreScalarAssignmentTo(nav.getPrefix())) { + expectMapping(node); + } + break; + default: + expectMapping(node); + break; + } + } + + private void checkForDuplicateKeys(MappingNode node) { + Set duplicateKeys = new HashSet<>(); + Set seenKeys = new HashSet<>(); + for (NodeTuple entry : node.getValue()) { + String key = asScalar(entry.getKeyNode()); + if (key!=null) { + if (!seenKeys.add(key)) { + duplicateKeys.add(key); + } + } + } + if (!duplicateKeys.isEmpty()) { + for (NodeTuple entry : node.getValue()) { + Node keyNode = entry.getKeyNode(); + String key = asScalar(keyNode); + if (key!=null && duplicateKeys.contains(key)) { + problems.accept(problem(YAML_DUPLICATE_KEY, keyNode, "Duplicate key '"+key+"'")); + } + } + } + } + + protected boolean isIgnoreScalarAssignmentTo(String propName) { + //See https://issuetracker.springsource.com/browse/STS-4144 + return propName!=null && propName.equals("spring.profiles"); + } + + private void reconcile(NodeTuple entry, IndexNavigator nav) { + Node keyNode = entry.getKeyNode(); + String key = asScalar(keyNode); + if (key==null) { + expectScalar(keyNode); + } else { + IndexNavigator subNav = nav.selectSubProperty(key); + PropertyInfo match = subNav.getExactMatch(); + PropertyInfo extension = subNav.getExtensionCandidate(); + if (match==null && extension==null) { + //nothing found for this key. Maybe user is using camelCase variation of the key? + String keyAlias = StringUtil.camelCaseToHyphens(key); + IndexNavigator subNavAlias = nav.selectSubProperty(keyAlias); + match = subNavAlias.getExactMatch(); + extension = subNavAlias.getExtensionCandidate(); + if (match!=null || extension!=null) { + //Got something for the alias, so use that instead. + //Note: do not swap for alias unless we actually found something. + // This gives more logical errors (in terms of user's key, not its canonical alias) + subNav = subNavAlias; + } + } + if (match!=null && extension!=null) { + //This is an odd situation, the current prefix lands on a propery + //but there are also other properties that have it as a prefix. + //This ambiguity is hard to deal with and we choose not to do so for now + return; + } else if (match!=null) { + Type type = TypeParser.parse(match.getType()); + if (match.isDeprecated()) { + deprecatedProperty(match, keyNode); + } + reconcile(entry.getValueNode(), type); + } else if (extension!=null) { + //We don't really care about the extension only about the fact that it + // exists and so it is meaningful to continue checking... + Node valueNode = entry.getValueNode(); + reconcile(valueNode, subNav); + } else { + //both are null, this means there's no valid property with the current prefix + //whether exact or extending it with further navigation + unkownProperty(keyNode, subNav.getPrefix(), entry); + } + } + } + + /** + * Reconcile a node given the type that we expect the node to be. + */ + private void reconcile(Node node, Type type) { + if (type!=null) { + switch (node.getNodeId()) { + case scalar: + reconcile((ScalarNode)node, type); + break; + case sequence: + reconcile((SequenceNode)node, type); + break; + case mapping: + reconcile((MappingNode)node, type); + break; + case anchor: + //TODO: what should we do with anchor nodes + break; + default: + throw new IllegalStateException("Missing switch case"); + } + } + } + + private void reconcile(MappingNode mapping, Type type) { + checkForDuplicateKeys(mapping); + if (typeUtil.isAtomic(type)) { + expectTypeFoundMapping(type, mapping); + } else if (TypeUtil.isMap(type) || TypeUtil.isSequencable(type)) { + Type keyType = typeUtil.getKeyType(type); + Type valueType = TypeUtil.getDomainType(type); + if (keyType!=null) { + for (NodeTuple entry : mapping.getValue()) { + reconcile(entry.getKeyNode(), keyType); + } + } + if (valueType!=null) { + for (NodeTuple entry : mapping.getValue()) { + Node value = entry.getValueNode(); + Type nestedValueType = valueType; + if (value.getNodeId()==NodeId.mapping) { + //Some special cases to handle here!! + // See https://issuetracker.springsource.com/browse/STS-4254 + // See https://issuetracker.springsource.com/browse/STS-4335 + if (TypeUtil.isObject(valueType)) { + nestedValueType = type; + } else if (TypeUtil.isString(keyType) && typeUtil.isAtomic(valueType)) { + nestedValueType = type; + } + } + reconcile(entry.getValueNode(), nestedValueType); + } + } + } else { + // Neither atomic, map or sequence-like => bean-like + Map props = typeUtil.getPropertiesMap(type, EnumCaseMode.ALIASED, BeanPropertyNameMode.ALIASED); + if (props!=null) { + for (NodeTuple entry : mapping.getValue()) { + Node keyNode = entry.getKeyNode(); + String key = NodeUtil.asScalar(keyNode); + if (key==null) { + expectBeanPropertyName(keyNode, type); + } else { + if (!props.containsKey(key)) { + unknownBeanProperty(keyNode, type, key); + } else { + Node valNode = entry.getValueNode(); + TypedProperty typedProperty = props.get(key); + if (typedProperty!=null) { + if (typedProperty.isDeprecated()) { + deprecatedProperty(type, typedProperty, keyNode); + } + reconcile(valNode, typedProperty.getType()); + } + } + } + } + } + } + } + + private void reconcile(SequenceNode seq, Type type) { + if (typeUtil.isAtomic(type)) { + expectTypeFoundSequence(type, seq); + } else if (TypeUtil.isSequencable(type)) { + Type domainType = TypeUtil.getDomainType(type); + if (domainType!=null) { + for (Node element : seq.getValue()) { + reconcile(element, domainType); + } + } + } else { + expectTypeFoundSequence(type, seq); + } + } + + + private void reconcile(ScalarNode scalar, Type type) { + String stringValue = scalar.getValue(); + if (!stringValue.contains("${")) { //don't check anything with ${} expressions in it as we + // don't know its actual value + ValueParser valueParser = typeUtil.getValueParser(type); + if (valueParser!=null) { + // Tag tag = scalar.getTag(); //use the tag? Actually, boot tolerates String values + // even if integeger etc are expected. It has its ways of parsing the String to the + // expected type + try { + valueParser.parse(stringValue); + } catch (Exception e) { + //Couldn't parse + valueTypeMismatch(type, scalar); + } + } + } + } + + private void expectTypeFoundMapping(Type type, MappingNode node) { + expectType(SpringPropertiesProblemType.YAML_EXPECT_TYPE_FOUND_MAPPING, type, node); + } + + private void expectTypeFoundSequence(Type type, SequenceNode seq) { + expectType(SpringPropertiesProblemType.YAML_EXPECT_TYPE_FOUND_SEQUENCE, type, seq); + } + + private void valueTypeMismatch(Type type, ScalarNode scalar) { + expectType(SpringPropertiesProblemType.YAML_VALUE_TYPE_MISMATCH, type, scalar); + } + + private void unkownProperty(Node node, String name, NodeTuple entry) { + SpringPropertyProblem p = problem(SpringPropertiesProblemType.YAML_UNKNOWN_PROPERTY, node, "Unknown property '"+name+"'"); + p.setPropertyName(extendForQuickfix(StringUtil.camelCaseToHyphens(name), entry.getValueNode())); + problems.accept(p); + } + + private String extendForQuickfix(String name, Node node) { + if (node!=null) { + TupleValueRef child = getFirstTupleValue(getChildren(node)); + if (child!=null) { + String extra = NodeUtil.asScalar(child.getKey()); + if (extra!=null) { + return extendForQuickfix(name + "." + StringUtil.camelCaseToHyphens(extra), + child.get()); + } + } + } + //couldn't extend name any further + return name; + } + + private TupleValueRef getFirstTupleValue(List> children) { + for (NodeRef nodeRef : children) { + if (nodeRef.getKind()==Kind.VAL) { + return (TupleValueRef) nodeRef; + } + } + return null; + } + + private void expectScalar(Node node) { + problems.accept(problem(SpringPropertiesProblemType.YAML_EXPECT_SCALAR, node, "Expecting a 'Scalar' node but got "+describe(node))); + } + + protected void expectMapping(Node node) { + problems.accept(problem(SpringPropertiesProblemType.YAML_EXPECT_MAPPING, node, "Expecting a 'Mapping' node but got "+describe(node))); + } + + private void expectBeanPropertyName(Node keyNode, Type type) { + problems.accept(problem(SpringPropertiesProblemType.YAML_EXPECT_BEAN_PROPERTY_NAME, keyNode, "Expecting a bean-property name for object of type '"+typeUtil.niceTypeName(type)+"' " + + "but got "+describe(keyNode))); + } + + private void unknownBeanProperty(Node keyNode, Type type, String name) { + problems.accept(problem(SpringPropertiesProblemType.YAML_INVALID_BEAN_PROPERTY, keyNode, "Unknown property '"+name+"' for type '"+typeUtil.niceTypeName(type)+"'")); + } + + private void expectType(SpringPropertiesProblemType problemType, Type type, Node node) { + problems.accept(problem(problemType, node, "Expecting a '"+typeUtil.niceTypeName(type)+"' but got "+describe(node))); + } + + private void deprecatedProperty(PropertyInfo property, Node keyNode) { + SpringPropertyProblem problem = deprecatedPropertyProblem(property.getId(), null, keyNode, + property.getDeprecationReplacement(), property.getDeprecationReason()); + problem.setMetadata(property); + problem.setProblemFixer(ReplaceDeprecatedYamlQuickfix.FIXER); + problems.accept(problem); + } + + private void deprecatedProperty(Type contextType, TypedProperty property, Node keyNode) { + SpringPropertyProblem problem = deprecatedPropertyProblem(property.getName(), typeUtil.niceTypeName(contextType), + keyNode, property.getDeprecationReplacement(), property.getDeprecationReason()); + problems.accept(problem); + } + + protected SpringPropertyProblem deprecatedPropertyProblem(String name, String contextType, Node keyNode, + String replace, String reason) { + SpringPropertyProblem problem = problem(YAML_DEPRECATED, keyNode, TypeUtil.deprecatedPropertyMessage(name, contextType, replace, reason)); + problem.setPropertyName(name); + return problem; + } + + protected SpringPropertyProblem problem(SpringPropertiesProblemType type, Node node, String msg) { + int start = node.getStartMark().getIndex(); + int end = node.getEndMark().getIndex(); + return SpringPropertyProblem.problem(type, msg, start, end-start); + } + + private String describe(Node node) { + switch (node.getNodeId()) { + case scalar: + return "'"+((ScalarNode)node).getValue()+"'"; + case mapping: + return "a 'Mapping' node"; + case sequence: + return "a 'Sequence' node"; + case anchor: + return "a 'Anchor' node"; + default: + throw new IllegalStateException("Missing switch case"); + } + } + +} diff --git a/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/ApplicationYamlReconcileEngine.java b/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/ApplicationYamlReconcileEngine.java new file mode 100644 index 000000000..3d7ee2dbf --- /dev/null +++ b/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/ApplicationYamlReconcileEngine.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2015, 2016 Pivotal, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.yaml.reconcile; + +import static org.springframework.ide.vscode.yaml.ApplicationYamlProblems.Type.YAML_SYNTAX_ERROR; + +import org.springframework.ide.vscode.boot.properties.metadata.IndexNavigator; +import org.springframework.ide.vscode.boot.properties.metadata.PropertyInfo; +import org.springframework.ide.vscode.boot.properties.metadata.SpringPropertyIndexProvider; +import org.springframework.ide.vscode.boot.properties.metadata.types.TypeUtilProvider; +import org.springframework.ide.vscode.boot.properties.util.FuzzyMap; +import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector; +import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem; +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; +import org.springframework.ide.vscode.yaml.ApplicationYamlProblems; +import org.springframework.ide.vscode.yaml.ast.YamlASTProvider; + +public class ApplicationYamlReconcileEngine extends YamlReconcileEngine { + + private SpringPropertyIndexProvider indexProvider; + private TypeUtilProvider typeUtilProvider; + + public ApplicationYamlReconcileEngine(YamlASTProvider astProvider, SpringPropertyIndexProvider indexProvider, TypeUtilProvider typeUtilProvider) { + super(astProvider); + this.indexProvider = indexProvider; + this.typeUtilProvider = typeUtilProvider; + } + + protected YamlASTReconciler getASTReconciler(IDocument doc, IProblemCollector problemCollector) { + FuzzyMap index = indexProvider.getIndex(doc); + if (index!=null && !index.isEmpty()) { + IndexNavigator nav = IndexNavigator.with(index); + return new ApplicationYamlASTReconciler(problemCollector, nav, typeUtilProvider.getTypeUtil(doc)); + } + return null; + } + + @Override + protected ReconcileProblem syntaxError(String msg, int offset, int len) { + return ApplicationYamlProblems.problem(YAML_SYNTAX_ERROR, msg, offset, len); + } + +} diff --git a/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/SpringPropertiesProblemType.java b/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/SpringPropertiesProblemType.java new file mode 100644 index 000000000..57fa02036 --- /dev/null +++ b/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/SpringPropertiesProblemType.java @@ -0,0 +1,129 @@ +/******************************************************************************* + * Copyright (c) 2015 Pivotal, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.yaml.reconcile; + +import static org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemSeverity.*; + +import java.util.ArrayList; + +import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemSeverity; +import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType; + +/** + * @author Kris De Volder + */ +public enum SpringPropertiesProblemType implements ProblemType { + + // Naming: + // YAML_* for all problems in .yml files. + // PROP_* for all problems in .properties files. + // All enum values must start with one or the other (or some stuff will break!). + +// PROP_INVALID_BEAN_NAVIGATION("Accessing a 'bean property' in a type that doesn't have properties (e.g. like String or Integer)"), +// PROP_INVALID_INDEXED_NAVIGATION("Accessing a property using [] in a type that doesn't support that"), +// PROP_EXPECTED_DOT_OR_LBRACK("Unexpected character found where a '.' or '[' was expected"), +// PROP_NO_MATCHING_RBRACK("Found a '[' but no matching ']'"), +// PROP_NON_INTEGER_IN_BRACKETS("Use of [..] navigation with non-integer value"), +// PROP_VALUE_TYPE_MISMATCH("Expecting a value of a certain type, but value doesn't parse as such"), +// PROP_INVALID_BEAN_PROPERTY("Accessing a named property in a type that doesn't provide a property accessor with that name"), +// PROP_UNKNOWN_PROPERTY(WARNING, "Property-key not found in any configuration metadata on the project's classpath"), +// PROP_DEPRECATED(WARNING, "Property is marked as Deprecated"), +// PROP_DUPLICATE_KEY("Multiple assignments to the same property value"), + + YAML_SYNTAX_ERROR("Error parsing the input using snakeyaml"), + YAML_UNKNOWN_PROPERTY(WARNING, "Property-key not found in the configuration metadata on the project's classpath"), + YAML_VALUE_TYPE_MISMATCH("Expecting a value of a certain type, but value doesn't parse as such"), + YAML_EXPECT_SCALAR("Expecting a 'scalar' value but found something more complex."), + YAML_EXPECT_TYPE_FOUND_SEQUENCE("Found a 'sequence' node where a non 'list-like' type is expected"), + YAML_EXPECT_TYPE_FOUND_MAPPING("Found a 'mapping' node where a type that can't be treated as a 'property map' is expected"), + YAML_EXPECT_MAPPING("Expecting a 'mapping' node but found something else"), + YAML_EXPECT_BEAN_PROPERTY_NAME("Expecting a 'bean property' name but found something more complex"), + YAML_INVALID_BEAN_PROPERTY("Accessing a named property in a type that doesn't provide a property accessor with that name"), + YAML_DEPRECATED(WARNING, "Property is marked as Deprecated"), + YAML_DUPLICATE_KEY("A mapping node contains multiple entries for the same key"); + + private final ProblemSeverity defaultSeverity; + private String description; + private String label; + + private SpringPropertiesProblemType(ProblemSeverity defaultSeverity, String description, String label) { + this.description = description; + this.defaultSeverity = defaultSeverity; + this.label = label; + } + + private SpringPropertiesProblemType(ProblemSeverity defaultSeverity, String description) { + this(defaultSeverity, description, null); + } + + private SpringPropertiesProblemType(String description) { + this(ERROR, description); + } + + public ProblemSeverity getDefaultSeverity() { + return defaultSeverity; + } + + + public static SpringPropertiesProblemType[] forProperties() { + return withPrefix("PROP_"); + } + + + private static SpringPropertiesProblemType[] withPrefix(String prefix) { + SpringPropertiesProblemType[] allValues = values(); + ArrayList values = new ArrayList(allValues.length); + for (SpringPropertiesProblemType v : allValues) { + if (v.toString().startsWith(prefix)) { + values.add(v); + } + } + return values.toArray(new SpringPropertiesProblemType[values.size()]); + } + + public String getLabel() { + if (label==null) { + label = createDefaultLabel(); + } + return label; + } + + public String getDescription() { + return description; + } + + private String createDefaultLabel() { + String label = this.toString().substring(5).toLowerCase().replace('_', ' '); + return Character.toUpperCase(label.charAt(0)) + label.substring(1); + } + + @Override + public String getCode() { + return name(); + } + +// TODO: obsolete? We should simply keep the problemtype implementations for yaml / props editor totally separate +// public static final SpringPropertiesProblemType[] FOR_YAML = FOR(EditorType.YAML); +// public static final SpringPropertiesProblemType[] FOR_PROPERTIES = FOR(EditorType.PROP); +// public static SpringPropertiesProblemType[] FOR(EditorType et) { +// return withPrefix(et.getProblemTypePrefix()); +// } +// public EditorType getEditorType() { +// String string = this.toString(); +// for (EditorType et : EditorType.values()) { +// String prefix = et.getProblemTypePrefix(); +// if (string.startsWith(prefix)) { +// return et; +// } +// } +// throw new IllegalStateException("Bug: unknown editor type for "+this); +// } +} diff --git a/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/SpringPropertyProblem.java b/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/SpringPropertyProblem.java new file mode 100644 index 000000000..53ac32be7 --- /dev/null +++ b/vscode-extensions/vscode-application-yaml/src/main/java/org/springframework/ide/vscode/yaml/reconcile/SpringPropertyProblem.java @@ -0,0 +1,34 @@ +package org.springframework.ide.vscode.yaml.reconcile; + +import org.springframework.ide.vscode.boot.properties.metadata.PropertyInfo; +import org.springframework.ide.vscode.commons.languageserver.quickfix.ProblemFixer; +import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType; +import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl; + +public class SpringPropertyProblem extends ReconcileProblemImpl { + + private PropertyInfo property = null; + private ProblemFixer fixer; + private String propertyName; + + public SpringPropertyProblem(ProblemType type, String msg, int offset, int len) { + super(type, msg, offset, len); + } + + public static SpringPropertyProblem problem(SpringPropertiesProblemType type, String msg, int offset, int len) { + return new SpringPropertyProblem(type, msg, offset, len); + } + + public void setMetadata(PropertyInfo property) { + this.property = property; + } + + public void setProblemFixer(ProblemFixer fixer) { + this.fixer = fixer; + } + + public void setPropertyName(String name) { + propertyName = name; + } + +} diff --git a/vscode-extensions/vscode-application-yaml/src/test/java/org/springframework/ide/vscode/yaml/AbstractPropsEditorTest.java b/vscode-extensions/vscode-application-yaml/src/test/java/org/springframework/ide/vscode/yaml/AbstractPropsEditorTest.java index 0a07aab79..69e34e137 100644 --- a/vscode-extensions/vscode-application-yaml/src/test/java/org/springframework/ide/vscode/yaml/AbstractPropsEditorTest.java +++ b/vscode-extensions/vscode-application-yaml/src/test/java/org/springframework/ide/vscode/yaml/AbstractPropsEditorTest.java @@ -11,9 +11,13 @@ import java.util.Set; import org.junit.Before; import org.springframework.ide.vscode.boot.properties.metadata.SpringPropertyIndexProvider; +import org.springframework.ide.vscode.boot.properties.metadata.types.TypeUtil; +import org.springframework.ide.vscode.boot.properties.metadata.types.TypeUtilProvider; +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; +import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; +import org.springframework.ide.vscode.java.IJavaProject; import org.springframework.ide.vscode.testharness.Editor; import org.springframework.ide.vscode.testharness.LanguageServerHarness; -import org.springframework.ide.vscode.testharness.TestProject; import org.springframework.ide.vscode.yaml.PropertyIndexHarness.ItemConfigurer; import io.typefox.lsapi.CompletionItem; @@ -22,7 +26,16 @@ public class AbstractPropsEditorTest { private PropertyIndexHarness md; private LanguageServerHarness harness; - + private IJavaProject testProject; + private TypeUtil typeUtil; + + private TypeUtilProvider typeUtilProvider = (IDocument doc) -> { + if (typeUtil==null) { + typeUtil = new TypeUtil(testProject); + } + return typeUtil; + }; + public Editor newEditor(String contents) throws Exception { return harness.newEditor(contents); } @@ -30,10 +43,14 @@ public class AbstractPropsEditorTest { @Before public void setup() throws Exception { md = new PropertyIndexHarness(); - harness = new LanguageServerHarness(ApplicationYamlLanguageServer::new); + harness = new LanguageServerHarness(this::newLanguageServer); harness.intialize(null); } + private SimpleLanguageServer newLanguageServer() { + return new ApplicationYamlLanguageServer(md.getIndexProvider(), typeUtilProvider); + } + public ItemConfigurer data(String id, String type, Object deflt, String description, String... sources) { return md.data(id, type, deflt, description, sources); } @@ -42,13 +59,15 @@ public class AbstractPropsEditorTest { md.defaultTestData(); } - public TestProject createPredefinedMavenProject(String string) { + public IJavaProject createPredefinedMavenProject(String string) { notImplemented(); return null; } - public void useProject(TestProject p) { - notImplemented(); //only tests that don't require project context / classpath work for now + public void useProject(IJavaProject p) throws Exception { + md.useProject(p); + this.testProject = p; + this.typeUtil = null; } /** diff --git a/vscode-extensions/vscode-application-yaml/src/test/java/org/springframework/ide/vscode/yaml/ApplicationYamlEditorTest.java b/vscode-extensions/vscode-application-yaml/src/test/java/org/springframework/ide/vscode/yaml/ApplicationYamlEditorTest.java index e031a657c..62fa611a5 100644 --- a/vscode-extensions/vscode-application-yaml/src/test/java/org/springframework/ide/vscode/yaml/ApplicationYamlEditorTest.java +++ b/vscode-extensions/vscode-application-yaml/src/test/java/org/springframework/ide/vscode/yaml/ApplicationYamlEditorTest.java @@ -20,9 +20,8 @@ import org.junit.Ignore; import org.junit.Test; import org.springframework.ide.vscode.boot.properties.metadata.CachingValueProvider; import org.springframework.ide.vscode.boot.properties.metadata.PropertyInfo; +import org.springframework.ide.vscode.java.IJavaProject; import org.springframework.ide.vscode.testharness.Editor; -import org.springframework.ide.vscode.testharness.LanguageServerHarness; -import org.springframework.ide.vscode.testharness.TestProject; import org.springframework.ide.vscode.util.StringUtil; import io.typefox.lsapi.CompletionItem; @@ -40,9 +39,6 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { //////////////////////////////////////////////////////////////////////////////////////// @Test public void linterRunsOnDocumentOpenAndChange() throws Exception { - LanguageServerHarness harness = new LanguageServerHarness(ApplicationYamlLanguageServer::new); - harness.intialize(null); - Editor editor = newEditor( "somemap: val\n"+ "- sequence" @@ -110,7 +106,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { @Ignore @Test public void testHoverInfoForEnumValueInMapKey() throws Exception { Editor editor; - TestProject project = createPredefinedMavenProject("boot13"); + IJavaProject project = createPredefinedMavenProject("boot13"); useProject(project); //This test will fail if source jars haven't been downloaded. @@ -142,7 +138,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { } @Ignore @Test public void testHoverInfoForEnumValueInMapKeyCompletion() throws Exception { - TestProject project = createPredefinedMavenProject("boot13"); + IJavaProject project = createPredefinedMavenProject("boot13"); useProject(project); //This test will fail if source jars haven't been downloaded. @@ -226,7 +222,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { @Ignore @Test public void testHyperlinkTargets() throws Exception { System.out.println(">>> testHyperlinkTargets"); - TestProject p = createPredefinedMavenProject("demo"); + IJavaProject p = createPredefinedMavenProject("demo"); useProject(p); Editor editor = newEditor( @@ -252,7 +248,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { System.out.println("<<< testHyperlinkTargets"); } - @Test @Ignore public void testReconcile() throws Exception { + @Test public void testReconcile() throws Exception { defaultTestData(); Editor editor = newEditor( "server:\n" + @@ -266,6 +262,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { " no: \n" + " good: true\n" ); + System.out.println(editor); editor.assertProblems( "extracrap: 8080|Expecting a 'int' but got a 'Mapping' node", "snuggem|Unknown property", @@ -438,7 +435,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { @Ignore @Test public void testReconcileCamelCaseBeanProp() throws Exception { Editor editor; - TestProject p = createPredefinedMavenProject("demo"); + IJavaProject p = createPredefinedMavenProject("demo"); useProject(p); data("demo.bean", "demo.CamelCaser", "For testing tolerance of camelCase", null); @@ -492,7 +489,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { } @Ignore @Test public void testContentAssistCamelCaseBeanProp() throws Exception { - TestProject p = createPredefinedMavenProject("demo"); + IJavaProject p = createPredefinedMavenProject("demo"); useProject(p); data("demo.bean", "demo.CamelCaser", "For testing tolerance of camelCase", null); @@ -543,7 +540,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { @Ignore @Test public void testReconcileBeanPropName() throws Exception { - TestProject p = createPredefinedMavenProject("demo-list-of-pojo"); + IJavaProject p = createPredefinedMavenProject("demo-list-of-pojo"); useProject(p); assertNotNull(p.findType("demo.Foo")); data("some-foo", "demo.Foo", null, "some Foo pojo property"); @@ -575,7 +572,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { } @Ignore @Test public void testReconcilePojoArray() throws Exception { - TestProject p = createPredefinedMavenProject("demo-list-of-pojo"); + IJavaProject p = createPredefinedMavenProject("demo-list-of-pojo"); useProject(p); assertNotNull(p.findType("demo.Foo")); @@ -652,7 +649,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { } @Ignore @Test public void testEnumPropertyReconciling() throws Exception { - TestProject p = createPredefinedMavenProject("demo-enum"); + IJavaProject p = createPredefinedMavenProject("demo-enum"); useProject(p); assertNotNull(p.findType("demo.Color")); @@ -1834,7 +1831,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { } @Ignore @Test public void testEnumsInLowerCaseContentAssist() throws Exception { - TestProject p = createPredefinedMavenProject("demo-enum"); + IJavaProject p = createPredefinedMavenProject("demo-enum"); useProject(p); assertNotNull(p.findType("demo.ClothingSize")); @@ -2161,13 +2158,13 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { @Ignore @Test public void test_STS4231() throws Exception { //Should the 'predefined' project need to be recreated... use the commented code below: // BootProjectTestHarness projectHarness = new BootProjectTestHarness(ResourcesPlugin.getWorkspace()); -// TestProject project = projectHarness.createBootProject("sts-4231", +// IJavaProject project = projectHarness.createBootProject("sts-4231", // bootVersionAtLeast("1.3.0"), // withStarters("web", "cloud-config-server") // ); //For more robust test use predefined project which is not so much a moving target: - TestProject project = createPredefinedMavenProject("sts-4231"); + IJavaProject project = createPredefinedMavenProject("sts-4231"); useProject(project); assertCompletionsDisplayString( @@ -2418,7 +2415,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { } @Ignore @Test public void testDeprecatedBeanPropertyHoverInfo() throws Exception { - TestProject jp = createPredefinedMavenProject("demo"); + IJavaProject jp = createPredefinedMavenProject("demo"); useProject(jp); data("foo", "demo.Deprecater", null, "A bean with deprecated property."); Editor editor = newEditor( @@ -2431,7 +2428,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { } @Ignore @Test public void testDeprecatedBeanPropertyReconcile() throws Exception { - TestProject jp = createPredefinedMavenProject("demo"); + IJavaProject jp = createPredefinedMavenProject("demo"); useProject(jp); data("foo", "demo.Deprecater", null, "A Bean with deprecated properties"); @@ -2464,7 +2461,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { } @Ignore @Test public void testDeprecatedBeanPropertyCompletions() throws Exception { - TestProject jp = createPredefinedMavenProject("demo"); + IJavaProject jp = createPredefinedMavenProject("demo"); useProject(jp); data("foo", "demo.Deprecater", null, "A Bean with deprecated properties"); diff --git a/vscode-extensions/vscode-application-yaml/src/test/java/org/springframework/ide/vscode/yaml/ApplicationYamlLanguageServerTests.java b/vscode-extensions/vscode-application-yaml/src/test/java/org/springframework/ide/vscode/yaml/ApplicationYamlLanguageServerTests.java index 4d980c571..e384e6115 100644 --- a/vscode-extensions/vscode-application-yaml/src/test/java/org/springframework/ide/vscode/yaml/ApplicationYamlLanguageServerTests.java +++ b/vscode-extensions/vscode-application-yaml/src/test/java/org/springframework/ide/vscode/yaml/ApplicationYamlLanguageServerTests.java @@ -5,18 +5,14 @@ import static org.assertj.core.api.Assertions.assertThat; import java.io.File; import java.net.URISyntaxException; import java.nio.file.Paths; -import java.util.List; +import java.util.concurrent.Callable; import org.junit.Test; import org.springframework.ide.vscode.testharness.LanguageServerHarness; -import org.springframework.ide.vscode.testharness.TextDocumentInfo; -import org.springframework.ide.vscode.yaml.ApplicationYamlLanguageServer; -import io.typefox.lsapi.CompletionItem; -import io.typefox.lsapi.CompletionList; import io.typefox.lsapi.InitializeResult; -import io.typefox.lsapi.ServerCapabilities; import io.typefox.lsapi.TextDocumentSyncKind; +import io.typefox.lsapi.services.LanguageServer; public class ApplicationYamlLanguageServerTests { @@ -24,17 +20,23 @@ public class ApplicationYamlLanguageServerTests { return Paths.get(ApplicationYamlLanguageServerTests.class.getResource(name).toURI()).toFile(); } + private LanguageServerHarness newHarness() throws Exception { + Callable f = () -> new ApplicationYamlLanguageServer((d) -> null, (d) -> null); + return new LanguageServerHarness(f); + } + @Test public void createAndInitializeServerWithWorkspace() throws Exception { - LanguageServerHarness harness = new LanguageServerHarness(ApplicationYamlLanguageServer::new); + LanguageServerHarness harness = newHarness(); File workspaceRoot = getTestResource("/workspace/"); assertExpectedInitResult(harness.intialize(workspaceRoot)); } + @Test public void createAndInitializeServerWithoutWorkspace() throws Exception { File workspaceRoot = null; - LanguageServerHarness harness = new LanguageServerHarness(ApplicationYamlLanguageServer::new); + LanguageServerHarness harness = newHarness(); assertExpectedInitResult(harness.intialize(workspaceRoot)); } diff --git a/vscode-extensions/vscode-application-yaml/src/test/java/org/springframework/ide/vscode/yaml/PropertyIndexHarness.java b/vscode-extensions/vscode-application-yaml/src/test/java/org/springframework/ide/vscode/yaml/PropertyIndexHarness.java index aee4bc943..717e3dedd 100644 --- a/vscode-extensions/vscode-application-yaml/src/test/java/org/springframework/ide/vscode/yaml/PropertyIndexHarness.java +++ b/vscode-extensions/vscode-application-yaml/src/test/java/org/springframework/ide/vscode/yaml/PropertyIndexHarness.java @@ -14,8 +14,8 @@ import org.springframework.ide.vscode.boot.properties.metadata.SpringPropertyInd import org.springframework.ide.vscode.boot.properties.metadata.SpringPropertyIndexProvider; import org.springframework.ide.vscode.boot.properties.metadata.ValueProviderRegistry; import org.springframework.ide.vscode.boot.properties.util.FuzzyMap; -import org.springframework.ide.vscode.testharness.TestProject; -import org.springframework.ide.vscode.util.IDocument; +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; +import org.springframework.ide.vscode.java.IJavaProject; /** * Provides some convenience apis for test code to create / use test data for a SpringPropertyIndex. @@ -25,7 +25,7 @@ public class PropertyIndexHarness { private Map datas = new LinkedHashMap<>(); private ValueProviderRegistry valueProviders = ValueProviderRegistry.getDefault(); private SpringPropertyIndex index = null; - private TestProject testProject = null; + private IJavaProject testProject = null; protected SpringPropertyIndexProvider indexProvider = new SpringPropertyIndexProvider() { public FuzzyMap getIndex(IDocument doc) { @@ -40,6 +40,11 @@ public class PropertyIndexHarness { } }; + public void useProject(IJavaProject p) throws Exception { + index = null; + this.testProject = p; + } + public class ItemConfigurer { private ConfigurationMetadataProperty item; diff --git a/vscode-extensions/vscode-application-yaml/test/examples/application.yml b/vscode-extensions/vscode-application-yaml/test/examples/application.yml index 46d24e076..565aac561 100644 --- a/vscode-extensions/vscode-application-yaml/test/examples/application.yml +++ b/vscode-extensions/vscode-application-yaml/test/examples/application.yml @@ -1,2 +1,3 @@ foo: bar - asss +foo bar \ No newline at end of file diff --git a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/cloudfoundry/manifest/editor/Main.java b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/cloudfoundry/manifest/editor/Main.java index 898c6a942..85ba3ea23 100644 --- a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/cloudfoundry/manifest/editor/Main.java +++ b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/cloudfoundry/manifest/editor/Main.java @@ -9,7 +9,8 @@ import java.net.Socket; import java.util.logging.Level; import java.util.logging.Logger; -import org.springframework.ide.vscode.util.LoggingFormat; +import org.springframework.ide.vscode.commons.languageserver.util.LoggingFormat; +import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; import io.typefox.lsapi.services.json.LoggingJsonAdapter; @@ -78,7 +79,7 @@ public class Main { * When the request stream is closed, wait for 5s for all outstanding responses to compute, then return. */ public static void run(Connection connection) { - ManifestYamlLanguageServer server = new ManifestYamlLanguageServer(); + SimpleLanguageServer server = new ManifestYamlLanguageServer(); LoggingJsonAdapter jsonServer = new LoggingJsonAdapter(server); jsonServer.setMessageLog(new PrintWriter(System.out)); diff --git a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/cloudfoundry/manifest/editor/ManifestYamlLanguageServer.java b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/cloudfoundry/manifest/editor/ManifestYamlLanguageServer.java index e443cebfe..ce442d132 100644 --- a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/cloudfoundry/manifest/editor/ManifestYamlLanguageServer.java +++ b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/cloudfoundry/manifest/editor/ManifestYamlLanguageServer.java @@ -1,20 +1,15 @@ package org.springframework.ide.vscode.cloudfoundry.manifest.editor; -import java.util.ArrayList; import java.util.Collection; -import java.util.List; -import java.util.concurrent.CompletableFuture; import javax.inject.Provider; -import org.springframework.ide.vscode.commons.completion.ICompletionEngine; -import org.springframework.ide.vscode.commons.reconcile.IProblemCollector; -import org.springframework.ide.vscode.commons.reconcile.ReconcileProblem; -import org.springframework.ide.vscode.util.Futures; -import org.springframework.ide.vscode.util.SimpleLanguageServer; -import org.springframework.ide.vscode.util.SimpleTextDocumentService; -import org.springframework.ide.vscode.util.TextDocument; +import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcileEngine; +import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; +import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService; +import org.springframework.ide.vscode.commons.languageserver.util.TextDocument; import org.springframework.ide.vscode.yaml.ast.YamlASTProvider; +import org.springframework.ide.vscode.yaml.ast.YamlParser; import org.springframework.ide.vscode.yaml.completion.SchemaBasedYamlAssistContextProvider; import org.springframework.ide.vscode.yaml.completion.YamlAssistContextProvider; import org.springframework.ide.vscode.yaml.completion.YamlCompletionEngine; @@ -26,15 +21,8 @@ import org.yaml.snakeyaml.Yaml; import com.google.common.collect.ImmutableList; -import io.typefox.lsapi.CompletionItem; -import io.typefox.lsapi.CompletionItemKind; -import io.typefox.lsapi.CompletionList; -import io.typefox.lsapi.ServerCapabilities; import io.typefox.lsapi.TextDocumentSyncKind; -import io.typefox.lsapi.impl.CompletionItemImpl; -import io.typefox.lsapi.impl.CompletionListImpl; import io.typefox.lsapi.impl.CompletionOptionsImpl; -import io.typefox.lsapi.impl.DiagnosticImpl; import io.typefox.lsapi.impl.ServerCapabilitiesImpl; public class ManifestYamlLanguageServer extends SimpleLanguageServer { @@ -55,7 +43,7 @@ public class ManifestYamlLanguageServer extends SimpleLanguageServer { // SimpleWorkspaceService workspace = getWorkspaceService(); documents.onDidChangeContent(params -> { TextDocument doc = params.getDocument(); - validateDocument(documents, doc); + validateWith(doc, getReconcileEngine()); }); // workspace.onDidChangeConfiguraton(settings -> { @@ -73,34 +61,10 @@ public class ManifestYamlLanguageServer extends SimpleLanguageServer { documents.onCompletionResolve(completionEngine::resolveCompletion); } - private void validateDocument(SimpleTextDocumentService documents, TextDocument doc) { - IProblemCollector problems = new IProblemCollector() { - - private List diagnostics = new ArrayList<>(); - - @Override - public void endCollecting() { - documents.publishDiagnostics(doc, diagnostics); - } - - @Override - public void beginCollecting() { - diagnostics.clear(); - } - - @Override - public void accept(ReconcileProblem problem) { - DiagnosticImpl d = new DiagnosticImpl(); - d.setCode(problem.getCode()); - d.setMessage(problem.getMessage()); - d.setRange(doc.toRange(problem.getOffset(), problem.getLength())); - diagnostics.add(d); - } - }; - + protected IReconcileEngine getReconcileEngine() { YamlASTProvider parser = new YamlParser(yaml); - YamlSchemaBasedReconcileEngine engine = new YamlSchemaBasedReconcileEngine(parser, schema); - engine.reconcile(doc, problems); + IReconcileEngine engine = new YamlSchemaBasedReconcileEngine(parser, schema); + return engine; } @Override diff --git a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/cloudfoundry/manifest/editor/ManifestYmlSchema.java b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/cloudfoundry/manifest/editor/ManifestYmlSchema.java index 7b9e82bae..9be4e6e28 100644 --- a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/cloudfoundry/manifest/editor/ManifestYmlSchema.java +++ b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/cloudfoundry/manifest/editor/ManifestYmlSchema.java @@ -15,6 +15,7 @@ import java.util.Set; import javax.inject.Provider; +import org.springframework.ide.vscode.util.HtmlSnippet; import org.springframework.ide.vscode.yaml.schema.YType; import org.springframework.ide.vscode.yaml.schema.YTypeFactory; import org.springframework.ide.vscode.yaml.schema.YTypeFactory.YAtomicType; @@ -23,7 +24,6 @@ import org.springframework.ide.vscode.yaml.schema.YTypeFactory.YTypedPropertyImp import org.springframework.ide.vscode.yaml.schema.YTypeUtil; import org.springframework.ide.vscode.yaml.schema.YValueHint; import org.springframework.ide.vscode.yaml.schema.YamlSchema; -import org.springframework.ide.vscode.yaml.util.Description; import org.springframework.ide.vscode.yaml.util.DescriptionProviders; import com.google.common.collect.ImmutableSet; @@ -106,11 +106,11 @@ public class ManifestYmlSchema implements YamlSchema { } } - private Provider descriptionFor(String propName) { + private Provider descriptionFor(String propName) { return DescriptionProviders.fromClasspath(this.getClass(), "/description-by-prop-name/"+propName+".html"); } - private Provider descriptionFor(YTypedPropertyImpl prop) { + private Provider descriptionFor(YTypedPropertyImpl prop) { return descriptionFor(prop.getName()); } diff --git a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/cloudfoundry/manifest/editor/ManifestYmlValueParsers.java b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/cloudfoundry/manifest/editor/ManifestYmlValueParsers.java index 765b3ed6f..171a392aa 100644 --- a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/cloudfoundry/manifest/editor/ManifestYmlValueParsers.java +++ b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/cloudfoundry/manifest/editor/ManifestYmlValueParsers.java @@ -13,7 +13,7 @@ package org.springframework.ide.vscode.cloudfoundry.manifest.editor; import java.util.Set; import org.springframework.ide.vscode.util.Assert; -import org.springframework.ide.vscode.yaml.util.ValueParser; +import org.springframework.ide.vscode.util.ValueParser; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; diff --git a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/cloudfoundry/manifest/editor/VscodeCompletionEngineAdapter.java b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/cloudfoundry/manifest/editor/VscodeCompletionEngineAdapter.java index 98fcdb516..bb6e401fe 100644 --- a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/cloudfoundry/manifest/editor/VscodeCompletionEngineAdapter.java +++ b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/cloudfoundry/manifest/editor/VscodeCompletionEngineAdapter.java @@ -7,14 +7,14 @@ import java.util.concurrent.CompletableFuture; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.ide.vscode.commons.completion.DocumentEdits; -import org.springframework.ide.vscode.commons.completion.DocumentEdits.TextReplace; -import org.springframework.ide.vscode.commons.completion.ICompletionEngine; -import org.springframework.ide.vscode.commons.completion.ICompletionProposal; +import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits; +import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine; +import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal; +import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits.TextReplace; +import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; +import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService; +import org.springframework.ide.vscode.commons.languageserver.util.TextDocument; import org.springframework.ide.vscode.util.Futures; -import org.springframework.ide.vscode.util.SimpleLanguageServer; -import org.springframework.ide.vscode.util.SimpleTextDocumentService; -import org.springframework.ide.vscode.util.TextDocument; import org.springframework.ide.vscode.yaml.completion.DefaultCompletionFactory; import org.springframework.ide.vscode.yaml.structure.YamlStructureParser; diff --git a/vscode-extensions/vscode-manifest-yaml/src/test/java/org/springframework/ide/vscode/yaml/ManifestYmlSchemaTest.java b/vscode-extensions/vscode-manifest-yaml/src/test/java/org/springframework/ide/vscode/yaml/ManifestYmlSchemaTest.java index 36399ad99..00b5db39b 100644 --- a/vscode-extensions/vscode-manifest-yaml/src/test/java/org/springframework/ide/vscode/yaml/ManifestYmlSchemaTest.java +++ b/vscode-extensions/vscode-manifest-yaml/src/test/java/org/springframework/ide/vscode/yaml/ManifestYmlSchemaTest.java @@ -112,8 +112,8 @@ public class ManifestYmlSchemaTest { ////////////////////////////////////////////////////////////////////////////// private void assertHasRealDescription(YTypedProperty p) { - String noDescriptionText = DescriptionProviders.NO_DESCRIPTION.get().toText(); - String actual = p.getDescription().toText(); + String noDescriptionText = DescriptionProviders.NO_DESCRIPTION.get().toHtml(); + String actual = p.getDescription().toHtml(); String msg = "Description missing for '"+p.getName()+"'"; assertTrue(msg, StringUtil.hasText(actual)); assertFalse(msg, noDescriptionText.equals(actual));