Groundwork for HierarchicalDocumentSymbolHandler

This commit is contained in:
Kris De Volder
2019-02-11 15:27:13 -08:00
parent b391a111a5
commit adf238f61d
17 changed files with 233 additions and 87 deletions

View File

@@ -0,0 +1,42 @@
/*******************************************************************************
* Copyright (c) 2019 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.commons.languageserver.util;
import java.util.List;
import org.eclipse.lsp4j.DocumentSymbol;
import org.eclipse.lsp4j.DocumentSymbolParams;
import org.eclipse.lsp4j.SymbolInformation;
import com.google.common.collect.ImmutableList;
/**
* Note if you implement HierarchicalDocumentSymbolHandler you must also implement the 'legacy'
* non-hierarchical handler because this is used as a fallback when client doesn't support
* hierarchical symbols.
*/
public interface HierarchicalDocumentSymbolHandler extends DocumentSymbolHandler {
HierarchicalDocumentSymbolHandler NO_SYMBOLS = new HierarchicalDocumentSymbolHandler() {
@Override
public List<? extends SymbolInformation> handle(DocumentSymbolParams params) {
return ImmutableList.of();
}
@Override
public List<? extends DocumentSymbol> handleHierarchic(DocumentSymbolParams params) {
return ImmutableList.of();
}
};
List<? extends DocumentSymbol> handleHierarchic(DocumentSymbolParams params);
}

View File

@@ -425,9 +425,6 @@ public final class SimpleLanguageServer implements Sts4LanguageServer, LanguageC
public final boolean hasLazyCompletionResolver() {
return completionResolver!=null;
}
public boolean hasHierarchicalDocumentSymbolSupport() {
return hasHierarchicalDocumentSymbolSupport;
}
private boolean hasDocumentSymbolHandler() {
return getTextDocumentService().hasDocumentSymbolHandler();
@@ -713,4 +710,7 @@ public final class SimpleLanguageServer implements Sts4LanguageServer, LanguageC
this.completionTriggerCharacters = completionTriggerCharacters;
}
public boolean hasHierarchicalDocumentSymbolSupport() {
return hasHierarchicalDocumentSymbolSupport;
}
}

View File

