Missing property quickfix now uses snippet generator

This commit is contained in:
Kris De Volder
2017-08-11 16:42:40 -07:00
parent 94fa2cf498
commit 01edae7366
17 changed files with 300 additions and 57 deletions

View File

@@ -26,7 +26,6 @@ import org.springframework.ide.vscode.bosh.models.ReleasesModel;
import org.springframework.ide.vscode.bosh.models.StemcellData;
import org.springframework.ide.vscode.bosh.models.StemcellModel;
import org.springframework.ide.vscode.bosh.models.StemcellsModel;
import org.springframework.ide.vscode.bosh.snippets.SchemaBasedSnippetGenerator;
import org.springframework.ide.vscode.commons.util.Assert;
import org.springframework.ide.vscode.commons.util.CollectorUtil;
import org.springframework.ide.vscode.commons.util.PartialCollection;
@@ -52,6 +51,7 @@ import org.springframework.ide.vscode.commons.yaml.schema.YTypeUtil;
import org.springframework.ide.vscode.commons.yaml.schema.YTypedProperty;
import org.springframework.ide.vscode.commons.yaml.schema.YamlSchema;
import org.springframework.ide.vscode.commons.yaml.schema.constraints.Constraints;
import org.springframework.ide.vscode.commons.yaml.snippet.SchemaBasedSnippetGenerator;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;

View File

@@ -15,7 +15,6 @@ import org.springframework.ide.vscode.bosh.models.CloudConfigModel;
import org.springframework.ide.vscode.bosh.models.DynamicModelProvider;
import org.springframework.ide.vscode.bosh.models.ReleasesModel;
import org.springframework.ide.vscode.bosh.models.StemcellsModel;
import org.springframework.ide.vscode.bosh.snippets.SchemaBasedSnippetGenerator;
import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter;
import org.springframework.ide.vscode.commons.languageserver.hover.HoverInfoProvider;
import org.springframework.ide.vscode.commons.languageserver.hover.VscodeHoverEngine;
@@ -37,6 +36,7 @@ import org.springframework.ide.vscode.commons.yaml.quickfix.YamlQuickfixes;
import org.springframework.ide.vscode.commons.yaml.reconcile.ASTTypeCache;
import org.springframework.ide.vscode.commons.yaml.reconcile.TypeBasedYamlSymbolHandler;
import org.springframework.ide.vscode.commons.yaml.reconcile.YamlSchemaBasedReconcileEngine;
import org.springframework.ide.vscode.commons.yaml.snippet.SchemaBasedSnippetGenerator;
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureProvider;
public class BoshLanguageServer extends SimpleLanguageServer {

View File

@@ -39,6 +39,7 @@ import org.springframework.ide.vscode.bosh.models.StemcellsModel;
import org.springframework.ide.vscode.commons.util.ExternalCommand;
import org.springframework.ide.vscode.commons.util.text.LanguageId;
import org.springframework.ide.vscode.commons.yaml.reconcile.YamlSchemaProblems;
import org.springframework.ide.vscode.languageserver.testharness.CodeAction;
import org.springframework.ide.vscode.languageserver.testharness.Editor;
import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness;
@@ -2475,6 +2476,52 @@ public class BoshEditorTest {
);
editor.assertContextualCompletions(PLAIN_COMPLETION, "<*>",
"cloud_properties:\n <*>");
}
@Test public void missingPropertiesQuickfix() throws Exception {
Editor editor = harness.newEditor(
"name: blah\n" +
"stemcells:\n" +
"- alias: ubuntu\n" +
" os: ubuntu-trusty\n" +
" version: 3421.11\n" +
"- alias: centos\n" +
" os: centos-7\n" +
" version: latest"
);
Diagnostic problem = editor.assertProblems("t|Properties [instance_groups, releases, update] are required").get(0);
CodeAction quickfix = editor.assertCodeAction(problem);
assertEquals("Add properties: [instance_groups, releases, update]", quickfix.getLabel());
quickfix.perform();
editor.assertText(
"name: blah\n" +
"stemcells:\n" +
"- alias: ubuntu\n" +
" os: ubuntu-trusty\n" +
" version: 3421.11\n" +
"- alias: centos\n" +
" os: centos-7\n" +
" version: latest\n" +
"releases:\n" +
"- name: <*>\n" +
" version: \n" +
"update:\n" +
" canaries: \n" +
" max_in_flight: \n" +
" canary_watch_time: \n" +
" update_watch_time: \n" +
"instance_groups:\n" +
"- name: \n" +
" azs:\n" +
" - \n" +
" instances: \n" +
" jobs:\n" +
" - name: \n" +
" release: \n" +
" vm_type: \n" +
" stemcell: \n" +
" networks:\n" +
" - name: "
);
}
}

