Cut down on the noise in content assist
Use a 'tiered' model for properties - primary property - requred - other Only suggest completions for a tier if the properties in the preceding tier are already defined.
This commit is contained in:
@@ -13,7 +13,6 @@ package org.springframework.ide.vscode.boot.java.completions;
|
||||
import org.eclipse.lsp4j.CompletionItemKind;
|
||||
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.util.Renderable;
|
||||
import org.springframework.ide.vscode.commons.util.text.IDocument;
|
||||
|
||||
|
||||
@@ -19,9 +19,10 @@ public abstract class ScoreableProposal implements ICompletionProposal {
|
||||
|
||||
public static final double DEEMP_EXISTS = 0.1;
|
||||
public static final double DEEMP_DEPRECATION = 0.2;
|
||||
public static final double DEEMP_DASH_PROPOSAL = 0.5;
|
||||
public static final double DEEMP_INDENTED_PROPOSAL = 1.0;
|
||||
public static final double DEEMP_DEDENTED_PROPOSAL = 1.5;
|
||||
public static final double DEEMP_NEXT_CONTEXT = 0.0;
|
||||
public static final double DEEMP_INDENTED_PROPOSAL = 0.4;
|
||||
public static final double DEEMP_DASH_PROPOSAL = 0.6;
|
||||
public static final double DEEMP_DEDENTED_PROPOSAL = 0.8;
|
||||
|
||||
private static final double DEEMP_VALUE = 10_000; // should be large enough to move deemphasized stuff to bottom of list.
|
||||
|
||||
@@ -53,7 +54,7 @@ public abstract class ScoreableProposal implements ICompletionProposal {
|
||||
}
|
||||
@Override
|
||||
public ScoreableProposal deemphasize(double howmuch) {
|
||||
Assert.isLegal(howmuch>0.0);
|
||||
Assert.isLegal(howmuch>=0.0);
|
||||
deemphasizedBy+= howmuch*DEEMP_VALUE;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -10,12 +10,15 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.yaml.completion;
|
||||
|
||||
import static org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal.DEEMP_DASH_PROPOSAL;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -105,51 +108,71 @@ public class YTypeAssistContext extends AbstractYamlAssistContext {
|
||||
int queryOffset = offset - query.length();
|
||||
SNode contextNode = getContextNode();
|
||||
DynamicSchemaContext dynamicCtxt = getSchemaContext();
|
||||
List<YTypedProperty> properties = typeUtil.getProperties(type);
|
||||
if (CollectionUtil.hasElements(properties)) {
|
||||
ArrayList<ICompletionProposal> proposals = new ArrayList<>(properties.size());
|
||||
List<YTypedProperty> allProperties = typeUtil.getProperties(type);
|
||||
if (CollectionUtil.hasElements(allProperties)) {
|
||||
List<List<YTypedProperty>> tieredProperties = sortIntoTiers(allProperties);
|
||||
Set<String> definedProps = dynamicCtxt.getDefinedProperties();
|
||||
for (YTypedProperty 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
|
||||
YType YType = p.getType();
|
||||
edits.delete(queryOffset, query);
|
||||
if (queryOffset>0 && !Character.isWhitespace(doc.getChar(queryOffset-1))) {
|
||||
//See https://www.pivotaltracker.com/story/show/137722057
|
||||
edits.insert(queryOffset, " ");
|
||||
for (List<YTypedProperty> thisTier : tieredProperties) {
|
||||
List<YTypedProperty> undefinedProps = thisTier.stream()
|
||||
.filter(p -> !definedProps.contains(p.getName()))
|
||||
.collect(Collectors.toList());
|
||||
if (!undefinedProps.isEmpty()) {
|
||||
List<ICompletionProposal> proposals = new ArrayList<>();
|
||||
for (YTypedProperty p : undefinedProps) {
|
||||
String name = p.getName();
|
||||
double score = FuzzyMatcher.matchScore(query, name);
|
||||
if (score!=0) {
|
||||
YamlPath relativePath = YamlPath.fromSimpleProperty(name);
|
||||
YamlPathEdits edits = new YamlPathEdits(doc);
|
||||
YType YType = p.getType();
|
||||
edits.delete(queryOffset, query);
|
||||
if (queryOffset>0 && !Character.isWhitespace(doc.getChar(queryOffset-1))) {
|
||||
//See https://www.pivotaltracker.com/story/show/137722057
|
||||
edits.insert(queryOffset, " ");
|
||||
}
|
||||
edits.createPathInPlace(contextNode, relativePath, queryOffset, appendTextFor(YType));
|
||||
proposals.add(completionFactory().beanProperty(doc.getDocument(),
|
||||
contextPath.toPropString(), getType(),
|
||||
query, p, score, edits, typeUtil)
|
||||
);
|
||||
}
|
||||
edits.createPathInPlace(contextNode, relativePath, queryOffset, appendTextFor(YType));
|
||||
proposals.add(completionFactory().beanProperty(doc.getDocument(),
|
||||
contextPath.toPropString(), getType(),
|
||||
query, p, score, edits, typeUtil)
|
||||
);
|
||||
} else {
|
||||
// This piece below deactivated becuase moving cursor like this doesn't work in vscode
|
||||
// //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(DEEMP_EXISTS) //deemphasize because it already exists
|
||||
// );
|
||||
}
|
||||
return proposals;
|
||||
}
|
||||
}
|
||||
return proposals;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Divides a given list of properties into tiers of decreasing significance. Property tiering
|
||||
* is a mechanism to reduce 'noise' in content assist proposals. Only properties of the
|
||||
* first tier that some still undefined properties will be used to generate proposals.
|
||||
* <p>
|
||||
* This allows, for example, to only suggest a 'name' property when starting to define
|
||||
* a new named entity. This is what a sane user would probably want, even though
|
||||
* in theory they would be free to define the properties in any order they want.
|
||||
*/
|
||||
protected List<List<YTypedProperty>> sortIntoTiers(List<YTypedProperty> properties) {
|
||||
if (properties.isEmpty()) {
|
||||
//Nothing to sort
|
||||
return ImmutableList.of();
|
||||
} else {
|
||||
ImmutableList.Builder<YTypedProperty> primary = ImmutableList.builder();
|
||||
ImmutableList.Builder<YTypedProperty> required = ImmutableList.builder();
|
||||
ImmutableList.Builder<YTypedProperty> other = ImmutableList.builder();
|
||||
for (YTypedProperty p : properties) {
|
||||
if (p.isPrimary()) {
|
||||
primary.add(p);
|
||||
} else if (p.isRequired()) {
|
||||
required.add(p);
|
||||
} else {
|
||||
other.add(p);
|
||||
}
|
||||
}
|
||||
return ImmutableList.of(primary.build(), required.build(), other.build());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the text that should be appended at the end of a completion
|
||||
@@ -379,7 +402,7 @@ public class YTypeAssistContext extends AbstractYamlAssistContext {
|
||||
protected String tranformLabel(String originalLabel) {
|
||||
return "- "+originalLabel;
|
||||
}
|
||||
}.deemphasize(0.5)
|
||||
}.deemphasize(DEEMP_DASH_PROPOSAL)
|
||||
);
|
||||
}
|
||||
return dashedCompletions;
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.yaml.completion;
|
||||
|
||||
import static org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal.DEEMP_DEDENTED_PROPOSAL;
|
||||
import static org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal.DEEMP_INDENTED_PROPOSAL;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -45,6 +42,8 @@ import org.springframework.ide.vscode.commons.yaml.util.YamlIndentUtil;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import static org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal.*;
|
||||
|
||||
/**
|
||||
* Implements {@link ICompletionEngine} for .yml file, based on a YamlAssistContextProvider
|
||||
* which has to to be injected into engine via its constructor.
|
||||
@@ -82,15 +81,17 @@ public class YamlCompletionEngine implements ICompletionEngine {
|
||||
if (!doc.isCommented(offset)) {
|
||||
SRootNode root = doc.getStructure();
|
||||
SNode current = root.find(offset);
|
||||
List<SNode> contextNodes = getContextNodes(doc, current, offset);
|
||||
int cursorIndent = doc.getColumn(offset);
|
||||
int nodeIndent = current.getIndent();
|
||||
int baseIndent = YamlIndentUtil.minIndent(cursorIndent, nodeIndent);
|
||||
List<SNode> contextNodes = getContextNodes(doc, current, offset, baseIndent);
|
||||
if (current.getNodeType()==SNodeType.RAW) {
|
||||
//relaxed indentation
|
||||
List<ICompletionProposal> completions = new ArrayList<>();
|
||||
int cursorIndent = doc.getColumn(offset);
|
||||
int nodeIndent = current.getIndent();
|
||||
int baseIndent = YamlIndentUtil.minIndent(cursorIndent, nodeIndent);
|
||||
double deempasizeBy = 0.0;
|
||||
for (SNode contextNode : contextNodes) {
|
||||
completions.addAll(getRelaxedCompletions(offset, doc, current, contextNode, baseIndent));
|
||||
completions.addAll(getRelaxedCompletions(offset, doc, current, contextNode, baseIndent, deempasizeBy));
|
||||
deempasizeBy += ScoreableProposal.DEEMP_NEXT_CONTEXT;
|
||||
}
|
||||
return completions;
|
||||
} else {
|
||||
@@ -104,29 +105,27 @@ public class YamlCompletionEngine implements ICompletionEngine {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
protected Collection<? extends ICompletionProposal> getRelaxedCompletions(int offset, YamlDocument doc, SNode current, SNode contextNode, int baseIndent) {
|
||||
protected Collection<? extends ICompletionProposal> getRelaxedCompletions(int offset, YamlDocument doc, SNode current, SNode contextNode, int baseIndent, double deempasizeBy) {
|
||||
try {
|
||||
return fixIndentations(getBaseCompletions(offset, doc, current, contextNode),
|
||||
current, contextNode, baseIndent);
|
||||
current, contextNode, baseIndent, deempasizeBy);
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
protected Collection<? extends ICompletionProposal> fixIndentations(Collection<ICompletionProposal> completions, SNode currentNode, SNode contextNode, int baseIndent) {
|
||||
protected Collection<? extends ICompletionProposal> fixIndentations(Collection<ICompletionProposal> completions, SNode currentNode,
|
||||
SNode contextNode, int baseIndent, double deempasizeBy) {
|
||||
if (!completions.isEmpty()) {
|
||||
int dashyIndent = getTargetIndent(contextNode, currentNode, true);
|
||||
int plainIndent = getTargetIndent(contextNode, currentNode, false);
|
||||
List<ICompletionProposal> transformed = new ArrayList<>();
|
||||
for (ICompletionProposal p : completions) {
|
||||
ICompletionProposal p_fixed = null;
|
||||
if (p.getLabel().startsWith("- ")) {
|
||||
p_fixed = indentFix(p, dashyIndent - baseIndent, currentNode, contextNode);
|
||||
} else {
|
||||
p_fixed = indentFix(p, plainIndent - baseIndent, currentNode, contextNode);
|
||||
}
|
||||
int targetIndent = p.getLabel().startsWith("- ") ? dashyIndent : plainIndent;
|
||||
ScoreableProposal p_fixed = indentFix((ScoreableProposal)p, targetIndent - baseIndent, currentNode, contextNode);
|
||||
if (p_fixed!=null) {
|
||||
p_fixed.deemphasize(deempasizeBy);
|
||||
transformed.add(p_fixed);
|
||||
}
|
||||
}
|
||||
@@ -135,11 +134,11 @@ public class YamlCompletionEngine implements ICompletionEngine {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
protected ICompletionProposal indentFix(ICompletionProposal p, int fixIndentBy, SNode currentNode, SNode contextNode) {
|
||||
protected ScoreableProposal indentFix(ScoreableProposal p, int fixIndentBy, SNode currentNode, SNode contextNode) {
|
||||
if (fixIndentBy==0) {
|
||||
return p;
|
||||
} else if (fixIndentBy>0) {
|
||||
if (isExtraIndentRelaxable(contextNode)) {
|
||||
if (isExtraIndentRelaxable(contextNode, fixIndentBy)) {
|
||||
return indented(p, Strings.repeat(" ", fixIndentBy));
|
||||
}
|
||||
} else { // fixIndentBy < 0
|
||||
@@ -182,7 +181,7 @@ public class YamlCompletionEngine implements ICompletionEngine {
|
||||
: contextNode.getIndent() + YamlIndentUtil.INDENT_BY;
|
||||
}
|
||||
|
||||
public ICompletionProposal dedented(ICompletionProposal proposal, int numSpacesToRemove, IDocument doc) {
|
||||
public ScoreableProposal dedented(ICompletionProposal proposal, int numSpacesToRemove, IDocument doc) {
|
||||
Assert.isLegal(numSpacesToRemove>0);
|
||||
int spacesEnd = proposal.getTextEdit().getFirstEditStart();
|
||||
int spacesStart = spacesEnd-numSpacesToRemove;
|
||||
@@ -214,23 +213,23 @@ public class YamlCompletionEngine implements ICompletionEngine {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public ICompletionProposal indented(ICompletionProposal proposal, String indentStr) {
|
||||
public ScoreableProposal indented(ICompletionProposal proposal, String indentStr) {
|
||||
int numArrows = (indentStr.length()+1)/2;
|
||||
ScoreableProposal transformed = new TransformedCompletion(proposal) {
|
||||
@Override public String tranformLabel(String originalLabel) {
|
||||
return Unicodes.RIGHT_ARROW+" " + originalLabel;
|
||||
return Strings.repeat(Unicodes.RIGHT_ARROW+" ", numArrows) + originalLabel;
|
||||
}
|
||||
@Override public DocumentEdits transformEdit(DocumentEdits originalEdit) {
|
||||
originalEdit.indentFirstEdit(indentStr);
|
||||
return originalEdit;
|
||||
}
|
||||
};
|
||||
transformed.deemphasize(DEEMP_INDENTED_PROPOSAL*indentStr.length()/2);
|
||||
transformed.deemphasize(numArrows * DEEMP_INDENTED_PROPOSAL);
|
||||
return transformed;
|
||||
}
|
||||
|
||||
private boolean isExtraIndentRelaxable(SNode contextNode) {
|
||||
return contextNode!=null && (
|
||||
private boolean isExtraIndentRelaxable(SNode contextNode, int fixIndentBy) {
|
||||
return contextNode!=null && /* fixIndentBy<=2 && */ (
|
||||
isBarrenKey(contextNode) ||
|
||||
isBarrenSeq(contextNode)
|
||||
);
|
||||
@@ -308,8 +307,9 @@ public class YamlCompletionEngine implements ICompletionEngine {
|
||||
* To allow for the ambiguity in indentation a list of context nodes is returned instead of a
|
||||
* single node. (Note we may still return a singleton list for cases where relaxed indentation
|
||||
* doesn't seem desirable).
|
||||
* @param baseIndent
|
||||
*/
|
||||
protected List<SNode> getContextNodes(YamlDocument doc, SNode node, int offset) {
|
||||
protected List<SNode> getContextNodes(YamlDocument doc, SNode node, int offset, int baseIndent) {
|
||||
if (node==null) {
|
||||
return null;
|
||||
} else if (node.getNodeType()==SNodeType.KEY) {
|
||||
@@ -334,8 +334,8 @@ public class YamlCompletionEngine implements ICompletionEngine {
|
||||
//This node has flexibility around indentation. So this is where me need to build a list of candidates!
|
||||
ImmutableList.Builder<SNode> contextNodes = ImmutableList.builder();
|
||||
while (node!=null ) {
|
||||
//Any node that represents a 'step' between contexts must be kept.
|
||||
if (node.getSegment()!=null) {
|
||||
//Any node that represents a 'step' between contexts and is not too deeply nested is kept.
|
||||
if (node.getSegment()!=null && node.getIndent()<=baseIndent) {
|
||||
contextNodes.add(node);
|
||||
}
|
||||
node = node.getParent();
|
||||
|
||||
@@ -464,11 +464,8 @@ public class YTypeFactory {
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to false (which is the default), then this type (when not yet inferred to a
|
||||
* more specific version of itself) will be treated as if it can be anything (i.e atomic, map or sequence)
|
||||
* <p>
|
||||
* If set to true, then it is treated as strictly atomic type instead (i.e it isn't valid to
|
||||
* use a map or sequence for its value).
|
||||
* Treat this type as an atomic type (i.e. it can't be a map or sequence), when not yet inferred to a
|
||||
* more specific version of itself).
|
||||
*/
|
||||
public AbstractType treatAsAtomic() {
|
||||
this.isAtomic = true;
|
||||
@@ -732,6 +729,7 @@ public class YTypeFactory {
|
||||
private Renderable description = Renderables.NO_DESCRIPTION;
|
||||
private boolean isRequired;
|
||||
private boolean isDeprecated;
|
||||
private boolean isPrimary;
|
||||
|
||||
private YTypedPropertyImpl(String name, YType type) {
|
||||
this.name = name;
|
||||
@@ -770,7 +768,7 @@ public class YTypeFactory {
|
||||
|
||||
@Override
|
||||
public boolean isRequired() {
|
||||
return isRequired;
|
||||
return isRequired || isPrimary;
|
||||
}
|
||||
|
||||
public void isDeprecated(boolean isDeprecated) {
|
||||
@@ -781,6 +779,16 @@ public class YTypeFactory {
|
||||
public boolean isDeprecated() {
|
||||
return this.isDeprecated;
|
||||
}
|
||||
|
||||
public YTypedPropertyImpl isPrimary(boolean b) {
|
||||
this.isPrimary = b;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrimary() {
|
||||
return isPrimary;
|
||||
}
|
||||
}
|
||||
|
||||
public YAtomicType yatomic(String name) {
|
||||
|
||||
@@ -13,7 +13,6 @@ package org.springframework.ide.vscode.commons.yaml.schema;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine;
|
||||
import org.springframework.ide.vscode.commons.util.ValueParser;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.constraints.Constraint;
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ public interface YTypedProperty {
|
||||
String getName();
|
||||
YType getType();
|
||||
Renderable getDescription();
|
||||
default boolean isRequired() { return false; }
|
||||
default boolean isRequired() { return isPrimary() || false; }
|
||||
default boolean isDeprecated() { return false; }
|
||||
default boolean isPrimary() { return false; }
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@@ -656,7 +657,6 @@ public class YamlStructureParser {
|
||||
if (indent==-1) {
|
||||
createRawNode(parent, line);
|
||||
} else {
|
||||
parent = dropTo(parent, indent);
|
||||
parent = parseLine(parent, line, true);
|
||||
}
|
||||
}
|
||||
@@ -668,15 +668,14 @@ public class YamlStructureParser {
|
||||
parent = createDocNode(parent.getRoot(), line);
|
||||
} else if (line.matches(SIMPLE_KEY_LINE)) {
|
||||
int currentIndent = line.getIndent();
|
||||
while (currentIndent==parent.getIndent() && parent.getNodeType()!=SNodeType.DOC) {
|
||||
parent = parent.getParent();
|
||||
}
|
||||
parent = dropToLevel(parent, (node) -> node.getIndent()<currentIndent);
|
||||
parent = createKeyNode(parent, line);
|
||||
} else if (line.matches(SEQ_LINE)) {
|
||||
int currentIndent = line.getIndent();
|
||||
while (currentIndent==parent.getIndent() && parent.getNodeType()==SNodeType.SEQ) {
|
||||
parent = parent.getParent();
|
||||
}
|
||||
parent = dropToLevel(parent, (node) -> {
|
||||
int indent = node.getIndent();
|
||||
return indent < currentIndent || node.getNodeType()!=SNodeType.SEQ && indent<=currentIndent;
|
||||
});
|
||||
parent = createSeqNode(parent, line);
|
||||
parent = parseLine(parent, line.moveIndentMark(2), false); //parse from just after "- " for nested seq and key nodes
|
||||
} else if (createRawNode) {
|
||||
@@ -685,6 +684,13 @@ public class YamlStructureParser {
|
||||
return parent;
|
||||
}
|
||||
|
||||
private SChildBearingNode dropToLevel(SChildBearingNode parent, Predicate<SNode> level) {
|
||||
while (parent.getNodeType()!=SNodeType.DOC && parent.getSegment()!=null && !level.test(parent)) {
|
||||
parent = parent.getParent();
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
|
||||
private SChildBearingNode createDocNode(SRootNode parent, YamlLine line) {
|
||||
int start = line.getStart();
|
||||
int end = line.getEnd();
|
||||
@@ -713,13 +719,6 @@ public class YamlStructureParser {
|
||||
}
|
||||
|
||||
|
||||
private SChildBearingNode dropTo(SChildBearingNode node, int indent) {
|
||||
while (indent<node.getIndent()) {
|
||||
node = node.getParent();
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
public class SSeqNode extends SChildBearingNode {
|
||||
|
||||
/**
|
||||
|
||||
@@ -207,7 +207,6 @@ public class YamlStructureParserTest {
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@Test public void testSequenceBasic() throws Exception {
|
||||
MockYamlEditor editor;
|
||||
|
||||
@@ -594,6 +593,41 @@ public class YamlStructureParserTest {
|
||||
path.traverse((SNode)root).toString());
|
||||
}
|
||||
|
||||
@Test public void testDedentedRawNode() throws Exception {
|
||||
MockYamlEditor editor = new MockYamlEditor(
|
||||
"world:\n" +
|
||||
" europe:\n" +
|
||||
" france:\n" +
|
||||
" cheese\n" +
|
||||
" belgium:\n" +
|
||||
" beer\n" + //De-dented raw node, doesn't obviously belong to any node, but we associate it with closest 'structural' node
|
||||
" canada:\n" +
|
||||
" montreal: poutine\n" +
|
||||
" vancouver:\n" +
|
||||
" salmon\n" +
|
||||
"moon:\n" +
|
||||
" moonbase-alfa:\n" +
|
||||
" moonstone\n"
|
||||
);
|
||||
assertParseOneDoc(editor, ////////////////
|
||||
"DOC(0): ",
|
||||
" KEY(0): world:",
|
||||
" KEY(2): europe:",
|
||||
" KEY(4): france:",
|
||||
" RAW(6): cheese",
|
||||
" KEY(4): belgium:",
|
||||
" RAW(2): beer",
|
||||
" KEY(2): canada:",
|
||||
" KEY(4): montreal: poutine",
|
||||
" KEY(4): vancouver:",
|
||||
" RAW(6): salmon",
|
||||
" KEY(0): moon:",
|
||||
" KEY(2): moonbase-alfa:",
|
||||
" RAW(4): moonstone",
|
||||
" RAW(-1):"
|
||||
);
|
||||
}
|
||||
|
||||
@Test public void testTreeEnd() throws Exception {
|
||||
MockYamlEditor editor = new MockYamlEditor(
|
||||
"world:\n" +
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
eclipse.preferences.version=1
|
||||
editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
|
||||
sp_cleanup.add_default_serial_version_id=true
|
||||
sp_cleanup.add_generated_serial_version_id=false
|
||||
sp_cleanup.add_missing_annotations=true
|
||||
sp_cleanup.add_missing_deprecated_annotations=true
|
||||
sp_cleanup.add_missing_methods=false
|
||||
sp_cleanup.add_missing_nls_tags=false
|
||||
sp_cleanup.add_missing_override_annotations=true
|
||||
sp_cleanup.add_missing_override_annotations_interface_methods=true
|
||||
sp_cleanup.add_serial_version_id=false
|
||||
sp_cleanup.always_use_blocks=true
|
||||
sp_cleanup.always_use_parentheses_in_expressions=false
|
||||
sp_cleanup.always_use_this_for_non_static_field_access=false
|
||||
sp_cleanup.always_use_this_for_non_static_method_access=false
|
||||
sp_cleanup.convert_functional_interfaces=false
|
||||
sp_cleanup.convert_to_enhanced_for_loop=false
|
||||
sp_cleanup.correct_indentation=false
|
||||
sp_cleanup.format_source_code=false
|
||||
sp_cleanup.format_source_code_changes_only=false
|
||||
sp_cleanup.insert_inferred_type_arguments=false
|
||||
sp_cleanup.make_local_variable_final=true
|
||||
sp_cleanup.make_parameters_final=false
|
||||
sp_cleanup.make_private_fields_final=true
|
||||
sp_cleanup.make_type_abstract_if_missing_method=false
|
||||
sp_cleanup.make_variable_declarations_final=false
|
||||
sp_cleanup.never_use_blocks=false
|
||||
sp_cleanup.never_use_parentheses_in_expressions=true
|
||||
sp_cleanup.on_save_use_additional_actions=true
|
||||
sp_cleanup.organize_imports=false
|
||||
sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
|
||||
sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
|
||||
sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
|
||||
sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
|
||||
sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
|
||||
sp_cleanup.remove_private_constructors=true
|
||||
sp_cleanup.remove_redundant_type_arguments=false
|
||||
sp_cleanup.remove_trailing_whitespaces=true
|
||||
sp_cleanup.remove_trailing_whitespaces_all=true
|
||||
sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
|
||||
sp_cleanup.remove_unnecessary_casts=true
|
||||
sp_cleanup.remove_unnecessary_nls_tags=false
|
||||
sp_cleanup.remove_unused_imports=false
|
||||
sp_cleanup.remove_unused_local_variables=false
|
||||
sp_cleanup.remove_unused_private_fields=true
|
||||
sp_cleanup.remove_unused_private_members=false
|
||||
sp_cleanup.remove_unused_private_methods=true
|
||||
sp_cleanup.remove_unused_private_types=true
|
||||
sp_cleanup.sort_members=false
|
||||
sp_cleanup.sort_members_all=false
|
||||
sp_cleanup.use_anonymous_class_creation=false
|
||||
sp_cleanup.use_blocks=false
|
||||
sp_cleanup.use_blocks_only_for_return_and_throw=false
|
||||
sp_cleanup.use_lambda=true
|
||||
sp_cleanup.use_parentheses_in_expressions=false
|
||||
sp_cleanup.use_this_for_non_static_field_access=false
|
||||
sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
|
||||
sp_cleanup.use_this_for_non_static_method_access=false
|
||||
sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
|
||||
@@ -202,7 +202,7 @@ public class PipelineYmlSchema implements YamlSchema {
|
||||
);
|
||||
|
||||
AbstractType t_resource = f.ybean("Resource");
|
||||
addProp(t_resource, "name", t_resource_name_def).isRequired(true);
|
||||
addProp(t_resource, "name", t_resource_name_def).isPrimary(true);
|
||||
addProp(t_resource, "type", t_resource_type_name).isRequired(true);
|
||||
addProp(t_resource, "source", resourceSource);
|
||||
addProp(t_resource, "check_every", t_duration);
|
||||
@@ -218,11 +218,11 @@ public class PipelineYmlSchema implements YamlSchema {
|
||||
t_platform.parseWith(ValueParsers.NE_STRING); //no errors because in theory platform are just strings.
|
||||
|
||||
AbstractType t_input = f.ybean("TaskInput");
|
||||
addProp(t_input, "name", t_ne_string).isRequired(true);
|
||||
addProp(t_input, "name", t_ne_string).isPrimary(true);
|
||||
addProp(t_input, "path", t_ne_string);
|
||||
|
||||
AbstractType t_output = f.ybean("TaskOutput");
|
||||
addProp(t_output, "name", t_ne_string).isRequired(true);
|
||||
addProp(t_output, "name", t_ne_string).isPrimary(true);
|
||||
addProp(t_output, "path", t_ne_string);
|
||||
|
||||
AbstractType t_command = f.ybean("Command");
|
||||
@@ -344,7 +344,7 @@ public class PipelineYmlSchema implements YamlSchema {
|
||||
models.setStepType(step);
|
||||
|
||||
AbstractType job = f.ybean("Job");
|
||||
addProp(job, "name", jobNameDef).isRequired(true);
|
||||
addProp(job, "name", jobNameDef).isPrimary(true);
|
||||
addProp(job, "plan", f.yseq(step)).isRequired(true);
|
||||
addProp(job, "serial", t_boolean);
|
||||
addProp(job, "build_logs_to_retain", t_pos_integer);
|
||||
@@ -354,12 +354,12 @@ public class PipelineYmlSchema implements YamlSchema {
|
||||
addProp(job, "disable_manual_trigger", t_boolean);
|
||||
|
||||
AbstractType resourceType = f.ybean("ResourceType");
|
||||
addProp(resourceType, "name", resourceTypeNameDef).isRequired(true);
|
||||
addProp(resourceType, "name", resourceTypeNameDef).isPrimary(true);
|
||||
addProp(resourceType, "type", t_resource_type_name).isRequired(true);
|
||||
addProp(resourceType, "source", resourceSource);
|
||||
|
||||
AbstractType group = f.ybean("Group");
|
||||
addProp(group, "name", t_ne_string).isRequired(true);
|
||||
addProp(group, "name", t_ne_string).isPrimary(true);
|
||||
addProp(group, "resources", f.yseq(t_resource_name));
|
||||
addProp(group, "jobs", f.yseq(t_job_name));
|
||||
|
||||
@@ -385,7 +385,7 @@ public class PipelineYmlSchema implements YamlSchema {
|
||||
// git :
|
||||
{
|
||||
AbstractType source = f.ybean("GitSource");
|
||||
addProp(source, "uri", t_ne_string).isRequired(true);
|
||||
addProp(source, "uri", t_ne_string).isPrimary(true);
|
||||
addProp(source, "branch", t_ne_string); //It's more complicated than that! Its only required in 'put' step. So we'll check this as a contrain in put steps!
|
||||
addProp(source, "private_key", t_ne_string);
|
||||
addProp(source, "username", t_ne_string);
|
||||
@@ -406,7 +406,7 @@ public class PipelineYmlSchema implements YamlSchema {
|
||||
addProp(get, "disable_git_lfs", t_boolean);
|
||||
|
||||
AbstractType put = f.ybean("GitPutParams");
|
||||
addProp(put, "repository", t_ne_string).isRequired(true);
|
||||
addProp(put, "repository", t_ne_string).isPrimary(true);
|
||||
addProp(put, "rebase", t_boolean);
|
||||
addProp(put, "tag", t_ne_string);
|
||||
addProp(put, "only_tag", t_boolean);
|
||||
@@ -419,7 +419,7 @@ public class PipelineYmlSchema implements YamlSchema {
|
||||
//docker-image:
|
||||
{
|
||||
AbstractType source = f.ybean("DockerImageSource");
|
||||
addProp(source, "repository", t_ne_string).isRequired(true);
|
||||
addProp(source, "repository", t_ne_string).isPrimary(true);
|
||||
addProp(source, "tag", t_ne_string);
|
||||
addProp(source, "username", t_ne_string);
|
||||
addProp(source, "password", t_ne_string);
|
||||
@@ -473,7 +473,7 @@ public class PipelineYmlSchema implements YamlSchema {
|
||||
);
|
||||
|
||||
AbstractType source = f.ybean("S3Source");
|
||||
addProp(source, "bucket", t_ne_string).isRequired(true);
|
||||
addProp(source, "bucket", t_ne_string).isPrimary(true);
|
||||
addProp(source, "access_key_id", t_ne_string);
|
||||
addProp(source, "secret_access_key", t_ne_string);
|
||||
addProp(source, "region_name", t_s3_region);
|
||||
@@ -492,7 +492,7 @@ public class PipelineYmlSchema implements YamlSchema {
|
||||
//Note: S3GetParams intentionally has no properties since no params are expected according to the docs.
|
||||
|
||||
AbstractType put = f.ybean("S3PutParams");
|
||||
addProp(put, "file", t_ne_string).isRequired(true);
|
||||
addProp(put, "file", t_ne_string).isPrimary(true);
|
||||
addProp(put, "acl", t_canned_acl);
|
||||
addProp(put, "content_type", t_mime_type);
|
||||
|
||||
@@ -526,7 +526,7 @@ public class PipelineYmlSchema implements YamlSchema {
|
||||
//semver
|
||||
{
|
||||
AbstractType git_source = f.ybean("GitSemverSource");
|
||||
addProp(git_source, "uri", t_ne_string).isRequired(true);
|
||||
addProp(git_source, "uri", t_ne_string).isPrimary(true);
|
||||
addProp(git_source, "branch", t_ne_string).isRequired(true);
|
||||
addProp(git_source, "file", t_ne_string).isRequired(true);
|
||||
addProp(git_source, "private_key", t_ne_string);
|
||||
@@ -535,7 +535,7 @@ public class PipelineYmlSchema implements YamlSchema {
|
||||
addProp(git_source, "git_user", t_ne_string);
|
||||
|
||||
AbstractType s3_source = f.ybean("S3SemverSource");
|
||||
addProp(s3_source, "bucket", t_ne_string).isRequired(true);
|
||||
addProp(s3_source, "bucket", t_ne_string).isPrimary(true);
|
||||
addProp(s3_source, "key", t_ne_string).isRequired(true);
|
||||
addProp(s3_source, "access_key_id", t_ne_string).isRequired(true);
|
||||
addProp(s3_source, "secret_access_key", t_ne_string).isRequired(true);
|
||||
@@ -544,7 +544,7 @@ public class PipelineYmlSchema implements YamlSchema {
|
||||
addProp(s3_source, "disable_ssl", t_boolean);
|
||||
|
||||
AbstractType swift_source = f.ybean("SwiftSemverSource");
|
||||
addProp(swift_source, "openstack", t_any).isRequired(true);
|
||||
addProp(swift_source, "openstack", t_any).isPrimary(true);
|
||||
|
||||
AbstractType[] driverSpecificSources = {
|
||||
git_source, s3_source, swift_source
|
||||
|
||||
@@ -10,14 +10,16 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.concourse;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.springframework.ide.vscode.languageserver.testharness.TestAsserts.assertContains;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.lsp4j.CompletionItem;
|
||||
import org.eclipse.lsp4j.Diagnostic;
|
||||
import org.eclipse.lsp4j.DiagnosticSeverity;
|
||||
import org.junit.Before;
|
||||
@@ -982,13 +984,25 @@ public class ConcourseEditorTest {
|
||||
}
|
||||
|
||||
@Test public void gitResourceSourceCompletions() throws Exception {
|
||||
assertContextualCompletions(
|
||||
assertContextualCompletions(PLAIN_COMPLETION,
|
||||
"resources:\n" +
|
||||
"- name: the-repo\n" +
|
||||
" type: git\n" +
|
||||
" source:\n" +
|
||||
" <*>\n" +
|
||||
" blah: blah"
|
||||
" <*>"
|
||||
, //================
|
||||
"<*>"
|
||||
, // ==>
|
||||
"uri: <*>"
|
||||
);
|
||||
|
||||
assertContextualCompletions(PLAIN_COMPLETION,
|
||||
"resources:\n" +
|
||||
"- name: the-repo\n" +
|
||||
" type: git\n" +
|
||||
" source:\n" +
|
||||
" uri:\n" +
|
||||
" <*>"
|
||||
, //================
|
||||
"<*>"
|
||||
, // ==>
|
||||
@@ -1021,8 +1035,6 @@ public class ConcourseEditorTest {
|
||||
,
|
||||
"tag_filter: <*>"
|
||||
,
|
||||
"uri: <*>"
|
||||
,
|
||||
"username: <*>"
|
||||
);
|
||||
|
||||
@@ -1156,6 +1168,22 @@ public class ConcourseEditorTest {
|
||||
}
|
||||
|
||||
@Test public void gitResourcePutParamsCompletions() throws Exception {
|
||||
assertContextualCompletions(PLAIN_COMPLETION,
|
||||
"resources:\n" +
|
||||
"- name: my-git\n" +
|
||||
" type: git\n" +
|
||||
"jobs:\n" +
|
||||
"- name: do-stuff\n" +
|
||||
" plan:\n" +
|
||||
" - put: my-git\n" +
|
||||
" params:\n" +
|
||||
" <*>"
|
||||
,
|
||||
"<*>"
|
||||
, // =>
|
||||
"repository: <*>"
|
||||
);
|
||||
|
||||
String context =
|
||||
"resources:\n" +
|
||||
"- name: my-git\n" +
|
||||
@@ -1165,10 +1193,10 @@ public class ConcourseEditorTest {
|
||||
" plan:\n" +
|
||||
" - put: my-git\n" +
|
||||
" params:\n" +
|
||||
" <*>\n" +
|
||||
" blah: blah";
|
||||
" repository: blah\n" +
|
||||
" <*>";
|
||||
|
||||
assertContextualCompletions(context,
|
||||
assertContextualCompletions(PLAIN_COMPLETION, context,
|
||||
"<*>"
|
||||
, // ===>
|
||||
"annotate: <*>"
|
||||
@@ -1179,8 +1207,6 @@ public class ConcourseEditorTest {
|
||||
,
|
||||
"rebase: <*>"
|
||||
,
|
||||
"repository: <*>"
|
||||
,
|
||||
"tag: <*>"
|
||||
,
|
||||
"tag_prefix: <*>"
|
||||
@@ -2011,41 +2037,57 @@ public class ConcourseEditorTest {
|
||||
}
|
||||
|
||||
@Test public void semverGitResourceSourceContentAssist() throws Exception {
|
||||
String conText =
|
||||
assertContextualCompletions(PLAIN_COMPLETION,
|
||||
"resources:\n" +
|
||||
"- name: version\n" +
|
||||
" type: semver\n" +
|
||||
" source:\n" +
|
||||
"<*>\n" +
|
||||
" blah: blah";
|
||||
assertContextualCompletions(conText,
|
||||
" driver: git\n" +
|
||||
" <*>"
|
||||
, // ===========
|
||||
"<*>"
|
||||
, // ==>
|
||||
"uri: <*>"
|
||||
);
|
||||
assertContextualCompletions(PLAIN_COMPLETION,
|
||||
"resources:\n" +
|
||||
"- name: version\n" +
|
||||
" type: semver\n" +
|
||||
" source:\n" +
|
||||
" driver: git\n" +
|
||||
" uri: something\n" +
|
||||
"<*>"
|
||||
, // =============
|
||||
" <*>"
|
||||
, // ==>
|
||||
" branch: <*>"
|
||||
,
|
||||
" driver: git\n" +
|
||||
" file: <*>"
|
||||
,
|
||||
);
|
||||
assertContextualCompletions(PLAIN_COMPLETION,
|
||||
"resources:\n" +
|
||||
"- name: version\n" +
|
||||
" type: semver\n" +
|
||||
" source:\n" +
|
||||
" driver: git\n" +
|
||||
" uri: something\n" +
|
||||
" branch: master\n" +
|
||||
" file: somefile\n" +
|
||||
"<*>"
|
||||
, // =============
|
||||
" <*>"
|
||||
, // ==>
|
||||
" git_user: <*>"
|
||||
,
|
||||
" driver: git\n" +
|
||||
" initial_version: <*>"
|
||||
,
|
||||
" driver: git\n" +
|
||||
" password: <*>"
|
||||
,
|
||||
" driver: git\n" +
|
||||
" private_key: <*>"
|
||||
,
|
||||
" driver: git\n" +
|
||||
" uri: <*>"
|
||||
,
|
||||
" driver: git\n" +
|
||||
" username: <*>"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@Test public void semverGitResourceSourceReconcileAndHovers() throws Exception {
|
||||
@@ -2593,6 +2635,19 @@ public class ConcourseEditorTest {
|
||||
|
||||
@Test public void contentAssistTaskFileToplevelProperties() throws Exception {
|
||||
assertTaskCompletions(
|
||||
"<*>"
|
||||
, // ==>
|
||||
"platform: <*>"
|
||||
,
|
||||
"run:\n" +
|
||||
" <*>"
|
||||
);
|
||||
|
||||
assertContextualTaskCompletions(
|
||||
"run: {}\n" +
|
||||
"platform: linux\n" +
|
||||
"<*>"
|
||||
,
|
||||
"<*>"
|
||||
, // ==>
|
||||
"image: <*>"
|
||||
@@ -2608,11 +2663,6 @@ public class ConcourseEditorTest {
|
||||
,
|
||||
"params:\n" +
|
||||
" <*>"
|
||||
,
|
||||
"platform: <*>"
|
||||
,
|
||||
"run:\n" +
|
||||
" <*>"
|
||||
);
|
||||
|
||||
assertTaskCompletions(
|
||||
@@ -2928,29 +2978,13 @@ public class ConcourseEditorTest {
|
||||
//"source", exists
|
||||
//"type", exists
|
||||
//For the nested context:
|
||||
"→ branch",
|
||||
"→ commit_verification_key_ids",
|
||||
"→ commit_verification_keys",
|
||||
"→ disable_ci_skip",
|
||||
"→ git_config",
|
||||
"→ gpg_keyserver",
|
||||
"→ ignore_paths",
|
||||
"→ password",
|
||||
"→ paths",
|
||||
"→ private_key",
|
||||
"→ skip_ssl_verification",
|
||||
"→ tag_filter",
|
||||
"→ uri",
|
||||
"→ username",
|
||||
// For the top-level context:
|
||||
"← groups",
|
||||
"← jobs",
|
||||
"← resource_types",
|
||||
// For the 'next job' context:
|
||||
"← - check_every",
|
||||
"← - name",
|
||||
"← - source",
|
||||
"← - type"
|
||||
"← - name"
|
||||
);
|
||||
|
||||
editor.assertCompletionWithLabel("check_every",
|
||||
@@ -2961,33 +2995,55 @@ public class ConcourseEditorTest {
|
||||
" check_every: <*>"
|
||||
);
|
||||
|
||||
editor.assertCompletionWithLabel("→ branch",
|
||||
editor.assertCompletionWithLabel("→ uri",
|
||||
"resources:\n" +
|
||||
"- name: foo\n" +
|
||||
" type: git\n" +
|
||||
" source:\n" +
|
||||
" branch: <*>"
|
||||
" uri: <*>"
|
||||
);
|
||||
|
||||
editor = harness.newEditor(
|
||||
"resources:\n" +
|
||||
"- name: foo\n" +
|
||||
" type: git\n" +
|
||||
" source:\n" +
|
||||
" uri: blah\n" +
|
||||
" <*>"
|
||||
);
|
||||
editor.assertCompletionWithLabel("→ commit_verification_key_ids",
|
||||
"resources:\n" +
|
||||
"- name: foo\n" +
|
||||
" type: git\n" +
|
||||
" source:\n" +
|
||||
" uri: blah\n" +
|
||||
" commit_verification_key_ids:\n" +
|
||||
" - <*>"
|
||||
);
|
||||
}
|
||||
|
||||
@Test public void relaxedIndentContextMoreSpaces2() throws Exception {
|
||||
|
||||
assertContextualCompletions(
|
||||
assertContextualCompletions(INDENTED_COMPLETION,
|
||||
"resources:\n" +
|
||||
"- name: foo\n" +
|
||||
" type: git\n" +
|
||||
" source:\n" +
|
||||
" <*>"
|
||||
, // =========
|
||||
"bra<*>"
|
||||
"ur"
|
||||
, //=>
|
||||
" uri: <*>"
|
||||
);
|
||||
|
||||
assertContextualCompletions(INDENTED_COMPLETION,
|
||||
"resources:\n" +
|
||||
"- name: foo\n" +
|
||||
" type: git\n" +
|
||||
" source:\n" +
|
||||
" uri: blah\n" +
|
||||
" <*>"
|
||||
, // =========
|
||||
"bra"
|
||||
, //=>
|
||||
" branch: <*>"
|
||||
);
|
||||
@@ -2997,6 +3053,7 @@ public class ConcourseEditorTest {
|
||||
"- name: foo\n" +
|
||||
" type: git\n" +
|
||||
" source:\n" +
|
||||
" uri: blah\n" +
|
||||
" <*>"
|
||||
, // =========
|
||||
"comverids<*>"
|
||||
@@ -3027,13 +3084,6 @@ public class ConcourseEditorTest {
|
||||
//"name", exists
|
||||
//"plan", exists
|
||||
//"public", exists
|
||||
//Completions with '-'
|
||||
"- aggregate",
|
||||
"- do",
|
||||
"- get",
|
||||
"- put",
|
||||
"- task",
|
||||
"- try",
|
||||
//Completions for nested context (i.e. task step)
|
||||
"→ attempts",
|
||||
"→ config",
|
||||
@@ -3048,18 +3098,18 @@ public class ConcourseEditorTest {
|
||||
"→ privileged",
|
||||
"→ tags",
|
||||
"→ timeout",
|
||||
//"→ task" exists
|
||||
"← groups\n" +
|
||||
"← resource_types\n" +
|
||||
"← resources\n" +
|
||||
"← - build_logs_to_retain\n" +
|
||||
"← - disable_manual_trigger\n" +
|
||||
"← - max_in_flight\n" +
|
||||
"← - name\n" +
|
||||
"← - plan\n" +
|
||||
"← - public\n" +
|
||||
"← - serial\n" +
|
||||
"← - serial_groups"
|
||||
//Completions with '-'
|
||||
"- aggregate",
|
||||
"- do",
|
||||
"- get",
|
||||
"- put",
|
||||
"- task",
|
||||
"- try",
|
||||
//Dedented completions
|
||||
"← groups",
|
||||
"← resource_types",
|
||||
"← resources",
|
||||
"← - name"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3445,6 +3495,24 @@ public class ConcourseEditorTest {
|
||||
);
|
||||
}
|
||||
|
||||
@Test public void relaxedContentAssist_primary_properties() throws Exception{
|
||||
//See https://www.pivotaltracker.com/story/show/144584163
|
||||
Editor editor;
|
||||
|
||||
editor = harness.newEditor(
|
||||
"resources:\n" +
|
||||
"- name: docker-git\n" +
|
||||
"<*>"
|
||||
);
|
||||
editor.assertCompletionLabels(
|
||||
"groups",
|
||||
"jobs",
|
||||
"resource_types",
|
||||
"→ type",
|
||||
"- name"
|
||||
);
|
||||
}
|
||||
|
||||
@Test public void relaxedContentAssistLessSpaces() throws Exception {
|
||||
Editor editor;
|
||||
|
||||
@@ -3543,7 +3611,15 @@ public class ConcourseEditorTest {
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void assertContextualCompletions(String conText, String textBefore, String... textAfter) throws Exception {
|
||||
Editor editor = harness.newEditor(conText);
|
||||
assertContextualCompletions((c) -> true, conText, textBefore, textAfter);
|
||||
}
|
||||
|
||||
private void assertContextualCompletions(Predicate<CompletionItem> isInteresting, String conText, String textBefore, String... textAfter) throws Exception {
|
||||
assertContextualCompletions(LanguageId.CONCOURSE_PIPELINE, isInteresting, conText, textBefore, textAfter);
|
||||
}
|
||||
|
||||
private void assertContextualCompletions(LanguageId language, Predicate<CompletionItem> isInteresting, String conText, String textBefore, String... textAfter) throws Exception {
|
||||
Editor editor = harness.newEditor(language, conText);
|
||||
editor.reconcile(); //this ensures the conText is parsed and its AST is cached (will be used for
|
||||
//dynamic CA when the conText + textBefore is not parsable.
|
||||
assertContains(CURSOR, conText);
|
||||
@@ -3552,7 +3628,7 @@ public class ConcourseEditorTest {
|
||||
.map((String t) -> conText.replace(CURSOR, t))
|
||||
.collect(Collectors.toList()).toArray(new String[0]);
|
||||
editor.setText(textBefore);
|
||||
editor.assertCompletions(textAfter);
|
||||
editor.assertCompletions(isInteresting, textAfter);
|
||||
}
|
||||
|
||||
private void assertCompletions(String textBefore, String... textAfter) throws Exception {
|
||||
@@ -3565,5 +3641,18 @@ public class ConcourseEditorTest {
|
||||
editor.assertCompletions(textAfter);
|
||||
}
|
||||
|
||||
private void assertContextualTaskCompletions(String conText, String textBefore, String... textAfter) throws Exception {
|
||||
assertContextualCompletions(LanguageId.CONCOURSE_TASK, c -> true, conText, textBefore, textAfter);
|
||||
}
|
||||
|
||||
public static final Predicate<CompletionItem> RELAXED_COMPLETION
|
||||
= c -> c.getLabel().startsWith("- ")
|
||||
|| c.getLabel().startsWith(Unicodes.LEFT_ARROW+" ")
|
||||
|| c.getLabel().startsWith(Unicodes.RIGHT_ARROW+" ")
|
||||
;
|
||||
|
||||
public static final Predicate<CompletionItem> PLAIN_COMPLETION = c -> !RELAXED_COMPLETION.test(c);
|
||||
public static final Predicate<CompletionItem> DEDENTED_COMPLETION = c -> c.getLabel().startsWith(Unicodes.LEFT_ARROW+" ");
|
||||
public static final Predicate<CompletionItem> INDENTED_COMPLETION = c -> c.getLabel().startsWith(Unicodes.RIGHT_ARROW+" ");
|
||||
|
||||
}
|
||||
|
||||
@@ -194,6 +194,7 @@ public class ManifestYmlSchema implements YamlSchema {
|
||||
f.yprop("services", f.yseq(t_service)),
|
||||
f.yprop("stack", t_stack),
|
||||
f.yprop("timeout", t_pos_integer),
|
||||
|
||||
f.yprop(HEALTH_CHECK_TYPE_PROP, t_health_check_type),
|
||||
f.yprop(HEALTH_CHECK_HTTP_ENDPOINT_PROP, t_ne_string)
|
||||
};
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.springframework.ide.vscode.commons.cloudfoundry.client.CFServiceInsta
|
||||
import org.springframework.ide.vscode.commons.cloudfoundry.client.CFStack;
|
||||
import org.springframework.ide.vscode.commons.cloudfoundry.client.ClientRequests;
|
||||
import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.NoTargetsException;
|
||||
import org.springframework.ide.vscode.commons.util.Unicodes;
|
||||
import org.springframework.ide.vscode.languageserver.testharness.CodeAction;
|
||||
import org.springframework.ide.vscode.languageserver.testharness.Editor;
|
||||
import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness;
|
||||
@@ -316,74 +317,101 @@ public class ManifestYamlEditorTest {
|
||||
"- <*>"
|
||||
);
|
||||
editor.assertCompletions(
|
||||
"applications:\n" +
|
||||
"- name: <*>"
|
||||
);
|
||||
|
||||
editor = harness.newEditor(
|
||||
"applications:\n" +
|
||||
"- name: foo\n" +
|
||||
" <*>"
|
||||
);
|
||||
editor.assertCompletions((c) -> !(c.getLabel().startsWith("- ") || c.getLabel().startsWith(Unicodes.LEFT_ARROW+" ")),
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- buildpack: <*>",
|
||||
"- name: foo\n" +
|
||||
" buildpack: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- command: <*>",
|
||||
"- name: foo\n" +
|
||||
" command: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- disk_quota: <*>",
|
||||
"- name: foo\n" +
|
||||
" disk_quota: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- domain: <*>",
|
||||
"- name: foo\n" +
|
||||
" domain: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- domains:\n"+
|
||||
"- name: foo\n" +
|
||||
" domains:\n"+
|
||||
" - <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- env:\n"+
|
||||
"- name: foo\n" +
|
||||
" env:\n"+
|
||||
" <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- health-check-http-endpoint: <*>",
|
||||
"- name: foo\n" +
|
||||
" health-check-http-endpoint: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- health-check-type: <*>",
|
||||
"- name: foo\n" +
|
||||
" health-check-type: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- host: <*>",
|
||||
"- name: foo\n" +
|
||||
" host: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- hosts:\n"+
|
||||
"- name: foo\n" +
|
||||
" hosts:\n"+
|
||||
" - <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- instances: <*>",
|
||||
"- name: foo\n" +
|
||||
" instances: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- memory: <*>",
|
||||
"- name: foo\n" +
|
||||
" memory: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- name: <*>",
|
||||
"- name: foo\n" +
|
||||
" no-hostname: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- no-hostname: <*>",
|
||||
"- name: foo\n" +
|
||||
" no-route: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- no-route: <*>",
|
||||
"- name: foo\n" +
|
||||
" path: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- path: <*>",
|
||||
"- name: foo\n" +
|
||||
" random-route: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- random-route: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- routes:\n"+
|
||||
"- name: foo\n" +
|
||||
" routes:\n"+
|
||||
" - route: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- services:\n"+
|
||||
"- name: foo\n" +
|
||||
" services:\n"+
|
||||
" - <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- stack: <*>",
|
||||
"- name: foo\n" +
|
||||
" stack: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- timeout: <*>"
|
||||
"- name: foo\n" +
|
||||
" timeout: <*>"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -391,7 +419,8 @@ public class ManifestYamlEditorTest {
|
||||
public void completionDetailsAndDocs() throws Exception {
|
||||
Editor editor = harness.newEditor(
|
||||
"applications:\n" +
|
||||
"- build<*>"
|
||||
"- name: foo\n" +
|
||||
" build<*>"
|
||||
);
|
||||
editor.assertCompletionDetails("buildpack", "Buildpack", "If your application requires a custom buildpack");
|
||||
}
|
||||
@@ -837,72 +866,7 @@ public class ManifestYamlEditorTest {
|
||||
"-<*>",
|
||||
// ===>
|
||||
"applications:\n" +
|
||||
"- buildpack: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- command: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- disk_quota: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- domain: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- domains:\n"+
|
||||
" - <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- env:\n"+
|
||||
" <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- health-check-http-endpoint: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- health-check-type: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- host: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- hosts:\n"+
|
||||
" - <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- instances: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- memory: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- name: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- no-hostname: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- no-route: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- path: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- random-route: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- routes:\n"+
|
||||
" - route: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- services:\n"+
|
||||
" - <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- stack: <*>",
|
||||
// ---------------
|
||||
"applications:\n" +
|
||||
"- timeout: <*>"
|
||||
"- name: <*>"
|
||||
);
|
||||
|
||||
//Second example
|
||||
@@ -912,93 +876,8 @@ public class ManifestYamlEditorTest {
|
||||
"- name: test"
|
||||
, // ==>
|
||||
"applications:\n" +
|
||||
"- buildpack: <*>\n" +
|
||||
"- name: test"
|
||||
, // ---------------------
|
||||
"applications:\n" +
|
||||
"- command: <*>\n" +
|
||||
"- name: test"
|
||||
, // ---------------------
|
||||
"applications:\n" +
|
||||
"- disk_quota: <*>\n" +
|
||||
"- name: test"
|
||||
, // ---------------------
|
||||
"applications:\n" +
|
||||
"- domain: <*>\n" +
|
||||
"- name: test"
|
||||
, // ---------------------
|
||||
"applications:\n" +
|
||||
"- domains:\n" +
|
||||
" - <*>\n" +
|
||||
"- name: test"
|
||||
, // ---------------------
|
||||
"applications:\n" +
|
||||
"- env:\n" +
|
||||
" <*>\n" +
|
||||
"- name: test"
|
||||
, // ---------------------
|
||||
"applications:\n" +
|
||||
"- health-check-http-endpoint: <*>\n" +
|
||||
"- name: test"
|
||||
, // ---------------------
|
||||
"applications:\n" +
|
||||
"- health-check-type: <*>\n" +
|
||||
"- name: test"
|
||||
, // ---------------------
|
||||
"applications:\n" +
|
||||
"- host: <*>\n" +
|
||||
"- name: test"
|
||||
, // ---------------------
|
||||
"applications:\n" +
|
||||
"- hosts:\n" +
|
||||
" - <*>\n" +
|
||||
"- name: test"
|
||||
, // ---------------------
|
||||
"applications:\n" +
|
||||
"- instances: <*>\n" +
|
||||
"- name: test"
|
||||
, // ---------------------
|
||||
"applications:\n" +
|
||||
"- memory: <*>\n" +
|
||||
"- name: test"
|
||||
, // ---------------------
|
||||
"applications:\n" +
|
||||
"- name: <*>\n" +
|
||||
"- name: test"
|
||||
, // ---------------------
|
||||
"applications:\n" +
|
||||
"- no-hostname: <*>\n" +
|
||||
"- name: test"
|
||||
, // ---------------------
|
||||
"applications:\n" +
|
||||
"- no-route: <*>\n" +
|
||||
"- name: test"
|
||||
, // ---------------------
|
||||
"applications:\n" +
|
||||
"- path: <*>\n" +
|
||||
"- name: test"
|
||||
, // ---------------------
|
||||
"applications:\n" +
|
||||
"- random-route: <*>\n" +
|
||||
"- name: test"
|
||||
, // ---------------------
|
||||
"applications:\n" +
|
||||
"- routes:\n" +
|
||||
" - route: <*>\n" +
|
||||
"- name: test"
|
||||
,// ---------------------
|
||||
"applications:\n" +
|
||||
"- services:\n" +
|
||||
" - <*>\n" +
|
||||
"- name: test"
|
||||
, // ---------------------
|
||||
"applications:\n" +
|
||||
"- stack: <*>\n" +
|
||||
"- name: test"
|
||||
, // ---------------------
|
||||
"applications:\n" +
|
||||
"- timeout: <*>\n" +
|
||||
"- name: test"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user