diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/common/AbstractPropertyRenderableProvider.java b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/common/AbstractPropertyRenderableProvider.java deleted file mode 100644 index 0f546b341..000000000 --- a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/common/AbstractPropertyRenderableProvider.java +++ /dev/null @@ -1,128 +0,0 @@ -/******************************************************************************* - * 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.common; - -import static org.springframework.ide.vscode.commons.util.Renderables.*; - -import java.util.Collection; - -import org.springframework.ide.vscode.commons.java.IJavaProject; -import org.springframework.ide.vscode.commons.util.Renderable; -import org.springframework.ide.vscode.commons.util.StringUtil; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableList.Builder; - -public abstract class AbstractPropertyRenderableProvider { - - public Renderable getRenderable() { - Builder renderableBuilder = ImmutableList.builder(); - - renderId(renderableBuilder); - - String type = getType(); - if (type==null) { - type = Object.class.getName(); - } - renderableBuilder.add(lineBreak()); - actionLink(renderableBuilder, type); - - String deflt = formatDefaultValue(getDefaultValue()); - if (deflt!=null) { - renderableBuilder.add(lineBreak()); - renderableBuilder.add(lineBreak()); - defaultValueRenderable(renderableBuilder, deflt); - } - - if (isDeprecated()) { - renderableBuilder.add(lineBreak()); - renderableBuilder.add(lineBreak()); - depreactionRenderable(renderableBuilder); - } - - Renderable description = getDescription(); - if (description!=null) { - renderableBuilder.add(lineBreak()); - descriptionRenderable(renderableBuilder, description); - } - - return concat(renderableBuilder.build()); - } - - final protected void renderId(Builder renderableBuilder) { - if (isDeprecated()) { - renderableBuilder.add(strikeThrough(text(getId()))); - String replacement = getDeprecationReplacement(); - if (StringUtil.hasText(replacement)) { - renderableBuilder.add(text(" -> " + replacement)); - } - } else { - renderableBuilder.add(bold(text(getId()))); - } - } - - protected abstract Object getDefaultValue(); - protected abstract IJavaProject getJavaProject(); - protected abstract Renderable getDescription(); - protected abstract String getType(); - protected abstract String getDeprecationReason(); - protected abstract String getId(); - protected abstract String getDeprecationReplacement(); - protected abstract boolean isDeprecated(); - - public static String formatDefaultValue(Object defaultValue) { - if (defaultValue!=null) { - if (defaultValue instanceof String) { - return (String) defaultValue; - } else if (defaultValue instanceof Number) { - return ((Number)defaultValue).toString(); - } else if (defaultValue instanceof Boolean) { - return Boolean.toString((Boolean) defaultValue); - } else if (defaultValue instanceof Object[]) { - return StringUtil.arrayToCommaDelimitedString((Object[]) defaultValue); - } else if (defaultValue instanceof Collection) { - return StringUtil.collectionToCommaDelimitedString((Collection) defaultValue); - } else { - //no idea what it is but try 'toString' and hope for the best - return defaultValue.toString(); - } - } - return null; - } - - /** - * Creates an 'action' link and adds it to the html buffer. When the user clicks the given - * link then the provided runnable is to be executed. - */ - public void actionLink(Builder renderableBuilder, String displayString) { - renderableBuilder.add(link(displayString, "null")); - } - - protected void defaultValueRenderable(Builder renderableBuilder, String defaultValue) { - renderableBuilder.add(text("Default: ")); - renderableBuilder.add(italic(text(defaultValue))); - } - - protected void depreactionRenderable(Builder renderableBuilder) { - String reason = getDeprecationReason(); - if (StringUtil.hasText(reason)) { - renderableBuilder.add(bold(text("Deprecated: "))); - renderableBuilder.add(text(reason)); - } else { - renderableBuilder.add(bold(text("Deprecated!"))); - } - } - - protected void descriptionRenderable(Builder renderableBuilder, Renderable description) { - renderableBuilder.add(paragraph(description)); - } - -} diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/common/InformationTemplates.java b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/common/InformationTemplates.java new file mode 100644 index 000000000..6b586fdcc --- /dev/null +++ b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/common/InformationTemplates.java @@ -0,0 +1,169 @@ +package org.springframework.ide.vscode.boot.common; + +import static org.springframework.ide.vscode.commons.util.Renderables.bold; +import static org.springframework.ide.vscode.commons.util.Renderables.concat; +import static org.springframework.ide.vscode.commons.util.Renderables.italic; +import static org.springframework.ide.vscode.commons.util.Renderables.lineBreak; +import static org.springframework.ide.vscode.commons.util.Renderables.link; +import static org.springframework.ide.vscode.commons.util.Renderables.paragraph; +import static org.springframework.ide.vscode.commons.util.Renderables.strikeThrough; +import static org.springframework.ide.vscode.commons.util.Renderables.text; + +import java.util.Collection; + +import org.springframework.boot.configurationmetadata.Deprecation; +import org.springframework.ide.vscode.application.properties.metadata.PropertyInfo; +import org.springframework.ide.vscode.commons.util.Renderable; +import org.springframework.ide.vscode.commons.util.Renderables; +import org.springframework.ide.vscode.commons.util.StringUtil; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableList.Builder; + +public class InformationTemplates { + + public static Renderable createHover(PropertyInfo info) { + Deprecation deprecation = createDeprecation(info); + return InformationTemplates.createHover(info.getId(), info.getType(), info.getDefaultValue(), text(info.getDescription()), deprecation); + } + + public static Renderable createCompletionDocumentation(PropertyInfo info) { + Deprecation deprecation = createDeprecation(info); + return InformationTemplates.createCompletionDocumentation(text(info.getDescription()), info.getDefaultValue(), deprecation); + } + + public static Renderable createHover(String id, String type, Object defaultValue, Renderable description, Deprecation deprecation) { + Builder renderableBuilder = ImmutableList.builder(); + + renderId(renderableBuilder, id, deprecation); + + if (type==null) { + type = Object.class.getName(); + } + renderableBuilder.add(lineBreak()); + actionLink(renderableBuilder, type); + + String deflt = formatDefaultValue(defaultValue); + if (deflt!=null) { + renderableBuilder.add(lineBreak()); + renderableBuilder.add(lineBreak()); + defaultValueRenderable(renderableBuilder, deflt); + } + + if (deprecation != null) { + renderableBuilder.add(lineBreak()); + renderableBuilder.add(lineBreak()); + depreactionRenderable(renderableBuilder, deprecation); + } + + if (description!=null) { + renderableBuilder.add(lineBreak()); + descriptionRenderable(renderableBuilder, description); + } + + return concat(renderableBuilder.build()); + } + + public static Renderable createCompletionDocumentation(Renderable description, Object defaultValue, Deprecation deprecation) { + Builder renderableBuilder = ImmutableList.builder(); + + if (description!=null) { + descriptionRenderable(renderableBuilder, description); + } + + String deflt = formatDefaultValue(defaultValue); + if (deflt!=null) { + if (description != null) { + renderableBuilder.add(lineBreak()); + } + defaultValueRenderable(renderableBuilder, deflt); + } + + if (deprecation != null) { + if (description != null) { + renderableBuilder.add(lineBreak()); + } + depreactionRenderable(renderableBuilder, deprecation); + } + + + ImmutableList pieces = renderableBuilder.build(); + + // Special case when there is no description, default value and deprecation data -> return `null` documentation. + if (pieces.size() == 1 && pieces.get(0) == Renderables.NO_DESCRIPTION) { + pieces = ImmutableList.of(); + } + return pieces.isEmpty() ? null : concat(pieces); + + } + + private static Deprecation createDeprecation(PropertyInfo info) { + Deprecation deprecation = null; + if (info.isDeprecated()) { + deprecation = new Deprecation(); + deprecation.setReason(info.getDeprecationReason()); + deprecation.setReplacement(info.getDeprecationReplacement()); + } + return deprecation; + } + + private static void renderId(Builder renderableBuilder, String id, Deprecation deprecation) { + if (deprecation == null) { + renderableBuilder.add(bold(text(id))); + } else { + renderableBuilder.add(strikeThrough(text(id))); + String replacement = deprecation.getReplacement(); + if (StringUtil.hasText(replacement)) { + renderableBuilder.add(text(" -> " + replacement)); + } + } + } + + private static String formatDefaultValue(Object defaultValue) { + if (defaultValue!=null) { + if (defaultValue instanceof String) { + return (String) defaultValue; + } else if (defaultValue instanceof Number) { + return ((Number)defaultValue).toString(); + } else if (defaultValue instanceof Boolean) { + return Boolean.toString((Boolean) defaultValue); + } else if (defaultValue instanceof Object[]) { + return StringUtil.arrayToCommaDelimitedString((Object[]) defaultValue); + } else if (defaultValue instanceof Collection) { + return StringUtil.collectionToCommaDelimitedString((Collection) defaultValue); + } else { + //no idea what it is but try 'toString' and hope for the best + return defaultValue.toString(); + } + } + return null; + } + + /** + * Creates an 'action' link and adds it to the html buffer. When the user clicks the given + * link then the provided runnable is to be executed. + */ + private static void actionLink(Builder renderableBuilder, String displayString) { + renderableBuilder.add(link(displayString, "null")); + } + + private static void defaultValueRenderable(Builder renderableBuilder, String defaultValue) { + renderableBuilder.add(text("Default: ")); + renderableBuilder.add(italic(text(defaultValue))); + } + + private static void depreactionRenderable(Builder renderableBuilder, Deprecation deprecation) { + String reason = deprecation.getReason(); + if (StringUtil.hasText(reason)) { + renderableBuilder.add(bold(text("Deprecated: "))); + renderableBuilder.add(text(reason)); + } else { + renderableBuilder.add(bold(text("Deprecated!"))); + } + } + + private static void descriptionRenderable(Builder renderableBuilder, Renderable description) { + renderableBuilder.add(paragraph(description)); + } + +} diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/common/PropertyCompletionFactory.java b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/common/PropertyCompletionFactory.java index b37ef73c1..22e6320c6 100644 --- a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/common/PropertyCompletionFactory.java +++ b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/common/PropertyCompletionFactory.java @@ -26,9 +26,6 @@ import org.springframework.ide.vscode.commons.util.Renderable; import org.springframework.ide.vscode.commons.yaml.hover.YPropertyInfoTemplates; import org.springframework.ide.vscode.commons.yaml.schema.YType; -import com.google.common.base.Supplier; -import com.google.common.base.Suppliers; - public class PropertyCompletionFactory { public ICompletionProposal valueProposal(String value, String query, String niceTypeName, double score, DocumentEdits edits, Renderable info) { @@ -126,14 +123,12 @@ public class PropertyCompletionFactory { private Match match; private Type type; private TypeUtil typeUtil; - private Supplier propertyRenderable; public PropertyProposal(IDocument doc, DocumentEdits applier, Match match, TypeUtil typeUtil) { super(doc, applier); this.typeUtil = typeUtil; this.match = match; - this.propertyRenderable = Suppliers.memoize(() -> new ShortDocumentationRenderableProvider(documentContextFinder.find(fDoc), match.data)); if (match.data.isDeprecated()) { deprecate(); } @@ -174,7 +169,7 @@ public class PropertyCompletionFactory { @Override public Renderable getDocumentation() { - return propertyRenderable.get().getRenderable(); + return InformationTemplates.createCompletionDocumentation(match.data); } } diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/common/PropertyRenderableProvider.java b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/common/PropertyRenderableProvider.java deleted file mode 100644 index 06fc6068c..000000000 --- a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/common/PropertyRenderableProvider.java +++ /dev/null @@ -1,228 +0,0 @@ -/******************************************************************************* - * 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.common; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty; -import org.springframework.ide.vscode.application.properties.metadata.PropertyInfo; -import org.springframework.ide.vscode.application.properties.metadata.PropertyInfo.PropertySource; -import org.springframework.ide.vscode.commons.java.IJavaElement; -import org.springframework.ide.vscode.commons.java.IJavaProject; -import org.springframework.ide.vscode.commons.java.IMethod; -import org.springframework.ide.vscode.commons.java.IType; -import org.springframework.ide.vscode.commons.util.Log; -import org.springframework.ide.vscode.commons.util.Renderable; -import org.springframework.ide.vscode.commons.util.Renderables; -import org.springframework.ide.vscode.commons.util.StringUtil; - - -/** - * Information object that is displayed in SpringPropertiesTextHover's information - * control. - *

- * Essentially this is a wrapper around {@link ConfigurationMetadataProperty} - * - * @author Kris De Volder - */ -public class PropertyRenderableProvider extends AbstractPropertyRenderableProvider { - - /** - * Java project which is used to find declaration for 'navigate to declaration' action - */ - private IJavaProject javaProject; - - /** - * Data object to display in 'hover text' - */ - private PropertyInfo data; - - public PropertyRenderableProvider(IJavaProject project, PropertyInfo data) { - this.javaProject = project; - this.data = data; - } - - public PropertyInfo getElement() { - return data; - } - - public boolean canOpenDeclaration() { - return getJavaElements()!=null; - } - - /** - * Like 'getSources' but converts raw info into IJavaElements. Raw data which fails to be converted - * is silenetly ignored. - */ - public List getJavaElements() { - try { - if (javaProject!=null) { - List sources = getSources(); - if (!sources.isEmpty()) { - ArrayList elements = new ArrayList(); - for (PropertySource source : sources) { - String typeName = source.getSourceType(); - if (typeName!=null) { - IType type = javaProject.findType(typeName); - IMethod method = null; - if (type!=null) { - String methodSig = source.getSourceMethod(); - if (methodSig!=null) { - method = getMethod(type, methodSig); - } else { - method = getSetter(type, getElement()); - } - } - if (method!=null) { - elements.add(method); - } else if (type!=null) { - elements.add(type); - } - } - } - return elements; - } - } else { - } - } catch (Exception e) { - Log.log(e); - } - return Collections.emptyList(); - } - - /** - * Attempt to find corresponding setter method for a given property. - * @return setter method, or null if not found. - */ - private IMethod getSetter(IType type, PropertyInfo propertyInfo) { - try { - String propName = propertyInfo.getName(); - String setterName = "set" - +Character.toUpperCase(propName.charAt(0)) - +toCamelCase(propName.substring(1)); - String sloppySetterName = setterName.toLowerCase(); - - IMethod sloppyMatch = null; - for (IMethod m : type.getMethods().collect(Collectors.toList())) { - String mname = m.getElementName(); - if (setterName.equals(mname)) { - //found 'exact' name match... done - return m; - } else if (mname.toLowerCase().equals(sloppySetterName)) { - sloppyMatch = m; - } - } - return sloppyMatch; - } catch (Exception e) { - Log.log(e); - return null; - } - } - - /** - * Convert hyphened name to camel case name. It is - * safe to call this on an already camel-cased name. - */ - private String toCamelCase(String name) { - if (name.isEmpty()) { - return name; - } else { - StringBuilder camel = new StringBuilder(); - char[] chars = name.toCharArray(); - for (int i = 0; i < chars.length; i++) { - char c = chars[i]; - if (c=='-') { - i++; - if (i getSources() { - return data.getSources(); - } - - private IMethod getMethod(IType type, String methodSig) { - int nameEnd = methodSig.indexOf('('); - String name; - if (nameEnd>=0) { - name = methodSig.substring(0, nameEnd); - } else { - name = methodSig; - } - //TODO: This code assumes 0 arguments, which is the case currently for all - // 'real' data in spring jars. - IMethod m = type.getMethod(name, Stream.empty()); - if (m!=null) { - return m; - } - //try find a method with the same name. - return type.getMethods().filter(meth -> name.equals(meth.getElementName())).findFirst().orElse(null); - } - - @Override - protected Object getDefaultValue() { - return data.getDefaultValue(); - } - - @Override - protected IJavaProject getJavaProject() { - return javaProject; - } - - @Override - protected Renderable getDescription() { - String desc = data.getDescription(); - if (StringUtil.hasText(desc)) { - return Renderables.text(desc); - } - return null; - } - - @Override - protected String getType() { - return data.getType(); - } - - @Override - protected String getDeprecationReason() { - return data.getDeprecationReason(); - } - - @Override - protected String getId() { - return data.getId(); - } - - @Override - protected String getDeprecationReplacement() { - return data.getDeprecationReplacement(); - } - - @Override - protected boolean isDeprecated() { - return data.isDeprecated(); - } - -} diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/common/ShortDocumentationRenderableProvider.java b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/common/ShortDocumentationRenderableProvider.java deleted file mode 100644 index 46c848f8b..000000000 --- a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/common/ShortDocumentationRenderableProvider.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.springframework.ide.vscode.boot.common; - -import static org.springframework.ide.vscode.commons.util.Renderables.concat; -import static org.springframework.ide.vscode.commons.util.Renderables.lineBreak; - -import org.springframework.ide.vscode.application.properties.metadata.PropertyInfo; -import org.springframework.ide.vscode.commons.java.IJavaProject; -import org.springframework.ide.vscode.commons.util.Renderable; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableList.Builder; - -public class ShortDocumentationRenderableProvider extends PropertyRenderableProvider { - - public ShortDocumentationRenderableProvider(IJavaProject project, PropertyInfo data) { - super(project, data); - } - - @Override - public Renderable getRenderable() { - Builder renderableBuilder = ImmutableList.builder(); - - Renderable description = getDescription(); - if (description!=null) { - descriptionRenderable(renderableBuilder, description); - } - - String deflt = formatDefaultValue(getDefaultValue()); - if (deflt!=null) { - if (description != null) { - renderableBuilder.add(lineBreak()); - } - defaultValueRenderable(renderableBuilder, deflt); - } - - if (isDeprecated()) { - if (description != null) { - renderableBuilder.add(lineBreak()); - } - depreactionRenderable(renderableBuilder); - } - - - ImmutableList pieces = renderableBuilder.build(); - return pieces.isEmpty() ? null : concat(pieces); - } - - - -} diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/properties/hover/PropertiesHoverCalculator.java b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/properties/hover/PropertiesHoverCalculator.java index d66d43253..dd3d7f468 100644 --- a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/properties/hover/PropertiesHoverCalculator.java +++ b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/properties/hover/PropertiesHoverCalculator.java @@ -3,7 +3,10 @@ package org.springframework.ide.vscode.boot.properties.hover; import static org.springframework.ide.vscode.boot.common.CommonLanguageTools.SPACES; import static org.springframework.ide.vscode.boot.common.CommonLanguageTools.getValueHints; import static org.springframework.ide.vscode.boot.common.CommonLanguageTools.getValueType; -import static org.springframework.ide.vscode.commons.util.Renderables.*; +import static org.springframework.ide.vscode.commons.util.Renderables.bold; +import static org.springframework.ide.vscode.commons.util.Renderables.concat; +import static org.springframework.ide.vscode.commons.util.Renderables.paragraph; +import static org.springframework.ide.vscode.commons.util.Renderables.text; import java.util.Collection; import java.util.Optional; @@ -15,7 +18,7 @@ import org.springframework.ide.vscode.application.properties.metadata.types.Type import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtil; import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtil.EnumCaseMode; import org.springframework.ide.vscode.application.properties.metadata.util.FuzzyMap; -import org.springframework.ide.vscode.boot.common.PropertyRenderableProvider; +import org.springframework.ide.vscode.boot.common.InformationTemplates; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.util.BadLocationException; import org.springframework.ide.vscode.commons.languageserver.util.DocumentRegion; @@ -79,7 +82,7 @@ class PropertiesHoverCalculator { if (best == null) { return null; } else { - Renderable renderable = new PropertyRenderableProvider(project, best).getRenderable(); + Renderable renderable = InformationTemplates.createHover(best); DocumentRegion region = createRegion(doc, property); return Tuples.of(renderable, region.asRegion()); } diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/yaml/completions/ApplicationYamlAssistContext.java b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/yaml/completions/ApplicationYamlAssistContext.java index 7754097bc..d85afda60 100644 --- a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/yaml/completions/ApplicationYamlAssistContext.java +++ b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/yaml/completions/ApplicationYamlAssistContext.java @@ -18,6 +18,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.springframework.boot.configurationmetadata.Deprecation; import org.springframework.ide.vscode.application.properties.metadata.IndexNavigator; import org.springframework.ide.vscode.application.properties.metadata.PropertyInfo; import org.springframework.ide.vscode.application.properties.metadata.hints.HintProvider; @@ -31,9 +32,13 @@ import org.springframework.ide.vscode.application.properties.metadata.types.Type import org.springframework.ide.vscode.application.properties.metadata.types.TypedProperty; import org.springframework.ide.vscode.application.properties.metadata.util.FuzzyMap; import org.springframework.ide.vscode.application.properties.metadata.util.FuzzyMap.Match; +import org.springframework.ide.vscode.boot.common.InformationTemplates; import org.springframework.ide.vscode.boot.common.PropertyCompletionFactory; -import org.springframework.ide.vscode.boot.common.PropertyRenderableProvider; import org.springframework.ide.vscode.boot.common.RelaxedNameConfig; +import org.springframework.ide.vscode.commons.java.IField; +import org.springframework.ide.vscode.commons.java.IJavaElement; +import org.springframework.ide.vscode.commons.java.IMember; +import org.springframework.ide.vscode.commons.javadoc.IJavadoc; 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.LazyProposalApplier; @@ -43,6 +48,7 @@ import org.springframework.ide.vscode.commons.util.CollectionUtil; import org.springframework.ide.vscode.commons.util.FuzzyMatcher; import org.springframework.ide.vscode.commons.util.Log; import org.springframework.ide.vscode.commons.util.Renderable; +import org.springframework.ide.vscode.commons.util.Renderables; import org.springframework.ide.vscode.commons.util.StringUtil; import org.springframework.ide.vscode.commons.yaml.completion.AbstractYamlAssistContext; import org.springframework.ide.vscode.commons.yaml.completion.TopLevelAssistContext; @@ -58,6 +64,8 @@ import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureParser import org.springframework.ide.vscode.commons.yaml.util.YamlIndentUtil; import org.springframework.ide.vscode.commons.yaml.util.YamlUtil; +import com.google.common.collect.ImmutableList; + /** * Represents a context insied a "application.yml" file relative to which we can provide * content assistance. @@ -365,7 +373,12 @@ public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistCon // the index to navigating type/bean properties return parent.getHoverInfo(); } else { - return new JavaTypeNavigationHoverInfo(contextPath.toPropString(), contextPath.getBeanPropertyName(), parent.getType(), getType(), typeUtil).getRenderable(); + String id = contextPath.toPropString(); + String propName = contextPath.getBeanPropertyName(); + String typeString = typeUtil.niceTypeName(getType()); + Type parentType = parent.getType(); + return InformationTemplates.createHover(id, typeString, null, + getDescription(typeUtil, parentType, propName), getDeprecation(typeUtil, parentType, propName)); } } @@ -495,7 +508,8 @@ public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistCon public Renderable getHoverInfo() { PropertyInfo prop = indexNav.getExactMatch(); if (prop!=null) { - return new PropertyRenderableProvider(typeUtil.getJavaProject(), prop).getRenderable(); + return InformationTemplates.createHover(prop); +// return new PropertyRenderableProvider(typeUtil.getJavaProject(), prop).getRenderable(); } return null; } @@ -526,4 +540,66 @@ public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistCon } }; } + + private static Deprecation getDeprecation(TypeUtil typeUtil, Type parentType, String propName) { + Map props = typeUtil.getPropertiesMap(parentType, EnumCaseMode.ALIASED, BeanPropertyNameMode.ALIASED); + if (props!=null) { + TypedProperty prop = props.get(propName); + if (prop!=null) { + return prop.getDeprecation(); + } + } + return null; + } + + private static Renderable getDescription(TypeUtil typeUtil, Type parentType, String propName) { + try { + List jes = getAllJavaElements(typeUtil, parentType, propName); + if (jes != null) { + for (IJavaElement je : jes) { + if (je instanceof IMember) { + IJavadoc javadoc = je.getJavaDoc(); + if (javadoc != null) { + return javadoc.getRenderable(); + } + } + } + } + } catch (Exception e) { + Log.log(e); + } + return Renderables.NO_DESCRIPTION; + } + + private static List getAllJavaElements(TypeUtil typeUtil, Type parentType, String propName) { + if (propName!=null) { + Type beanType = parentType; + if (TypeUtil.isMap(beanType)) { + Type keyType = typeUtil.getKeyType(beanType); + if (keyType!=null && typeUtil.isEnum(keyType)) { + IField field = typeUtil.getEnumConstant(keyType, propName); + if (field!=null) { + return ImmutableList.of(field); + } + } + } else { + ArrayList elements = new ArrayList(3); + maybeAdd(elements, typeUtil.getField(beanType, propName)); + maybeAdd(elements, typeUtil.getSetter(beanType, propName).get()); + maybeAdd(elements, typeUtil.getGetter(beanType, propName)); + if (!elements.isEmpty()) { + return elements; + } + } + } + return ImmutableList.of(); + } + + private static void maybeAdd(ArrayList elements, IJavaElement e) { + if (e!=null) { + elements.add(e); + } + } + + } diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/yaml/completions/JavaTypeNavigationHoverInfo.java b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/yaml/completions/JavaTypeNavigationHoverInfo.java deleted file mode 100644 index e1b8b81b3..000000000 --- a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/yaml/completions/JavaTypeNavigationHoverInfo.java +++ /dev/null @@ -1,255 +0,0 @@ -/******************************************************************************* - * 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.boot.yaml.completions; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.springframework.boot.configurationmetadata.Deprecation; -import org.springframework.ide.vscode.application.properties.metadata.types.Type; -import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtil; -import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtil.BeanPropertyNameMode; -import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtil.EnumCaseMode; -import org.springframework.ide.vscode.boot.common.AbstractPropertyRenderableProvider; -import org.springframework.ide.vscode.application.properties.metadata.types.TypedProperty; -import org.springframework.ide.vscode.commons.java.IField; -import org.springframework.ide.vscode.commons.java.IJavaElement; -import org.springframework.ide.vscode.commons.java.IJavaProject; -import org.springframework.ide.vscode.commons.java.IMember; -import org.springframework.ide.vscode.commons.javadoc.IJavadoc; -import org.springframework.ide.vscode.commons.util.Renderable; - -import com.google.common.collect.ImmutableList; - - -/** - * Example used as reference for explaingin the meaning of the instance variables: - * - * foo.bar[0].children.wavelen - */ -public class JavaTypeNavigationHoverInfo extends AbstractPropertyRenderableProvider { - - - private static final Logger LOG = Logger.getLogger(JavaTypeNavigationHoverInfo.class.getName()); - - /** - * Property expression that represents the full path to the point being hovered over. - * E.g. foo.bar[0].data.wavelen" - */ - private final String id; - - /** - * Last sgment of the path as a property name. - * This is only set if the naviation is accessing a property name (so, for example, will be null for navigation into - * indexed element in a sequence/list) - *

- * Example: "wavelen" - */ - private final String propName; - - /** - * The type from which we are navigating. - * E.g. the type of "foo.bar[0].data" - */ - private Type parentType; - - /** - * The type at which we arrive. - * E.g the type of "foo.bar[0].data.wavelen" - */ - private Type type; - - private TypeUtil typeUtil; - - private Deprecation deprecation; - - public JavaTypeNavigationHoverInfo(String id, String propName, Type fromType, Type toType, TypeUtil typeUtil) { - this.id = id; - this.propName = propName; - this.parentType = fromType; - this.type = toType; - this.typeUtil = typeUtil; - //Note: If you are considerind caching the result of this method... don't. - //The rendered html itself is cached by the superclass, which means this method only gets called once. - Map props = typeUtil.getPropertiesMap(parentType, EnumCaseMode.ALIASED, BeanPropertyNameMode.ALIASED); - if (props!=null) { - TypedProperty prop = props.get(propName); - if (prop!=null) { - this.deprecation = prop.getDeprecation(); - } - } - } - -// @Override -// protected String renderAsHtml() { -// JavaTypeLinks jtLinks = new JavaTypeLinks(this); -// HtmlBuffer html = new HtmlBuffer(); -// -// html.raw(""); -// html.text(id); -// html.raw(""); -// html.raw("
"); -// -// if (type!=null) { -// jtLinks.javaTypeLink(html, typeUtil, type); -// } else { -// jtLinks.javaTypeLink(html, typeUtil.getJavaProject(), Object.class.toString()); -// } -// -// if (isDeprecated()) { -// html.raw("

"); -// html.bold("Deprecated!"); -// } -// -// // String deflt = formatDefaultValue(data.getDefaultValue()); -// // if (deflt!=null) { -// // html.raw("

"); -// // html.text("Default: "); -// // html.raw(""); -// // html.text(deflt); -// // html.raw(""); -// // } -// -// String description = getDescription(); -// if (description!=null) { -// html.raw("

"); -// html.raw(description); -// } -// -// return html.toString(); -// } - - @Override - protected boolean isDeprecated() { - return deprecation!=null; - } - - @Override - protected Renderable getDescription() { - try { - List jes = getAllJavaElements(); - if (jes!=null) { - for (IJavaElement je : jes) { - if (je instanceof IMember) { - IJavadoc javadoc = je.getJavaDoc(); - if (javadoc != null) { - return javadoc.getRenderable(); - } - } - } - } - } catch (Exception e) { - LOG.log(Level.SEVERE, e.getMessage(), e); - } - return null; - } - - public List getJavaElements() { - if (propName!=null) { - if (TypeUtil.isMap(parentType)) { - Type enumType = typeUtil.getKeyType(parentType); - if (typeUtil.isEnum(enumType)) { - IField f = typeUtil.getEnumConstant(enumType, propName); - if (f!=null) { - return ImmutableList.of(f); - } - } - } else { - IJavaElement je; - Type beanType = parentType; - je = typeUtil.getSetter(beanType, propName).get(); - if (je!=null) { - return Collections.singletonList(je); - } - je = typeUtil.getGetter(beanType, propName); - if (je!=null) { - return Collections.singletonList(je); - } - je = typeUtil.getField(beanType, propName); - if (je!=null) { - return Collections.singletonList(je); - } - } - } - return Collections.emptyList(); - } - - private List getAllJavaElements() { - if (propName!=null) { - Type beanType = parentType; - if (TypeUtil.isMap(beanType)) { - Type keyType = typeUtil.getKeyType(beanType); - if (keyType!=null && typeUtil.isEnum(keyType)) { - IField field = typeUtil.getEnumConstant(keyType, propName); - if (field!=null) { - return ImmutableList.of(field); - } - } - } else { - ArrayList elements = new ArrayList(3); - maybeAdd(elements, typeUtil.getField(beanType, propName)); - maybeAdd(elements, typeUtil.getSetter(beanType, propName).get()); - maybeAdd(elements, typeUtil.getGetter(beanType, propName)); - if (!elements.isEmpty()) { - return elements; - } - } - } - return ImmutableList.of(); - } - - private void maybeAdd(ArrayList elements, IJavaElement e) { - if (e!=null) { - elements.add(e); - } - } - - @Override - protected Object getDefaultValue() { - //Not supported - return null; - } - - @Override - protected IJavaProject getJavaProject() { - return typeUtil.getJavaProject(); - } - - @Override - protected String getType() { - return typeUtil.niceTypeName(type); - } - - @Override - protected String getDeprecationReason() { - if (deprecation!=null) { - return deprecation.getReason(); - } - return null; - } - - @Override - protected String getId() { - return id; - } - - @Override - protected String getDeprecationReplacement() { - if (deprecation!=null) { - return deprecation.getReplacement(); - } - return null; - } -} \ No newline at end of file