View File

@@ -14,11 +14,11 @@ import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.springframework.ide.vscode.bosh.models.BoshModels;
import org.springframework.ide.vscode.bosh.snippets.SchemaBasedSnippetGenerator;
import org.springframework.ide.vscode.commons.languageserver.util.SnippetBuilder;
import org.springframework.ide.vscode.commons.yaml.schema.DynamicSchemaContext;
import org.springframework.ide.vscode.commons.yaml.schema.YType;
import org.springframework.ide.vscode.commons.yaml.schema.YTypeUtil;
import org.springframework.ide.vscode.commons.yaml.snippet.SchemaBasedSnippetGenerator;
public class SchemaBasedSnippetGeneratorTest {

View File

@@ -0,0 +1,96 @@
/*******************************************************************************
* Copyright (c) 2017 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.commons.languageserver.util;
import java.util.Map;
import org.springframework.ide.vscode.commons.util.CollectionUtil;
import org.springframework.ide.vscode.commons.util.text.IRegion;
import com.google.common.collect.ImmutableMap;
/**
* Represents a string with placeholder inside. Provides methods to retrieve
* the location of a placeholder given its 'id'.
*/
public class PlaceHolderString {
public static class PlaceHolder {
public final Object id; // object used to identify the placeholder
public final IRegion location;
public PlaceHolder(Object id, IRegion location) {
super();
this.id = id;
this.location = location;
}
public int getOffset() {
return location.getOffset();
}
public int getEnd() {
return location.getOffset() + location.getLength();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
PlaceHolder other = (PlaceHolder) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}
private final ImmutableMap<Object, PlaceHolder> placeHolders;
private final String string;
public PlaceHolderString(Map<Object, PlaceHolder> placeHolders, String string) {
super();
this.placeHolders = ImmutableMap.copyOf(placeHolders);
this.string = string;
}
@Override
public String toString() {
if (placeHolders.size()==1) {
PlaceHolder placeHolder = CollectionUtil.getAny(placeHolders.values());
if (string.length()==placeHolder.getEnd()) {
return string.substring(0, placeHolder.getOffset());
}
}
return string;
}
public PlaceHolder getPlaceHolder(Object id) {
return placeHolders.get(id);
}
}

View File

@@ -10,11 +10,31 @@
*******************************************************************************/
package org.springframework.ide.vscode.commons.languageserver.util;
import java.util.HashMap;
import org.springframework.ide.vscode.commons.languageserver.util.PlaceHolderString.PlaceHolder;
import org.springframework.ide.vscode.commons.util.text.Region;
public class SnippetBuilder {
/**
* Create a 'gimped' snippetbuilder which generates snippets without
* the '$' placeholders. This is useful to provide some snippet-like
* support in contexts that don't provide snippet support.
*/
public static SnippetBuilder gimped() {
return new SnippetBuilder() {
@Override
protected String createPlaceHolder(int id) {
return "";
}
};
}
private static final int FIRST_PLACE_HOLDER_ID = 1;
private int nextPlaceHolderId = FIRST_PLACE_HOLDER_ID;
private StringBuilder buf = new StringBuilder();
private HashMap<Object, PlaceHolder> placeHolders = new HashMap<>();
public SnippetBuilder text(String text) {
buf.append(text);
@@ -25,7 +45,11 @@ public class SnippetBuilder {
* Create a new `placeholder` and appends it to the snippet.
*/
public SnippetBuilder placeHolder() {
buf.append(createPlaceHolder(nextPlaceHolderId++));
int offset = buf.length();
int id = nextPlaceHolderId++;
buf.append(createPlaceHolder(id));
int end = buf.length();
placeHolders.put(id, new PlaceHolderString.PlaceHolder(id, new Region(offset, end-offset)));
return this;
}
@@ -42,6 +66,10 @@ public class SnippetBuilder {
return "$"+id;
}
public PlaceHolderString build() {
return new PlaceHolderString(placeHolders, buf.toString());
}
@Override
public String toString() {
String str = buf.toString();

View File

@@ -166,7 +166,7 @@ public class YTypeAssistContext extends AbstractYamlAssistContext {
DocumentEdits edits;
if (snippetProvider!=null) {
// Generate edits from snippet
Snippet snippet = snippetProvider.getSnippet(type, p);
Snippet snippet = snippetProvider.getSnippet(p);
edits = createEditFromSnippet(doc, node, offset, query, indenter, snippet);
} else {
//Generate edits the old-fashioned way

View File

@@ -112,7 +112,7 @@ public class YamlPathEdits extends DocumentEdits {
return buf.toString();
}
private int getNewPathInsertionOffset(SChildBearingNode parent) throws Exception {
public int getNewPathInsertionOffset(SChildBearingNode parent) throws Exception {
int insertAfterLine = doc.getLineOfOffset(parent.getTreeEnd());
while (insertAfterLine>=0 && doc.getLineIndentation(insertAfterLine)==-1) {
insertAfterLine--;

View File

@@ -30,6 +30,7 @@ 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.SNode;
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureProvider;
import org.springframework.ide.vscode.commons.yaml.util.YamlIndentUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableList;
@@ -58,11 +59,22 @@ public class YamlQuickfixes {
YamlPath path = YamlPath.decode(params.getPath());
SNode _target = path.traverse(root);
if (_target instanceof SChildBearingNode) {
YamlPathEdits edits = new YamlPathEdits(doc);
YamlIndentUtil indenter = new YamlIndentUtil(doc);
SChildBearingNode target = (SChildBearingNode) _target;
for (String prop : params.getProps()) {
edits.createPath(target, new YamlPath(YamlPathSegment.valueAt(prop)), " ");
edits.freezeCursor();
YamlPathEdits edits = new YamlPathEdits(doc);
int insertAt = edits.getNewPathInsertionOffset(target);
int indentBy = YamlIndentUtil.getNewChildKeyIndent(target);
boolean first = true;
String propSnippet = params.getSnippet();
int cursorOffset = params.getCursorOffset();
{
edits.insert(insertAt, indenter.newlineWithIndent(indentBy));
edits.insert(insertAt, indenter.applyIndentation(propSnippet.substring(0,cursorOffset), indentBy));
if (first) {
edits.freezeCursor();
first = false;
}
edits.insert(insertAt, indenter.applyIndentation(propSnippet.substring(cursorOffset), indentBy));
}
TextReplace replaceEdit = edits.asReplacement(_doc);
if (replaceEdit!=null) {
@@ -94,14 +106,13 @@ public class YamlQuickfixes {
ImmutableMap.of(params.getUri(), ImmutableList.of(params.getEdit())),
null
),
null //TODO: compute end of the range after applying the edit
null //TODO: compute end of the range after applying the edit
);
}
} catch (Exception e) {
Log.log(e);
}
//Something went wrong. Return empty edit object.
//Something went wrong. Return empty edit object.
return NULL_FIX;
});
}
@@ -113,7 +124,7 @@ public class YamlQuickfixes {
//There is probably a more efficient way to compute the new cursor position. But its tricky...
//... because we need to compute line/char coordinate, in terms of lines in the *new* document.
//So we have to take into account how newlines have been inserted or shifted around by the edits.
//Doing that without actually applying the edits is... difficult.
//Doing that without actually applying the edits is... difficult.
TextDocument doc = _doc.copy();
edits.apply(doc);
return doc.toPosition(newSelection.getOffset());

View File

@@ -12,20 +12,43 @@ package org.springframework.ide.vscode.commons.yaml.reconcile;
import java.util.List;
import com.google.common.collect.ImmutableList;
public class MissingPropertiesData {
private String uri;
/**
* Yaml path (encoded segments) pointing to the node where
* the missing properties should be added (as children of that node).
*/
private List<String> path;
/**
* The properties that are missing and should be added.
*/
private List<String> props;
public MissingPropertiesData(String uri, List<String> path, List<String> props) {
/**
* Snippet to insert when applying the quickfix.
*/
private String snippet;
/**
* Offset where to place cursor relative to snippet start.
*/
private int cursorOffset;
public MissingPropertiesData() {
}
public MissingPropertiesData(String uri, List<String> path, List<String> props, String snippet, int cursorOffset) {
super();
this.uri = uri;
this.path = path;
this.props = props;
}
public MissingPropertiesData() {
this.snippet = snippet;
this.cursorOffset = cursorOffset;
}
public String getUri() {
@@ -47,8 +70,24 @@ public class MissingPropertiesData {
this.props = props;
}
public String getSnippet() {
return snippet;
}
public void setSnippet(String snippet) {
this.snippet = snippet;
}
@Override
public String toString() {
return "MissingPropertiesData [uri=" + uri + ", path=" + path + ", props=" + props + "]";
}
public int getCursorOffset() {
return cursorOffset;
}
public void setCursorOffset(int cursorOffset) {
this.cursorOffset = cursorOffset;
}
}

View File

@@ -31,6 +31,8 @@ import org.springframework.ide.vscode.commons.languageserver.reconcile.Reconcile
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReplacementQuickfix;
import org.springframework.ide.vscode.commons.languageserver.util.DocumentRegion;
import org.springframework.ide.vscode.commons.languageserver.util.SnippetBuilder;
import org.springframework.ide.vscode.commons.util.CollectorUtil;
import org.springframework.ide.vscode.commons.util.ExceptionUtil;
import org.springframework.ide.vscode.commons.util.IntegerRange;
import org.springframework.ide.vscode.commons.util.Log;
@@ -51,6 +53,9 @@ import org.springframework.ide.vscode.commons.yaml.schema.YTypeUtil;
import org.springframework.ide.vscode.commons.yaml.schema.YTypedProperty;
import org.springframework.ide.vscode.commons.yaml.schema.YamlSchema;
import org.springframework.ide.vscode.commons.yaml.schema.constraints.Constraint;
import org.springframework.ide.vscode.commons.yaml.snippet.SchemaBasedSnippetGenerator;
import org.springframework.ide.vscode.commons.yaml.snippet.Snippet;
import org.springframework.ide.vscode.commons.yaml.snippet.TypeBasedSnippetProvider;
import org.yaml.snakeyaml.nodes.MappingNode;
import org.yaml.snakeyaml.nodes.Node;
import org.yaml.snakeyaml.nodes.NodeId;
@@ -285,21 +290,25 @@ public class SchemaBasedYamlASTReconciler implements YamlASTReconciler {
//Don't check for missing properties if some properties look like they might be spelled incorrectly.
if (allPropertiesKnown) {
//Check for missing required properties:
Set<String> missingProps = beanProperties.values().stream()
List<YTypedProperty> missingProps = beanProperties.values().stream()
.filter(YTypedProperty::isRequired)
.filter(prop -> !foundProps.contains(prop.getName()))
.collect(CollectorUtil.toImmutableList());
Set<String> missingPropNames = missingProps.stream()
.map(YTypedProperty::getName)
.filter((required) -> !foundProps.contains(required))
.collect(Collectors.toCollection(TreeSet::new));
if (!missingProps.isEmpty()) {
if (!missingPropNames.isEmpty()) {
String message;
if (missingProps.size()==1) {
if (missingPropNames.size()==1) {
// slightly more specific message when only one missing property
String missing = missingProps.stream().findFirst().get();
String missing = missingPropNames.stream().findFirst().get();
message = "Property '"+missing+"' is required for '"+type+"'";
} else {
message = "Properties "+missingProps+" are required for '"+type+"'";
message = "Properties "+missingPropNames+" are required for '"+type+"'";
}
problems.accept(YamlSchemaProblems.missingProperties(message, dc, missingProps, parent, map, quickfixes.MISSING_PROP_FIX));
SchemaBasedSnippetGenerator snippetProvider = new SchemaBasedSnippetGenerator(typeUtil, SnippetBuilder::gimped);
Snippet snippet = snippetProvider.getSnippet(missingProps);
problems.accept(YamlSchemaProblems.missingProperties(message, dc, missingPropNames, snippet.getSnippet(), snippet.getPlaceHolder(1).getOffset(), parent, map, quickfixes.MISSING_PROP_FIX));
}
}
}

View File

@@ -23,6 +23,7 @@ import org.springframework.ide.vscode.commons.languageserver.reconcile.Reconcile
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl;
import org.springframework.ide.vscode.commons.languageserver.util.DocumentRegion;
import org.springframework.ide.vscode.commons.util.CollectionUtil;
import org.springframework.ide.vscode.commons.util.CollectorUtil;
import org.springframework.ide.vscode.commons.util.text.IDocument;
import org.springframework.ide.vscode.commons.yaml.ast.NodeUtil;
import org.springframework.ide.vscode.commons.yaml.path.YamlPath;
@@ -30,6 +31,7 @@ import org.springframework.ide.vscode.commons.yaml.path.YamlPathSegment;
import org.springframework.ide.vscode.commons.yaml.schema.DynamicSchemaContext;
import org.springframework.ide.vscode.commons.yaml.schema.YType;
import org.springframework.ide.vscode.commons.yaml.schema.YTypedProperty;
import org.springframework.ide.vscode.commons.yaml.snippet.Snippet;
import org.yaml.snakeyaml.error.Mark;
import org.yaml.snakeyaml.nodes.MappingNode;
import org.yaml.snakeyaml.nodes.Node;
@@ -138,7 +140,7 @@ public class YamlSchemaProblems {
return problem(MISSING_PROPERTY, msg, underline);
}
public static ReconcileProblem missingProperties(String msg, DynamicSchemaContext dc, Set<String> missingProps, Node parent, MappingNode map, QuickfixType quickfixType) {
public static ReconcileProblem missingProperties(String msg, DynamicSchemaContext dc, Set<String> missingProps, String snippet, int cursorOffset, Node parent, MappingNode map, QuickfixType quickfixType) {
YamlPath contextPath = dc.getPath();
List<String> segments = Stream.of(contextPath.getSegments())
.map(YamlPathSegment::encode)
@@ -152,7 +154,9 @@ public class YamlSchemaProblems {
new MissingPropertiesData(
dc.getDocument().getUri(),
segments,
ImmutableList.copyOf(missingProps)
ImmutableList.copyOf(missingProps),
snippet,
cursorOffset
),
fixTitle
);

View File

@@ -8,26 +8,21 @@
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.bosh.snippets;
package org.springframework.ide.vscode.commons.yaml.snippet;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import org.springframework.ide.vscode.commons.languageserver.util.PlaceHolderString;
import org.springframework.ide.vscode.commons.languageserver.util.SnippetBuilder;
import org.springframework.ide.vscode.commons.util.CollectorUtil;
import org.springframework.ide.vscode.commons.util.Log;
import org.springframework.ide.vscode.commons.yaml.schema.YType;
import org.springframework.ide.vscode.commons.yaml.schema.YTypeUtil;
import org.springframework.ide.vscode.commons.yaml.schema.YTypedProperty;
import org.springframework.ide.vscode.commons.yaml.snippet.Snippet;
import org.springframework.ide.vscode.commons.yaml.snippet.TypeBasedSnippetProvider;
import org.springframework.ide.vscode.commons.yaml.util.YamlIndentUtil;
import com.google.common.base.Supplier;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableList;
/**
@@ -45,19 +40,11 @@ public class SchemaBasedSnippetGenerator implements TypeBasedSnippetProvider {
this.snippetBuilderFactory = snippetBuilderFactory;
}
private Cache<YType, Collection<Snippet>> cache = CacheBuilder.newBuilder()
.weakKeys()
.build();
private int maxNesting = Integer.MAX_VALUE;
@Override
public Collection<Snippet> getSnippets(YType type) {
try {
return cache.get(type, () -> generateSnippets(type));
} catch (ExecutionException e) {
Log.log(e);
return ImmutableList.of();
}
return generateSnippets(type);
}
private Collection<Snippet> generateSnippets(YType type) {
@@ -76,7 +63,7 @@ public class SchemaBasedSnippetGenerator implements TypeBasedSnippetProvider {
generateBeanSnippet(requiredProps, builder, indent, maxNesting);
}
if (builder.getPlaceholderCount()>=2) {
return new Snippet(typeUtil.niceTypeName(type)+" Snippet", builder.toString(), (dc) ->
return new Snippet(typeUtil.niceTypeName(type)+" Snippet", builder.build(), (dc) ->
requiredProps.stream().noneMatch(p -> dc.getDefinedProperties().contains(p.getName()))
);
}
@@ -103,16 +90,21 @@ public class SchemaBasedSnippetGenerator implements TypeBasedSnippetProvider {
}
@Override
public Snippet getSnippet(YType contextType, YTypedProperty p) {
//TODO: cache?
public Snippet getSnippet(List<YTypedProperty> props) {
SnippetBuilder builder = snippetBuilderFactory.get();
generateBeanSnippet(ImmutableList.of(p), builder, 0, maxNesting);
String propName = p.getName();
return new Snippet(propName, builder.toString(), (dc) ->
!dc.getDefinedProperties().contains(propName)
generateBeanSnippet(props, builder, 0, maxNesting);
String snippetName;
if (props.size()==1) {
snippetName = props.get(0).getName();
} else {
snippetName = props.stream().map(p -> p.getName()).collect(Collectors.toList()).toString() + " Snippet";
}
return new Snippet(snippetName, builder.build(), (dc) ->
props.stream().allMatch(p -> !dc.getDefinedProperties().contains(p.getName()))
);
}
private void generateNestedSnippet(boolean parentIsSeq, YType type, SnippetBuilder builder, int indent, int nestingLimit) {
if (type==null) {
//Assume its some kind of pojo bean

View File

@@ -12,16 +12,18 @@ package org.springframework.ide.vscode.commons.yaml.snippet;
import java.util.function.Predicate;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl;
import org.springframework.ide.vscode.commons.languageserver.util.PlaceHolderString;
import org.springframework.ide.vscode.commons.languageserver.util.PlaceHolderString.PlaceHolder;
import org.springframework.ide.vscode.commons.yaml.schema.DynamicSchemaContext;
import org.springframework.ide.vscode.commons.yaml.schema.YTypedProperty;
public class Snippet {
private final String name;
private final String snippet;
private final PlaceHolderString snippet;
private final Predicate<DynamicSchemaContext> applicability;
public Snippet(String name, String snippet, Predicate<DynamicSchemaContext> applicability) {
public Snippet(String name, PlaceHolderString snippet, Predicate<DynamicSchemaContext> applicability) {
super();
this.name = name;
this.snippet = snippet;
@@ -31,7 +33,7 @@ public class Snippet {
return name;
}
public String getSnippet() {
return snippet;
return snippet.toString();
}
@Override
@@ -44,4 +46,7 @@ public class Snippet {
public boolean isApplicable(DynamicSchemaContext dc) {
return applicability==null || applicability.test(dc);
}
public PlaceHolder getPlaceHolder(Object id) {
return snippet.getPlaceHolder(id);
}
}

View File

@@ -11,13 +11,19 @@
package org.springframework.ide.vscode.commons.yaml.snippet;
import java.util.Collection;
import java.util.List;
import org.springframework.ide.vscode.commons.yaml.schema.YType;
import org.springframework.ide.vscode.commons.yaml.schema.YTypedProperty;
import com.google.common.collect.ImmutableList;
public interface TypeBasedSnippetProvider {
Collection<Snippet> getSnippets(YType contextType);
Snippet getSnippet(YType contextType, YTypedProperty p);
default Snippet getSnippet(YTypedProperty p) {
return getSnippet(ImmutableList.of(p));
}
Snippet getSnippet(List<YTypedProperty> props);
}

View File

@@ -84,6 +84,12 @@ public class YamlIndentUtil {
return buf.toString();
}
public String indentString(int indent) {
StringBuilder buf = new StringBuilder();
addIndent(indent, buf);
return buf.toString();
}
/**
* Applies a certain level of indentation to all new lines in the given text. Newlines
* are expressed by '\n' characters in the text will be replaced by the appropriate

View File

@@ -100,9 +100,9 @@ public class ConcourseEditorTest {
" type: pool\n" +
" source:\n" +
" username: someone\n" +
" branch: <*>\n" +
" pool: \n" +
" uri: \n"
" uri: <*>\n" +
" branch: \n" +
" pool: \n"
);
}