Goto defintion for releases
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
/*******************************************************************************
|
||||
* 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.bosh;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.eclipse.lsp4j.Location;
|
||||
import org.eclipse.lsp4j.TextDocumentPositionParams;
|
||||
import org.springframework.ide.vscode.commons.languageserver.definition.SimpleDefinitionFinder;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
import org.springframework.ide.vscode.commons.yaml.ast.NodeUtil;
|
||||
import org.springframework.ide.vscode.commons.yaml.ast.YamlAstCache;
|
||||
import org.springframework.ide.vscode.commons.yaml.ast.YamlFileAST;
|
||||
import org.springframework.ide.vscode.commons.yaml.reconcile.ASTTypeCache;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YType;
|
||||
import org.yaml.snakeyaml.nodes.Node;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
public class BoshDefintionFinder extends SimpleDefinitionFinder<BoshLanguageServer> {
|
||||
|
||||
//TODO: lots of common code between BoshDefintionFinder and ConcourseDefinitionFinder.
|
||||
// should be possible to pull up into a common super class.
|
||||
|
||||
private final YamlAstCache asts;
|
||||
private final ASTTypeCache astTypes;
|
||||
private final BoshDeploymentManifestSchema schema;
|
||||
|
||||
private Map<YType, Handler> handlers = new HashMap<>();
|
||||
|
||||
@FunctionalInterface
|
||||
private interface Handler {
|
||||
Flux<Location> handle(Node refNode, TextDocument doc, YamlFileAST ast);
|
||||
}
|
||||
|
||||
public BoshDefintionFinder(BoshLanguageServer server, BoshDeploymentManifestSchema schema, YamlAstCache asts, ASTTypeCache astTypes) {
|
||||
super(server);
|
||||
this.schema = schema;
|
||||
this.asts = asts;
|
||||
this.astTypes = astTypes;
|
||||
for (Pair<YType, YType> defAndRef : schema.getDefAndRefTypes()) {
|
||||
YType def = defAndRef.getLeft();
|
||||
if (def!=null) {
|
||||
YType ref = defAndRef.getRight();
|
||||
if (ref!=null) {
|
||||
findByType(def, ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Flux<Location> findDefinitions(TextDocumentPositionParams params) {
|
||||
try {
|
||||
TextDocument doc = server.getTextDocumentService().get(params);
|
||||
if (doc!=null) {
|
||||
YamlFileAST ast = asts.getSafeAst(doc, false);
|
||||
if (ast!=null) {
|
||||
Node refNode = ast.findNode(doc.toOffset(params.getPosition()));
|
||||
if (refNode!=null) {
|
||||
YType type = astTypes.getType(ast, refNode);
|
||||
if (type!=null) {
|
||||
Handler handler = handlers.get(type);
|
||||
if (handler!=null) {
|
||||
return handler.handle(refNode, doc, ast);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
return Flux.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a handler that finds the definitions for a target node within the same document
|
||||
* by retrieving nodes of a given type as candidates.
|
||||
*/
|
||||
protected void findByType(YType def, YType ref) {
|
||||
astTypes.addInterestingType(def);
|
||||
astTypes.addInterestingType(ref);
|
||||
Handler handler = (Node refNode, TextDocument doc, YamlFileAST ast) -> {
|
||||
String uri = doc.getUri();
|
||||
if (uri!=null) {
|
||||
String name = NodeUtil.asScalar(refNode);
|
||||
if (name!=null) {
|
||||
Collection<Node> candidates = astTypes.getNodes(uri, def);
|
||||
return Flux.fromIterable(candidates)
|
||||
.filter((node) -> name.equals(NodeUtil.asScalar(node)))
|
||||
.map((node) -> toLocation(doc, node))
|
||||
.filter(Optional::isPresent)
|
||||
.map(Optional::get);
|
||||
}
|
||||
}
|
||||
return Flux.empty();
|
||||
};
|
||||
handlers.put(ref, handler);
|
||||
}
|
||||
|
||||
protected Optional<Location> toLocation(TextDocument doc, Node node) {
|
||||
int start = node.getStartMark().getIndex();
|
||||
int end = node.getEndMark().getIndex();
|
||||
try {
|
||||
return Optional.of(new Location(doc.getUri(), doc.toRange(start, end-start)));
|
||||
} catch (BadLocationException e) {
|
||||
Log.log(e);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,13 +11,16 @@
|
||||
package org.springframework.ide.vscode.bosh;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.springframework.ide.vscode.bosh.models.CachingModelProvider;
|
||||
import org.springframework.ide.vscode.bosh.models.CloudConfigModel;
|
||||
import org.springframework.ide.vscode.bosh.models.DynamicModelProvider;
|
||||
import org.springframework.ide.vscode.commons.util.Assert;
|
||||
import org.springframework.ide.vscode.commons.util.CollectorUtil;
|
||||
import org.springframework.ide.vscode.commons.util.Renderable;
|
||||
import org.springframework.ide.vscode.commons.util.Renderables;
|
||||
import org.springframework.ide.vscode.commons.util.ValueParsers;
|
||||
@@ -81,6 +84,7 @@ public class BoshDeploymentManifestSchema implements YamlSchema {
|
||||
private YType t_var_name_def;
|
||||
private final ASTTypeCache astTypes;
|
||||
private DynamicModelProvider<CloudConfigModel> cloudConfigProvider;
|
||||
private List<Pair<YType, YType>> defAndRefTypes;
|
||||
|
||||
public BoshDeploymentManifestSchema(ASTTypeCache astTypes, DynamicModelProvider<CloudConfigModel> cloudConfigProvider) {
|
||||
this.astTypes = astTypes;
|
||||
@@ -280,14 +284,28 @@ public class BoshDeploymentManifestSchema implements YamlSchema {
|
||||
|
||||
public Collection<YType> getDefinitionTypes() {
|
||||
if (definitionTypes==null) {
|
||||
definitionTypes = ImmutableList.of(
|
||||
t_instance_group_name_def,
|
||||
t_stemcell_alias_def,
|
||||
t_release_name_def,
|
||||
t_var_name_def
|
||||
);
|
||||
definitionTypes = getDefAndRefTypes().stream()
|
||||
.map(pair -> pair.getLeft())
|
||||
.collect(CollectorUtil.toImmutableList());
|
||||
}
|
||||
return definitionTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Pairs of types. Each pair contains a 'def' type and a 'ref' type. Nodes with the ref-type
|
||||
* shall be interpreted as reference to a corresponding node with the 'def' type if the def and ref node
|
||||
* contain the same scalar value.
|
||||
*/
|
||||
public Collection<Pair<YType, YType>> getDefAndRefTypes() {
|
||||
if (defAndRefTypes==null) {
|
||||
defAndRefTypes = ImmutableList.of(
|
||||
Pair.of(t_instance_group_name_def, null),
|
||||
Pair.of(t_stemcell_alias_def, null),
|
||||
Pair.of(t_release_name_def, t_release_name_ref),
|
||||
Pair.of(t_var_name_def, null)
|
||||
);
|
||||
}
|
||||
return defAndRefTypes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocu
|
||||
import org.springframework.ide.vscode.commons.util.text.LanguageId;
|
||||
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.ast.YamlParser;
|
||||
import org.springframework.ide.vscode.commons.yaml.ast.YamlAstCache;
|
||||
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;
|
||||
@@ -34,18 +34,18 @@ 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.structure.YamlStructureProvider;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
public class BoshLanguageServer extends SimpleLanguageServer {
|
||||
|
||||
private Yaml yaml = new Yaml();
|
||||
private final LazyCompletionResolver completionResolver = new LazyCompletionResolver(); //Set to null to disable lazy resolving
|
||||
private final VscodeCompletionEngineAdapter completionEngine;
|
||||
|
||||
public BoshLanguageServer(DynamicModelProvider<CloudConfigModel> cloudConfigProvider) {
|
||||
super("vscode-bosh");
|
||||
YamlASTProvider parser = new YamlParser(yaml);
|
||||
YamlAstCache asts = new YamlAstCache();
|
||||
YamlASTProvider parser = asts.getAstProvider(false);
|
||||
SimpleTextDocumentService documents = getTextDocumentService();
|
||||
|
||||
ASTTypeCache astTypeCache = new ASTTypeCache();
|
||||
BoshDeploymentManifestSchema schema = new BoshDeploymentManifestSchema(astTypeCache, cloudConfigProvider);
|
||||
|
||||
@@ -67,6 +67,7 @@ public class BoshLanguageServer extends SimpleLanguageServer {
|
||||
documents.onCompletion(completionEngine::getCompletions);
|
||||
documents.onCompletionResolve(completionEngine::resolveCompletion);
|
||||
documents.onHover(hoverEngine ::getHover);
|
||||
documents.onDefinition(new BoshDefintionFinder(this, schema, asts, astTypeCache));
|
||||
}
|
||||
|
||||
private void validateOnDocumentChange(IReconcileEngine engine, TextDocument doc) {
|
||||
|
||||
@@ -26,7 +26,6 @@ import org.springframework.ide.vscode.commons.yaml.reconcile.YamlSchemaProblems;
|
||||
import org.springframework.ide.vscode.languageserver.testharness.Editor;
|
||||
import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness;
|
||||
|
||||
|
||||
public class BoshEditorTest {
|
||||
|
||||
LanguageServerHarness harness;
|
||||
@@ -920,4 +919,34 @@ public class BoshEditorTest {
|
||||
assertContains("Reading cloud config timed out", completion.getDocumentation());
|
||||
}
|
||||
|
||||
@Test public void gotoReleaseDefinition() throws Exception {
|
||||
Editor editor = harness.newEditor(
|
||||
"name: foo\n" +
|
||||
"instance_groups: \n" +
|
||||
"- name: some-server\n" +
|
||||
" jobs:\n" +
|
||||
" - release: some-release\n" +
|
||||
"- name: some-other-server\n" +
|
||||
" jobs:\n" +
|
||||
" - release: bogus-release\n" +
|
||||
"releases:\n" +
|
||||
"- name: some-release\n" +
|
||||
" url: https://release-hub.info/some-release.tar.gz?version=99.3.2\n" +
|
||||
" sha1: asddsfsd\n" +
|
||||
"- name: other-release\n" +
|
||||
" url: https://release-hub.info/other-release.tar.gz?version=99.3.2\n" +
|
||||
" sha1: asddsfsd\n"
|
||||
);
|
||||
|
||||
editor.assertGotoDefinition(editor.positionOf("some-release"),
|
||||
editor.rangeOf(
|
||||
"releases:\n" +
|
||||
"- name: some-release\n"
|
||||
,
|
||||
"some-release"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user