Switch HTML hover tests to markdown tests

This commit is contained in:
BoykoAlex
2016-12-01 15:45:21 -05:00
parent f2f2324d66
commit db1402cf6b
9 changed files with 130 additions and 92 deletions

View File

@@ -10,11 +10,11 @@ import java.util.Optional;
import org.springframework.ide.vscode.application.properties.metadata.PropertyInfo;
import org.springframework.ide.vscode.application.properties.metadata.SpringPropertyIndex;
import org.springframework.ide.vscode.application.properties.metadata.hints.StsValueHint;
import org.springframework.ide.vscode.application.properties.metadata.hover.PropertyRenderableProvider;
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.properties.tools.PropertyRenderableProvider;
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;

View File

@@ -0,0 +1,135 @@
/*******************************************************************************
* Copyright (c) 2016 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.properties.tools;
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 {
/**
* Fake host name that is used in 'action link' urls so that we can
* recognize them as such.
*/
private static final String ACTION_HOST = "action";
public Renderable getRenderable() {
Builder<Renderable> renderableBuilder = ImmutableList.builder();
renderId(renderableBuilder);
String type = getType();
if (type==null) {
type = Object.class.getName();
}
actionLink(renderableBuilder, type);
String deflt = formatDefaultValue(getDefaultValue());
if (deflt!=null) {
defaultValueRenderable(renderableBuilder, deflt);
}
if (isDeprecated()) {
depreactionRenderable(renderableBuilder);
}
Renderable description = getDescription();
if (description!=null) {
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) {
String url = "http://"+ACTION_HOST+"/action-id";
renderableBuilder.add(lineBreak());
renderableBuilder.add(link(displayString, url));
}
private void defaultValueRenderable(Builder<Renderable> renderableBuilder, String defaultValue) {
renderableBuilder.add(lineBreak());
renderableBuilder.add(lineBreak());
renderableBuilder.add(text("Default: "));
renderableBuilder.add(italic(text(defaultValue)));
}
private void depreactionRenderable(Builder<Renderable> renderableBuilder) {
renderableBuilder.add(lineBreak());
renderableBuilder.add(lineBreak());
String reason = getDeprecationReason();
if (StringUtil.hasText(reason)) {
renderableBuilder.add(bold(text("Deprecated: ")));
renderableBuilder.add(text(reason));
} else {
renderableBuilder.add(bold(text("Deprecated!")));
}
}
private void descriptionRenderable(Builder<Renderable> renderableBuilder, Renderable description) {
renderableBuilder.add(lineBreak());
renderableBuilder.add(paragraph(description));
}
}

View File

@@ -0,0 +1,228 @@
/*******************************************************************************
* Copyright (c) 2016 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.properties.tools;
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();
}
}

View File

@@ -25,7 +25,6 @@ import org.springframework.ide.vscode.application.properties.metadata.completion
import org.springframework.ide.vscode.application.properties.metadata.hints.HintProvider;
import org.springframework.ide.vscode.application.properties.metadata.hints.StsValueHint;
import org.springframework.ide.vscode.application.properties.metadata.hints.ValueHintHoverInfo;
import org.springframework.ide.vscode.application.properties.metadata.hover.PropertyRenderableProvider;
import org.springframework.ide.vscode.application.properties.metadata.types.Type;
import org.springframework.ide.vscode.application.properties.metadata.types.TypeParser;
import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtil;
@@ -34,6 +33,7 @@ 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.properties.tools.PropertyRenderableProvider;
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;

View File

@@ -18,11 +18,11 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import org.springframework.boot.configurationmetadata.Deprecation;
import org.springframework.ide.vscode.application.properties.metadata.hover.AbstractPropertyRenderableProvider;
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.properties.tools.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;