Merge branch 'master' into javadoc
# Conflicts: # vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/application/properties/metadata/hints/StsValueHint.java
This commit is contained in:
@@ -1,9 +1,5 @@
|
||||
package org.springframework.ide.vscode.application.properties.metadata.hints;
|
||||
|
||||
import static org.springframework.ide.vscode.application.properties.metadata.util.DeprecationUtil.*;
|
||||
|
||||
import javax.inject.Provider;
|
||||
|
||||
import org.springframework.boot.configurationmetadata.Deprecation;
|
||||
import org.springframework.boot.configurationmetadata.ValueHint;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtil;
|
||||
@@ -11,10 +7,13 @@ import org.springframework.ide.vscode.application.properties.metadata.util.Depre
|
||||
import org.springframework.ide.vscode.commons.java.IJavaElement;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.java.IType;
|
||||
import org.springframework.ide.vscode.commons.javadoc.IJavadoc;
|
||||
import org.springframework.ide.vscode.commons.languageserver.hover.HoverInfo;
|
||||
import org.springframework.ide.vscode.commons.util.Assert;
|
||||
import org.springframework.ide.vscode.commons.util.HtmlSnippet;
|
||||
import org.springframework.ide.vscode.commons.util.HtmlBuffer;
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
import org.springframework.ide.vscode.commons.util.StringUtil;
|
||||
import org.springframework.ide.vscode.commons.yaml.util.DescriptionProviders;
|
||||
|
||||
/**
|
||||
* Sts version of {@link ValueHint} contains similar data, but accomoates
|
||||
@@ -28,12 +27,9 @@ import org.springframework.ide.vscode.commons.util.StringUtil;
|
||||
*/
|
||||
public class StsValueHint {
|
||||
|
||||
private static final HtmlSnippet EMPTY_DESCRIPTION = HtmlSnippet.italic("No description");
|
||||
|
||||
private static final Provider<HtmlSnippet> EMPTY_DESCRIPTION_PROVIDER = () -> EMPTY_DESCRIPTION;
|
||||
|
||||
private final String value;
|
||||
private final Provider<HtmlSnippet> description;
|
||||
private final HoverInfo description;
|
||||
private final Deprecation deprecation;
|
||||
|
||||
/**
|
||||
@@ -42,7 +38,7 @@ public class StsValueHint {
|
||||
* This constructor is private. Use one of the provided
|
||||
* static 'create' methods instead.
|
||||
*/
|
||||
private StsValueHint(String value, Provider<HtmlSnippet> description, Deprecation deprecation) {
|
||||
private StsValueHint(String value, HoverInfo description, Deprecation deprecation) {
|
||||
this.value = value==null?"null":value.toString();
|
||||
Assert.isLegal(!this.value.startsWith("StsValueHint"));
|
||||
this.description = description;
|
||||
@@ -62,7 +58,7 @@ public class StsValueHint {
|
||||
}
|
||||
|
||||
public static StsValueHint create(String value) {
|
||||
return new StsValueHint(value, EMPTY_DESCRIPTION_PROVIDER, null);
|
||||
return new StsValueHint(value, DescriptionProviders.NO_DESCRIPTION, null);
|
||||
}
|
||||
|
||||
public static StsValueHint create(ValueHint hint) {
|
||||
@@ -96,36 +92,46 @@ public class StsValueHint {
|
||||
/**
|
||||
* Create a html snippet from a text snippet.
|
||||
*/
|
||||
private static Provider<HtmlSnippet> textSnippet(String description) {
|
||||
private static HoverInfo textSnippet(String description) {
|
||||
if (StringUtil.hasText(description)) {
|
||||
return () -> HtmlSnippet.text(description);
|
||||
return DescriptionProviders.text(description);
|
||||
}
|
||||
return EMPTY_DESCRIPTION_PROVIDER;
|
||||
return DescriptionProviders.NO_DESCRIPTION;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public HtmlSnippet getDescription() {
|
||||
return description.get();
|
||||
public HoverInfo getDescription() {
|
||||
return description;
|
||||
}
|
||||
public Provider<HtmlSnippet> getDescriptionProvider() {
|
||||
public HoverInfo getDescriptionProvider() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public static Provider<HtmlSnippet> javaDocSnippet(IJavaElement je) {
|
||||
return () -> {
|
||||
try {
|
||||
HtmlSnippet jdoc = HtmlSnippet.raw(je.getJavaDoc().html());
|
||||
if (jdoc!=null) {
|
||||
return jdoc;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
public static HoverInfo javaDocSnippet(IJavaElement je) {
|
||||
try {
|
||||
IJavadoc jdoc = je.getJavaDoc();
|
||||
if (jdoc != null) {
|
||||
return new HoverInfo() {
|
||||
|
||||
@Override
|
||||
public void renderAsMarkdown(StringBuilder buffer) {
|
||||
// TODO not correct md
|
||||
buffer.append(jdoc.markdown());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderAsHtml(HtmlBuffer buffer) {
|
||||
buffer.raw(jdoc.html());
|
||||
}
|
||||
};
|
||||
}
|
||||
return EMPTY_DESCRIPTION;
|
||||
};
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
return DescriptionProviders.NO_DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,7 +3,7 @@ package org.springframework.ide.vscode.application.properties.metadata.types;
|
||||
import javax.inject.Provider;
|
||||
|
||||
import org.springframework.boot.configurationmetadata.Deprecation;
|
||||
import org.springframework.ide.vscode.commons.util.HtmlSnippet;
|
||||
import org.springframework.ide.vscode.commons.languageserver.hover.HoverInfo;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YTypedProperty;
|
||||
import org.springframework.ide.vscode.commons.yaml.util.DescriptionProviders;
|
||||
|
||||
@@ -27,7 +27,7 @@ public class TypedProperty implements YTypedProperty {
|
||||
/**
|
||||
* Provides a description for this property.
|
||||
*/
|
||||
private final Provider<HtmlSnippet> descriptionProvider;
|
||||
private final HoverInfo descriptionProvider;
|
||||
|
||||
private final Deprecation deprecation;
|
||||
|
||||
@@ -35,7 +35,7 @@ public class TypedProperty implements YTypedProperty {
|
||||
this(name, type, DescriptionProviders.NO_DESCRIPTION, deprecation);
|
||||
}
|
||||
|
||||
public TypedProperty(String name, Type type, Provider<HtmlSnippet> descriptionProvider, Deprecation deprecation) {
|
||||
public TypedProperty(String name, Type type, HoverInfo descriptionProvider, Deprecation deprecation) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.descriptionProvider = descriptionProvider;
|
||||
@@ -56,14 +56,14 @@ public class TypedProperty implements YTypedProperty {
|
||||
}
|
||||
|
||||
@Override
|
||||
public HtmlSnippet getDescription() {
|
||||
public HoverInfo getDescription() {
|
||||
//TODO: real implementation that somehow gets this from somewhere (i.e. the JavaDoc)
|
||||
// Note that presently the application.yml and application.properties editor do not actually
|
||||
// use this description provider but produce hover infos in a different way (so this is only
|
||||
// used in Schema-based content assist, reconciling and hovering.
|
||||
//So in that sense putting a good implementation here is kind of pointless right now.
|
||||
//More refactoring needs to be done to also make use of this.
|
||||
return descriptionProvider.get();
|
||||
return descriptionProvider;
|
||||
}
|
||||
|
||||
public static Type typeOf(TypedProperty typedProperty) {
|
||||
|
||||
@@ -60,7 +60,11 @@
|
||||
<artifactId>jackson-datatype-jdk8</artifactId>
|
||||
<version>${jackson-2-version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-core</artifactId>
|
||||
<version>${reactor-version}</version>
|
||||
</dependency>
|
||||
<!-- testing -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.ide.vscode</groupId>
|
||||
|
||||
@@ -147,6 +147,7 @@ public abstract class LaunguageServerApp {
|
||||
Function<MessageConsumer, MessageConsumer> wrapper = (MessageConsumer consumer) -> {
|
||||
return (msg) -> {
|
||||
try {
|
||||
LOG.info(""+msg);
|
||||
consumer.consume(msg);
|
||||
} catch (UnsupportedOperationException e) {
|
||||
//log a warning and ignore. We are getting some messages from vsCode the server doesn't know about
|
||||
|
||||
@@ -10,15 +10,27 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.languageserver.hover;
|
||||
|
||||
import org.springframework.ide.vscode.commons.util.HtmlBuffer;
|
||||
|
||||
/**
|
||||
* Placeholder. Still need to figure out what exactly we should do with this in vscode.
|
||||
* Placeholder. Still need to figure out what exactly we should do with this in
|
||||
* vscode. TODO: rename to Renderable
|
||||
*/
|
||||
public interface HoverInfo {
|
||||
|
||||
String renderAsText();
|
||||
void renderAsHtml(HtmlBuffer buffer);
|
||||
|
||||
String renderAsHtml();
|
||||
void renderAsMarkdown(StringBuilder buffer);
|
||||
|
||||
String renderAsMarkdown();
|
||||
default String toMarkdown() {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
renderAsMarkdown(buffer);
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
default String toHtml() {
|
||||
HtmlBuffer buffer = new HtmlBuffer();
|
||||
renderAsHtml(buffer);
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,9 +11,12 @@
|
||||
package org.springframework.ide.vscode.commons.languageserver.hover;
|
||||
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.IDocument;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.IRegion;
|
||||
|
||||
public interface IHoverEngine {
|
||||
import reactor.util.function.Tuple2;
|
||||
|
||||
HoverInfo getHover(IDocument document, int offset) throws Exception;
|
||||
public interface HoverInfoProvider {
|
||||
|
||||
Tuple2<HoverInfo, IRegion> getHoverInfo(IDocument document, int offset) throws Exception;
|
||||
|
||||
}
|
||||
@@ -14,23 +14,27 @@ import java.util.Collections;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.TextDocumentPositionParams;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.IRegion;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.TextDocument;
|
||||
import org.springframework.ide.vscode.commons.util.Futures;
|
||||
|
||||
import reactor.util.function.Tuple2;
|
||||
|
||||
public class VscodeHoverEngineAdapter implements VscodeHoverEngine {
|
||||
|
||||
private IHoverEngine engine;
|
||||
private HoverInfoProvider hoverInfoProvider;
|
||||
private SimpleLanguageServer server;
|
||||
final static Logger logger = LoggerFactory.getLogger(VscodeHoverEngineAdapter.class);
|
||||
|
||||
|
||||
public VscodeHoverEngineAdapter(SimpleLanguageServer server, IHoverEngine engine) {
|
||||
this.engine = engine;
|
||||
public VscodeHoverEngineAdapter(SimpleLanguageServer server, HoverInfoProvider hoverInfoProvider) {
|
||||
this.hoverInfoProvider = hoverInfoProvider;
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@@ -44,16 +48,17 @@ public class VscodeHoverEngineAdapter implements VscodeHoverEngine {
|
||||
TextDocument doc = documents.get(params);
|
||||
if (doc!=null) {
|
||||
int offset = doc.toOffset(params.getPosition());
|
||||
HoverInfo hoverInfo = engine.getHover(doc, offset);
|
||||
if (hoverInfo != null) {
|
||||
Hover hover = new Hover();
|
||||
hover.setContents(Collections.singletonList(hoverInfo.renderAsMarkdown()));
|
||||
|
||||
Tuple2<HoverInfo, IRegion> hoverTuple = hoverInfoProvider.getHoverInfo(doc, offset);
|
||||
if (hoverTuple != null) {
|
||||
HoverInfo hoverInfo = hoverTuple.getT1();
|
||||
IRegion region = hoverTuple.getT2();
|
||||
Range range = doc.toRange(region.getOffset(), region.getLength());
|
||||
|
||||
Hover hover = new Hover(Collections.singletonList(hoverInfo.toMarkdown()), range);
|
||||
|
||||
return Futures.of(hover);
|
||||
}
|
||||
else{
|
||||
return Futures.of(null);
|
||||
}
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("error computing hover", e);
|
||||
|
||||
@@ -20,12 +20,8 @@ import java.net.URLEncoder;
|
||||
*/
|
||||
public class HtmlBuffer {
|
||||
|
||||
private StringBuffer buffer = new StringBuffer();
|
||||
private boolean epilogAdded = false; //to ensure only added once.
|
||||
private StringBuilder buffer = new StringBuilder();
|
||||
|
||||
public HtmlBuffer() {
|
||||
this.buffer = new StringBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Append text, applies escaping to the text as needed.
|
||||
@@ -38,9 +34,6 @@ public class HtmlBuffer {
|
||||
* Append 'raw' text. Doesn't apply any escaping.
|
||||
*/
|
||||
public void raw(String rawText) {
|
||||
if (epilogAdded) {
|
||||
throw new IllegalStateException("Can not append more text after epilog was added");
|
||||
}
|
||||
buffer.append(rawText);
|
||||
}
|
||||
|
||||
@@ -57,10 +50,7 @@ public class HtmlBuffer {
|
||||
|
||||
|
||||
public String toString() {
|
||||
if (!epilogAdded && buffer.length()>0) {
|
||||
epilogAdded = true;
|
||||
addPrologAndEpilog();
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -12,9 +12,13 @@ package org.springframework.ide.vscode.commons.util;
|
||||
|
||||
/**
|
||||
* A snippet that can be rendered into html.
|
||||
* <p/>
|
||||
* Deprecated. Use DescriptionProviders instead.
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class HtmlSnippet {
|
||||
public abstract void render(HtmlBuffer html);
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2015, 2016 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.util;
|
||||
|
||||
public class HtmlUtil {
|
||||
|
||||
public static String text2html(String s) {
|
||||
HtmlBuffer buf = new HtmlBuffer();
|
||||
buf.text(s);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,6 +14,8 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
|
||||
import org.springframework.ide.vscode.commons.languageserver.hover.HoverInfo;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.DocumentRegion;
|
||||
import org.springframework.ide.vscode.commons.yaml.path.YamlPathSegment;
|
||||
import org.springframework.ide.vscode.commons.yaml.structure.YamlDocument;
|
||||
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureParser.SNode;
|
||||
@@ -49,19 +51,20 @@ public abstract class TopLevelAssistContext implements YamlAssistContext {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public HoverInfo getHoverInfo() {
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// public HoverInfo getHoverInfo(YamlPathSegment lastSegment) {
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public HoverInfo getValueHoverInfo(YamlDocument doc, DocumentRegion documentRegion) {
|
||||
// return null;
|
||||
// }
|
||||
@Override
|
||||
public HoverInfo getHoverInfo() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HoverInfo getHoverInfo(YamlPathSegment lastSegment) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HoverInfo getValueHoverInfo(YamlDocument doc, DocumentRegion documentRegion) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected abstract YamlAssistContext getDocumentContext(int documentSelector);
|
||||
}
|
||||
|
||||
@@ -22,8 +22,11 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
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.hover.HoverInfo;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.DocumentRegion;
|
||||
import org.springframework.ide.vscode.commons.util.CollectionUtil;
|
||||
import org.springframework.ide.vscode.commons.util.FuzzyMatcher;
|
||||
import org.springframework.ide.vscode.commons.yaml.hover.YPropertyHoverInfo;
|
||||
import org.springframework.ide.vscode.commons.yaml.path.YamlPath;
|
||||
import org.springframework.ide.vscode.commons.yaml.path.YamlPathSegment;
|
||||
import org.springframework.ide.vscode.commons.yaml.path.YamlPathSegment.YamlPathSegmentType;
|
||||
@@ -215,35 +218,42 @@ public class YTypeAssistContext extends AbstractYamlAssistContext {
|
||||
}
|
||||
|
||||
|
||||
// @Override
|
||||
// public HoverInfo getHoverInfo() {
|
||||
// if (parent!=null) {
|
||||
// return parent.getHoverInfo(contextPath.getLastSegment());
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
@Override
|
||||
public HoverInfo getHoverInfo() {
|
||||
if (parent!=null) {
|
||||
return parent.getHoverInfo(contextPath.getLastSegment());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public YType getType() {
|
||||
return type;
|
||||
}
|
||||
//
|
||||
// @Override
|
||||
// public HoverInfo getHoverInfo(YamlPathSegment lastSegment) {
|
||||
// //Hoverinfo is only attached to YTypedProperties so...
|
||||
// switch (lastSegment.getType()) {
|
||||
// case VAL_AT_KEY:
|
||||
// case KEY_AT_KEY:
|
||||
// YTypedProperty prop = getProperty(lastSegment.toPropString());
|
||||
// if (prop!=null) {
|
||||
// return new YPropertyHoverInfo(contextPath.toPropString(), getType(), prop);
|
||||
// }
|
||||
// break;
|
||||
// default:
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
|
||||
// private YTypedProperty getProperty(String name) {
|
||||
// return typeUtil.getPropertiesMap(getType()).get(name);
|
||||
// }
|
||||
@Override
|
||||
public HoverInfo getHoverInfo(YamlPathSegment lastSegment) {
|
||||
//Hoverinfo is only attached to YTypedProperties so...
|
||||
switch (lastSegment.getType()) {
|
||||
case VAL_AT_KEY:
|
||||
case KEY_AT_KEY:
|
||||
YTypedProperty prop = getProperty(lastSegment.toPropString());
|
||||
if (prop!=null) {
|
||||
return YPropertyHoverInfo.create(contextPath.toPropString(), getType(), prop);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HoverInfo getValueHoverInfo(YamlDocument doc, DocumentRegion documentRegion) {
|
||||
//By default we don't provide value-specific hover, so just show the same hover
|
||||
// as the assistContext the value is in. This is likely more interesting than showing nothing at all.
|
||||
return getHoverInfo();
|
||||
}
|
||||
|
||||
private YTypedProperty getProperty(String name) {
|
||||
return typeUtil.getPropertiesMap(getType()).get(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,10 @@ package org.springframework.ide.vscode.commons.yaml.completion;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
|
||||
import org.springframework.ide.vscode.commons.languageserver.hover.HoverInfo;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.DocumentRegion;
|
||||
import org.springframework.ide.vscode.commons.yaml.path.YamlNavigable;
|
||||
import org.springframework.ide.vscode.commons.yaml.path.YamlPathSegment;
|
||||
import org.springframework.ide.vscode.commons.yaml.structure.YamlDocument;
|
||||
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureParser.SNode;
|
||||
|
||||
@@ -25,8 +28,8 @@ public interface YamlAssistContext extends YamlNavigable<YamlAssistContext> {
|
||||
|
||||
//TODO: conceptually... the right thing would be to only implement the second of these
|
||||
// two methods and get rid of the first one.
|
||||
// HoverInfo getHoverInfo();
|
||||
// HoverInfo getHoverInfo(YamlPathSegment lastSegment);
|
||||
//
|
||||
// HoverInfo getValueHoverInfo(YamlDocument doc, DocumentRegion documentRegion);
|
||||
HoverInfo getHoverInfo();
|
||||
HoverInfo getHoverInfo(YamlPathSegment lastSegment);
|
||||
|
||||
HoverInfo getValueHoverInfo(YamlDocument doc, DocumentRegion documentRegion);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2015, 2016 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.yaml.hover;
|
||||
|
||||
import static org.springframework.ide.vscode.commons.yaml.util.DescriptionProviders.bold;
|
||||
import static org.springframework.ide.vscode.commons.yaml.util.DescriptionProviders.concat;
|
||||
import static org.springframework.ide.vscode.commons.yaml.util.DescriptionProviders.lineBreak;
|
||||
import static org.springframework.ide.vscode.commons.yaml.util.DescriptionProviders.link;
|
||||
import static org.springframework.ide.vscode.commons.yaml.util.DescriptionProviders.text;
|
||||
|
||||
import org.springframework.ide.vscode.commons.languageserver.hover.HoverInfo;
|
||||
import org.springframework.ide.vscode.commons.util.StringUtil;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YType;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YTypedProperty;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableList.Builder;
|
||||
|
||||
/**
|
||||
* Nicely formatted hover info for a {@link YTypedProperty}
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class YPropertyHoverInfo {
|
||||
|
||||
public static HoverInfo create(String contextProperty, YType contextType, YTypedProperty prop) {
|
||||
|
||||
Builder<HoverInfo> html = ImmutableList.builder();
|
||||
if (StringUtil.hasText(contextProperty)) {
|
||||
html.add(text(contextProperty));
|
||||
html.add(text("."));
|
||||
}
|
||||
|
||||
html.add(bold(text(prop.getName())));
|
||||
|
||||
html.add(lineBreak());
|
||||
|
||||
YType type = prop.getType();
|
||||
if (type != null) {
|
||||
html.add(link(type.toString(), /* no URL */ null));
|
||||
}
|
||||
|
||||
HoverInfo description = prop.getDescription();
|
||||
if (description != null) {
|
||||
html.add(lineBreak());
|
||||
html.add(description);
|
||||
}
|
||||
|
||||
return concat(html.build());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2015, 2016 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.yaml.hover;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.ide.vscode.commons.languageserver.hover.HoverInfo;
|
||||
import org.springframework.ide.vscode.commons.languageserver.hover.HoverInfoProvider;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.DocumentRegion;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.IDocument;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.IRegion;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.Region;
|
||||
import org.springframework.ide.vscode.commons.util.Assert;
|
||||
import org.springframework.ide.vscode.commons.yaml.ast.NodeRef;
|
||||
import org.springframework.ide.vscode.commons.yaml.ast.YamlASTProvider;
|
||||
import org.springframework.ide.vscode.commons.yaml.ast.YamlFileAST;
|
||||
import org.springframework.ide.vscode.commons.yaml.completion.YamlAssistContext;
|
||||
import org.springframework.ide.vscode.commons.yaml.completion.YamlAssistContextProvider;
|
||||
import org.springframework.ide.vscode.commons.yaml.path.YamlPath;
|
||||
import org.springframework.ide.vscode.commons.yaml.path.YamlPathSegment;
|
||||
import org.springframework.ide.vscode.commons.yaml.structure.YamlDocument;
|
||||
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureProvider;
|
||||
import org.yaml.snakeyaml.nodes.Node;
|
||||
import org.yaml.snakeyaml.nodes.NodeId;
|
||||
import org.yaml.snakeyaml.parser.ParserException;
|
||||
import org.yaml.snakeyaml.scanner.ScannerException;
|
||||
|
||||
import reactor.util.function.Tuple2;
|
||||
import reactor.util.function.Tuples;
|
||||
|
||||
/**
|
||||
* Implements {@link HoverInfoProvider} for Yaml files based on
|
||||
* {@link YamlAssistContext}.
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class YamlHoverInfoProvider implements HoverInfoProvider {
|
||||
|
||||
private YamlASTProvider astProvider;
|
||||
private YamlAssistContextProvider assistContextProvider;
|
||||
private YamlStructureProvider structureProvider;
|
||||
|
||||
public YamlHoverInfoProvider(YamlASTProvider astProvider, YamlStructureProvider structureProvider,
|
||||
YamlAssistContextProvider assistContextProvider) {
|
||||
Assert.isNotNull(astProvider);
|
||||
Assert.isNotNull(structureProvider);
|
||||
Assert.isNotNull(assistContextProvider);
|
||||
this.astProvider = astProvider;
|
||||
this.structureProvider = structureProvider;
|
||||
this.assistContextProvider = assistContextProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tuple2<HoverInfo, IRegion> getHoverInfo(IDocument doc, int offset) throws Exception {
|
||||
YamlFileAST ast = getAst(doc);
|
||||
if (ast != null) {
|
||||
IRegion region = getHoverRegion(ast, offset);
|
||||
YamlDocument ymlDoc = new YamlDocument(doc, structureProvider);
|
||||
YamlAssistContext assistContext = assistContextProvider.getGlobalAssistContext(ymlDoc);
|
||||
if (assistContext != null) {
|
||||
List<NodeRef<?>> astPath = ast.findPath(offset);
|
||||
final YamlPath path = YamlPath.fromASTPath(astPath);
|
||||
if (path != null) {
|
||||
YamlPath assistPath = path;
|
||||
if (assistPath.pointsAtKey()) {
|
||||
// When a path points at a key we must tramsform it to a
|
||||
// 'value-terminating path'
|
||||
// to be able to reuse the 'getHoverInfo' method on
|
||||
// YamlAssistContext (as navigation
|
||||
// into 'key' is not defined for YamlAssistContext.
|
||||
String key = path.getLastSegment().toPropString();
|
||||
assistPath = path.dropLast().append(YamlPathSegment.valueAt(key));
|
||||
}
|
||||
assistContext = assistPath.traverse(assistContext);
|
||||
if (assistContext != null) {
|
||||
if (path.pointsAtValue()) {
|
||||
HoverInfo info = assistContext.getValueHoverInfo(ymlDoc, new DocumentRegion(doc, region));
|
||||
return Tuples.of(info, region);
|
||||
}
|
||||
HoverInfo info = assistContext.getHoverInfo();
|
||||
return Tuples.of(info, region);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private IRegion getHoverRegion(YamlFileAST ast, int offset) {
|
||||
if (ast != null) {
|
||||
Node n = ast.findNode(offset);
|
||||
if (n != null && n.getNodeId() == NodeId.scalar) {
|
||||
int start = n.getStartMark().getIndex();
|
||||
int end = n.getEndMark().getIndex();
|
||||
return new Region(start, end - start);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private YamlFileAST getAst(IDocument doc) throws Exception {
|
||||
try {
|
||||
return astProvider.getAST(doc);
|
||||
} catch (ParserException | ScannerException e) {
|
||||
// ignore, the user just typed some crap
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -21,8 +21,8 @@ import java.util.Set;
|
||||
|
||||
import javax.inject.Provider;
|
||||
|
||||
import org.springframework.ide.vscode.commons.languageserver.hover.HoverInfo;
|
||||
import org.springframework.ide.vscode.commons.util.EnumValueParser;
|
||||
import org.springframework.ide.vscode.commons.util.HtmlSnippet;
|
||||
import org.springframework.ide.vscode.commons.util.ValueParser;
|
||||
import org.springframework.ide.vscode.commons.yaml.util.DescriptionProviders;
|
||||
|
||||
@@ -193,7 +193,7 @@ public class YTypeFactory {
|
||||
propertyList.add(p);
|
||||
}
|
||||
|
||||
public void addProperty(String name, YType type, Provider<HtmlSnippet> description) {
|
||||
public void addProperty(String name, YType type, HoverInfo description) {
|
||||
YTypedPropertyImpl prop;
|
||||
addProperty(prop = new YTypedPropertyImpl(name, type));
|
||||
prop.setDescriptionProvider(description);
|
||||
@@ -314,7 +314,7 @@ public class YTypeFactory {
|
||||
|
||||
final private String name;
|
||||
final private YType type;
|
||||
private Provider<HtmlSnippet> descriptionProvider = DescriptionProviders.NO_DESCRIPTION;
|
||||
private HoverInfo description = DescriptionProviders.NO_DESCRIPTION;
|
||||
|
||||
private YTypedPropertyImpl(String name, YType type) {
|
||||
this.name = name;
|
||||
@@ -337,14 +337,13 @@ public class YTypeFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public HtmlSnippet getDescription() {
|
||||
return descriptionProvider.get();
|
||||
public HoverInfo getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescriptionProvider(Provider<HtmlSnippet> descriptionProvider) {
|
||||
this.descriptionProvider = descriptionProvider;
|
||||
public void setDescriptionProvider(HoverInfo description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public YAtomicType yatomic(String name) {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.yaml.schema;
|
||||
|
||||
import org.springframework.ide.vscode.commons.util.HtmlSnippet;
|
||||
import org.springframework.ide.vscode.commons.languageserver.hover.HoverInfo;
|
||||
|
||||
/**
|
||||
* @author Kris De Volder
|
||||
@@ -18,5 +18,5 @@ import org.springframework.ide.vscode.commons.util.HtmlSnippet;
|
||||
public interface YTypedProperty {
|
||||
String getName();
|
||||
YType getType();
|
||||
HtmlSnippet getDescription();
|
||||
HoverInfo getDescription();
|
||||
}
|
||||
|
||||
@@ -10,26 +10,32 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.yaml.util;
|
||||
|
||||
import static org.springframework.ide.vscode.commons.util.HtmlSnippet.*;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Provider;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.commons.languageserver.hover.HoverInfo;
|
||||
import org.springframework.ide.vscode.commons.util.HtmlBuffer;
|
||||
import org.springframework.ide.vscode.commons.util.HtmlSnippet;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/**
|
||||
* Static methods and convenience constants for creating some 'description providers'.
|
||||
* Static methods and convenience constants for creating some 'description
|
||||
* providers'.
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class DescriptionProviders {
|
||||
|
||||
|
||||
private static final String NO_DESCRIPTION_TEXT = "no description";
|
||||
|
||||
final static Logger logger = LoggerFactory.getLogger(DescriptionProviders.class);
|
||||
|
||||
public static final Provider<HtmlSnippet> NO_DESCRIPTION = () -> italic(text("no description"));
|
||||
public static final HoverInfo NO_DESCRIPTION = italic(text(NO_DESCRIPTION_TEXT));
|
||||
|
||||
public static Provider<HtmlSnippet> snippet(final HtmlSnippet snippet) {
|
||||
return new Provider<HtmlSnippet>() {
|
||||
@@ -37,6 +43,7 @@ public class DescriptionProviders {
|
||||
public String toString() {
|
||||
return snippet.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HtmlSnippet get() {
|
||||
return snippet;
|
||||
@@ -44,24 +51,179 @@ public class DescriptionProviders {
|
||||
};
|
||||
}
|
||||
|
||||
public static Provider<HtmlSnippet> fromClasspath(final Class<?> klass, final String resourcePath) {
|
||||
return new Provider<HtmlSnippet>() {
|
||||
public static HoverInfo concat(HoverInfo... pieces) {
|
||||
return concat(ImmutableList.copyOf(pieces));
|
||||
}
|
||||
|
||||
public static HoverInfo concat(List<HoverInfo> pieces) {
|
||||
if (pieces == null || pieces.size() == 0) {
|
||||
throw new IllegalArgumentException("At least one hover information is required for concat");
|
||||
} else if (pieces.size() == 1) {
|
||||
return pieces.get(0);
|
||||
} else {
|
||||
return new ConcatHoverInfo(pieces);
|
||||
}
|
||||
}
|
||||
|
||||
public static HoverInfo italic(HoverInfo text) {
|
||||
return new HoverInfo() {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DescriptionFromClassPth(class="+klass.getSimpleName()+", "+resourcePath+")";
|
||||
public void renderAsMarkdown(StringBuilder buffer) {
|
||||
buffer.append("*");
|
||||
text.renderAsMarkdown(buffer);
|
||||
buffer.append("*");
|
||||
}
|
||||
|
||||
@Override
|
||||
public HtmlSnippet get() {
|
||||
try {
|
||||
InputStream stream = klass.getResourceAsStream(resourcePath);
|
||||
if (stream!=null) {
|
||||
return HtmlSnippet.text(IOUtil.toString(stream));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Error", e);;
|
||||
}
|
||||
return NO_DESCRIPTION.get();
|
||||
public void renderAsHtml(HtmlBuffer buffer) {
|
||||
buffer.raw("<i>");
|
||||
text.renderAsHtml(buffer);
|
||||
buffer.raw("</i>");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static HoverInfo link(String text, String url) {
|
||||
return new HoverInfo() {
|
||||
|
||||
@Override
|
||||
public void renderAsMarkdown(StringBuilder buffer) {
|
||||
buffer.append('[');
|
||||
buffer.append(text);
|
||||
buffer.append(']');
|
||||
if (url != null) {
|
||||
buffer.append('(');
|
||||
buffer.append(url);
|
||||
buffer.append(')');
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderAsHtml(HtmlBuffer buffer) {
|
||||
buffer.raw("<a href=\"");
|
||||
buffer.url("" + url);
|
||||
buffer.raw("\">");
|
||||
buffer.text(text);
|
||||
buffer.raw("</a>");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static HoverInfo lineBreak() {
|
||||
return new HoverInfo() {
|
||||
|
||||
@Override
|
||||
public void renderAsMarkdown(StringBuilder buffer) {
|
||||
buffer.append("\n\n");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderAsHtml(HtmlBuffer buffer) {
|
||||
buffer.raw("<br>");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static HoverInfo bold(HoverInfo text) {
|
||||
|
||||
return new HoverInfo() {
|
||||
|
||||
@Override
|
||||
public void renderAsMarkdown(StringBuilder buffer) {
|
||||
buffer.append("**");
|
||||
text.renderAsMarkdown(buffer);
|
||||
buffer.append("**");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderAsHtml(HtmlBuffer buffer) {
|
||||
buffer.raw("<b>");
|
||||
text.renderAsHtml(buffer);
|
||||
buffer.raw("</b>");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static HoverInfo text(String text) {
|
||||
return new HoverInfo() {
|
||||
@Override
|
||||
public void renderAsMarkdown(StringBuilder buffer) {
|
||||
// TODO: handle escaping
|
||||
buffer.append(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderAsHtml(HtmlBuffer buffer) {
|
||||
buffer.text(text);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static HoverInfo fromClasspath(final Class<?> klass, final String resourcePath) {
|
||||
return new HoverInfo() {
|
||||
|
||||
@Override
|
||||
public void renderAsMarkdown(StringBuilder buffer) {
|
||||
String extension = ".md";
|
||||
String value = getText(klass, resourcePath, extension);
|
||||
if (value != null) {
|
||||
buffer.append(value);
|
||||
} else {
|
||||
NO_DESCRIPTION.renderAsMarkdown(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderAsHtml(HtmlBuffer buffer) {
|
||||
String extension = ".html";
|
||||
String value = getText(klass, resourcePath, extension);
|
||||
if (value != null) {
|
||||
buffer.raw(value);
|
||||
} else {
|
||||
NO_DESCRIPTION.renderAsHtml(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
private String getText(final Class<?> klass, final String resourcePath, String extension) {
|
||||
try {
|
||||
InputStream stream = klass.getResourceAsStream(resourcePath + extension);
|
||||
if (stream != null) {
|
||||
return IOUtil.toString(stream);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Error", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static class ConcatHoverInfo implements HoverInfo {
|
||||
|
||||
private HoverInfo[] pieces;
|
||||
|
||||
ConcatHoverInfo(HoverInfo[] pieces) {
|
||||
this.pieces = pieces;
|
||||
}
|
||||
|
||||
public ConcatHoverInfo(List<HoverInfo> pieces) {
|
||||
this(pieces.toArray(new HoverInfo[pieces.size()]));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderAsHtml(HtmlBuffer buffer) {
|
||||
for (HoverInfo hoverInfo : pieces) {
|
||||
hoverInfo.renderAsHtml(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderAsMarkdown(StringBuilder buffer) {
|
||||
for (HoverInfo hoverInfo : pieces) {
|
||||
hoverInfo.renderAsMarkdown(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.springframework.ide.vscode.languageserver.testharness;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.springframework.ide.vscode.languageserver.testharness.TestAsserts.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -16,6 +17,7 @@ import javax.swing.text.BadLocationException;
|
||||
import org.eclipse.lsp4j.CompletionItem;
|
||||
import org.eclipse.lsp4j.CompletionList;
|
||||
import org.eclipse.lsp4j.Diagnostic;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.Position;
|
||||
import org.eclipse.lsp4j.PublishDiagnosticsParams;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
@@ -307,13 +309,16 @@ public class Editor {
|
||||
return document.toPosition(selectionStart);
|
||||
}
|
||||
|
||||
public void assertIsHoverRegion(String string) {
|
||||
throw new UnsupportedOperationException("Not implemented yet!");
|
||||
public void assertIsHoverRegion(String string) throws Exception {
|
||||
int hoverPosition = getRawText().indexOf(string) + string.length() / 2;
|
||||
Hover hover = harness.getHover(document, document.toPosition(hoverPosition));
|
||||
assertEquals(string, getText(hover.getRange()));
|
||||
}
|
||||
|
||||
public void assertHoverContains(String string, String string2) {
|
||||
throw new UnsupportedOperationException("Not implemented yet!");
|
||||
}
|
||||
public void assertHoverContains(String hoverOver, String snippet) throws Exception {
|
||||
int hoverPosition = getRawText().indexOf(hoverOver) + hoverOver.length() / 2;
|
||||
Hover hover = harness.getHover(document, document.toPosition(hoverPosition));
|
||||
assertContains(snippet, hover.getContents().toString()); }
|
||||
|
||||
public void assertNoHover(String string) {
|
||||
throw new UnsupportedOperationException("Not implemented yet!");
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.eclipse.lsp4j.Diagnostic;
|
||||
import org.eclipse.lsp4j.DiagnosticSeverity;
|
||||
import org.eclipse.lsp4j.DidChangeTextDocumentParams;
|
||||
import org.eclipse.lsp4j.DidOpenTextDocumentParams;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.InitializeParams;
|
||||
import org.eclipse.lsp4j.InitializeResult;
|
||||
import org.eclipse.lsp4j.MessageParams;
|
||||
@@ -242,6 +243,15 @@ public class LanguageServerHarness {
|
||||
return server.getTextDocumentService().completion(params).get();
|
||||
}
|
||||
|
||||
public Hover getHover(TextDocumentInfo document, Position cursor) throws Exception {
|
||||
|
||||
TextDocumentPositionParams params = new TextDocumentPositionParams();
|
||||
params.setPosition(cursor);
|
||||
params.setTextDocument(document.getId());
|
||||
return server.getTextDocumentService().hover(params ).get();
|
||||
}
|
||||
|
||||
|
||||
private CompletionItem resolveCompletionItem(CompletionItem unresolved) {
|
||||
try {
|
||||
return server.getTextDocumentService().resolveCompletionItem(unresolved).get();
|
||||
@@ -313,5 +323,4 @@ public class LanguageServerHarness {
|
||||
CompletionItem completion = editor.getFirstCompletion();
|
||||
assertEquals(expected, completion.getLabel());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.springframework.ide.vscode.project.harness;
|
||||
package org.springframework.ide.vscode.languageserver.testharness;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
Reference in New Issue
Block a user