diff --git a/concourse/tasks/build-vscode-extensions.sh b/concourse/tasks/build-vscode-extensions.sh index b3226f270..7f89d261a 100755 --- a/concourse/tasks/build-vscode-extensions.sh +++ b/concourse/tasks/build-vscode-extensions.sh @@ -2,13 +2,13 @@ set -e workdir=`pwd` -#if [ -d "maven-cache" ]; then +if [ -d "maven-cache" ]; then echo "Prepopulating maven cache" tar xzf maven-cache/*.tar.gz -C ${HOME} -#else -# echo "!!!No stored maven cache found!!! " -# echo "!!!This may slow down the build!!!" -#fi +else + echo "!!!No stored maven cache found!!! " + echo "!!!This may slow down the build!!!" +fi cd sts4/vscode-extensions ./build-all.sh diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/ScoreableProposal.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/ScoreableProposal.java index e45bddf10..d7d3ff2c5 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/ScoreableProposal.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/ScoreableProposal.java @@ -22,6 +22,7 @@ public abstract class ScoreableProposal implements ICompletionProposal { * A sorter suitable for sorting ScoreableProposals based on their score. */ public static final Comparator COMPARATOR = new Comparator() { + @Override public int compare(ICompletionProposal p1, ICompletionProposal p2) { if (p1 instanceof ScoreableProposal && p2 instanceof ScoreableProposal) { double s1 = ((ScoreableProposal)p1).getScore(); @@ -41,6 +42,7 @@ public abstract class ScoreableProposal implements ICompletionProposal { public final double getScore() { return getBaseScore() - deemphasizedBy; } + @Override public ScoreableProposal deemphasize() { deemphasizedBy+= DEEMP_VALUE; return this; @@ -113,4 +115,9 @@ public abstract class ScoreableProposal implements ICompletionProposal { // return completionOffset; // } + @Override + public String toString() { + return getLabel(); + } + } \ No newline at end of file diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/YamlCompletionEngine.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/YamlCompletionEngine.java index 31999218f..b1ccb64ee 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/YamlCompletionEngine.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/YamlCompletionEngine.java @@ -83,6 +83,7 @@ public class YamlCompletionEngine implements ICompletionEngine { if (!completions.isEmpty()) { List transformed = new ArrayList<>(); for (ICompletionProposal p : completions) { + System.out.println(p.getLabel()); transformed.add(indented(p)); } return transformed; @@ -137,8 +138,8 @@ public class YamlCompletionEngine implements ICompletionEngine { } private Collection getRelaxedCompletions(int offset, YamlDocument doc, SNode preciseContextNode, SNode currentNode) throws Exception { - if (preciseContextNode!=null) { - SNode contextNode = getRelaxedContextNode(preciseContextNode, currentNode); + SNode contextNode = getContextNode(doc, currentNode, offset, YamlIndentUtil.INDENT_BY); + if (preciseContextNode!=contextNode && isRelaxable(contextNode)) { YamlAssistContext context = getContext(doc, contextNode); if (context!=null) { return context.getCompletions(doc, currentNode, offset); @@ -147,6 +148,13 @@ public class YamlCompletionEngine implements ICompletionEngine { return Collections.emptyList(); } + private boolean isRelaxable(SNode contextNode) throws Exception { + return contextNode!=null && ( + isBarrenKey(contextNode) || + contextNode.getNodeType()==SNodeType.SEQ + ); + } + private boolean isBarrenKey(SNode node) throws Exception { if (node.getNodeType()==SNodeType.KEY) { SKeyNode keyNode = (SKeyNode) node; @@ -156,20 +164,6 @@ public class YamlCompletionEngine implements ICompletionEngine { return false; } - private SNode getRelaxedContextNode(SNode preciseContextNode, SNode currentNode) throws Exception { - while (currentNode!=null) { - if (currentNode.getParent()==preciseContextNode) { - if (isBarrenKey(currentNode)) { - return currentNode; - } else { - return null; - } - } - currentNode = currentNode.getParent(); - } - return currentNode; - } - protected Collection getPreciseCompletions(int offset, YamlDocument doc, SNode current, SNode contextNode) throws Exception { if (contextNode!=null) { @@ -211,7 +205,8 @@ public class YamlCompletionEngine implements ICompletionEngine { return null; } - protected SNode getContextNode(YamlDocument doc, SNode node, int offset) throws Exception { + protected SNode getContextNode(YamlDocument doc, SNode node, int offset, int adjustIndent) throws Exception { + Assert.isLegal(adjustIndent>=0); //The code doesn't handle negative indents yet. if (node==null) { return null; } else if (node.getNodeType()==SNodeType.KEY) { @@ -232,11 +227,12 @@ public class YamlCompletionEngine implements ICompletionEngine { // the correct context depends on text the user has not typed yet.(which will change the // indentation level of the current line. So we must use the cursorIndentation // rather than the structure-tree to determine the 'context' node. - int cursorIndent = doc.getColumn(offset); - int nodeIndent = node.getIndent(); + int cursorIndent = YamlIndentUtil.add(doc.getColumn(offset), adjustIndent); + int nodeIndent = YamlIndentUtil.add(node.getIndent(), adjustIndent); int currentIndent = YamlIndentUtil.minIndent(cursorIndent, nodeIndent); - while (node.getIndent()==-1 || (node.getIndent()>=currentIndent && node.getNodeType()!=SNodeType.DOC)) { + while (nodeIndent==-1 || (nodeIndent>=currentIndent && node.getNodeType()!=SNodeType.DOC)) { node = node.getParent(); + nodeIndent = node.getIndent(); } return node; } else if (node.getNodeType()==SNodeType.SEQ) { @@ -252,6 +248,10 @@ public class YamlCompletionEngine implements ICompletionEngine { return null; } + protected SNode getContextNode(YamlDocument doc, SNode node, int offset) throws Exception { + return getContextNode(doc, node, offset, 0); + } + protected YamlPath getContextPath(YamlDocument doc, SNode node, int offset) throws Exception { if (node==null) { return YamlPath.EMPTY; diff --git a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/util/YamlIndentUtil.java b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/util/YamlIndentUtil.java index 369de08fe..4952c4b05 100644 --- a/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/util/YamlIndentUtil.java +++ b/vscode-extensions/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/util/YamlIndentUtil.java @@ -35,7 +35,7 @@ public class YamlIndentUtil { * for the current document). */ public final String NEWLINE; - + public YamlIndentUtil(String newline) { this.NEWLINE = newline; Assert.isNotNull(NEWLINE); @@ -100,4 +100,16 @@ public class YamlIndentUtil { return offset + indent; } + /** + * Add given offset to an indent, correctly handling the case + * were the indent is -1 (unknown) + */ + public static int add(int indent, int adjustment) { + if (indent==-1) { + return indent; //indent remains unknown + } + indent += adjustment; + return indent>=0 ? indent : 0; + } + } diff --git a/vscode-extensions/vscode-concourse/src/main/java/org/springframework/ide/vscode/concourse/ConcourseLanguageServer.java b/vscode-extensions/vscode-concourse/src/main/java/org/springframework/ide/vscode/concourse/ConcourseLanguageServer.java index 00379f134..8749edf3a 100644 --- a/vscode-extensions/vscode-concourse/src/main/java/org/springframework/ide/vscode/concourse/ConcourseLanguageServer.java +++ b/vscode-extensions/vscode-concourse/src/main/java/org/springframework/ide/vscode/concourse/ConcourseLanguageServer.java @@ -45,10 +45,12 @@ public class ConcourseLanguageServer extends SimpleLanguageServer { SimpleTextDocumentService documents = getTextDocumentService(); ConcourseModel models = new ConcourseModel(documents); YamlASTProvider currentAsts = models.getAstProvider(false); + private SchemaSpecificPieces forPipelines; + private SchemaSpecificPieces forTasks; private class SchemaSpecificPieces { - final VscodeCompletionEngine completionEngine; + final VscodeCompletionEngineAdapter completionEngine; final VscodeHoverEngineAdapter hoverEngine; final YamlSchemaBasedReconcileEngine reconcileEngine; @@ -64,13 +66,16 @@ public class ConcourseLanguageServer extends SimpleLanguageServer { reconcileEngine.setTypeCollector(models.getAstTypeCache()); } + public void setMaxCompletions(int max) { + completionEngine.setMaxCompletionsNumber(max); + } } public ConcourseLanguageServer() { PipelineYmlSchema pipelineSchema = new PipelineYmlSchema(models); - SchemaSpecificPieces forPipelines = new SchemaSpecificPieces(pipelineSchema); - SchemaSpecificPieces forTasks = new SchemaSpecificPieces(pipelineSchema.getTaskSchema()); + this.forPipelines = new SchemaSpecificPieces(pipelineSchema); + this.forTasks = new SchemaSpecificPieces(pipelineSchema.getTaskSchema()); ConcourseDefinitionFinder definitionFinder = new ConcourseDefinitionFinder(this, models, pipelineSchema); // SimpleWorkspaceService workspace = getWorkspaceService(); @@ -134,6 +139,11 @@ public class ConcourseLanguageServer extends SimpleLanguageServer { } return super.getDiagnosticSeverity(problem); } + public SimpleLanguageServer setMaxCompletions(int max) { + forPipelines.setMaxCompletions(max); + forTasks.setMaxCompletions(max); + return this; + } @Override protected ServerCapabilities getServerCapabilities() { @@ -150,4 +160,5 @@ public class ConcourseLanguageServer extends SimpleLanguageServer { return c; } + } diff --git a/vscode-extensions/vscode-concourse/src/test/java/org/springframework/ide/vscode/concourse/ConcourseEditorTest.java b/vscode-extensions/vscode-concourse/src/test/java/org/springframework/ide/vscode/concourse/ConcourseEditorTest.java index 091e8d2ac..b5a49ba0a 100644 --- a/vscode-extensions/vscode-concourse/src/test/java/org/springframework/ide/vscode/concourse/ConcourseEditorTest.java +++ b/vscode-extensions/vscode-concourse/src/test/java/org/springframework/ide/vscode/concourse/ConcourseEditorTest.java @@ -34,7 +34,12 @@ public class ConcourseEditorTest { LanguageServerHarness harness; @Before public void setup() throws Exception { - harness = new LanguageServerHarness(ConcourseLanguageServer::new, LanguageIds.CONCOURSE_PIPELINE); + harness = new LanguageServerHarness(() -> { + return new ConcourseLanguageServer() + .setMaxCompletions(100); + }, + LanguageIds.CONCOURSE_PIPELINE + ); harness.intialize(null); } @@ -2704,6 +2709,46 @@ public class ConcourseEditorTest { ); } + @Test public void relaxedIndentContextMoreSpaces3() throws Exception { + Editor editor = harness.newEditor( + "jobs:\n" + + "- name: job-hello-world\n" + + " public: true\n" + + " plan:\n" + + " - get: resource-tutorial\n" + + " - task: hello-world\n" + + " <*>" + ); + + editor.assertCompletionLabels( + //completions for current (i.e Job) context: + "build_logs_to_retain", + "disable_manual_trigger", + "max_in_flight", + "serial", + "serial_groups", + "name", + "plan", + "public", + //Completions for nested context (i.e. task step) + "➔ attempts", + "➔ config", + "➔ ensure", + "➔ file", + "➔ image", + "➔ input_mapping", + "➔ on_failure", + "➔ on_success", + "➔ output_mapping", + "➔ params", + "➔ privileged", + "➔ tags", + "➔ task", + "➔ timeout" + ); + } + + ////////////////////////////////////////////////////////////////////////////// private void assertContextualCompletions(String conText, String textBefore, String... textAfter) throws Exception {