diff --git a/headless-services/boot-properties-language-server/src/main/java/org/springframework/ide/vscode/boot/BootPropertiesLanguageServer.java b/headless-services/boot-properties-language-server/src/main/java/org/springframework/ide/vscode/boot/BootPropertiesLanguageServer.java index 726eaa7b2..4a4cb45ca 100644 --- a/headless-services/boot-properties-language-server/src/main/java/org/springframework/ide/vscode/boot/BootPropertiesLanguageServer.java +++ b/headless-services/boot-properties-language-server/src/main/java/org/springframework/ide/vscode/boot/BootPropertiesLanguageServer.java @@ -44,6 +44,7 @@ import org.springframework.ide.vscode.commons.yaml.ast.YamlParser; 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.completion.YamlCompletionEngineOptions; import org.springframework.ide.vscode.commons.yaml.hover.YamlHoverInfoProvider; import org.springframework.ide.vscode.commons.yaml.structure.YamlDocument; import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureProvider; @@ -68,6 +69,10 @@ public class BootPropertiesLanguageServer extends SimpleLanguageServer { private static final String YML = ".yml"; private static final String PROPERTIES = ".properties"; + + private static final YamlCompletionEngineOptions COMPLETION_OPTIONS = new YamlCompletionEngineOptions() { + public boolean includeDeindentedProposals() { return false; }; + }; // Shared: private final JavaProjectFinder javaProjectFinder; private final SpringPropertyIndexProvider indexProvider; @@ -120,12 +125,7 @@ public class BootPropertiesLanguageServer extends SimpleLanguageServer { private ICompletionEngine getCompletionEngine() { ICompletionEngine propertiesCompletions = new SpringPropertiesCompletionEngine(indexProvider, typeUtilProvider, javaProjectFinder); - ICompletionEngine yamlCompletions = new YamlCompletionEngine(yamlStructureProvider, yamlAssistContextProvider) { - @Override - protected boolean isLesserIndentRelaxable(SNode currentNode, SNode contextNode) { - return false; - } - }; + ICompletionEngine yamlCompletions = new YamlCompletionEngine(yamlStructureProvider, yamlAssistContextProvider, COMPLETION_OPTIONS); return (IDocument document, int offset) -> { String uri = document.getUri(); if (uri!=null) { diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/VscodeCompletionEngineAdapter.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/VscodeCompletionEngineAdapter.java index d5bf7c76c..abc766969 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/VscodeCompletionEngineAdapter.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/VscodeCompletionEngineAdapter.java @@ -40,10 +40,9 @@ import reactor.core.scheduler.Schedulers; */ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine { - private final static int MAX_COMPLETIONS = 50; + private final static int MAX_COMPLETIONS = 50; //TODO: move this to CompletionEngineOptions. private int maxCompletions = MAX_COMPLETIONS; final static Logger logger = LoggerFactory.getLogger(VscodeCompletionEngineAdapter.class); - public static final String VS_CODE_CURSOR_MARKER = "{{}}"; private SimpleLanguageServer server; private ICompletionEngine engine; diff --git a/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/YamlCompletionEngine.java b/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/YamlCompletionEngine.java index 3ec679dd4..e5bce3e1d 100644 --- a/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/YamlCompletionEngine.java +++ b/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/YamlCompletionEngine.java @@ -10,6 +10,9 @@ *******************************************************************************/ 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; @@ -42,8 +45,6 @@ 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. @@ -59,8 +60,10 @@ public class YamlCompletionEngine implements ICompletionEngine { private final YamlAssistContextProvider contextProvider; protected final YamlStructureProvider structureProvider; + private YamlCompletionEngineOptions options; - public YamlCompletionEngine(YamlStructureProvider structureProvider, YamlAssistContextProvider contextProvider) { + public YamlCompletionEngine(YamlStructureProvider structureProvider, YamlAssistContextProvider contextProvider, YamlCompletionEngineOptions options) { + this.options = options; Assert.isNotNull(structureProvider); Assert.isNotNull(contextProvider); this.structureProvider= structureProvider; @@ -149,7 +152,10 @@ public class YamlCompletionEngine implements ICompletionEngine { return null; } - protected boolean isLesserIndentRelaxable(final SNode currentNode, final SNode contextNode) { + protected final boolean isLesserIndentRelaxable(final SNode currentNode, final SNode contextNode) { + if (!options.includeDeindentedProposals()) { + return false; + } SChildBearingNode parent = currentNode.getParent(); while (parent!=null && parent!=contextNode) { SNode lastChild = parent.getLastRealChild(); diff --git a/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/YamlCompletionEngineOptions.java b/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/YamlCompletionEngineOptions.java new file mode 100644 index 000000000..f10db2a60 --- /dev/null +++ b/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/YamlCompletionEngineOptions.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * 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.yaml.completion; + +public interface YamlCompletionEngineOptions { + /** + * Whether the completion engine includes 'less indented' proposals (i.e. proposals + * that aren't valid at the current CA position, but are valid if we delete + * some spaces in front of the cursor first. + */ + default boolean includeDeindentedProposals() { + //Disabled by default for now because of bug introduced in VSCode 1.12: + //https://github.com/Microsoft/vscode/issues/26096 + return false; + } + + YamlCompletionEngineOptions DEFAULT = new YamlCompletionEngineOptions() {}; + YamlCompletionEngineOptions TEST_DEFAULT = new YamlCompletionEngineOptions() { + @Override public boolean includeDeindentedProposals() { return true; } + }; +} \ No newline at end of file diff --git a/headless-services/concourse-language-server/src/main/java/org/springframework/ide/vscode/concourse/ConcourseLanguageServer.java b/headless-services/concourse-language-server/src/main/java/org/springframework/ide/vscode/concourse/ConcourseLanguageServer.java index ad0796a36..5e81d46c8 100644 --- a/headless-services/concourse-language-server/src/main/java/org/springframework/ide/vscode/concourse/ConcourseLanguageServer.java +++ b/headless-services/concourse-language-server/src/main/java/org/springframework/ide/vscode/concourse/ConcourseLanguageServer.java @@ -30,6 +30,7 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument; import org.springframework.ide.vscode.commons.yaml.ast.YamlASTProvider; import org.springframework.ide.vscode.commons.yaml.completion.SchemaBasedYamlAssistContextProvider; import org.springframework.ide.vscode.commons.yaml.completion.YamlCompletionEngine; +import org.springframework.ide.vscode.commons.yaml.completion.YamlCompletionEngineOptions; import org.springframework.ide.vscode.commons.yaml.hover.YamlHoverInfoProvider; import org.springframework.ide.vscode.commons.yaml.quickfix.YamlQuickfixes; import org.springframework.ide.vscode.commons.yaml.reconcile.YamlSchemaBasedReconcileEngine; @@ -42,6 +43,7 @@ import com.google.common.collect.ImmutableList; public class ConcourseLanguageServer extends SimpleLanguageServer { + private final YamlCompletionEngineOptions COMPLETION_OPTIONS; YamlStructureProvider structureProvider = YamlStructureProvider.DEFAULT; SimpleTextDocumentService documents = getTextDocumentService(); ConcourseModel models = new ConcourseModel(this); @@ -59,7 +61,7 @@ public class ConcourseLanguageServer extends SimpleLanguageServer { SchemaSpecificPieces(YamlSchema schema, List definitionTypes) { SchemaBasedYamlAssistContextProvider contextProvider = new SchemaBasedYamlAssistContextProvider(schema); - YamlCompletionEngine yamlCompletionEngine = new YamlCompletionEngine(structureProvider, contextProvider); + YamlCompletionEngine yamlCompletionEngine = new YamlCompletionEngine(structureProvider, contextProvider, COMPLETION_OPTIONS); this.completionEngine = new VscodeCompletionEngineAdapter(ConcourseLanguageServer.this, yamlCompletionEngine); HoverInfoProvider infoProvider = new YamlHoverInfoProvider(currentAsts, structureProvider, contextProvider); @@ -78,8 +80,9 @@ public class ConcourseLanguageServer extends SimpleLanguageServer { } } - public ConcourseLanguageServer() { + public ConcourseLanguageServer(YamlCompletionEngineOptions completionOptions) { super("vscode-concourse"); + this.COMPLETION_OPTIONS = completionOptions; PipelineYmlSchema pipelineSchema = new PipelineYmlSchema(models); this.yamlQuickfixes = new YamlQuickfixes(getQuickfixRegistry(), documents, structureProvider); diff --git a/headless-services/concourse-language-server/src/main/java/org/springframework/ide/vscode/concourse/Main.java b/headless-services/concourse-language-server/src/main/java/org/springframework/ide/vscode/concourse/Main.java index af1006194..ae7c30be6 100644 --- a/headless-services/concourse-language-server/src/main/java/org/springframework/ide/vscode/concourse/Main.java +++ b/headless-services/concourse-language-server/src/main/java/org/springframework/ide/vscode/concourse/Main.java @@ -14,12 +14,12 @@ package org.springframework.ide.vscode.concourse; import java.io.IOException; import org.springframework.ide.vscode.commons.languageserver.LaunguageServerApp; -import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; +import org.springframework.ide.vscode.commons.yaml.completion.YamlCompletionEngineOptions; public class Main { - SimpleLanguageServer server = new ConcourseLanguageServer(); - + private static final YamlCompletionEngineOptions OPTIONS = YamlCompletionEngineOptions.DEFAULT; + public static void main(String[] args) throws IOException, InterruptedException { - LaunguageServerApp.start(ConcourseLanguageServer::new); + LaunguageServerApp.start(() -> new ConcourseLanguageServer(OPTIONS)); } } diff --git a/headless-services/concourse-language-server/src/test/java/org/springframework/ide/vscode/concourse/ConcourseEditorTest.java b/headless-services/concourse-language-server/src/test/java/org/springframework/ide/vscode/concourse/ConcourseEditorTest.java index 193fe65fc..dbd600951 100644 --- a/headless-services/concourse-language-server/src/test/java/org/springframework/ide/vscode/concourse/ConcourseEditorTest.java +++ b/headless-services/concourse-language-server/src/test/java/org/springframework/ide/vscode/concourse/ConcourseEditorTest.java @@ -28,6 +28,7 @@ import org.junit.Test; import org.springframework.ide.vscode.commons.util.IOUtil; import org.springframework.ide.vscode.commons.util.Unicodes; import org.springframework.ide.vscode.commons.util.text.LanguageId; +import org.springframework.ide.vscode.commons.yaml.completion.YamlCompletionEngineOptions; import org.springframework.ide.vscode.languageserver.testharness.CodeAction; import org.springframework.ide.vscode.languageserver.testharness.Editor; import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness; @@ -35,12 +36,14 @@ import org.springframework.ide.vscode.languageserver.testharness.Synchronization public class ConcourseEditorTest { + private static final YamlCompletionEngineOptions OPTIONS = YamlCompletionEngineOptions.TEST_DEFAULT; + private static final String CURSOR = "<*>"; LanguageServerHarness harness; @Before public void setup() throws Exception { harness = new LanguageServerHarness(() -> { - return new ConcourseLanguageServer() + return new ConcourseLanguageServer(OPTIONS) .setMaxCompletions(100); }, LanguageId.CONCOURSE_PIPELINE diff --git a/headless-services/concourse-language-server/src/test/java/org/springframework/ide/vscode/concourse/ConcourseLanguageServerTest.java b/headless-services/concourse-language-server/src/test/java/org/springframework/ide/vscode/concourse/ConcourseLanguageServerTest.java index 63b3f4433..8a48f5d08 100644 --- a/headless-services/concourse-language-server/src/test/java/org/springframework/ide/vscode/concourse/ConcourseLanguageServerTest.java +++ b/headless-services/concourse-language-server/src/test/java/org/springframework/ide/vscode/concourse/ConcourseLanguageServerTest.java @@ -22,6 +22,7 @@ import org.eclipse.lsp4j.TextDocumentSyncKind; import org.junit.Test; import org.springframework.ide.vscode.concourse.ConcourseLanguageServer; import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness; +import static org.springframework.ide.vscode.commons.yaml.completion.YamlCompletionEngineOptions.*; public class ConcourseLanguageServerTest { @@ -31,7 +32,7 @@ public class ConcourseLanguageServerTest { @Test public void createAndInitializeServerWithWorkspace() throws Exception { - LanguageServerHarness harness = new LanguageServerHarness(ConcourseLanguageServer::new); + LanguageServerHarness harness = new LanguageServerHarness(() -> new ConcourseLanguageServer(TEST_DEFAULT)); File workspaceRoot = getTestResource("/workspace/"); assertExpectedInitResult(harness.intialize(workspaceRoot)); } @@ -39,7 +40,7 @@ public class ConcourseLanguageServerTest { @Test public void createAndInitializeServerWithoutWorkspace() throws Exception { File workspaceRoot = null; - LanguageServerHarness harness = new LanguageServerHarness(ConcourseLanguageServer::new); + LanguageServerHarness harness = new LanguageServerHarness(() -> new ConcourseLanguageServer(TEST_DEFAULT)); assertExpectedInitResult(harness.intialize(workspaceRoot)); } diff --git a/headless-services/manifest-yaml-language-server/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServer.java b/headless-services/manifest-yaml-language-server/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServer.java index 4b716cbfd..be5d614cb 100644 --- a/headless-services/manifest-yaml-language-server/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServer.java +++ b/headless-services/manifest-yaml-language-server/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlLanguageServer.java @@ -34,6 +34,7 @@ import org.springframework.ide.vscode.commons.yaml.ast.YamlParser; import org.springframework.ide.vscode.commons.yaml.completion.SchemaBasedYamlAssistContextProvider; 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.completion.YamlCompletionEngineOptions; import org.springframework.ide.vscode.commons.yaml.hover.YamlHoverInfoProvider; import org.springframework.ide.vscode.commons.yaml.quickfix.YamlQuickfixes; import org.springframework.ide.vscode.commons.yaml.reconcile.YamlSchemaBasedReconcileEngine; @@ -66,7 +67,7 @@ public class ManifestYamlLanguageServer extends SimpleLanguageServer { YamlStructureProvider structureProvider = YamlStructureProvider.DEFAULT; YamlAssistContextProvider contextProvider = new SchemaBasedYamlAssistContextProvider(schema); - YamlCompletionEngine yamlCompletionEngine = new YamlCompletionEngine(structureProvider, contextProvider); + YamlCompletionEngine yamlCompletionEngine = new YamlCompletionEngine(structureProvider, contextProvider, YamlCompletionEngineOptions.DEFAULT); VscodeCompletionEngine completionEngine = new VscodeCompletionEngineAdapter(this, yamlCompletionEngine); HoverInfoProvider infoProvider = new YamlHoverInfoProvider(parser, structureProvider, contextProvider); VscodeHoverEngine hoverEngine = new VscodeHoverEngineAdapter(this, infoProvider);