Groundwork for HierarchicalDocumentSymbolHandler
This commit is contained in:
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user