@@ -84,6 +84,7 @@ public class SimpleTextDocumentService implements TextDocumentService, DocumentE
private HoverHandler hoverHandler = null;
private DefinitionHandler definitionHandler;
private ReferencesHandler referencesHandler;
private DocumentSymbolHandler documentSymbolHandler;
private DocumentHighlightHandler documentHighlightHandler;
@@ -93,6 +94,7 @@ public class SimpleTextDocumentService implements TextDocumentService, DocumentE
private List<Consumer<TextDocumentSaveChange>> documentSaveListeners = ImmutableList.of();
private AsyncRunner async;
public SimpleTextDocumentService(SimpleLanguageServer server) {
this.server = server;
this.async = server.getAsync();
@@ -349,18 +351,28 @@ public class SimpleTextDocumentService implements TextDocumentService, DocumentE
@Override
public CompletableFuture<List<Either<SymbolInformation, DocumentSymbol>>> documentSymbol(DocumentSymbolParams params) {
return async.invoke(() -> {
DocumentSymbolHandler documentSymbolHandler = this.documentSymbolHandler;
if (documentSymbolHandler==null) {
return async.invoke(() -> {
DocumentSymbolHandler h = this.documentSymbolHandler;
if (h!=null) {
server.waitForReconcile();
if (server.hasHierarchicalDocumentSymbolSupport() && h instanceof HierarchicalDocumentSymbolHandler) {
List<? extends DocumentSymbol> r = ((HierarchicalDocumentSymbolHandler)h).handleHierarchic(params);
//handle it when symbolHandler is sloppy and returns null instead of empty list.
return r == null
? ImmutableList.of()
: r.stream().map(symbolInfo -> Either.<SymbolInformation, DocumentSymbol>forRight(symbolInfo))
.collect(Collectors.toList());
} else {
List<? extends SymbolInformation> r = h.handle(params);
//handle it when symbolHandler is sloppy and returns null instead of empty list.
return r == null
? ImmutableList.of()
: r.stream().map(symbolInfo -> Either.<SymbolInformation, DocumentSymbol>forLeft(symbolInfo))
.collect(Collectors.toList());
}
}
return ImmutableList.of();
}
server.waitForReconcile();
List<? extends SymbolInformation> r = documentSymbolHandler.handle(params);
//handle it when symbolHandler is sloppy and returns null instead of empty list.
return r == null ? ImmutableList.of()
: r.stream().map(symbolInfo -> Either.<SymbolInformation, DocumentSymbol>forLeft(symbolInfo))
.collect(Collectors.toList());
});
});
}
@Override

View File

@@ -22,6 +22,7 @@ import org.springframework.ide.vscode.commons.util.StringUtil;
import org.springframework.ide.vscode.commons.util.text.IDocument;
import org.springframework.ide.vscode.commons.yaml.ast.NodeUtil;
import org.springframework.ide.vscode.commons.yaml.ast.YamlFileAST;
import org.springframework.ide.vscode.commons.yaml.path.YamlPath;
import org.springframework.ide.vscode.commons.yaml.schema.DynamicSchemaContext;
import org.springframework.ide.vscode.commons.yaml.schema.YType;
import org.yaml.snakeyaml.nodes.Node;
@@ -52,10 +53,10 @@ public class ASTTypeCache implements ITypeCollector {
*/
private static class NodeTypesImpl implements NodeTypes {
private ImmutableMap<Node, YType> node2type;
private final ImmutableMap<Node, YType> node2type;
private Multimap<YType, Node> type2node = null; //lazy initialized when used.
public NodeTypesImpl(ImmutableMap<Node, YType> node2type) {
public NodeTypesImpl(YamlFileAST ast, ImmutableMap<Node, YType> node2type) {
this.node2type = node2type;
}
@@ -82,6 +83,8 @@ public class ASTTypeCache implements ITypeCollector {
*/
private YamlFileAST currentAst = null;
public ASTTypeCache() {}
/**
* Collects types for the current session.
*/
@@ -101,14 +104,15 @@ public class ASTTypeCache implements ITypeCollector {
public synchronized void endCollecting(YamlFileAST ast) {
Assert.isLegal(currentAst==ast);
String uri = ast.getDocument().getUri();
typeIndex.put(uri, new NodeTypesImpl(currentTypes.build()));
typeIndex.put(uri, new NodeTypesImpl(currentAst, currentTypes.build()));
this.currentAst = null;
this.currentTypes = null;
}
@Override
public void accept(Node node, YType type) {
public void accept(Node node, YType type, YamlPath path) {
if (interestingTypes.contains(type)) {
System.out.println(path.toPropString() + " = " +NodeUtil.asScalar(node) +" :: "+type);
currentTypes.put(node, type);
}
}

View File

@@ -11,6 +11,7 @@
package org.springframework.ide.vscode.commons.yaml.reconcile;
import org.springframework.ide.vscode.commons.yaml.ast.YamlFileAST;
import org.springframework.ide.vscode.commons.yaml.path.YamlPath;
import org.springframework.ide.vscode.commons.yaml.schema.YType;
import org.yaml.snakeyaml.nodes.Node;
@@ -23,6 +24,6 @@ import org.yaml.snakeyaml.nodes.Node;
*/
public interface ITypeCollector {
void beginCollecting(YamlFileAST ast);
void accept(Node node, YType type);
void accept(Node node, YType type, YamlPath path);
void endCollecting(YamlFileAST ast);
}

View File

@@ -145,7 +145,7 @@ public class SchemaBasedYamlASTReconciler implements YamlASTReconciler {
DynamicSchemaContext schemaContext = new ASTDynamicSchemaContext(ast, path, node);
YType type = typeUtil.inferMoreSpecificType(_type, schemaContext);
if (typeCollector!=null) {
typeCollector.accept(node, type);
typeCollector.accept(node, type, path);
}
checkConstraints(parent, node, type, schemaContext);
switch (getNodeId(node)) {

View File

@@ -15,9 +15,6 @@ import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import javax.inject.Provider;
import org.eclipse.lsp4j.DocumentSymbol;
import org.eclipse.lsp4j.DocumentSymbolParams;
import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.SymbolInformation;
@@ -28,14 +25,12 @@ import org.springframework.ide.vscode.commons.languageserver.util.DocumentSymbol
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
import org.springframework.ide.vscode.commons.util.Assert;
import org.springframework.ide.vscode.commons.util.BadLocationException;
import org.springframework.ide.vscode.commons.util.Log;
import org.springframework.ide.vscode.commons.util.text.DocumentRegion;
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.schema.YType;
import org.yaml.snakeyaml.nodes.Node;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.common.collect.ImmutableSet;
@@ -55,14 +50,12 @@ public class TypeBasedYamlSymbolHandler implements DocumentSymbolHandler {
private ASTTypeCache astTypeCache;
private Set<YType> definitionTypes;
private SimpleTextDocumentService documents;
private Supplier<Boolean> hiearchicalSymbolSupport;
public TypeBasedYamlSymbolHandler(SimpleTextDocumentService documents, ASTTypeCache astTypeCache, Collection<YType> definitionTypes, Supplier<Boolean> hasHierarchicalSymbolSupport) {
public TypeBasedYamlSymbolHandler(SimpleTextDocumentService documents, ASTTypeCache astTypeCache, Collection<YType> definitionTypes) {
Assert.isTrue(!definitionTypes.isEmpty()); // If there's no interesting types then you are better of using DocumentSymbolHandler.NO_SYMBOLS
this.documents = documents;
this.astTypeCache = astTypeCache;
this.definitionTypes = ImmutableSet.copyOf(definitionTypes);
this.hiearchicalSymbolSupport = hasHierarchicalSymbolSupport;
for (YType yType : definitionTypes) {
astTypeCache.addInterestingType(yType);
}

View File

@@ -11,12 +11,22 @@
package org.springframework.ide.vscode.commons.yaml.reconcile;
import java.util.Collection;
import org.springframework.context.ApplicationContext;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem;
import org.springframework.ide.vscode.commons.util.CollectionUtil;
import org.springframework.ide.vscode.commons.util.text.IDocument;
import org.springframework.ide.vscode.commons.yaml.ast.YamlASTProvider;
import org.springframework.ide.vscode.commons.yaml.ast.YamlFileAST;
import org.springframework.ide.vscode.commons.yaml.path.YamlPath;
import org.springframework.ide.vscode.commons.yaml.quickfix.YamlQuickfixes;
import org.springframework.ide.vscode.commons.yaml.schema.YType;
import org.springframework.ide.vscode.commons.yaml.schema.YamlSchema;
import org.yaml.snakeyaml.nodes.Node;
import com.google.common.collect.ImmutableList;
/**
* @author Kris De Volder
@@ -24,18 +34,15 @@ import org.springframework.ide.vscode.commons.yaml.schema.YamlSchema;
public final class YamlSchemaBasedReconcileEngine extends YamlReconcileEngine {
private final YamlSchema schema;
/**
* An optional type collector can be added. It will notified about all the types
* the reconciler infers when reconciling an AST.
*/
private ITypeCollector typeCollector;
private YamlQuickfixes quickfixes;
public YamlSchemaBasedReconcileEngine(YamlASTProvider parser, YamlSchema schema, YamlQuickfixes quickfixes) {
private ApplicationContext appContext;
public YamlSchemaBasedReconcileEngine(YamlASTProvider parser, YamlSchema schema, YamlQuickfixes quickfixes, ApplicationContext appContext) {
super(parser);
this.schema = schema;
this.quickfixes = quickfixes;
this.appContext = appContext;
}
@Override
@@ -45,14 +52,34 @@ public final class YamlSchemaBasedReconcileEngine extends YamlReconcileEngine {
@Override
protected YamlASTReconciler getASTReconciler(IDocument doc, IProblemCollector problems) {
Collection<ITypeCollector> typeCollectors = appContext.getBeansOfType(ITypeCollector.class).values();
ITypeCollector typeCollector = null;
if (CollectionUtil.hasElements(typeCollectors)) {
typeCollector = new ITypeCollector() {
@Override
public void endCollecting(YamlFileAST ast) {
for (ITypeCollector c : typeCollectors) {
c.endCollecting(ast);
}
}
@Override
public void beginCollecting(YamlFileAST ast) {
for (ITypeCollector c : typeCollectors) {
c.beginCollecting(ast);
}
}
@Override
public void accept(Node node, YType type, YamlPath path) {
for (ITypeCollector c : typeCollectors) {
c.accept(node, type, path);
}
}
};
}
return new SchemaBasedYamlASTReconciler(problems, schema, typeCollector, quickfixes);
}
public ITypeCollector getTypeCollector() {
return typeCollector;
}
public void setTypeCollector(ITypeCollector typeCollector) {
this.typeCollector = typeCollector;
}
}

View File

@@ -26,11 +26,12 @@ import org.springframework.ide.vscode.commons.languageserver.config.LanguageServ
import org.springframework.ide.vscode.commons.languageserver.config.LanguageServerProperties;
import org.springframework.ide.vscode.commons.languageserver.reconcile.DiagnosticSeverityProvider;
import org.springframework.ide.vscode.commons.languageserver.util.DefinitionHandler;
import org.springframework.ide.vscode.commons.languageserver.util.DocumentSymbolHandler;
import org.springframework.ide.vscode.commons.languageserver.util.LanguageSpecific;
import org.springframework.ide.vscode.commons.languageserver.util.LspClient;
import org.springframework.ide.vscode.commons.languageserver.util.LspClient.Client;
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
import org.springframework.ide.vscode.commons.languageserver.util.LspClient.Client;
import org.springframework.ide.vscode.commons.util.text.LanguageId;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
import org.springframework.util.Assert;
@@ -100,4 +101,12 @@ public class LanguageServerAutoConf {
}
}
@ConditionalOnBean(DocumentSymbolHandler.class)
@Bean
InitializingBean registerDocumentSymbolHandler(SimpleTextDocumentService documents, DocumentSymbolHandler handler) {
return () -> {
documents.onDocumentSymbol(handler);
};
}
}

View File

@@ -44,9 +44,9 @@ public class ConcourseDefinitionFinder extends SimpleDefinitionFinder<SimpleLang
private Map<YType, Handler> handlers = new HashMap<>();
private final YamlAstCache asts;
public ConcourseDefinitionFinder(SimpleLanguageServer server, ConcourseModel models, PipelineYmlSchema schema) {
public ConcourseDefinitionFinder(SimpleLanguageServer server, ConcourseModel models, PipelineYmlSchema schema, ASTTypeCache astTypeCache) {
super(server);
this.astTypes = models.getAstTypeCache();
this.astTypes = astTypeCache;
this.asts = models.getAstCache();
findByPath(schema.t_resource_name, ConcourseModel.RESOURCE_NAMES_PATH);
findByPath(schema.t_maybe_resource_name, ConcourseModel.RESOURCE_NAMES_PATH);

View File

@@ -13,7 +13,11 @@ package org.springframework.ide.vscode.concourse;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
import org.springframework.ide.vscode.commons.util.LogRedirect;
import org.springframework.ide.vscode.commons.yaml.reconcile.ASTTypeCache;
import org.springframework.ide.vscode.commons.yaml.reconcile.TypeBasedYamlSymbolHandler;
import org.springframework.ide.vscode.concourse.github.DefaultGithubInfoProvider;
import org.springframework.ide.vscode.concourse.github.GithubInfoProvider;
@@ -34,4 +38,20 @@ public class ConcourseLanguageServerBootApp {
@Bean GithubInfoProvider github() {
return new DefaultGithubInfoProvider();
}
@Bean ConcourseModel concourseModel(SimpleLanguageServer server, ASTTypeCache astTypeCache) {
return new ConcourseModel(server, astTypeCache);
}
@Bean ASTTypeCache astTypeCache() {
return new ASTTypeCache();
}
@Bean TypeBasedYamlSymbolHandler documentSymbolHandler(SimpleTextDocumentService documents, ASTTypeCache astTypeCache, PipelineYmlSchema schema) {
return new TypeBasedYamlSymbolHandler(documents, astTypeCache, schema.getDefinitionTypes());
}
@Bean PipelineYmlSchema pipelineYmlSchema(ConcourseModel models, GithubInfoProvider github) {
return new PipelineYmlSchema(models, github);
}
}

View File

@@ -12,9 +12,12 @@ package org.springframework.ide.vscode.concourse;
import java.util.List;
import javax.annotation.PostConstruct;
import org.eclipse.lsp4j.CompletionList;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter;
import org.springframework.ide.vscode.commons.languageserver.hover.HoverInfoProvider;
import org.springframework.ide.vscode.commons.languageserver.hover.VscodeHoverEngineAdapter;
@@ -31,12 +34,14 @@ import org.springframework.ide.vscode.commons.yaml.completion.YamlCompletionEngi
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.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.schema.YType;
import org.springframework.ide.vscode.commons.yaml.schema.YamlSchema;
import org.springframework.ide.vscode.commons.yaml.snippet.SchemaBasedSnippetGenerator;
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureProvider;
import org.springframework.ide.vscode.concourse.PipelineYmlSchema.HierarchicalDefType;
import org.springframework.ide.vscode.concourse.github.GithubInfoProvider;
import org.springframework.stereotype.Component;
@@ -45,12 +50,11 @@ import com.google.common.collect.ImmutableList;
import reactor.core.publisher.Mono;
@Component
public class ConcourseLanguageServerInitializer implements InitializingBean {
public class ConcourseLanguageServerInitializer {
private final YamlCompletionEngineOptions COMPLETION_OPTIONS = YamlCompletionEngineOptions.DEFAULT;
private final YamlStructureProvider structureProvider = YamlStructureProvider.DEFAULT;
private ConcourseModel models;
private SchemaSpecificPieces forPipelines;
private SchemaSpecificPieces forTasks;
@@ -59,15 +63,19 @@ public class ConcourseLanguageServerInitializer implements InitializingBean {
@Autowired private SimpleLanguageServer server;
@Autowired private GithubInfoProvider github;
@Autowired private ASTTypeCache astTypeCache;
@Autowired private ApplicationContext appContext;
@Autowired private ConcourseModel models;
@Autowired private PipelineYmlSchema pipelineSchema;
private class SchemaSpecificPieces {
final VscodeCompletionEngineAdapter completionEngine;
final VscodeHoverEngineAdapter hoverEngine;
final YamlSchemaBasedReconcileEngine reconcileEngine;
final DocumentSymbolHandler symbolHandler;
// final DocumentSymbolHandler symbolHandler;
SchemaSpecificPieces(YamlSchema schema, List<YType> definitionTypes) {
SchemaSpecificPieces(YamlSchema schema, List<YType> definitionTypes, List<HierarchicalDefType> hierarchicalDefinitions) {
SchemaBasedYamlAssistContextProvider contextProvider = new SchemaBasedYamlAssistContextProvider(schema);
YamlCompletionEngine yamlCompletionEngine = new YamlCompletionEngine(structureProvider, contextProvider, COMPLETION_OPTIONS);
this.completionEngine = server.createCompletionEngineAdapter(yamlCompletionEngine);
@@ -75,12 +83,11 @@ public class ConcourseLanguageServerInitializer implements InitializingBean {
HoverInfoProvider infoProvider = new YamlHoverInfoProvider(currentAsts, structureProvider, contextProvider);
this.hoverEngine = new VscodeHoverEngineAdapter(server, infoProvider);
this.reconcileEngine = new YamlSchemaBasedReconcileEngine(currentAsts, schema, yamlQuickfixes);
reconcileEngine.setTypeCollector(models.getAstTypeCache());
this.reconcileEngine = new YamlSchemaBasedReconcileEngine(currentAsts, schema, yamlQuickfixes, appContext);
this.symbolHandler = CollectionUtil.hasElements(definitionTypes)
? new TypeBasedYamlSymbolHandler(server.getTextDocumentService(), models.getAstTypeCache(), definitionTypes, server::hasHierarchicalDocumentSymbolSupport)
: DocumentSymbolHandler.NO_SYMBOLS;
// this.symbolHandler = CollectionUtil.hasElements(definitionTypes)
// ? new TypeBasedYamlSymbolHandler(server.getTextDocumentService(), astTypeCache, definitionTypes)
// : DocumentSymbolHandler.NO_SYMBOLS;
}
public void setMaxCompletions(int max) {
@@ -89,6 +96,7 @@ public class ConcourseLanguageServerInitializer implements InitializingBean {
}
public void enableSnippets(PipelineYmlSchema schema, boolean enable) {
//TODO: move to where schema bean is defined?
if (enable) {
schema.f.setSnippetProvider(new SchemaBasedSnippetGenerator(schema.getTypeUtil(), server::createSnippetBuilder));
} else {
@@ -96,18 +104,16 @@ public class ConcourseLanguageServerInitializer implements InitializingBean {
}
}
@Override
@PostConstruct
public void afterPropertiesSet() throws Exception {
this.models = new ConcourseModel(server);
this.currentAsts = models.getAstCache().getAstProvider(false);
PipelineYmlSchema pipelineSchema = new PipelineYmlSchema(models, github);
enableSnippets(pipelineSchema, true);
SimpleTextDocumentService documents = server.getTextDocumentService();
this.yamlQuickfixes = new YamlQuickfixes(server.getQuickfixRegistry(), documents, structureProvider);
this.forPipelines = new SchemaSpecificPieces(pipelineSchema, pipelineSchema.getDefinitionTypes());
this.forTasks = new SchemaSpecificPieces(pipelineSchema.getTaskSchema(), null);
ConcourseDefinitionFinder definitionFinder = new ConcourseDefinitionFinder(server, models, pipelineSchema);
this.forPipelines = new SchemaSpecificPieces(pipelineSchema, pipelineSchema.getDefinitionTypes(), pipelineSchema.getHierarchicalDefinitionTypes());
this.forTasks = new SchemaSpecificPieces(pipelineSchema.getTaskSchema(), null, null);
ConcourseDefinitionFinder definitionFinder = new ConcourseDefinitionFinder(server, models, pipelineSchema, astTypeCache);
// SimpleWorkspaceService workspace = getWorkspaceService();
documents.onDidChangeContent(params -> {
@@ -159,18 +165,18 @@ public class ConcourseLanguageServerInitializer implements InitializingBean {
return SimpleTextDocumentService.NO_HOVER;
});
documents.onDefinition(definitionFinder);
documents.onDocumentSymbol((params) -> {
DocumentSymbolHandler handler = DocumentSymbolHandler.NO_SYMBOLS;
TextDocument doc = documents.getDocument(params.getTextDocument().getUri());
if (doc!=null) {
if (LanguageId.CONCOURSE_PIPELINE.equals(doc.getLanguageId())) {
handler = forPipelines.symbolHandler;
} else if (LanguageId.CONCOURSE_TASK.equals(doc.getLanguageId())) {
handler = forTasks.symbolHandler;
}
}
return handler.handle(params);
});
// documents.onDocumentSymbol((params) -> {
// DocumentSymbolHandler handler = DocumentSymbolHandler.NO_SYMBOLS;
// TextDocument doc = documents.getDocument(params.getTextDocument().getUri());
// if (doc!=null) {
// if (LanguageId.CONCOURSE_PIPELINE.equals(doc.getLanguageId())) {
// handler = forPipelines.symbolHandler;
// } else if (LanguageId.CONCOURSE_TASK.equals(doc.getLanguageId())) {
// handler = forTasks.symbolHandler;
// }
// }
// return handler.handle(params);
// });
}
// @Override

View File

@@ -76,13 +76,13 @@ public class ConcourseModel {
* that same type of something).
*/
public Constraint isUsed(YType refType, String entityTypeName) {
getAstTypeCache().addInterestingType(refType); //ensure the type is tracked in the type-cache
astTypeCache.addInterestingType(refType); //ensure the type is tracked in the type-cache
return new Constraint() {
@Override
public void verify(DynamicSchemaContext dc, Node parent, Node node, YType type, IProblemCollector problems) {
String defName = NodeUtil.asScalar(node);
if (StringUtil.hasText(defName)) { //Avoid silly 'not used' errors for empty names (will have an other error already).
NodeTypes nodeTypes = getAstTypeCache().getNodeTypes(dc.getDocument().getUri());
NodeTypes nodeTypes = astTypeCache.getNodeTypes(dc.getDocument().getUri());
if (nodeTypes!=null) {
Optional<Node> reference = nodeTypes.getNodes(refType).stream()
.filter(refNode -> defName.equals(NodeUtil.asScalar(refNode)))
@@ -286,8 +286,9 @@ public class ConcourseModel {
valueAt("name")
);
private final ASTTypeCache astTypeCache;
private final YamlAstCache asts = new YamlAstCache();
private final ASTTypeCache astTypes = new ASTTypeCache();
private ResourceTypeRegistry resourceTypes;
@@ -295,7 +296,8 @@ public class ConcourseModel {
private YBeanUnionType stepType;
public ConcourseModel(SimpleLanguageServer languageServer) {
public ConcourseModel(SimpleLanguageServer languageServer, ASTTypeCache astTypeCache) {
this.astTypeCache = astTypeCache;
this.snippetBuilderFactory = languageServer::createSnippetBuilder;
}
@@ -448,10 +450,6 @@ public class ConcourseModel {
}
public ASTTypeCache getAstTypeCache() {
return astTypes;
}
public void setResourceTypeRegistry(ResourceTypeRegistry resourceTypes) {
this.resourceTypes = resourceTypes;
}

View File

@@ -61,6 +61,30 @@ import com.google.common.collect.ImmutableList;
*/
public class PipelineYmlSchema implements YamlSchema {
public static class HierarchicalDefType {
/**
* A yaml node of this type constitutes a definion. This should identify the 'whole' definition not just the
* part of the node that contains the name of the defined entity.
*/
public final YType defType;
/**
* A yaml path that points to the part of the node where the defined entity's name can be found.
*/
public final YamlPath nameNode;
public HierarchicalDefType(YType defType, YamlPath nameNode) {
super();
this.defType = defType;
this.nameNode = nameNode;
}
@Override
public String toString() {
return "HierarchicalDefType [defType=" + defType + ", nameNode=" + nameNode + "]";
}
}
//TODO: the infos for composing this should probably be integrated somehow in the ResourceTypeRegistry so
// we only have a list of built-in resource types in a single place.
public static final YValueHint[] BUILT_IN_RESOURCE_TYPES = {
@@ -807,4 +831,10 @@ public class PipelineYmlSchema implements YamlSchema {
public List<YType> getDefinitionTypes() {
return definitionTypes;
}
public List<HierarchicalDefType> getHierarchicalDefinitionTypes() {
// TODO Auto-generated method stub
return null;
}
}

View File

@@ -3684,7 +3684,7 @@ public class ConcourseEditorTest {
"- name: group-two\n"
);
editor.assertDocumentSymbols(
editor.assertDocumentSymbols(
"some-resource-type|ResourceType",
"foo-resource|Resource",
"bar-resource|Resource",

View File

@@ -16,6 +16,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter.CompletionFilter;
import org.springframework.ide.vscode.commons.util.LogRedirect;
import org.springframework.ide.vscode.commons.util.Unicodes;
import org.springframework.ide.vscode.commons.yaml.reconcile.ASTTypeCache;
@SpringBootApplication
public class ManifestYamlLanguageServerBootApp {
@@ -44,4 +45,8 @@ public class ManifestYamlLanguageServerBootApp {
return true;
};
}
@Bean ASTTypeCache astTypeCache() {
return new ASTTypeCache();
}
}

View File

@@ -13,12 +13,12 @@ package org.springframework.ide.vscode.manifest.yaml;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.ide.vscode.commons.cloudfoundry.client.ClientTimeouts;
import org.springframework.ide.vscode.commons.cloudfoundry.client.CloudFoundryClientFactory;
import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFTargetCache;
@@ -29,7 +29,6 @@ import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.Clien
import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.NoTargetsException;
import org.springframework.ide.vscode.commons.cloudfoundry.client.v2.DefaultCloudFoundryClientFactoryV2;
import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter;
import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter.CompletionFilter;
import org.springframework.ide.vscode.commons.languageserver.hover.HoverInfoProvider;
import org.springframework.ide.vscode.commons.languageserver.hover.VscodeHoverEngineAdapter;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcileEngine;
@@ -69,7 +68,9 @@ public class ManifestYamlLanguageServerInitializer implements InitializingBean {
private CloudFoundryClientFactory cfClientFactory;
ClientParamsProvider defaultClientParamsProvider;
@Autowired private ApplicationContext appContext;
@Autowired private SimpleLanguageServer server;
@Autowired private ASTTypeCache astTypeCache;
@Override
public void afterPropertiesSet() throws Exception {
@@ -89,11 +90,9 @@ public class ManifestYamlLanguageServerInitializer implements InitializingBean {
HoverInfoProvider infoProvider = new YamlHoverInfoProvider(parser, structureProvider, contextProvider);
HoverHandler hoverEngine = new VscodeHoverEngineAdapter(server, infoProvider);
YamlQuickfixes quickfixes = new YamlQuickfixes(server.getQuickfixRegistry(), server.getTextDocumentService(), structureProvider);
YamlSchemaBasedReconcileEngine engine = new YamlSchemaBasedReconcileEngine(parser, schema, quickfixes);
YamlSchemaBasedReconcileEngine engine = new YamlSchemaBasedReconcileEngine(parser, schema, quickfixes, appContext);
ASTTypeCache astTypeCache = new ASTTypeCache();
engine.setTypeCollector(astTypeCache);
documents.onDocumentSymbol(new TypeBasedYamlSymbolHandler(documents, astTypeCache, schema.getDefinitionTypes(), server::hasHierarchicalDocumentSymbolSupport));
documents.onDocumentSymbol(new TypeBasedYamlSymbolHandler(documents, astTypeCache, schema.getDefinitionTypes()));
documents.onDidChangeContent(params -> {
validateOnDocumentChange(engine, params.getDocument());