diff --git a/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/EnumValueParser.java b/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/EnumValueParser.java index be6e16946..73a231735 100644 --- a/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/EnumValueParser.java +++ b/vscode-extensions/commons/commons-util/src/main/java/org/springframework/ide/vscode/commons/util/EnumValueParser.java @@ -11,6 +11,7 @@ package org.springframework.ide.vscode.commons.util; import java.util.Collection; +import java.util.concurrent.Callable; import javax.inject.Provider; @@ -32,15 +33,18 @@ public class EnumValueParser implements ValueParser { } public EnumValueParser(String typeName, Collection values) { - this(typeName, () -> values); + this(typeName, provider(values)); + } + public EnumValueParser(String typeName, Callable> values) { + this(typeName, provider(values)); } public EnumValueParser(String typeName, Provider> values) { this.typeName = typeName; this.values = values; } - - public Object parse(String str) { + + public Object parse(String str) { // IMPORTANT: check the text FIRST before fetching values // from the hints provider, as the hints provider may be expensive when resolving values if (!StringUtil.hasText(str)) { @@ -48,6 +52,7 @@ public class EnumValueParser implements ValueParser { } Collection values = this.values.get(); + //If values is not known (null) then just assume the str is acceptable. if (values==null || values.contains(str)) { return str; @@ -63,5 +68,21 @@ public class EnumValueParser implements ValueParser { protected String createErrorMessage(String parseString, Collection values) { return "'"+parseString+"' is not valid for Enum '"+typeName+"'. Valid values are: "+values; } + + + private static Provider provider(T values) { + return () -> values; + } + + private static Provider provider(Callable values) { + return () -> { + try { + return values.call(); + } catch (Exception e) { + // Ignore + return null; + } + }; + } } diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/CompletionFactory.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/CompletionFactory.java index 6275507ff..5f7b185b5 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/CompletionFactory.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/CompletionFactory.java @@ -24,5 +24,17 @@ public interface CompletionFactory { ICompletionProposal beanProperty(IDocument doc, String contextProperty, YType contextType, String query, YTypedProperty p, double score, DocumentEdits edits, YTypeUtil typeUtil); ICompletionProposal valueProposal(String value, String query, String label, YType type, double score, DocumentEdits edits, YTypeUtil typeUtil); - + + /** + * Creates a completion with an EMPTY value and a display message indicating some error condition. The purpose of this is + * to show the user a completion with some meaningful information on why completion values were not fetched. + * + * @param message the error message to display to the user in the completion + * @param query + * @param type + * @param edits + * @param typeUtil + * @return + */ + ICompletionProposal errorMessage(String message, String query, YType type, DocumentEdits edits, YTypeUtil typeUtil); } diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/DefaultCompletionFactory.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/DefaultCompletionFactory.java index 9ab544b84..8e22dbb69 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/DefaultCompletionFactory.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/DefaultCompletionFactory.java @@ -11,11 +11,11 @@ package org.springframework.ide.vscode.commons.yaml.completion; -import org.apache.commons.lang3.reflect.TypeUtils; import org.eclipse.lsp4j.CompletionItemKind; 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.ScoreableProposal; +import org.springframework.ide.vscode.commons.util.FuzzyMatcher; import org.springframework.ide.vscode.commons.util.Renderable; import org.springframework.ide.vscode.commons.util.text.IDocument; import org.springframework.ide.vscode.commons.yaml.hover.YPropertyInfoTemplates; @@ -145,4 +145,11 @@ public class DefaultCompletionFactory implements CompletionFactory { return new ValueProposal(value, query, label, type, score, edits, typeUtil); } + @Override + public ICompletionProposal errorMessage(String message, String query, YType type, DocumentEdits edits, + YTypeUtil typeUtil) { + String value = ""; // Empty value for the proposal. Purpose is to show a message with no value to fill in. + double score = FuzzyMatcher.matchScore(query, value); + return new ValueProposal(value, query, message, type, score, edits, typeUtil); + } } diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/YTypeAssistContext.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/YTypeAssistContext.java index e0cc9a5d1..e07c817ee 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/YTypeAssistContext.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/YTypeAssistContext.java @@ -23,6 +23,7 @@ import org.springframework.ide.vscode.commons.languageserver.completion.Document import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal; import org.springframework.ide.vscode.commons.languageserver.util.DocumentRegion; import org.springframework.ide.vscode.commons.util.CollectionUtil; +import org.springframework.ide.vscode.commons.util.ExceptionUtil; import org.springframework.ide.vscode.commons.util.FuzzyMatcher; import org.springframework.ide.vscode.commons.util.Log; import org.springframework.ide.vscode.commons.util.Renderable; @@ -41,6 +42,8 @@ import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureParser import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureParser.SNode; import org.springframework.ide.vscode.commons.yaml.util.YamlIndentUtil; +import com.google.common.collect.ImmutableList; + public class YTypeAssistContext extends AbstractYamlAssistContext { final static Logger logger = LoggerFactory.getLogger(YTypeAssistContext.class); @@ -147,7 +150,13 @@ public class YTypeAssistContext extends AbstractYamlAssistContext { } private List getValueCompletions(YamlDocument doc, int offset, String query) { - YValueHint[] values = typeUtil.getHintValues(type, getSchemaContext()); + YValueHint[] values=null; + try { + values = typeUtil.getHintValues(type, getSchemaContext()); + } catch (Exception e) { + DocumentEdits edits = new DocumentEdits(doc.getDocument()); + return ImmutableList.of(completionFactory().errorMessage(ExceptionUtil.getMessage(e), query, type, edits, typeUtil)); + } if (values!=null) { ArrayList completions = new ArrayList<>(); for (YValueHint value : values) { diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/YTypeFactory.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/YTypeFactory.java index 4ea3f21de..173accd7e 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/YTypeFactory.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/YTypeFactory.java @@ -11,7 +11,6 @@ package org.springframework.ide.vscode.commons.yaml.schema; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; @@ -20,11 +19,10 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.concurrent.Callable; import java.util.function.BiFunction; import java.util.stream.Collectors; -import javax.inject.Provider; - import org.springframework.ide.vscode.commons.util.Assert; import org.springframework.ide.vscode.commons.util.EnumValueParser; import org.springframework.ide.vscode.commons.util.Renderable; @@ -101,7 +99,7 @@ public class YTypeFactory { } @Override - public YValueHint[] getHintValues(YType type, DynamicSchemaContext dc) { + public YValueHint[] getHintValues(YType type, DynamicSchemaContext dc) throws Exception { return ((AbstractType)type).getHintValues(dc); } @@ -147,7 +145,7 @@ public class YTypeFactory { private List propertyList = new ArrayList<>(); private final List hints = new ArrayList<>(); private Map cachedPropertyMap; - private SchemaContextAware> hintProvider; + private SchemaContextAware>> hintProvider; public boolean isSequenceable() { return false; @@ -169,17 +167,17 @@ public class YTypeFactory { return null; } - public void addHintProvider(Provider> hintProvider) { - addHintProvider((DynamicSchemaContext dc) -> hintProvider.get()); + public void addHintProvider(Callable> hintProvider) { + addHintProvider((DynamicSchemaContext dc) -> hintProvider); } - public void addHintProvider(SchemaContextAware> hintProvider) { + public void addHintProvider(SchemaContextAware>> hintProvider) { this.hintProvider = hintProvider; } - public YValueHint[] getHintValues(DynamicSchemaContext dc) { - Collection providerHints = hintProvider != null ? hintProvider.withContext(dc) : null; - + public YValueHint[] getHintValues(DynamicSchemaContext dc) throws Exception { + Collection providerHints=getProviderHints(dc); + if (providerHints == null || providerHints.isEmpty()) { return hints.toArray(new YValueHint[hints.size()]); } else { @@ -199,6 +197,16 @@ public class YTypeFactory { } } + private Collection getProviderHints(DynamicSchemaContext dc) throws Exception { + if (hintProvider != null) { + Callable> withContext = hintProvider.withContext(dc); + if (withContext != null) { + return withContext.call(); + } + } + return ImmutableList.of(); + } + public List getProperties(DynamicSchemaContext dc) { return Collections.unmodifiableList(propertyList); } @@ -627,7 +635,7 @@ public class YTypeFactory { Collection strings = values.withContext(dc); return strings==null ? null - : strings.stream() + : () -> strings.stream() .map((s) -> new BasicYValueHint(s)) .collect(Collectors.toSet()); }); diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/YTypeUtil.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/YTypeUtil.java index 1b9bde220..b0348789d 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/YTypeUtil.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/YTypeUtil.java @@ -29,7 +29,7 @@ public interface YTypeUtil { boolean isSequencable(YType type); boolean isBean(YType type); YType getDomainType(YType type); - YValueHint[] getHintValues(YType yType, DynamicSchemaContext dc); + YValueHint[] getHintValues(YType yType, DynamicSchemaContext dc) throws Exception; String niceTypeName(YType type); YType getKeyType(YType type); ValueParser getValueParser(YType type, DynamicSchemaContext dc); diff --git a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/AbstractCFHintsProvider.java b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/AbstractCFHintsProvider.java index 58450ea76..58734d6e0 100644 --- a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/AbstractCFHintsProvider.java +++ b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/AbstractCFHintsProvider.java @@ -14,11 +14,10 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.concurrent.Callable; import java.util.logging.Level; import java.util.logging.Logger; -import javax.inject.Provider; - import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFTarget; import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFTargetCache; import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.NoTargetsException; @@ -27,7 +26,7 @@ import org.springframework.ide.vscode.commons.util.ExceptionUtil; import org.springframework.ide.vscode.commons.yaml.schema.BasicYValueHint; import org.springframework.ide.vscode.commons.yaml.schema.YValueHint; -public abstract class AbstractCFHintsProvider implements Provider> { +public abstract class AbstractCFHintsProvider implements Callable> { public static final String EMPTY_VALUE = ""; protected final CFTargetCache targetCache; @@ -40,7 +39,7 @@ public abstract class AbstractCFHintsProvider implements Provider get() { + public Collection call() throws Exception { Collection hints = new ArrayList<>(); // TODO: Probably not the most ideal thing to do, but for now show any // CF errors diff --git a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServer.java b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServer.java index 9cce8dee9..232499d01 100644 --- a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServer.java +++ b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServer.java @@ -11,8 +11,7 @@ package org.springframework.ide.vscode.manifest.yaml; import java.util.Collection; - -import javax.inject.Provider; +import java.util.concurrent.Callable; import org.eclipse.lsp4j.CompletionOptions; import org.eclipse.lsp4j.ServerCapabilities; @@ -56,8 +55,8 @@ public class ManifestYamlLanguageServer extends SimpleLanguageServer { YamlASTProvider parser = new YamlParser(yaml); - Provider> buildPacksProvider = getBuildpacksProvider(); - Provider> servicesProvider = getServicesProvider(); + Callable> buildPacksProvider = getBuildpacksProvider(); + Callable> servicesProvider = getServicesProvider(); schema = new ManifestYmlSchema(buildPacksProvider, servicesProvider); @@ -100,11 +99,11 @@ public class ManifestYamlLanguageServer extends SimpleLanguageServer { return cfTargetCache; } - private Provider> getBuildpacksProvider() { + private Callable> getBuildpacksProvider() { return new ManifestYamlCFBuildpacksProvider(getCfTargetCache()); } - private Provider> getServicesProvider() { + private Callable> getServicesProvider() { return new ManifestYamlCFServicesProvider(getCfTargetCache()); } diff --git a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYmlSchema.java b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYmlSchema.java index 819ee9c30..b792fd39b 100644 --- a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYmlSchema.java +++ b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYmlSchema.java @@ -12,8 +12,7 @@ package org.springframework.ide.vscode.manifest.yaml; import java.util.Collection; import java.util.Set; - -import javax.inject.Provider; +import java.util.concurrent.Callable; import org.springframework.ide.vscode.commons.util.Renderable; import org.springframework.ide.vscode.commons.util.Renderables; @@ -35,13 +34,13 @@ public class ManifestYmlSchema implements YamlSchema { private final YBeanType TOPLEVEL_TYPE; private final YTypeUtil TYPE_UTIL; - private final Provider> buildpackProvider; + private final Callable> buildpackProvider; private static final Set TOPLEVEL_EXCLUDED = ImmutableSet.of( "name", "host", "hosts" ); - public ManifestYmlSchema(Provider> buildpackProvider, Provider> servicesProvider) { + public ManifestYmlSchema(Callable> buildpackProvider, Callable> servicesProvider) { this.buildpackProvider = buildpackProvider; YTypeFactory f = new YTypeFactory(); TYPE_UTIL = f.TYPE_UTIL; diff --git a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYmlValueParsers.java b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYmlValueParsers.java index 0d922f9de..505377e26 100644 --- a/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYmlValueParsers.java +++ b/vscode-extensions/vscode-manifest-yaml/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYmlValueParsers.java @@ -12,8 +12,7 @@ package org.springframework.ide.vscode.manifest.yaml; import java.util.Collection; import java.util.Set; - -import javax.inject.Provider; +import java.util.concurrent.Callable; import org.springframework.ide.vscode.commons.util.Assert; import org.springframework.ide.vscode.commons.util.EnumValueParser; @@ -93,9 +92,9 @@ public class ManifestYmlValueParsers { }; } - public static ValueParser fromHints(String typeName, Provider> hintProvider) { - Provider> values= () -> { - Collection hints = hintProvider.get(); + public static ValueParser fromHints(String typeName, Callable> hintProvider) { + Callable> values= () -> { + Collection hints = hintProvider.call(); if (hints != null) { Builder builder = ImmutableSet.builder();