Implement 'goto symbol' within pipeline.yml files.
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
/*******************************************************************************
|
||||
* 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.languageserver.util;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.eclipse.lsp4j.DocumentSymbolParams;
|
||||
import org.eclipse.lsp4j.SymbolInformation;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface DocumentSymbolHandler {
|
||||
|
||||
DocumentSymbolHandler NO_SYMBOLS = (params) -> CompletableFuture.completedFuture(ImmutableList.of());
|
||||
|
||||
CompletableFuture<List<? extends SymbolInformation>> handle(DocumentSymbolParams params);
|
||||
|
||||
}
|
||||
@@ -150,18 +150,23 @@ public abstract class SimpleLanguageServer implements LanguageServer, LanguageCl
|
||||
if (hasQuickFixes()) {
|
||||
c.setCodeActionProvider(true);
|
||||
}
|
||||
|
||||
if (hasDefinitionHandler()) {
|
||||
c.setDefinitionProvider(true);
|
||||
}
|
||||
|
||||
if (hasReferencesHandler()) {
|
||||
c.setReferencesProvider(true);
|
||||
}
|
||||
if (hasDocumentSymbolHandler()) {
|
||||
c.setDocumentSymbolProvider(true);
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
private boolean hasDocumentSymbolHandler() {
|
||||
return getTextDocumentService().hasDocumentSymbolHandler();
|
||||
}
|
||||
|
||||
private boolean hasReferencesHandler() {
|
||||
return getTextDocumentService().hasReferencesHandler();
|
||||
}
|
||||
|
||||
@@ -79,6 +79,8 @@ public class SimpleTextDocumentService implements TextDocumentService {
|
||||
private DefinitionHandler definitionHandler;
|
||||
private ReferencesHandler referencesHandler;
|
||||
|
||||
private DocumentSymbolHandler documentSymbolHandler;
|
||||
|
||||
public SimpleTextDocumentService(SimpleLanguageServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
@@ -88,6 +90,11 @@ public class SimpleTextDocumentService implements TextDocumentService {
|
||||
this.hoverHandler = h;
|
||||
}
|
||||
|
||||
public synchronized void onDocumentSymbol(DocumentSymbolHandler h) {
|
||||
Assert.isNull("A DocumentSymbolHandler is already set, multiple handlers not supported yet", documentSymbolHandler);
|
||||
this.documentSymbolHandler = h;
|
||||
}
|
||||
|
||||
public synchronized void onCompletion(CompletionHandler h) {
|
||||
Assert.isNull("A completion handler is already set, multiple handlers not supported yet", completionHandler);
|
||||
this.completionHandler = h;
|
||||
@@ -273,6 +280,9 @@ public class SimpleTextDocumentService implements TextDocumentService {
|
||||
|
||||
@Override
|
||||
public CompletableFuture<List<? extends SymbolInformation>> documentSymbol(DocumentSymbolParams params) {
|
||||
if (documentSymbolHandler!=null) {
|
||||
return documentSymbolHandler.handle(params);
|
||||
}
|
||||
return CompletableFuture.completedFuture(Collections.emptyList());
|
||||
}
|
||||
|
||||
@@ -360,4 +370,8 @@ public class SimpleTextDocumentService implements TextDocumentService {
|
||||
return this.referencesHandler!=null;
|
||||
}
|
||||
|
||||
public boolean hasDocumentSymbolHandler() {
|
||||
return this.documentSymbolHandler!=null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public class ASTTypeCache implements ITypeCollector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endCollecting(YamlFileAST ast) {
|
||||
public synchronized void endCollecting(YamlFileAST ast) {
|
||||
Assert.isLegal(currentAst==ast);
|
||||
String uri = ast.getDocument().getUri();
|
||||
typeIndex.put(uri, currentTypes.build());
|
||||
@@ -68,7 +68,7 @@ public class ASTTypeCache implements ITypeCollector {
|
||||
}
|
||||
}
|
||||
|
||||
public YType getType(YamlFileAST ast, Node node) {
|
||||
public synchronized YType getType(YamlFileAST ast, Node node) {
|
||||
ImmutableMap<Node, YType> types = typeIndex.get(ast.getDocument().getUri());
|
||||
if (types!=null) {
|
||||
return types.get(node);
|
||||
@@ -84,5 +84,9 @@ public class ASTTypeCache implements ITypeCollector {
|
||||
this.interestingTypes.add(type);
|
||||
}
|
||||
|
||||
public synchronized ImmutableMap<Node, YType> getNodes(String uri) {
|
||||
return typeIndex.get(uri);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/*******************************************************************************
|
||||
* 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.concourse;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.eclipse.lsp4j.DocumentSymbolParams;
|
||||
import org.eclipse.lsp4j.Location;
|
||||
import org.eclipse.lsp4j.SymbolInformation;
|
||||
import org.eclipse.lsp4j.SymbolKind;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.DocumentRegion;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.DocumentSymbolHandler;
|
||||
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.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.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableList.Builder;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
* Finds symbols in a concourse document. This relies on type information cached
|
||||
* during reconcile and stored in the {@link ConcourseModel}. Therefore,
|
||||
* this handler only works if invoked after a reconcile.
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class ConcourseDocumentSymbolHandler implements DocumentSymbolHandler {
|
||||
|
||||
private ASTTypeCache astTypeCache;
|
||||
private Set<YType> definitionTypes;
|
||||
private SimpleTextDocumentService documents;
|
||||
|
||||
public ConcourseDocumentSymbolHandler(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);
|
||||
for (YType yType : definitionTypes) {
|
||||
astTypeCache.addInterestingType(yType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<List<? extends SymbolInformation>> handle(DocumentSymbolParams params) {
|
||||
Builder<SymbolInformation> builder = ImmutableList.builder();
|
||||
TextDocument doc = documents.getDocument(params.getTextDocument().getUri());
|
||||
for (Entry<Node, YType> entry : astTypeCache.getNodes(params.getTextDocument().getUri()).entrySet()) {
|
||||
if (definitionTypes.contains(entry.getValue())) {
|
||||
try {
|
||||
builder.add(createSymbol(doc, entry.getKey(), entry.getValue()));
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return CompletableFuture.completedFuture(builder.build());
|
||||
}
|
||||
|
||||
protected SymbolInformation createSymbol(TextDocument doc, Node node, YType type) throws BadLocationException {
|
||||
DocumentRegion region = NodeUtil.region(doc, node);
|
||||
Location location = new Location(doc.getUri(), doc.toRange(region.getStart(), region.getLength()));
|
||||
SymbolInformation symbol = new SymbolInformation();
|
||||
symbol.setName(region.toString());
|
||||
symbol.setKind(symbolKind(type));
|
||||
symbol.setLocation(location);
|
||||
symbol.setContainerName(containerName(type));
|
||||
return symbol;
|
||||
}
|
||||
|
||||
protected String containerName(YType type) {
|
||||
return type.toString().replaceAll("(\\s)*[Nn]ame", "");
|
||||
}
|
||||
|
||||
protected SymbolKind symbolKind(YType type) {
|
||||
return SymbolKind.String; //TODO: try to return something different for different types of symbols
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,13 +10,11 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.concourse;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.eclipse.lsp4j.CompletionList;
|
||||
import org.eclipse.lsp4j.CompletionOptions;
|
||||
import org.eclipse.lsp4j.DiagnosticSeverity;
|
||||
import org.eclipse.lsp4j.ServerCapabilities;
|
||||
import org.eclipse.lsp4j.TextDocumentSyncKind;
|
||||
import org.springframework.ide.vscode.commons.languageserver.LanguageIds;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter;
|
||||
import org.springframework.ide.vscode.commons.languageserver.hover.HoverInfoProvider;
|
||||
@@ -24,8 +22,10 @@ import org.springframework.ide.vscode.commons.languageserver.hover.VscodeHoverEn
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcileEngine;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.DocumentSymbolHandler;
|
||||
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.CollectionUtil;
|
||||
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;
|
||||
@@ -34,6 +34,7 @@ import org.springframework.ide.vscode.commons.yaml.hover.YamlHoverInfoProvider;
|
||||
import org.springframework.ide.vscode.commons.yaml.reconcile.YamlQuickfixes;
|
||||
import org.springframework.ide.vscode.commons.yaml.reconcile.YamlSchemaBasedReconcileEngine;
|
||||
import org.springframework.ide.vscode.commons.yaml.reconcile.YamlSchemaProblems;
|
||||
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.structure.YamlStructureProvider;
|
||||
|
||||
@@ -54,8 +55,9 @@ public class ConcourseLanguageServer extends SimpleLanguageServer {
|
||||
final VscodeCompletionEngineAdapter completionEngine;
|
||||
final VscodeHoverEngineAdapter hoverEngine;
|
||||
final YamlSchemaBasedReconcileEngine reconcileEngine;
|
||||
final DocumentSymbolHandler symbolHandler;
|
||||
|
||||
SchemaSpecificPieces(YamlSchema schema) {
|
||||
SchemaSpecificPieces(YamlSchema schema, List<YType> definitionTypes) {
|
||||
SchemaBasedYamlAssistContextProvider contextProvider = new SchemaBasedYamlAssistContextProvider(schema);
|
||||
YamlCompletionEngine yamlCompletionEngine = new YamlCompletionEngine(structureProvider, contextProvider);
|
||||
this.completionEngine = new VscodeCompletionEngineAdapter(ConcourseLanguageServer.this, yamlCompletionEngine);
|
||||
@@ -65,6 +67,10 @@ public class ConcourseLanguageServer extends SimpleLanguageServer {
|
||||
|
||||
this.reconcileEngine = new YamlSchemaBasedReconcileEngine(currentAsts, schema, yamlQuickfixes);
|
||||
reconcileEngine.setTypeCollector(models.getAstTypeCache());
|
||||
|
||||
this.symbolHandler = CollectionUtil.hasElements(definitionTypes)
|
||||
? new ConcourseDocumentSymbolHandler(documents, models.getAstTypeCache(), definitionTypes)
|
||||
: DocumentSymbolHandler.NO_SYMBOLS;
|
||||
}
|
||||
|
||||
public void setMaxCompletions(int max) {
|
||||
@@ -77,8 +83,8 @@ public class ConcourseLanguageServer extends SimpleLanguageServer {
|
||||
PipelineYmlSchema pipelineSchema = new PipelineYmlSchema(models);
|
||||
this.yamlQuickfixes = new YamlQuickfixes(getQuickfixRegistry(), documents, structureProvider);
|
||||
|
||||
this.forPipelines = new SchemaSpecificPieces(pipelineSchema);
|
||||
this.forTasks = new SchemaSpecificPieces(pipelineSchema.getTaskSchema());
|
||||
this.forPipelines = new SchemaSpecificPieces(pipelineSchema, pipelineSchema.getDefinitionTypes());
|
||||
this.forTasks = new SchemaSpecificPieces(pipelineSchema.getTaskSchema(), null);
|
||||
ConcourseDefinitionFinder definitionFinder = new ConcourseDefinitionFinder(this, models, pipelineSchema);
|
||||
|
||||
// SimpleWorkspaceService workspace = getWorkspaceService();
|
||||
@@ -132,6 +138,18 @@ public class ConcourseLanguageServer extends SimpleLanguageServer {
|
||||
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 (LanguageIds.CONCOURSE_PIPELINE.equals(doc.getLanguageId())) {
|
||||
handler = forPipelines.symbolHandler;
|
||||
} else if (LanguageIds.CONCOURSE_TASK.equals(doc.getLanguageId())) {
|
||||
handler = forTasks.symbolHandler;
|
||||
}
|
||||
}
|
||||
return handler.handle(params);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
package org.springframework.ide.vscode.concourse;
|
||||
|
||||
import java.time.ZoneId;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -47,6 +49,8 @@ import org.springframework.ide.vscode.concourse.ConcourseModel.StepModel;
|
||||
import org.yaml.snakeyaml.nodes.MappingNode;
|
||||
import org.yaml.snakeyaml.nodes.Node;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
/**
|
||||
@@ -155,6 +159,8 @@ public class PipelineYmlSchema implements YamlSchema {
|
||||
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
|
||||
);
|
||||
|
||||
private List<YType> definitionTypes = new ArrayList<>();
|
||||
|
||||
public PipelineYmlSchema(ConcourseModel models) {
|
||||
this.models = models;
|
||||
TYPE_UTIL = f.TYPE_UTIL;
|
||||
@@ -366,6 +372,12 @@ public class PipelineYmlSchema implements YamlSchema {
|
||||
addProp(TOPLEVEL_TYPE, "resource_types", f.yseq(resourceType));
|
||||
addProp(TOPLEVEL_TYPE, "groups", f.yseq(group));
|
||||
|
||||
definitionTypes = ImmutableList.of(
|
||||
jobNameDef,
|
||||
resourceTypeNameDef,
|
||||
resourceNameDef
|
||||
);
|
||||
|
||||
initializeDefaultResourceTypes();
|
||||
}
|
||||
|
||||
@@ -700,4 +712,8 @@ public class PipelineYmlSchema implements YamlSchema {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public List<YType> getDefinitionTypes() {
|
||||
return definitionTypes;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user