Merge branch 'application-yml-completions'
This commit is contained in:
@@ -7,9 +7,13 @@ import org.springframework.ide.vscode.commons.languageserver.util.IDocument;
|
||||
|
||||
public class DefaultSpringPropertyIndexProvider implements SpringPropertyIndexProvider {
|
||||
|
||||
private JavaProjectFinder javaProjectFinder = JavaProjectFinder.DEFAULT;
|
||||
private JavaProjectFinder javaProjectFinder;
|
||||
private SpringPropertiesIndexManager indexManager = new SpringPropertiesIndexManager(ValueProviderRegistry.getDefault());
|
||||
|
||||
public DefaultSpringPropertyIndexProvider(JavaProjectFinder javaProjectFinder) {
|
||||
this.javaProjectFinder = javaProjectFinder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FuzzyMap<PropertyInfo> getIndex(IDocument doc) {
|
||||
IJavaProject jp = javaProjectFinder.find(doc);
|
||||
|
||||
@@ -20,6 +20,11 @@ import org.springframework.boot.configurationmetadata.Deprecation;
|
||||
import org.springframework.boot.configurationmetadata.ValueHint;
|
||||
import org.springframework.boot.configurationmetadata.ValueProvider;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.ValueProviderRegistry.ValueProviderStrategy;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.hints.HintProvider;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.hints.HintProviders;
|
||||
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;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableList.Builder;
|
||||
@@ -134,32 +139,32 @@ public class PropertyInfo {
|
||||
return description;
|
||||
}
|
||||
|
||||
// public HintProvider getHints(TypeUtil typeUtil, boolean dimensionAware) {
|
||||
// Type type = TypeParser.parse(this.type);
|
||||
// if (TypeUtil.isMap(type)) {
|
||||
// return HintProviders.forMap(keyHints(typeUtil), valueHints(typeUtil), TypeUtil.getDomainType(type), dimensionAware);
|
||||
// } else if (TypeUtil.isSequencable(type)) {
|
||||
// if (dimensionAware) {
|
||||
// if (TypeUtil.isSequencable(type)) {
|
||||
// return HintProviders.forDomainAt(valueHints(typeUtil), TypeUtil.getDimensionality(type));
|
||||
// } else {
|
||||
// return HintProviders.forHere(valueHints(typeUtil));
|
||||
// }
|
||||
// } else {
|
||||
// return HintProviders.forAllValueContexts(valueHints(typeUtil));
|
||||
// }
|
||||
// } else {
|
||||
// return HintProviders.forHere(valueHints(typeUtil));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private HintProvider keyHints(TypeUtil typeUtil) {
|
||||
// return HintProviders.basic(typeUtil.getJavaProject(), keyHints, keyProvider);
|
||||
// }
|
||||
//
|
||||
// private HintProvider valueHints(TypeUtil typeUtil) {
|
||||
// return HintProviders.basic(typeUtil.getJavaProject(), valueHints, valueProvider);
|
||||
// }
|
||||
public HintProvider getHints(TypeUtil typeUtil, boolean dimensionAware) {
|
||||
Type type = TypeParser.parse(this.type);
|
||||
if (TypeUtil.isMap(type)) {
|
||||
return HintProviders.forMap(keyHints(typeUtil), valueHints(typeUtil), TypeUtil.getDomainType(type), dimensionAware);
|
||||
} else if (TypeUtil.isSequencable(type)) {
|
||||
if (dimensionAware) {
|
||||
if (TypeUtil.isSequencable(type)) {
|
||||
return HintProviders.forDomainAt(valueHints(typeUtil), TypeUtil.getDimensionality(type));
|
||||
} else {
|
||||
return HintProviders.forHere(valueHints(typeUtil));
|
||||
}
|
||||
} else {
|
||||
return HintProviders.forAllValueContexts(valueHints(typeUtil));
|
||||
}
|
||||
} else {
|
||||
return HintProviders.forHere(valueHints(typeUtil));
|
||||
}
|
||||
}
|
||||
|
||||
private HintProvider keyHints(TypeUtil typeUtil) {
|
||||
return HintProviders.basic(typeUtil.getJavaProject(), keyHints, keyProvider);
|
||||
}
|
||||
|
||||
private HintProvider valueHints(TypeUtil typeUtil) {
|
||||
return HintProviders.basic(typeUtil.getJavaProject(), valueHints, valueProvider);
|
||||
}
|
||||
|
||||
public List<PropertySource> getSources() {
|
||||
if (sources!=null) {
|
||||
|
||||
@@ -17,7 +17,7 @@ import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.boot.configurationmetadata.ValueProvider;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.types.StsValueHint;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.hints.StsValueHint;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.CollectionUtil;
|
||||
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
/*******************************************************************************
|
||||
* 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.application.properties.metadata.completions;
|
||||
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.IDocument;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YType;
|
||||
|
||||
import io.typefox.lsapi.CompletionItemKind;
|
||||
|
||||
public abstract class AbstractPropertyProposal extends ScoreableProposal {
|
||||
|
||||
protected final IDocument fDoc;
|
||||
private final DocumentEdits proposalApplier;
|
||||
private boolean isDeprecated = false;
|
||||
|
||||
public AbstractPropertyProposal(IDocument doc, DocumentEdits applier) {
|
||||
this.proposalApplier = applier;
|
||||
this.fDoc = doc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return getBaseDisplayString();
|
||||
}
|
||||
|
||||
// public IRegion getSelection(IDocument document) {
|
||||
// try {
|
||||
// return proposalApplier.getSelection(document);
|
||||
// } catch (Exception e) {
|
||||
// Log.log(e);
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// public String getDisplayString() {
|
||||
// StyledString styledText = getStyledDisplayString();
|
||||
// return styledText.getString();
|
||||
// }
|
||||
|
||||
// public Image getImage() {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
// public IContextInformation getContextInformation() {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
// @Override
|
||||
// public StyledString getStyledDisplayString() {
|
||||
// StyledString result = new StyledString();
|
||||
// result = result.append(super.getStyledDisplayString());
|
||||
// YType type = getType();
|
||||
// if (type!=null) {
|
||||
// String typeStr = niceTypeName(type);
|
||||
// result.append(" : "+typeStr, StyledString.DECORATIONS_STYLER);
|
||||
// }
|
||||
// return result;
|
||||
// }
|
||||
|
||||
protected boolean isDeprecated() {
|
||||
return isDeprecated;
|
||||
}
|
||||
public void deprecate() {
|
||||
if (!isDeprecated()) {
|
||||
deemphasize();
|
||||
deemphasize();
|
||||
isDeprecated = true;
|
||||
}
|
||||
}
|
||||
protected abstract YType getType();
|
||||
protected abstract String getHighlightPattern();
|
||||
protected abstract String getBaseDisplayString();
|
||||
protected abstract String niceTypeName(YType type);
|
||||
|
||||
@Override
|
||||
public CompletionItemKind getKind() {
|
||||
return CompletionItemKind.Field;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getBaseDisplayString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final DocumentEdits getTextEdit() {
|
||||
return this.proposalApplier;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void apply(IDocument document) {
|
||||
// try {
|
||||
// proposalApplier.apply(document);
|
||||
// } catch (Exception e) {
|
||||
// EditorSupportActivator.log(e);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014-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.application.properties.metadata.completions;
|
||||
|
||||
import org.springframework.ide.vscode.application.properties.metadata.PropertyInfo;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.hints.ValueHintHoverInfo;
|
||||
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;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.types.TypedProperty;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.util.FuzzyMap.Match;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.IDocument;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YType;
|
||||
|
||||
import io.typefox.lsapi.CompletionItemKind;
|
||||
|
||||
public class PropertyCompletionFactory {
|
||||
|
||||
|
||||
public ICompletionProposal valueProposal(String value, String query, Type type, double score, DocumentEdits edits, ValueHintHoverInfo info) {
|
||||
return new ScoreableProposal() {
|
||||
|
||||
@Override
|
||||
public DocumentEdits getTextEdit() {
|
||||
return edits;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionItemKind getKind() {
|
||||
return CompletionItemKind.Value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getBaseScore() {
|
||||
return score;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public ScoreableProposal property(IDocument doc, DocumentEdits applier, Match<PropertyInfo> prop, TypeUtil typeUtil) {
|
||||
return new PropertyProposal(doc, applier, prop, typeUtil);
|
||||
}
|
||||
|
||||
public ScoreableProposal beanProperty(IDocument doc, final String contextProperty, final Type contextType, final String pattern, final TypedProperty property, final double score, DocumentEdits applier, final TypeUtil typeUtil) {
|
||||
AbstractPropertyProposal proposal = new AbstractPropertyProposal(doc, applier) {
|
||||
|
||||
// private HoverInfo hoverInfo;
|
||||
|
||||
|
||||
// @Override
|
||||
// public HoverInfo getAdditionalProposalInfo(IProgressMonitor monitor) {
|
||||
// if (hoverInfo==null) {
|
||||
// String prefix = contextProperty==null?"":contextProperty+".";
|
||||
// hoverInfo = new JavaTypeNavigationHoverInfo(prefix+property.getName(), property.getName(), contextType, property.getType(), typeUtil);
|
||||
// }
|
||||
// return hoverInfo;
|
||||
// }
|
||||
|
||||
@Override
|
||||
protected String getBaseDisplayString() {
|
||||
return property.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getHighlightPattern() {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Type getType() {
|
||||
return property.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getBaseScore() {
|
||||
return score;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String niceTypeName(YType type) {
|
||||
return typeUtil.niceTypeName((Type) type);
|
||||
}
|
||||
|
||||
};
|
||||
if (property.isDeprecated()) {
|
||||
proposal.deprecate();
|
||||
}
|
||||
return proposal;
|
||||
}
|
||||
|
||||
private JavaProjectFinder documentContextFinder;
|
||||
|
||||
public PropertyCompletionFactory(JavaProjectFinder documentContextFinder) {
|
||||
this.documentContextFinder = documentContextFinder;
|
||||
}
|
||||
|
||||
private class PropertyProposal extends AbstractPropertyProposal {
|
||||
private Match<PropertyInfo> match;
|
||||
private Type type;
|
||||
private TypeUtil typeUtil;
|
||||
|
||||
public PropertyProposal(IDocument doc, DocumentEdits applier, Match<PropertyInfo> match,
|
||||
TypeUtil typeUtil) {
|
||||
super(doc, applier);
|
||||
this.typeUtil = typeUtil;
|
||||
this.match = match;
|
||||
if (match.data.isDeprecated()) {
|
||||
deprecate();
|
||||
}
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public HoverInfo getAdditionalProposalInfo(IProgressMonitor monitor) {
|
||||
// return new SpringPropertyHoverInfo(documentContextFinder.getJavaProject(fDoc), match.data);
|
||||
// }
|
||||
|
||||
@Override
|
||||
protected String getBaseDisplayString() {
|
||||
return match.data.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getBaseScore() {
|
||||
return match.score;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Type getType() {
|
||||
if (type==null) {
|
||||
type = TypeParser.parse(match.data.getType());
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getHighlightPattern() {
|
||||
return match.getPattern();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String niceTypeName(YType type) {
|
||||
return typeUtil.niceTypeName(((Type)type));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package org.springframework.ide.vscode.application.properties.metadata.completions;
|
||||
|
||||
import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtil.BeanPropertyNameMode;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtil.EnumCaseMode;
|
||||
|
||||
/**
|
||||
* Config object that determines some aspects of how the freedom of 'relaxed name binding'
|
||||
* are taken into account when generating content-assist completions.
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class RelaxedNameConfig {
|
||||
|
||||
public static final RelaxedNameConfig ALIASSED = new RelaxedNameConfig(EnumCaseMode.ALIASED, BeanPropertyNameMode.ALIASED);
|
||||
public static final RelaxedNameConfig COMPLETION_DEFAULTS = new RelaxedNameConfig(EnumCaseMode.LOWER_CASE, BeanPropertyNameMode.HYPHENATED);
|
||||
|
||||
private EnumCaseMode enumMode = EnumCaseMode.LOWER_CASE;
|
||||
private BeanPropertyNameMode beanMode = BeanPropertyNameMode.HYPHENATED;
|
||||
|
||||
public RelaxedNameConfig(EnumCaseMode enumMode, BeanPropertyNameMode beanMode) {
|
||||
this.enumMode = enumMode;
|
||||
this.beanMode = beanMode;
|
||||
}
|
||||
public EnumCaseMode getEnumMode() {
|
||||
return enumMode;
|
||||
}
|
||||
public void setEnumMode(EnumCaseMode preferredEnumCompletions) {
|
||||
this.enumMode = preferredEnumCompletions;
|
||||
}
|
||||
public BeanPropertyNameMode getBeanMode() {
|
||||
return beanMode;
|
||||
}
|
||||
public void setBeanMode(BeanPropertyNameMode preferredBeanCompletions) {
|
||||
this.beanMode = preferredBeanCompletions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RelaxedNameConfig("+enumMode+", "+beanMode+")";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*******************************************************************************
|
||||
* 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.application.properties.metadata.hints;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.configurationmetadata.ValueHint;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.ValueProviderRegistry.ValueProviderStrategy;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.types.TypedProperty;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.CollectionUtil;
|
||||
import org.springframework.ide.vscode.commons.yaml.path.YamlPathSegment;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableList.Builder;
|
||||
|
||||
/**
|
||||
* A single hint provider that combines the two kinds of 'hint' metadata that spring boot
|
||||
* may contain (namely 'values' data and 'valueProvider' data).
|
||||
* <p>
|
||||
* This basic hint provider is not context-aware and returns the same value hints regardless of the
|
||||
* yaml context.
|
||||
* <p>
|
||||
* This hint provider doesn't provide 'property' hints because property hints typically require
|
||||
* context information (i.e the type of the parent context).
|
||||
* <p>
|
||||
* To make this provider 'context aware' it can be wrapped in an adapter created by calling
|
||||
* one of the static methods in the {@link HintProviders} class.
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class BasicHintProvider implements HintProvider {
|
||||
|
||||
private IJavaProject javaProject;
|
||||
private ImmutableList<ValueHint> valueHints;
|
||||
private ValueProviderStrategy valueProvider;
|
||||
|
||||
public BasicHintProvider(IJavaProject javaProject,
|
||||
ImmutableList<ValueHint> valueHints,
|
||||
ValueProviderStrategy valueProvider) {
|
||||
this.javaProject = javaProject;
|
||||
this.valueHints = valueHints;
|
||||
this.valueProvider = valueProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HintProvider traverse(YamlPathSegment s) throws Exception {
|
||||
//since this provider is not context sensitive it just returns itself (So hints provides in 'sub-contexts'
|
||||
// are exaclty the same as hints in the parent context.
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StsValueHint> getValueHints(String query) {
|
||||
Builder<StsValueHint> builder = ImmutableList.builder();
|
||||
if (CollectionUtil.hasElements(valueHints)) {
|
||||
for (ValueHint hint : valueHints) {
|
||||
builder.add(StsValueHint.create(hint));
|
||||
}
|
||||
}
|
||||
if (valueProvider!=null) {
|
||||
Collection<StsValueHint> provided = valueProvider.getValuesNow(javaProject, query);
|
||||
if (CollectionUtil.hasElements(provided)) {
|
||||
builder.addAll(provided);
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TypedProperty> getPropertyHints(String query) {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*******************************************************************************
|
||||
* 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.application.properties.metadata.hints;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.ide.vscode.application.properties.metadata.types.TypedProperty;
|
||||
import org.springframework.ide.vscode.commons.yaml.path.YamlNavigable;
|
||||
|
||||
/**
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public interface HintProvider extends YamlNavigable<HintProvider> {
|
||||
List<StsValueHint> getValueHints(String query);
|
||||
List<TypedProperty> getPropertyHints(String query);
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
/*******************************************************************************
|
||||
* 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.application.properties.metadata.hints;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.configurationmetadata.ValueHint;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.ValueProviderRegistry.ValueProviderStrategy;
|
||||
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.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.CollectionUtil;
|
||||
import org.springframework.ide.vscode.commons.yaml.path.YamlPathSegment;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/**
|
||||
* Methods for creating hints providers that provide hint in specific kind of context.
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class HintProviders {
|
||||
|
||||
/**
|
||||
* HintProvider that never returns any hints. This should be used
|
||||
* instead of null pointer.
|
||||
*/
|
||||
public static final HintProvider NULL = new HintProvider() {
|
||||
|
||||
@Override
|
||||
public HintProvider traverse(YamlPathSegment s) throws Exception {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StsValueHint> getValueHints(String query) {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TypedProperty> getPropertyHints(String query) {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a non-context-aware hint provider. Typically a hint provider is created by composing the result of
|
||||
* this with one or more of the other methods in this class to wrap the basic provider so it becomes context-aware.
|
||||
*/
|
||||
public static HintProvider basic(IJavaProject jp, final ImmutableList<ValueHint> valueHints, final ValueProviderStrategy valueProvider) {
|
||||
if (!CollectionUtil.hasElements(valueHints) && valueProvider==null) {
|
||||
return NULL;
|
||||
}
|
||||
return new BasicHintProvider(jp, valueHints, valueProvider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a hint provider that will return the given hints in the context following
|
||||
* a traversal that goes down into a 'domain of' context a given number of times.
|
||||
*/
|
||||
public static HintProvider forDomainAt(final HintProvider valueHints, final int dim) {
|
||||
if (isNull(valueHints)) {
|
||||
return NULL;
|
||||
}
|
||||
if (dim==0) {
|
||||
return forHere(valueHints);
|
||||
}
|
||||
return new HintProvider() {
|
||||
public HintProvider traverse(YamlPathSegment s) throws Exception {
|
||||
switch (s.getType()) {
|
||||
case VAL_AT_INDEX:
|
||||
case VAL_AT_KEY:
|
||||
return forDomainAt(valueHints, dim-1);
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
public List<StsValueHint> getValueHints(String query) {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TypedProperty> getPropertyHints(String query) {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Only returns the given hints in this context but not one of its 'sub contexts'.
|
||||
*/
|
||||
public static HintProvider forHere(final HintProvider valueHints) {
|
||||
if (isNull(valueHints)) {
|
||||
return NULL;
|
||||
}
|
||||
return new HintProvider() {
|
||||
|
||||
@Override
|
||||
public HintProvider traverse(YamlPathSegment s) throws Exception {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StsValueHint> getValueHints(String query) {
|
||||
return valueHints.getValueHints(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TypedProperty> getPropertyHints(String query) {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* REturns the given hints in this context and any of its subcontexts that expect values.
|
||||
*/
|
||||
public static HintProvider forAllValueContexts(final HintProvider valueProvider) {
|
||||
if (isNull(valueProvider)) {
|
||||
return NULL;
|
||||
}
|
||||
return new HintProvider() {
|
||||
@Override
|
||||
public HintProvider traverse(YamlPathSegment s) throws Exception {
|
||||
switch (s.getType()) {
|
||||
case VAL_AT_INDEX:
|
||||
case VAL_AT_KEY:
|
||||
return this;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StsValueHint> getValueHints(String query) {
|
||||
return valueProvider.getValueHints(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TypedProperty> getPropertyHints(String query) {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static boolean isNull(HintProvider p) {
|
||||
//If everyone is nice and doesn't ever use null pointers then the p==null check is
|
||||
// not needed. But just in case.
|
||||
return p == NULL || p==null;
|
||||
}
|
||||
|
||||
public static HintProvider forMap(HintProvider _keyProvider, HintProvider _valueProvider, final Type valueType, final boolean dimensionAware) {
|
||||
final HintProvider keyProvider = notNull(_keyProvider);
|
||||
final HintProvider valueProvider = notNull(_valueProvider);
|
||||
if (isNull(keyProvider) && isNull(valueProvider)) {
|
||||
return NULL;
|
||||
}
|
||||
return new HintProvider() {
|
||||
|
||||
@Override
|
||||
public HintProvider traverse(YamlPathSegment s) throws Exception {
|
||||
switch (s.getType()) {
|
||||
case VAL_AT_INDEX:
|
||||
case VAL_AT_KEY:
|
||||
if (dimensionAware) {
|
||||
return forHere(valueProvider);
|
||||
} else {
|
||||
return forAllValueContexts(valueProvider);
|
||||
}
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StsValueHint> getValueHints(String query) {
|
||||
if (dimensionAware) {
|
||||
//pickier, completions only suggested in the domain of map, but not for map itself.
|
||||
return ImmutableList.of();
|
||||
} else {
|
||||
return valueProvider.getValueHints(query);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TypedProperty> getPropertyHints(String query) {
|
||||
List<StsValueHint> keyHints = keyProvider.getValueHints(query);
|
||||
if (CollectionUtil.hasElements(keyHints)) {
|
||||
List<TypedProperty> props = new ArrayList<>(keyHints.size());
|
||||
for (StsValueHint keyHint : keyHints) {
|
||||
Object key = keyHint.getValue();
|
||||
if (key instanceof String) {
|
||||
props.add(new TypedProperty((String)key, valueType, null));
|
||||
}
|
||||
}
|
||||
return props;
|
||||
}
|
||||
return ImmutableList.of();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Protection against bad code passing us null pointers.
|
||||
*/
|
||||
private static HintProvider notNull(HintProvider p) {
|
||||
if (p==null) {
|
||||
return NULL;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.springframework.ide.vscode.application.properties.metadata.types;
|
||||
package org.springframework.ide.vscode.application.properties.metadata.hints;
|
||||
|
||||
import static org.springframework.ide.vscode.application.properties.metadata.util.DeprecationUtil.*;
|
||||
|
||||
@@ -6,6 +6,7 @@ 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;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.util.DeprecationUtil;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaElement;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.springframework.ide.vscode.application.properties.metadata.hints;
|
||||
|
||||
public class ValueHintHoverInfo {
|
||||
|
||||
public ValueHintHoverInfo(StsValueHint hint) {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import javax.inject.Provider;
|
||||
|
||||
import org.springframework.boot.configurationmetadata.Deprecation;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.ValueProviderRegistry.ValueProviderStrategy;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.hints.StsValueHint;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.util.DeprecationUtil;
|
||||
import org.springframework.ide.vscode.commons.java.Flags;
|
||||
import org.springframework.ide.vscode.commons.java.IField;
|
||||
|
||||
@@ -16,6 +16,7 @@ import org.springframework.ide.vscode.commons.languageserver.util.BadLocationExc
|
||||
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.languageserver.util.TextDocument;
|
||||
import org.springframework.ide.vscode.commons.util.Assert;
|
||||
|
||||
import io.typefox.lsapi.TextEdit;
|
||||
@@ -322,12 +323,12 @@ public class DocumentEdits implements ProposalApplier {
|
||||
return null;
|
||||
}
|
||||
|
||||
public TextReplace asReplacement(IDocument doc) throws BadLocationException {
|
||||
public TextReplace asReplacement(TextDocument doc) throws BadLocationException {
|
||||
if (!edits.isEmpty()) {
|
||||
int start = edits.stream().mapToInt(Edit::getStart).min().getAsInt();
|
||||
int end = edits.stream().mapToInt(Edit::getEnd).max().getAsInt();
|
||||
|
||||
DocumentState state = new DocumentState(doc);
|
||||
DocumentState state = new DocumentState(doc.copy());
|
||||
for (Edit edit : edits) {
|
||||
edit.apply(state);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
package org.springframework.ide.vscode.commons.languageserver.completion;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
public abstract class ScoreableProposal implements ICompletionProposal {
|
||||
private static final double DEEMP_VALUE = 100000; // should be large enough to move deemphasized stuff to bottom of list.
|
||||
|
||||
private double deemphasizedBy = 0.0;
|
||||
|
||||
/**
|
||||
* A sorter suitable for sorting ScoreableProposals based on their score.
|
||||
*/
|
||||
public static final Comparator<ICompletionProposal> COMPARATOR = new Comparator<ICompletionProposal>() {
|
||||
public int compare(ICompletionProposal p1, ICompletionProposal p2) {
|
||||
if (p1 instanceof ScoreableProposal && p2 instanceof ScoreableProposal) {
|
||||
double s1 = ((ScoreableProposal)p1).getScore();
|
||||
double s2 = ((ScoreableProposal)p2).getScore();
|
||||
if (s1==s2) {
|
||||
String name1 = ((ScoreableProposal)p1).getLabel();
|
||||
String name2 = ((ScoreableProposal)p2).getLabel();
|
||||
return name1.compareTo(name2);
|
||||
} else {
|
||||
return Double.compare(s2, s1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
public abstract double getBaseScore();
|
||||
public final double getScore() {
|
||||
return getBaseScore() - deemphasizedBy;
|
||||
}
|
||||
public ScoreableProposal deemphasize() {
|
||||
deemphasizedBy+= DEEMP_VALUE;
|
||||
return this;
|
||||
}
|
||||
public boolean isDeemphasized() {
|
||||
return deemphasizedBy > 0;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public boolean isAutoInsertable() {
|
||||
// return !isDeemphasized();
|
||||
// }
|
||||
|
||||
// public StyledString getStyledDisplayString() {
|
||||
// StyledString result = new StyledString();
|
||||
// highlightPattern(getHighlightPattern(), getBaseDisplayString(), result);
|
||||
// return result;
|
||||
// }
|
||||
|
||||
// private void highlightPattern(String pattern, String data, StyledString result) {
|
||||
// Styler highlightStyle = CompletionFactory.HIGHLIGHT;
|
||||
// Styler plainStyle = isDeemphasized()?CompletionFactory.DEEMPHASIZE:CompletionFactory.NULL_STYLER;
|
||||
// if (isDeprecated()) {
|
||||
// highlightStyle = CompletionFactory.compose(highlightStyle, CompletionFactory.DEPRECATE);
|
||||
// plainStyle = CompletionFactory.compose(plainStyle, CompletionFactory.DEPRECATE);
|
||||
// }
|
||||
// if (StringUtils.hasText(pattern)) {
|
||||
// int dataPos = 0; int dataLen = data.length();
|
||||
// int patternPos = 0; int patternLen = pattern.length();
|
||||
//
|
||||
// while (dataPos<dataLen && patternPos<patternLen) {
|
||||
// int pChar = pattern.charAt(patternPos++);
|
||||
// int highlightPos = data.indexOf(pChar, dataPos);
|
||||
// if (dataPos<highlightPos) {
|
||||
// result.append(data.substring(dataPos, highlightPos), plainStyle);
|
||||
// }
|
||||
// result.append(data.charAt(highlightPos), highlightStyle);
|
||||
// dataPos = highlightPos+1;
|
||||
// }
|
||||
// if (dataPos<dataLen) {
|
||||
// result.append(data.substring(dataPos), plainStyle);
|
||||
// }
|
||||
// } else { //no pattern to highlight
|
||||
// result.append(data, plainStyle);
|
||||
// }
|
||||
// }
|
||||
|
||||
// protected abstract boolean isDeprecated();
|
||||
// protected abstract String getHighlightPattern();
|
||||
// protected abstract String getBaseDisplayString();
|
||||
|
||||
// @Override
|
||||
// public String getAdditionalProposalInfo() {
|
||||
// HoverInfo hoverInfo = getAdditionalProposalInfo(new NullProgressMonitor());
|
||||
// if (hoverInfo!=null) {
|
||||
// return hoverInfo.getHtml();
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
// @Override
|
||||
// public abstract HoverInfo getAdditionalProposalInfo(IProgressMonitor monitor);
|
||||
|
||||
// @Override
|
||||
// public CharSequence getPrefixCompletionText(IDocument document, int completionOffset) {
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public int getPrefixCompletionStart(IDocument document, int completionOffset) {
|
||||
// return completionOffset;
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.springframework.ide.vscode.manifest.yaml;
|
||||
package org.springframework.ide.vscode.commons.languageserver.completion;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.springframework.ide.vscode.manifest.yaml;
|
||||
package org.springframework.ide.vscode.commons.languageserver.completion;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -7,16 +7,13 @@ import java.util.concurrent.CompletableFuture;
|
||||
|
||||
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.ICompletionEngine;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits.TextReplace;
|
||||
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.SortKeys;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.TextDocument;
|
||||
import org.springframework.ide.vscode.commons.util.Futures;
|
||||
import org.springframework.ide.vscode.commons.yaml.completion.DefaultCompletionFactory;
|
||||
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureParser;
|
||||
import org.springframework.ide.vscode.commons.util.StringUtil;
|
||||
|
||||
import io.typefox.lsapi.CompletionItem;
|
||||
import io.typefox.lsapi.CompletionList;
|
||||
@@ -31,6 +28,8 @@ import io.typefox.lsapi.impl.TextEditImpl;
|
||||
*/
|
||||
public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
|
||||
|
||||
final private int MAX_COMPLETIONS = 10;
|
||||
|
||||
final static Logger logger = LoggerFactory.getLogger(VscodeCompletionEngineAdapter.class);
|
||||
|
||||
public static final String VS_CODE_CURSOR_MARKER = "{{}}";
|
||||
@@ -54,12 +53,18 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
|
||||
if (doc!=null) {
|
||||
int offset = doc.toOffset(params.getPosition());
|
||||
List<ICompletionProposal> completions = new ArrayList<>(engine.getCompletions(doc, offset));
|
||||
Collections.sort(completions, DefaultCompletionFactory.COMPARATOR);
|
||||
Collections.sort(completions, ScoreableProposal.COMPARATOR);
|
||||
CompletionListImpl list = new CompletionListImpl();
|
||||
list.setIncomplete(false);
|
||||
List<CompletionItemImpl> items = new ArrayList<>(completions.size());
|
||||
SortKeys sortkeys = new SortKeys();
|
||||
int count = 0;
|
||||
for (ICompletionProposal c : completions) {
|
||||
count++;
|
||||
if (count>MAX_COMPLETIONS) {
|
||||
list.setIncomplete(true);
|
||||
break;
|
||||
}
|
||||
try {
|
||||
items.add(adaptItem(doc, c, sortkeys));
|
||||
} catch (Exception e) {
|
||||
@@ -105,7 +110,7 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
|
||||
//Vscode applies some magic indent to a multi-line edit text. We do everything ourself so we have adjust for the magic
|
||||
// and do some kind of 'inverse magic' here.
|
||||
int vscodeMagicIndent = start.getCharacter();
|
||||
return YamlStructureParser.stripIndentation(vscodeMagicIndent, newText);
|
||||
return StringUtil.stripIndentation(vscodeMagicIndent, newText);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.springframework.ide.vscode.commons.languageserver.hover;
|
||||
|
||||
/**
|
||||
* Placeholder. Still need to figure out what exactly we should do with this in vscode.
|
||||
*/
|
||||
public interface HoverInfo {
|
||||
|
||||
}
|
||||
@@ -133,6 +133,7 @@ public class SimpleTextDocumentService implements TextDocumentService {
|
||||
|
||||
@Override
|
||||
public void didClose(DidCloseTextDocumentParams params) {
|
||||
System.out.println("closing: "+params.getTextDocument().getUri());
|
||||
String url = params.getTextDocument().getUri();
|
||||
if (url!=null) {
|
||||
documents.remove(url);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.springframework.ide.vscode.manifest.yaml;
|
||||
package org.springframework.ide.vscode.commons.languageserver.util;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
@@ -131,4 +131,48 @@ public class StringUtil {
|
||||
return f.format(d);
|
||||
}
|
||||
|
||||
private static final Pattern NEWLINE = Pattern.compile("(\\n|\\r)+");
|
||||
|
||||
/**
|
||||
* Removes a given number of spaces from all lines of text in a String,
|
||||
* except for the first line.
|
||||
* <p>
|
||||
* Note: this method only deals with spaces its not suitable for strings
|
||||
* which use tabs for indentation.
|
||||
*/
|
||||
public static String stripIndentation(int indent, String indentedText) {
|
||||
StringBuilder out = new StringBuilder();
|
||||
boolean first = true;
|
||||
Matcher matcher = NEWLINE.matcher(indentedText);
|
||||
int pos = 0;
|
||||
while (matcher.find()) {
|
||||
int newline = matcher.start();
|
||||
int newline_end = matcher.end();
|
||||
String line = indentedText.substring(pos, newline);
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
line = stripIndentationFromLine(indent, line);
|
||||
}
|
||||
out.append(line);
|
||||
out.append(indentedText.substring(newline, newline_end));
|
||||
pos = newline_end;
|
||||
}
|
||||
String line = indentedText.substring(pos);
|
||||
if (!first) {
|
||||
line = stripIndentationFromLine(indent, line);
|
||||
}
|
||||
out.append(line);
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
public static String stripIndentationFromLine(int indent, String line) {
|
||||
int start = 0;
|
||||
while (start<line.length() && start < indent && line.charAt(start)==' ') {
|
||||
start++;
|
||||
}
|
||||
return line.substring(start);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package org.springframework.ide.vscode.commons.yaml.completion;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.IDocument;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YType;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YTypeUtil;
|
||||
@@ -13,110 +12,6 @@ import io.typefox.lsapi.CompletionItemKind;
|
||||
|
||||
public class DefaultCompletionFactory implements CompletionFactory {
|
||||
|
||||
/**
|
||||
* A sorter suitable for sorting proposals created by this factory
|
||||
*/
|
||||
public static final Comparator<ICompletionProposal> COMPARATOR = new Comparator<ICompletionProposal>() {
|
||||
public int compare(ICompletionProposal p1, ICompletionProposal p2) {
|
||||
if (p1 instanceof ScoreableProposal && p2 instanceof ScoreableProposal) {
|
||||
double s1 = ((ScoreableProposal)p1).getScore();
|
||||
double s2 = ((ScoreableProposal)p2).getScore();
|
||||
if (s1==s2) {
|
||||
String name1 = ((ScoreableProposal)p1).getLabel();
|
||||
String name2 = ((ScoreableProposal)p2).getLabel();
|
||||
return name1.compareTo(name2);
|
||||
} else {
|
||||
return Double.compare(s2, s1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public static abstract class ScoreableProposal implements ICompletionProposal {
|
||||
private static final double DEEMP_VALUE = 100000; // should be large enough to move deemphasized stuff to bottom of list.
|
||||
|
||||
private double deemphasizedBy = 0.0;
|
||||
public abstract double getBaseScore();
|
||||
public final double getScore() {
|
||||
return getBaseScore() - deemphasizedBy;
|
||||
}
|
||||
public ScoreableProposal deemphasize() {
|
||||
deemphasizedBy+= DEEMP_VALUE;
|
||||
return this;
|
||||
}
|
||||
public boolean isDeemphasized() {
|
||||
return deemphasizedBy > 0;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public boolean isAutoInsertable() {
|
||||
// return !isDeemphasized();
|
||||
// }
|
||||
|
||||
// public StyledString getStyledDisplayString() {
|
||||
// StyledString result = new StyledString();
|
||||
// highlightPattern(getHighlightPattern(), getBaseDisplayString(), result);
|
||||
// return result;
|
||||
// }
|
||||
|
||||
// private void highlightPattern(String pattern, String data, StyledString result) {
|
||||
// Styler highlightStyle = CompletionFactory.HIGHLIGHT;
|
||||
// Styler plainStyle = isDeemphasized()?CompletionFactory.DEEMPHASIZE:CompletionFactory.NULL_STYLER;
|
||||
// if (isDeprecated()) {
|
||||
// highlightStyle = CompletionFactory.compose(highlightStyle, CompletionFactory.DEPRECATE);
|
||||
// plainStyle = CompletionFactory.compose(plainStyle, CompletionFactory.DEPRECATE);
|
||||
// }
|
||||
// if (StringUtils.hasText(pattern)) {
|
||||
// int dataPos = 0; int dataLen = data.length();
|
||||
// int patternPos = 0; int patternLen = pattern.length();
|
||||
//
|
||||
// while (dataPos<dataLen && patternPos<patternLen) {
|
||||
// int pChar = pattern.charAt(patternPos++);
|
||||
// int highlightPos = data.indexOf(pChar, dataPos);
|
||||
// if (dataPos<highlightPos) {
|
||||
// result.append(data.substring(dataPos, highlightPos), plainStyle);
|
||||
// }
|
||||
// result.append(data.charAt(highlightPos), highlightStyle);
|
||||
// dataPos = highlightPos+1;
|
||||
// }
|
||||
// if (dataPos<dataLen) {
|
||||
// result.append(data.substring(dataPos), plainStyle);
|
||||
// }
|
||||
// } else { //no pattern to highlight
|
||||
// result.append(data, plainStyle);
|
||||
// }
|
||||
// }
|
||||
|
||||
// protected abstract boolean isDeprecated();
|
||||
// protected abstract String getHighlightPattern();
|
||||
// protected abstract String getBaseDisplayString();
|
||||
|
||||
// @Override
|
||||
// public String getAdditionalProposalInfo() {
|
||||
// HoverInfo hoverInfo = getAdditionalProposalInfo(new NullProgressMonitor());
|
||||
// if (hoverInfo!=null) {
|
||||
// return hoverInfo.getHtml();
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
// @Override
|
||||
// public abstract HoverInfo getAdditionalProposalInfo(IProgressMonitor monitor);
|
||||
|
||||
// @Override
|
||||
// public CharSequence getPrefixCompletionText(IDocument document, int completionOffset) {
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public int getPrefixCompletionStart(IDocument document, int completionOffset) {
|
||||
// return completionOffset;
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static class BeanPropertyProposal extends ScoreableProposal {
|
||||
|
||||
private IDocument doc;
|
||||
|
||||
@@ -105,8 +105,9 @@ public class YamlPathEdits extends DocumentEdits {
|
||||
buf.append(":");
|
||||
if (i<path.size()-1) {
|
||||
indent += YamlIndentUtil.INDENT_BY;
|
||||
} else {
|
||||
buf.append(indentUtil.applyIndentation(appendText, indent));
|
||||
}
|
||||
buf.append(indentUtil.applyIndentation(appendText, indent));
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.IRegion;
|
||||
@@ -691,7 +690,7 @@ public class YamlStructureParser {
|
||||
String indentedText = StringUtil.trimEnd(doc.textBetween(start, end));
|
||||
int indent = getIndent();
|
||||
if (indent>0) {
|
||||
return stripIndentation(indent, indentedText);
|
||||
return StringUtil.stripIndentation(indent, indentedText);
|
||||
}
|
||||
return indentedText;
|
||||
}
|
||||
@@ -702,39 +701,4 @@ public class YamlStructureParser {
|
||||
return keyAliases.getKeyAliases(key);
|
||||
}
|
||||
|
||||
public static String stripIndentation(int indent, String indentedText) {
|
||||
StringBuilder out = new StringBuilder();
|
||||
Pattern NEWLINE = Pattern.compile("(\\n|\\r)+");
|
||||
boolean first = true;
|
||||
Matcher matcher = NEWLINE.matcher(indentedText);
|
||||
int pos = 0;
|
||||
while (matcher.find()) {
|
||||
int newline = matcher.start();
|
||||
int newline_end = matcher.end();
|
||||
String line = indentedText.substring(pos, newline);
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
line = stripIndentationFromLine(indent, line);
|
||||
}
|
||||
out.append(line);
|
||||
out.append(indentedText.substring(newline, newline_end));
|
||||
pos = newline_end;
|
||||
}
|
||||
String line = indentedText.substring(pos);
|
||||
if (!first) {
|
||||
line = stripIndentationFromLine(indent, line);
|
||||
}
|
||||
out.append(line);
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
private static String stripIndentationFromLine(int indent, String line) {
|
||||
int start = 0;
|
||||
while (start<line.length() && start < indent && line.charAt(start)==' ') {
|
||||
start++;
|
||||
}
|
||||
return line.substring(start);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -258,8 +258,9 @@ public class LanguageServerHarness {
|
||||
|
||||
public void assertCompletion(String textBefore, String expectTextAfter) throws Exception {
|
||||
Editor editor = newEditor(textBefore);
|
||||
assertNotNull(editor.getCompletions());
|
||||
assertFalse(editor.getCompletions().isEmpty());
|
||||
List<CompletionItem> completions = editor.getCompletions();
|
||||
assertNotNull(completions);
|
||||
assertFalse(completions.isEmpty());
|
||||
CompletionItem completion = editor.getFirstCompletion();
|
||||
editor.apply(completion);
|
||||
assertEquals(expectTextAfter, editor.getText());
|
||||
|
||||
@@ -14,6 +14,7 @@ import org.springframework.ide.vscode.application.properties.metadata.SpringProp
|
||||
import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtil;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtilProvider;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.IDocument;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject;
|
||||
@@ -32,6 +33,8 @@ public abstract class AbstractPropsEditorTest {
|
||||
|
||||
private ProjectsHarness projects = ProjectsHarness.INSTANCE;
|
||||
protected PropertyIndexHarness md;
|
||||
protected final JavaProjectFinder javaProjectFinder = (doc) -> getTestProject();
|
||||
|
||||
private LanguageServerHarness harness;
|
||||
private IJavaProject testProject;
|
||||
private TypeUtil typeUtil;
|
||||
@@ -47,6 +50,10 @@ public abstract class AbstractPropsEditorTest {
|
||||
return harness.newEditor(contents);
|
||||
}
|
||||
|
||||
private IJavaProject getTestProject() {
|
||||
return testProject;
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
md = new PropertyIndexHarness();
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.springframework.ide.vscode.application.properties.metadata.DefaultSpr
|
||||
import org.springframework.ide.vscode.application.properties.metadata.SpringPropertyIndexProvider;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtil;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtilProvider;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.IDocument;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.LoggingFormat;
|
||||
|
||||
@@ -130,9 +131,9 @@ public class Main {
|
||||
* When the request stream is closed, wait for 5s for all outstanding responses to compute, then return.
|
||||
*/
|
||||
public static void run(Connection connection) {
|
||||
SpringPropertyIndexProvider indexProvider = new DefaultSpringPropertyIndexProvider();
|
||||
TypeUtil typeUtil = new TypeUtil(null);
|
||||
TypeUtilProvider typeUtilProvider = (IDocument doc) -> typeUtil;
|
||||
JavaProjectFinder javaProjectFinder = JavaProjectFinder.DEFAULT;
|
||||
SpringPropertyIndexProvider indexProvider = new DefaultSpringPropertyIndexProvider(javaProjectFinder);
|
||||
TypeUtilProvider typeUtilProvider = (IDocument doc) -> new TypeUtil(javaProjectFinder.find(doc));
|
||||
|
||||
ApplicationPropertiesLanguageServer server = new ApplicationPropertiesLanguageServer(indexProvider, typeUtilProvider);
|
||||
|
||||
|
||||
@@ -1,27 +1,24 @@
|
||||
package org.springframework.ide.vscode.application.yaml;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.springframework.ide.vscode.application.properties.metadata.SpringPropertyIndexProvider;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.completions.RelaxedNameConfig;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtilProvider;
|
||||
import org.springframework.ide.vscode.application.yaml.completions.ApplicationYamlCompletionEngine;
|
||||
import org.springframework.ide.vscode.application.yaml.completions.ApplicationYamlStructureProvider;
|
||||
import org.springframework.ide.vscode.application.yaml.reconcile.ApplicationYamlReconcileEngine;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngine;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcileEngine;
|
||||
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 org.springframework.ide.vscode.commons.yaml.ast.YamlASTProvider;
|
||||
import org.springframework.ide.vscode.commons.yaml.ast.YamlParser;
|
||||
import org.springframework.ide.vscode.commons.yaml.completion.YamlCompletionEngine;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
import io.typefox.lsapi.CompletionItem;
|
||||
import io.typefox.lsapi.CompletionItemKind;
|
||||
import io.typefox.lsapi.CompletionList;
|
||||
import io.typefox.lsapi.TextDocumentSyncKind;
|
||||
import io.typefox.lsapi.impl.CompletionItemImpl;
|
||||
import io.typefox.lsapi.impl.CompletionListImpl;
|
||||
import io.typefox.lsapi.impl.CompletionOptionsImpl;
|
||||
import io.typefox.lsapi.impl.ServerCapabilitiesImpl;
|
||||
|
||||
@@ -32,7 +29,7 @@ public class ApplicationYamlLanguageServer extends SimpleLanguageServer {
|
||||
private SpringPropertyIndexProvider indexProvider;
|
||||
private TypeUtilProvider typeUtilProvider;
|
||||
|
||||
public ApplicationYamlLanguageServer(SpringPropertyIndexProvider indexProvider, TypeUtilProvider typeUtilProvider) {
|
||||
public ApplicationYamlLanguageServer(SpringPropertyIndexProvider indexProvider, TypeUtilProvider typeUtilProvider, JavaProjectFinder javaProjectFinder) {
|
||||
this.indexProvider = indexProvider;
|
||||
this.typeUtilProvider = typeUtilProvider;
|
||||
SimpleTextDocumentService documents = getTextDocumentService();
|
||||
@@ -54,54 +51,16 @@ public class ApplicationYamlLanguageServer extends SimpleLanguageServer {
|
||||
// }
|
||||
// });
|
||||
|
||||
documents.onCompletion(params -> {
|
||||
CompletableFuture<CompletionList> promise = new CompletableFuture<>();
|
||||
CompletionListImpl completions = new CompletionListImpl();
|
||||
completions.setIncomplete(false);
|
||||
List<CompletionItemImpl> items = new ArrayList<>();
|
||||
{
|
||||
// {
|
||||
// label: 'TypeScript',
|
||||
// kind: CompletionItemKind.Text,
|
||||
// data: 1
|
||||
// },
|
||||
CompletionItemImpl item = new CompletionItemImpl();
|
||||
item.setLabel("TypeScript");
|
||||
item.setKind(CompletionItemKind.Text);
|
||||
item.setData(1);
|
||||
items.add(item);
|
||||
}
|
||||
|
||||
{
|
||||
// {
|
||||
// label: 'JavaScript',
|
||||
// kind: CompletionItemKind.Text,
|
||||
// data: 2
|
||||
// }
|
||||
CompletionItemImpl item = new CompletionItemImpl();
|
||||
item.setLabel("JavaScript");
|
||||
item.setKind(CompletionItemKind.Text);
|
||||
item.setData(2);
|
||||
items.add(item);
|
||||
}
|
||||
completions.setItems(items);
|
||||
|
||||
promise.complete(completions);
|
||||
return promise;
|
||||
});
|
||||
|
||||
documents.onCompletionResolve((_item) -> {
|
||||
CompletionItemImpl item = (CompletionItemImpl) _item;
|
||||
Object data = item.getData();
|
||||
if (Integer.valueOf(1).equals(data)) {
|
||||
item.setDetail("TypeScript details");
|
||||
item.setDocumentation("TypeScript docs");
|
||||
} else {
|
||||
item.setDetail("JavaScript details");
|
||||
item.setDocumentation("JavaScript docs");
|
||||
}
|
||||
return Futures.of((CompletionItem)item);
|
||||
});
|
||||
YamlCompletionEngine yamlCompletionEngine = ApplicationYamlCompletionEngine.create(
|
||||
indexProvider,
|
||||
javaProjectFinder,
|
||||
ApplicationYamlStructureProvider.INSTANCE,
|
||||
typeUtilProvider,
|
||||
RelaxedNameConfig.COMPLETION_DEFAULTS
|
||||
);
|
||||
VscodeCompletionEngine completionEngine = new VscodeCompletionEngineAdapter(this, yamlCompletionEngine);
|
||||
documents.onCompletion(completionEngine::getCompletions);
|
||||
documents.onCompletionResolve(completionEngine::resolveCompletion);
|
||||
}
|
||||
|
||||
protected IReconcileEngine getReconcileEngine() {
|
||||
@@ -115,7 +74,7 @@ public class ApplicationYamlLanguageServer extends SimpleLanguageServer {
|
||||
c.setTextDocumentSync(TextDocumentSyncKind.Full);
|
||||
|
||||
CompletionOptionsImpl completionProvider = new CompletionOptionsImpl();
|
||||
completionProvider.setResolveProvider(true);
|
||||
completionProvider.setResolveProvider(false);
|
||||
c.setCompletionProvider(completionProvider);
|
||||
|
||||
return c;
|
||||
|
||||
@@ -13,6 +13,7 @@ import org.springframework.ide.vscode.application.properties.metadata.DefaultSpr
|
||||
import org.springframework.ide.vscode.application.properties.metadata.SpringPropertyIndexProvider;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtil;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtilProvider;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.IDocument;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.LoggingFormat;
|
||||
|
||||
@@ -83,14 +84,14 @@ public class Main {
|
||||
* When the request stream is closed, wait for 5s for all outstanding responses to compute, then return.
|
||||
*/
|
||||
public static void run(Connection connection) {
|
||||
//TODO: proper TypeUtilProvider and IndexProvider that somehow determine classpath that should be
|
||||
JavaProjectFinder javaProjectFinder = JavaProjectFinder.DEFAULT;
|
||||
//TODO: proper TypeUtilProvider and IndexProvider that somehow determine classpath that should be
|
||||
// in effect for given IDocument and provide TypeUtil or SpringPropertyIndex parsed from that classpath.
|
||||
// Note that the provider is responsible for doing some kind of sensible caching so that indexes are not
|
||||
// rebuilt every time the index is being used.
|
||||
SpringPropertyIndexProvider indexProvider = new DefaultSpringPropertyIndexProvider();
|
||||
TypeUtil typeUtil = new TypeUtil(null);
|
||||
TypeUtilProvider typeUtilProvider = (IDocument doc) -> typeUtil;
|
||||
ApplicationYamlLanguageServer server = new ApplicationYamlLanguageServer(indexProvider, typeUtilProvider);
|
||||
SpringPropertyIndexProvider indexProvider = new DefaultSpringPropertyIndexProvider(javaProjectFinder);
|
||||
TypeUtilProvider typeUtilProvider = (IDocument doc) -> new TypeUtil(javaProjectFinder.find(doc));
|
||||
ApplicationYamlLanguageServer server = new ApplicationYamlLanguageServer(indexProvider, typeUtilProvider, javaProjectFinder);
|
||||
LoggingJsonAdapter jsonServer = new LoggingJsonAdapter(server);
|
||||
jsonServer.setMessageLog(new PrintWriter(System.out));
|
||||
|
||||
|
||||
@@ -0,0 +1,509 @@
|
||||
/*******************************************************************************
|
||||
* 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.application.yaml.completions;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
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.completions.PropertyCompletionFactory;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.completions.RelaxedNameConfig;
|
||||
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.types.Type;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.types.TypeParser;
|
||||
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.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.commons.languageserver.completion.DocumentEdits;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ProposalApplier;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal;
|
||||
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.util.Log;
|
||||
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;
|
||||
import org.springframework.ide.vscode.commons.yaml.completion.YamlAssistContext;
|
||||
import org.springframework.ide.vscode.commons.yaml.completion.YamlPathEdits;
|
||||
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;
|
||||
import org.springframework.ide.vscode.commons.yaml.structure.YamlDocument;
|
||||
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureParser.SChildBearingNode;
|
||||
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureParser.SKeyNode;
|
||||
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureParser.SNode;
|
||||
import org.springframework.ide.vscode.commons.yaml.util.YamlIndentUtil;
|
||||
import org.springframework.ide.vscode.commons.yaml.util.YamlUtil;
|
||||
|
||||
/**
|
||||
* Represents a context insied a "application.yml" file relative to which we can provide
|
||||
* content assistance.
|
||||
*/
|
||||
public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistContext {
|
||||
|
||||
protected final RelaxedNameConfig conf;
|
||||
|
||||
// This may prove useful later but we don't need it for now
|
||||
// /**
|
||||
// * AssistContextKind is an classification of the different kinds of
|
||||
// * syntactic context that CA can be invoked from.
|
||||
// */
|
||||
// public static enum Kind {
|
||||
// SKEY_KEY, /* CA called from a SKeyNode and node.isInKey(cursor)==true */
|
||||
// SKEY_VALUE, /* CA called from a SKeyNode and node.isInKey(cursor)==false */
|
||||
// SRAW /* CA called from a SRawNode */
|
||||
// }
|
||||
// protected final Kind contextKind;
|
||||
|
||||
public final TypeUtil typeUtil;
|
||||
|
||||
public ApplicationYamlAssistContext(int documentSelector, YamlPath contextPath, TypeUtil typeUtil, RelaxedNameConfig conf) {
|
||||
super(documentSelector, contextPath);
|
||||
this.typeUtil = typeUtil;
|
||||
this.conf = conf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the text that should be appended at the end of a completion
|
||||
* proposal depending on what type of value is expected.
|
||||
*/
|
||||
protected String appendTextFor(Type type) {
|
||||
//Note that proper indentation after each \n" is added automatically
|
||||
//so the strings created here do not need to contain indentation spaces
|
||||
if (TypeUtil.isMap(type)) {
|
||||
//ready to enter nested map key on next line
|
||||
return "\n"+YamlIndentUtil.INDENT_STR;
|
||||
} if (TypeUtil.isSequencable(type)) {
|
||||
//ready to enter sequence element on next line
|
||||
return "\n- ";
|
||||
} else if (typeUtil.isAtomic(type)) {
|
||||
//ready to enter whatever on the same line
|
||||
return " ";
|
||||
} else {
|
||||
//Assume its some kind of pojo bean
|
||||
return "\n"+YamlIndentUtil.INDENT_STR;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the type expected at this context, may return null if unknown.
|
||||
*/
|
||||
protected abstract Type getType();
|
||||
|
||||
public static ApplicationYamlAssistContext subdocument(int documentSelector, FuzzyMap<PropertyInfo> index, PropertyCompletionFactory completionFactory, TypeUtil typeUtil, RelaxedNameConfig conf) {
|
||||
return new IndexContext(documentSelector, YamlPath.EMPTY, IndexNavigator.with(index), completionFactory, typeUtil, conf);
|
||||
}
|
||||
|
||||
public static YamlAssistContext forPath(YamlPath contextPath, FuzzyMap<PropertyInfo> index, PropertyCompletionFactory completionFactory, TypeUtil typeUtil, RelaxedNameConfig conf) {
|
||||
try {
|
||||
YamlPathSegment documentSelector = contextPath.getSegment(0);
|
||||
if (documentSelector!=null) {
|
||||
contextPath = contextPath.dropFirst(1);
|
||||
YamlAssistContext context = ApplicationYamlAssistContext.subdocument(documentSelector.toIndex(), index, completionFactory, typeUtil, conf);
|
||||
for (YamlPathSegment s : contextPath.getSegments()) {
|
||||
if (context==null) return null;
|
||||
context = context.traverse(s);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
abstract public YamlAssistContext traverse(YamlPathSegment s) throws Exception;
|
||||
|
||||
private static class TypeContext extends ApplicationYamlAssistContext {
|
||||
|
||||
private PropertyCompletionFactory completionFactory;
|
||||
private Type type;
|
||||
private ApplicationYamlAssistContext parent;
|
||||
private HintProvider hints;
|
||||
|
||||
public TypeContext(ApplicationYamlAssistContext parent, YamlPath contextPath, Type type,
|
||||
PropertyCompletionFactory completionFactory, TypeUtil typeUtil, RelaxedNameConfig conf, HintProvider hints) {
|
||||
super(parent.documentSelector, contextPath, typeUtil, conf);
|
||||
this.parent = parent;
|
||||
this.completionFactory = completionFactory;
|
||||
this.type = type;
|
||||
this.hints = hints;
|
||||
}
|
||||
|
||||
private HintProvider getHintProvider() {
|
||||
return hints;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ICompletionProposal> getCompletions(YamlDocument doc, SNode node, int offset) throws Exception {
|
||||
String query = getPrefix(doc, node, offset);
|
||||
EnumCaseMode enumCaseMode = enumCaseMode(query);
|
||||
BeanPropertyNameMode beanMode = conf.getBeanMode();
|
||||
List<ICompletionProposal> valueCompletions = getValueCompletions(doc, offset, query, enumCaseMode);
|
||||
if (!valueCompletions.isEmpty()) {
|
||||
return valueCompletions;
|
||||
}
|
||||
return getKeyCompletions(doc, offset, query, enumCaseMode, beanMode);
|
||||
}
|
||||
|
||||
private EnumCaseMode enumCaseMode(String query) {
|
||||
if (query.isEmpty()) {
|
||||
return conf.getEnumMode();
|
||||
} else {
|
||||
return EnumCaseMode.ALIASED; // will match candidates from both lower and original based on what user typed
|
||||
}
|
||||
}
|
||||
|
||||
public List<ICompletionProposal> getKeyCompletions(YamlDocument doc, int offset, String query,
|
||||
EnumCaseMode enumCaseMode, BeanPropertyNameMode beanMode) throws Exception {
|
||||
int queryOffset = offset - query.length();
|
||||
List<TypedProperty> properties = getProperties(query, enumCaseMode, beanMode);
|
||||
if (CollectionUtil.hasElements(properties)) {
|
||||
ArrayList<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>(properties.size());
|
||||
SNode contextNode = getContextNode(doc);
|
||||
Set<String> definedProps = getDefinedProperties(contextNode);
|
||||
for (TypedProperty p : properties) {
|
||||
String name = p.getName();
|
||||
double score = FuzzyMatcher.matchScore(query, name);
|
||||
if (score!=0) {
|
||||
YamlPath relativePath = YamlPath.fromSimpleProperty(name);
|
||||
YamlPathEdits edits = new YamlPathEdits(doc);
|
||||
if (!definedProps.contains(name)) {
|
||||
//property not yet defined
|
||||
Type type = p.getType();
|
||||
edits.delete(queryOffset, query);
|
||||
edits.createPathInPlace(contextNode, relativePath, queryOffset, appendTextFor(type));
|
||||
proposals.add(completionFactory.beanProperty(doc.getDocument(),
|
||||
contextPath.toPropString(), getType(),
|
||||
query, p, score, edits, typeUtil)
|
||||
);
|
||||
} else {
|
||||
//property already defined
|
||||
// instead of filtering, navigate to the place where its defined.
|
||||
deleteQueryAndLine(doc, query, queryOffset, edits);
|
||||
//Cast to SChildBearingNode cannot fail because otherwise definedProps would be the empty set.
|
||||
edits.createPath((SChildBearingNode) contextNode, relativePath, "");
|
||||
proposals.add(
|
||||
completionFactory.beanProperty(doc.getDocument(),
|
||||
contextPath.toPropString(), getType(),
|
||||
query, p, score, edits, typeUtil)
|
||||
.deemphasize() //deemphasize because it already exists
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return proposals;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
protected List<TypedProperty> getProperties(String query, EnumCaseMode enumCaseMode, BeanPropertyNameMode beanMode) {
|
||||
ArrayList<TypedProperty> props = new ArrayList<>();
|
||||
List<TypedProperty> fromType = typeUtil.getProperties(type, enumCaseMode, beanMode);
|
||||
if (CollectionUtil.hasElements(fromType)) {
|
||||
props.addAll(fromType);
|
||||
}
|
||||
HintProvider hints = getHintProvider();
|
||||
if (hints!=null) {
|
||||
List<TypedProperty> fromHints = hints.getPropertyHints(query);
|
||||
if (CollectionUtil.hasElements(fromHints)) {
|
||||
props.addAll(fromHints);
|
||||
}
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
private Set<String> getDefinedProperties(SNode contextNode) {
|
||||
try {
|
||||
if (contextNode instanceof SChildBearingNode) {
|
||||
List<SNode> children = ((SChildBearingNode)contextNode).getChildren();
|
||||
if (CollectionUtil.hasElements(children)) {
|
||||
Set<String> keys = new HashSet<String>(children.size());
|
||||
for (SNode c : children) {
|
||||
if (c instanceof SKeyNode) {
|
||||
keys.add(((SKeyNode) c).getKey());
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
private List<ICompletionProposal> getValueCompletions(YamlDocument doc, int offset, String query, EnumCaseMode enumCaseMode) {
|
||||
Collection<StsValueHint> hints = getHintValues(query, doc, offset, enumCaseMode);
|
||||
if (hints!=null) {
|
||||
ArrayList<ICompletionProposal> completions = new ArrayList<ICompletionProposal>();
|
||||
for (StsValueHint hint : hints) {
|
||||
String value = hint.getValue();
|
||||
double score = FuzzyMatcher.matchScore(query, value);
|
||||
if (score!=0 && !value.equals(query)) {
|
||||
DocumentEdits edits = new DocumentEdits(doc.getDocument());
|
||||
int valueStart = offset-query.length();
|
||||
edits.delete(valueStart, offset);
|
||||
if (doc.getChar(valueStart-1)==':') {
|
||||
edits.insert(offset, " ");
|
||||
}
|
||||
edits.insert(offset, YamlUtil.stringEscape(value));
|
||||
completions.add(completionFactory.valueProposal(value, query, type, score, edits, new ValueHintHoverInfo(hint)));
|
||||
}
|
||||
}
|
||||
return completions;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public HoverInfo getValueHoverInfo(YamlDocument doc, DocumentRegion valueRegion) {
|
||||
// String value = valueRegion.toString();
|
||||
//
|
||||
// if (TypeUtil.isClass(type)) {
|
||||
// //Special case. We want hovers/hyperlinks even if the class is not a valid hint (as long as it is a class)
|
||||
// StsValueHint hint = StsValueHint.className(value.toString(), typeUtil);
|
||||
// if (hint!=null) {
|
||||
// return new ValueHintHoverInfo(hint);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Collection<StsValueHint> hints = getHintValues(value, doc, valueRegion.getEnd(), EnumCaseMode.ALIASED);
|
||||
// //The hints where found by fuzzy match so they may not actually match exactly!
|
||||
// for (StsValueHint h : hints) {
|
||||
// if (value.equals(h.getValue())) {
|
||||
// return new ValueHintHoverInfo(h);
|
||||
// }
|
||||
// }
|
||||
// return super.getValueHoverInfo(doc, valueRegion);
|
||||
// }
|
||||
|
||||
protected Collection<StsValueHint> getHintValues(
|
||||
String query,
|
||||
YamlDocument doc, int offset,
|
||||
EnumCaseMode enumCaseMode
|
||||
) {
|
||||
Collection<StsValueHint> allHints = new ArrayList<>();
|
||||
{
|
||||
Collection<StsValueHint> hints = typeUtil.getHintValues(type, query, enumCaseMode);
|
||||
if (CollectionUtil.hasElements(hints)) {
|
||||
allHints.addAll(hints);
|
||||
}
|
||||
}
|
||||
{
|
||||
HintProvider hintProvider = getHintProvider();
|
||||
if (hintProvider!=null) {
|
||||
allHints.addAll(hintProvider.getValueHints(query));
|
||||
}
|
||||
}
|
||||
return allHints;
|
||||
}
|
||||
|
||||
@Override
|
||||
public YamlAssistContext traverse(YamlPathSegment s) {
|
||||
if (s.getType()==YamlPathSegmentType.VAL_AT_KEY) {
|
||||
if (TypeUtil.isSequencable(type) || TypeUtil.isMap(type)) {
|
||||
return contextWith(s, TypeUtil.getDomainType(type));
|
||||
}
|
||||
String key = s.toPropString();
|
||||
Map<String, TypedProperty> subproperties = typeUtil.getPropertiesMap(type, EnumCaseMode.ALIASED, BeanPropertyNameMode.ALIASED);
|
||||
if (subproperties!=null) {
|
||||
return contextWith(s, TypedProperty.typeOf(subproperties.get(key)));
|
||||
}
|
||||
} else if (s.getType()==YamlPathSegmentType.VAL_AT_INDEX) {
|
||||
if (TypeUtil.isSequencable(type)) {
|
||||
return contextWith(s, TypeUtil.getDomainType(type));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private AbstractYamlAssistContext contextWith(YamlPathSegment s, Type nextType) {
|
||||
if (nextType!=null) {
|
||||
return new TypeContext(this, contextPath.append(s), nextType, completionFactory, typeUtil, conf,
|
||||
new YamlPath(s).traverse(hints));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TypeContext("+contextPath.toPropString()+"::"+type+")";
|
||||
}
|
||||
|
||||
|
||||
// @Override
|
||||
// public HoverInfo getHoverInfo() {
|
||||
// if (parent instanceof IndexContext) {
|
||||
// //this context is in fact an 'alias' of its parent, representing the
|
||||
// // point in the context hierarchy where a we transition from navigating
|
||||
// // the index to navigating type/bean properties
|
||||
// return parent.getHoverInfo();
|
||||
// } else {
|
||||
// return new JavaTypeNavigationHoverInfo(contextPath.toPropString(), contextPath.getBeanPropertyName(), parent.getType(), getType(), typeUtil);
|
||||
// }
|
||||
// }
|
||||
|
||||
@Override
|
||||
protected Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class IndexContext extends ApplicationYamlAssistContext {
|
||||
|
||||
private IndexNavigator indexNav;
|
||||
PropertyCompletionFactory completionFactory;
|
||||
|
||||
public IndexContext(int documentSelector, YamlPath contextPath, IndexNavigator indexNav,
|
||||
PropertyCompletionFactory completionFactory, TypeUtil typeUtil, RelaxedNameConfig conf) {
|
||||
super(documentSelector, contextPath, typeUtil, conf);
|
||||
this.indexNav = indexNav;
|
||||
this.completionFactory = completionFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ICompletionProposal> getCompletions(YamlDocument doc, SNode node, int offset) throws Exception {
|
||||
String query = getPrefix(doc, node, offset);
|
||||
Collection<Match<PropertyInfo>> matchingProps = indexNav.findMatching(query);
|
||||
if (!matchingProps.isEmpty()) {
|
||||
ArrayList<ICompletionProposal> completions = new ArrayList<ICompletionProposal>();
|
||||
for (Match<PropertyInfo> match : matchingProps) {
|
||||
DocumentEdits edits = createEdits(doc, offset, query, match);
|
||||
ScoreableProposal completion = completionFactory.property(
|
||||
doc.getDocument(), edits, match, typeUtil
|
||||
);
|
||||
if (getContextRoot(doc).exists(YamlPath.fromProperty(match.data.getId()))) {
|
||||
completion.deemphasize();
|
||||
}
|
||||
completions.add(completion);
|
||||
}
|
||||
return completions;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
protected DocumentEdits createEdits(final YamlDocument file,
|
||||
final int offset, final String query, final Match<PropertyInfo> match)
|
||||
throws Exception {
|
||||
//Edits created lazyly as they are somwehat expensive to compute and mostly
|
||||
// we need only the edits for the one proposal that user picks.
|
||||
return LazyProposalApplier.from(() -> {
|
||||
YamlPathEdits edits = new YamlPathEdits(file);
|
||||
|
||||
int queryOffset = offset-query.length();
|
||||
edits.delete(queryOffset, query);
|
||||
|
||||
YamlPath propertyPath = YamlPath.fromProperty(match.data.getId());
|
||||
YamlPath relativePath = propertyPath.dropFirst(contextPath.size());
|
||||
YamlPathSegment nextSegment = relativePath.getSegment(0);
|
||||
SNode contextNode = getContextNode(file);
|
||||
//To determine if this completion is 'in place' or needs to be inserted
|
||||
// elsewhere in the tree, we check whether a node already exists in our
|
||||
// context. If it doesn't we can create it as any child of the context
|
||||
// so that includes, right at place the user is typing now.
|
||||
SNode existingNode = contextNode.traverse(nextSegment);
|
||||
String appendText = appendTextFor(TypeParser.parse(match.data.getType()));
|
||||
if (existingNode==null) {
|
||||
edits.createPathInPlace(contextNode, relativePath, queryOffset, appendText);
|
||||
} else {
|
||||
String wholeLine = file.getLineTextAtOffset(queryOffset);
|
||||
if (wholeLine.trim().equals(query.trim())) {
|
||||
edits.deleteLineBackwardAtOffset(queryOffset);
|
||||
}
|
||||
edits.createPath(getContextRoot(file), YamlPath.fromProperty(match.data.getId()), appendText);
|
||||
}
|
||||
return edits;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractYamlAssistContext traverse(YamlPathSegment s) {
|
||||
if (s.getType()==YamlPathSegmentType.VAL_AT_KEY) {
|
||||
String key = s.toPropString();
|
||||
IndexNavigator subIndex = indexNav.selectSubProperty(key);
|
||||
if (subIndex.isEmpty()) {
|
||||
//Nothing found for actual key... maybe its a 'camelCased' alias of real key?
|
||||
String keyAlias = StringUtil.camelCaseToHyphens(key);
|
||||
if (!keyAlias.equals(key)) { // no point checking alias is the same (likely key was not camelCased)
|
||||
IndexNavigator aliasedSubIndex = indexNav.selectSubProperty(keyAlias);
|
||||
if (!aliasedSubIndex.isEmpty()) {
|
||||
subIndex = aliasedSubIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (subIndex.getExtensionCandidate()!=null) {
|
||||
return new IndexContext(documentSelector, contextPath.append(s), subIndex, completionFactory, typeUtil, conf);
|
||||
} else if (subIndex.getExactMatch()!=null) {
|
||||
IndexContext asIndexContext = new IndexContext(documentSelector, contextPath.append(s), subIndex, completionFactory, typeUtil, conf);
|
||||
PropertyInfo prop = subIndex.getExactMatch();
|
||||
return new TypeContext(asIndexContext, contextPath.append(s), TypeParser.parse(prop.getType()), completionFactory, typeUtil, conf, prop.getHints(typeUtil, true));
|
||||
}
|
||||
}
|
||||
//Unsuported navigation => no context for assist
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "YamlAssistIndexContext("+indexNav+")";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Type getType() {
|
||||
PropertyInfo match = indexNav.getExactMatch();
|
||||
if (match!=null) {
|
||||
return TypeParser.parse(match.getType());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public HoverInfo getHoverInfo() {
|
||||
// PropertyInfo prop = indexNav.getExactMatch();
|
||||
// if (prop!=null) {
|
||||
// return new SpringPropertyHoverInfo(typeUtil.getJavaProject(), prop);
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
}
|
||||
|
||||
// public abstract HoverInfo getHoverInfo();
|
||||
// public HoverInfo getHoverInfo(YamlPathSegment s) {
|
||||
// //ApplicationYamlAssistContext implements getHoverInfo directly. so this is not needed.
|
||||
// return null;
|
||||
// }
|
||||
|
||||
public static YamlAssistContext global(final FuzzyMap<PropertyInfo> index, final PropertyCompletionFactory completionFactory, final TypeUtil typeUtil, final RelaxedNameConfig conf) {
|
||||
return new TopLevelAssistContext() {
|
||||
@Override
|
||||
protected YamlAssistContext getDocumentContext(int documentSelector) {
|
||||
return subdocument(documentSelector, index, completionFactory, typeUtil, conf);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2015 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.application.yaml.completions;
|
||||
|
||||
import org.springframework.ide.vscode.application.properties.metadata.PropertyInfo;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.SpringPropertyIndexProvider;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.completions.PropertyCompletionFactory;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.completions.RelaxedNameConfig;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtilProvider;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.util.FuzzyMap;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.IDocument;
|
||||
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.completion.YamlCompletionEngine;
|
||||
import org.springframework.ide.vscode.commons.yaml.structure.YamlDocument;
|
||||
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureProvider;
|
||||
|
||||
/**
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class ApplicationYamlCompletionEngine {
|
||||
public static YamlCompletionEngine create(
|
||||
final SpringPropertyIndexProvider indexProvider,
|
||||
final JavaProjectFinder documentContextFinder,
|
||||
final YamlStructureProvider structureProvider,
|
||||
final TypeUtilProvider typeUtilProvider,
|
||||
final RelaxedNameConfig conf
|
||||
) {
|
||||
final PropertyCompletionFactory completionFactory = new PropertyCompletionFactory(documentContextFinder);
|
||||
YamlAssistContextProvider contextProvider = new YamlAssistContextProvider() {
|
||||
@Override
|
||||
public YamlAssistContext getGlobalAssistContext(YamlDocument ydoc) {
|
||||
IDocument doc = ydoc.getDocument();
|
||||
FuzzyMap<PropertyInfo> index = indexProvider.getIndex(doc);
|
||||
return ApplicationYamlAssistContext.global(index, completionFactory, typeUtilProvider.getTypeUtil(doc), conf);
|
||||
}
|
||||
};
|
||||
return new YamlCompletionEngine(structureProvider, contextProvider);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*******************************************************************************
|
||||
* 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.application.yaml.completions;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.ide.vscode.commons.util.StringUtil;
|
||||
import org.springframework.ide.vscode.commons.yaml.path.KeyAliases;
|
||||
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureProvider;
|
||||
|
||||
public class ApplicationYamlStructureProvider {
|
||||
|
||||
private static final KeyAliases KEY_ALIASES = new KeyAliases() {
|
||||
@Override
|
||||
public Iterable<String> getKeyAliases(String base) {
|
||||
String camelCased = StringUtil.hyphensToCamelCase(base, false);
|
||||
if (!camelCased.equals(base)) {
|
||||
return Collections.singletonList(camelCased);
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
};
|
||||
|
||||
public static final YamlStructureProvider INSTANCE = YamlStructureProvider.withAliases(KEY_ALIASES);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.springframework.ide.vscode.application.yaml.completions;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
|
||||
/**
|
||||
* Temprary placeholder which sort of replaces the LazyProposalApplier from old STS.
|
||||
* It really does nothing right now. Somehow this should be tied into LS protocol so
|
||||
* that the edits are not computed until a completion is being resolved.
|
||||
* <p>
|
||||
* Right now this is not lazy at all and the completion edits are just computed immediatly.
|
||||
*/
|
||||
public class LazyProposalApplier {
|
||||
|
||||
public static DocumentEdits from(Callable<DocumentEdits> createEdits) throws Exception {
|
||||
return createEdits.call();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.springframework.ide.vscode.application.yaml;
|
||||
package org.springframework.ide.vscode.application.yaml.reconcile;
|
||||
|
||||
import static org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemSeverity.ERROR;
|
||||
|
||||
@@ -10,14 +10,13 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.application.yaml.reconcile;
|
||||
|
||||
import static org.springframework.ide.vscode.application.yaml.ApplicationYamlProblems.Type.YAML_SYNTAX_ERROR;
|
||||
import static org.springframework.ide.vscode.application.yaml.reconcile.ApplicationYamlProblems.Type.YAML_SYNTAX_ERROR;
|
||||
|
||||
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.SpringPropertyIndexProvider;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtilProvider;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.util.FuzzyMap;
|
||||
import org.springframework.ide.vscode.application.yaml.ApplicationYamlProblems;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.IDocument;
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.junit.Test;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.CachingValueProvider;
|
||||
import org.springframework.ide.vscode.application.properties.metadata.PropertyInfo;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.util.StringUtil;
|
||||
import org.springframework.ide.vscode.languageserver.testharness.Editor;
|
||||
@@ -41,6 +42,8 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private JavaProjectFinder javaProjectFinder;
|
||||
|
||||
@Test public void linterRunsOnDocumentOpenAndChange() throws Exception {
|
||||
Editor editor = newEditor(
|
||||
"somemap: val\n"+
|
||||
@@ -716,7 +719,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
|
||||
);
|
||||
}
|
||||
|
||||
@Ignore @Test public void testContentAssistSimple() throws Exception {
|
||||
@Test public void testContentAssistSimple() throws Exception {
|
||||
defaultTestData();
|
||||
assertCompletion("port<*>",
|
||||
"server:\n"+
|
||||
@@ -3519,7 +3522,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
|
||||
|
||||
@Override
|
||||
protected SimpleLanguageServer newLanguageServer() {
|
||||
return new ApplicationYamlLanguageServer(md.getIndexProvider(), typeUtilProvider);
|
||||
return new ApplicationYamlLanguageServer(md.getIndexProvider(), typeUtilProvider, javaProjectFinder);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ public class ApplicationYamlLanguageServerTests {
|
||||
}
|
||||
|
||||
private LanguageServerHarness newHarness() throws Exception {
|
||||
Callable<? extends LanguageServer> f = () -> new ApplicationYamlLanguageServer((d) -> null, (d) -> null);
|
||||
Callable<? extends LanguageServer> f = () -> new ApplicationYamlLanguageServer((d) -> null, (d) -> null, (d) -> null);
|
||||
return new LanguageServerHarness(f);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@ import java.util.Collection;
|
||||
|
||||
import javax.inject.Provider;
|
||||
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngine;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcileEngine;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
|
||||
|
||||
Reference in New Issue
Block a user