Refactor property renderable providers into InformationTemplates
This commit is contained in:
@@ -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<Renderable> 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<Renderable> 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<Renderable> renderableBuilder, String displayString) {
|
||||
renderableBuilder.add(link(displayString, "null"));
|
||||
}
|
||||
|
||||
protected void defaultValueRenderable(Builder<Renderable> renderableBuilder, String defaultValue) {
|
||||
renderableBuilder.add(text("Default: "));
|
||||
renderableBuilder.add(italic(text(defaultValue)));
|
||||
}
|
||||
|
||||
protected void depreactionRenderable(Builder<Renderable> 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<Renderable> renderableBuilder, Renderable description) {
|
||||
renderableBuilder.add(paragraph(description));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<Renderable> 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<Renderable> 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<Renderable> 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<Renderable> 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<Renderable> renderableBuilder, String displayString) {
|
||||
renderableBuilder.add(link(displayString, "null"));
|
||||
}
|
||||
|
||||
private static void defaultValueRenderable(Builder<Renderable> renderableBuilder, String defaultValue) {
|
||||
renderableBuilder.add(text("Default: "));
|
||||
renderableBuilder.add(italic(text(defaultValue)));
|
||||
}
|
||||
|
||||
private static void depreactionRenderable(Builder<Renderable> 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<Renderable> renderableBuilder, Renderable description) {
|
||||
renderableBuilder.add(paragraph(description));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<PropertyInfo> match;
|
||||
private Type type;
|
||||
private TypeUtil typeUtil;
|
||||
private Supplier<PropertyRenderableProvider> propertyRenderable;
|
||||
|
||||
public PropertyProposal(IDocument doc, DocumentEdits applier, Match<PropertyInfo> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
* <p>
|
||||
* 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<IJavaElement> getJavaElements() {
|
||||
try {
|
||||
if (javaProject!=null) {
|
||||
List<PropertySource> sources = getSources();
|
||||
if (!sources.isEmpty()) {
|
||||
ArrayList<IJavaElement> elements = new ArrayList<IJavaElement>();
|
||||
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<chars.length) {
|
||||
camel.append(Character.toUpperCase(chars[i]));
|
||||
}
|
||||
} else {
|
||||
camel.append(chars[i]);
|
||||
}
|
||||
}
|
||||
return camel.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get 'raw' info about sources that define this property.
|
||||
*/
|
||||
public List<PropertySource> 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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<Renderable> 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<Renderable> pieces = renderableBuilder.build();
|
||||
return pieces.isEmpty() ? null : concat(pieces);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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<String, TypedProperty> 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<IJavaElement> 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<IJavaElement> 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<IJavaElement> elements = new ArrayList<IJavaElement>(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<IJavaElement> elements, IJavaElement e) {
|
||||
if (e!=null) {
|
||||
elements.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
* <p>
|
||||
* 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<String, TypedProperty> 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("<b>");
|
||||
// html.text(id);
|
||||
// html.raw("</b>");
|
||||
// html.raw("<br>");
|
||||
//
|
||||
// if (type!=null) {
|
||||
// jtLinks.javaTypeLink(html, typeUtil, type);
|
||||
// } else {
|
||||
// jtLinks.javaTypeLink(html, typeUtil.getJavaProject(), Object.class.toString());
|
||||
// }
|
||||
//
|
||||
// if (isDeprecated()) {
|
||||
// html.raw("<br><br>");
|
||||
// html.bold("Deprecated!");
|
||||
// }
|
||||
//
|
||||
// // String deflt = formatDefaultValue(data.getDefaultValue());
|
||||
// // if (deflt!=null) {
|
||||
// // html.raw("<br><br>");
|
||||
// // html.text("Default: ");
|
||||
// // html.raw("<i>");
|
||||
// // html.text(deflt);
|
||||
// // html.raw("</i>");
|
||||
// // }
|
||||
//
|
||||
// String description = getDescription();
|
||||
// if (description!=null) {
|
||||
// html.raw("<br><br>");
|
||||
// html.raw(description);
|
||||
// }
|
||||
//
|
||||
// return html.toString();
|
||||
// }
|
||||
|
||||
@Override
|
||||
protected boolean isDeprecated() {
|
||||
return deprecation!=null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Renderable getDescription() {
|
||||
try {
|
||||
List<IJavaElement> 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<IJavaElement> 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<IJavaElement> 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<IJavaElement> elements = new ArrayList<IJavaElement>(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<IJavaElement> 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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user