diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServer.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServer.java index 9cbeb5063..acb06e000 100644 --- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServer.java +++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServer.java @@ -14,6 +14,7 @@ import org.springframework.ide.vscode.boot.java.completions.BootJavaCompletionEn import org.springframework.ide.vscode.boot.java.completions.BootJavaReconcileEngine; import org.springframework.ide.vscode.boot.java.hover.BootJavaHoverProvider; import org.springframework.ide.vscode.boot.java.references.BootJavaReferencesHandler; +import org.springframework.ide.vscode.boot.java.symbols.BootJavaDocumentSymbolHandler; import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider; import org.springframework.ide.vscode.commons.gradle.GradleCore; import org.springframework.ide.vscode.commons.gradle.GradleProjectFinderStrategy; @@ -68,6 +69,7 @@ public class BootJavaLanguageServer extends SimpleLanguageServer { ReferencesHandler referencesHandler = new BootJavaReferencesHandler(this, javaProjectFinder); documents.onReferences(referencesHandler); + documents.onDocumentSymbol(new BootJavaDocumentSymbolHandler(this, javaProjectFinder)); } public void setMaxCompletionsNumber(int number) { diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/symbols/BootJavaDocumentSymbolHandler.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/symbols/BootJavaDocumentSymbolHandler.java new file mode 100644 index 000000000..553d26e32 --- /dev/null +++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/symbols/BootJavaDocumentSymbolHandler.java @@ -0,0 +1,184 @@ +/******************************************************************************* + * 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.boot.java.symbols; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.ASTParser; +import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.Annotation; +import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration; +import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.ITypeBinding; +import org.eclipse.jdt.core.dom.MarkerAnnotation; +import org.eclipse.jdt.core.dom.MemberValuePair; +import org.eclipse.jdt.core.dom.NormalAnnotation; +import org.eclipse.jdt.core.dom.SingleMemberAnnotation; +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.java.IClasspath; +import org.springframework.ide.vscode.commons.java.IJavaProject; +import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; +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.text.IDocument; +import org.springframework.ide.vscode.commons.util.text.TextDocument; + +/** + * @author Martin Lippert + */ +public class BootJavaDocumentSymbolHandler implements DocumentSymbolHandler { + + private SimpleLanguageServer server; + private JavaProjectFinder projectFinder; + + public BootJavaDocumentSymbolHandler(SimpleLanguageServer server, JavaProjectFinder projectFinder) { + this.server = server; + this.projectFinder = projectFinder; + } + + @Override + public List handle(DocumentSymbolParams params) { + SimpleTextDocumentService documents = server.getTextDocumentService(); + TextDocument doc = documents.get(params.getTextDocument().getUri()).copy(); + if (doc != null) { + try { + return provideDocumentSymbols(doc); + } catch (Exception e) { + e.printStackTrace(); + } + } + + return SimpleTextDocumentService.NO_SYMBOLS; + } + + private List provideDocumentSymbols(TextDocument document) throws Exception { + ASTParser parser = ASTParser.newParser(AST.JLS8); + Map options = JavaCore.getOptions(); + JavaCore.setComplianceOptions(JavaCore.VERSION_1_8, options); + parser.setCompilerOptions(options); + parser.setKind(ASTParser.K_COMPILATION_UNIT); + parser.setStatementsRecovery(true); + parser.setBindingsRecovery(true); + parser.setResolveBindings(true); + + String[] classpathEntries = getClasspathEntries(document); + String[] sourceEntries = new String[] {}; + parser.setEnvironment(classpathEntries, sourceEntries, null, true); + + String docURI = document.getUri(); + String unitName = docURI.substring(docURI.lastIndexOf("/")); + parser.setUnitName(unitName); + parser.setSource(document.get(0, document.getLength()).toCharArray()); + + CompilationUnit cu = (CompilationUnit) parser.createAST(null); + if (cu != null) { + System.out.println("AST node found: " + cu.getClass().getName()); + return provideDocumentSymbolsForAnnotations(cu, document); + } + + return null; + } + + private List provideDocumentSymbolsForAnnotations(ASTNode node, TextDocument doc) { + List result = new ArrayList<>(); + ASTVisitor visitor = new ASTVisitor() { + @Override + public boolean visit(AnnotationTypeDeclaration node) { + // TODO Auto-generated method stub + return super.visit(node); + } + + @Override + public boolean visit(SingleMemberAnnotation node) { + ITypeBinding type = node.resolveTypeBinding(); + if (type != null) { + String qualifiedName = type.getQualifiedName(); + if (qualifiedName != null && qualifiedName.startsWith("org.springframework")) { + provideDocumentSymbolsForSpringAnnotations(node, type, doc, result); + } + } + return super.visit(node); + } + + @Override + public boolean visit(AnnotationTypeMemberDeclaration node) { + // TODO Auto-generated method stub + return super.visit(node); + } + + @Override + public boolean visit(MemberValuePair node) { + // TODO Auto-generated method stub + return super.visit(node); + } + + @Override + public boolean visit(NormalAnnotation node) { + ITypeBinding type = node.resolveTypeBinding(); + if (type != null) { + String qualifiedName = type.getQualifiedName(); + if (qualifiedName != null && qualifiedName.startsWith("org.springframework")) { + provideDocumentSymbolsForSpringAnnotations(node, type, doc, result); + } + } + return super.visit(node); + } + + @Override + public boolean visit(MarkerAnnotation node) { + ITypeBinding type = node.resolveTypeBinding(); + if (type != null) { + String qualifiedName = type.getQualifiedName(); + if (qualifiedName != null && qualifiedName.startsWith("org.springframework")) { + provideDocumentSymbolsForSpringAnnotations(node, type, doc, result); + } + } + return super.visit(node); + } + }; + node.accept(visitor); + + return result; + } + + private void provideDocumentSymbolsForSpringAnnotations(Annotation node, ITypeBinding type, + TextDocument doc, List resultAccumulator) { + try { + resultAccumulator.add(new SymbolInformation(node.toString(), SymbolKind.Interface, new Location(doc.getUri(), + doc.toRange(node.getStartPosition(), node.getLength())))); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + private String[] getClasspathEntries(IDocument doc) throws Exception { + IJavaProject project = this.projectFinder.find(doc); + IClasspath classpath = project.getClasspath(); + Stream classpathEntries = classpath.getClasspathEntries(); + return classpathEntries + .filter(path -> path.toFile().exists()) + .map(path -> path.toAbsolutePath().toString()).toArray(String[]::new); + } + +} diff --git a/headless-services/bosh-language-server/src/main/resources/desc/Stemcell/alias.md b/headless-services/bosh-language-server/src/main/resources/desc/Stemcell/alias.md new file mode 100644 index 000000000..e8f170fab --- /dev/null +++ b/headless-services/bosh-language-server/src/main/resources/desc/Stemcell/alias.md @@ -0,0 +1 @@ +*Required*. Name of a stemcell used in the deployment. \ No newline at end of file diff --git a/headless-services/bosh-language-server/src/main/resources/desc/Stemcell/name.md b/headless-services/bosh-language-server/src/main/resources/desc/Stemcell/name.md new file mode 100644 index 000000000..710f2ac3d --- /dev/null +++ b/headless-services/bosh-language-server/src/main/resources/desc/Stemcell/name.md @@ -0,0 +1 @@ +Full name of a matching stemcell. Either `name` or `os` keys can be specified. \ No newline at end of file diff --git a/headless-services/bosh-language-server/src/main/resources/desc/Stemcell/os.md b/headless-services/bosh-language-server/src/main/resources/desc/Stemcell/os.md new file mode 100644 index 000000000..6e3ae6d80 --- /dev/null +++ b/headless-services/bosh-language-server/src/main/resources/desc/Stemcell/os.md @@ -0,0 +1 @@ +Operating system of a matching stemcell. Example: `ubuntu-trusty`. Either `name` or `os` keys can be specified. \ No newline at end of file diff --git a/headless-services/bosh-language-server/src/main/resources/desc/Stemcell/version.md b/headless-services/bosh-language-server/src/main/resources/desc/Stemcell/version.md new file mode 100644 index 000000000..5d67c6c21 --- /dev/null +++ b/headless-services/bosh-language-server/src/main/resources/desc/Stemcell/version.md @@ -0,0 +1 @@ +*Required*. The version of a matching stemcell. Version can be `latest`. \ No newline at end of file diff --git a/headless-services/bosh-language-server/src/test/java/org/springframework/ide/vscode/bosh/BoshEditorTest.java b/headless-services/bosh-language-server/src/test/java/org/springframework/ide/vscode/bosh/BoshEditorTest.java index 071b916d4..3acb9bba7 100644 --- a/headless-services/bosh-language-server/src/test/java/org/springframework/ide/vscode/bosh/BoshEditorTest.java +++ b/headless-services/bosh-language-server/src/test/java/org/springframework/ide/vscode/bosh/BoshEditorTest.java @@ -213,6 +213,22 @@ public class BoshEditorTest { ); } + @Test public void stemcellHovers() throws Exception { + Editor editor = harness.newEditor( + "stemcells:\n" + + "- alias: default\n" + + " os: ubuntu-trusty\n" + + " version: 3147\n" + + " name: bosh-aws-xen-hvm-ubuntu-trusty-go_agent" + ); + editor.assertHoverContains("alias", "Name of a stemcell used in the deployment"); + editor.assertHoverContains("os", "Operating system of a matching stemcell"); + editor.assertHoverContains("version", "The version of a matching stemcell"); + editor.assertHoverContains("name", "Full name of a matching stemcell. Either `name` or `os` keys can be specified."); + } + + + @Test public void releasesBlockCompletions() throws Exception { Editor editor = harness.newEditor( "releases:\n" + diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/VscodeCompletionEngineAdapter.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/VscodeCompletionEngineAdapter.java index bc1881baa..ee377f932 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/VscodeCompletionEngineAdapter.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/VscodeCompletionEngineAdapter.java @@ -72,7 +72,6 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine { if (id!=null) { Consumer resolver = resolvers.get(id); if (resolver!=null) { - Log.info("Resolving lazy completion item: "+unresolved.getLabel()); resolver.accept(unresolved); unresolved.setData(null); //No longer needed after item is resolved. } else { diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java index b3a31ae63..b01e39089 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java @@ -219,6 +219,7 @@ public class SimpleTextDocumentService implements TextDocumentService { public final static CompletionList NO_COMPLETIONS = new CompletionList(false, Collections.emptyList()); public final static CompletableFuture NO_HOVER = CompletableFuture.completedFuture(new Hover(ImmutableList.of(), null)); public final static CompletableFuture> NO_REFERENCES = CompletableFuture.completedFuture(ImmutableList.of()); + public final static List NO_SYMBOLS = ImmutableList.of(); @Override public CompletableFuture, CompletionList>> completion(TextDocumentPositionParams position) { @@ -369,7 +370,11 @@ public class SimpleTextDocumentService implements TextDocumentService { } public synchronized TextDocument get(TextDocumentPositionParams params) { - TrackedDocument td = documents.get(params.getTextDocument().getUri()); + return get(params.getTextDocument().getUri()); + } + + public synchronized TextDocument get(String uri) { + TrackedDocument td = documents.get(uri); return td == null ? null : td.getDocument(); } diff --git a/vscode-extensions/vscode-boot-java/.vscode/launch.json b/vscode-extensions/vscode-boot-java/.vscode/launch.json index 9d73948ec..1c135881c 100644 --- a/vscode-extensions/vscode-boot-java/.vscode/launch.json +++ b/vscode-extensions/vscode-boot-java/.vscode/launch.json @@ -3,14 +3,17 @@ "version": "0.1.0", "configurations": [ { - "name": "Launch Extension", "type": "extensionHost", "request": "launch", + "name": "Launch Extension", "runtimeExecutable": "${execPath}", - "args": ["--extensionDevelopmentPath=${workspaceRoot}" ], - "stopOnEntry": false, + "args": [ + "--extensionDevelopmentPath=${workspaceRoot}" + ], "sourceMaps": true, - "outFiles": ["${workspaceRoot}/out/lib"], + "outFiles": [ + "${workspaceRoot}/out/**/*.js" + ], "preLaunchTask": "npm" }, { diff --git a/vscode-extensions/vscode-boot-java/.vscode/settings.json b/vscode-extensions/vscode-boot-java/.vscode/settings.json index c5592bee9..6ec5515d8 100644 --- a/vscode-extensions/vscode-boot-java/.vscode/settings.json +++ b/vscode-extensions/vscode-boot-java/.vscode/settings.json @@ -1,7 +1,7 @@ // Place your settings in this file to overwrite default and user settings. { "files.exclude": { - "out": true, // set this to true to hide the "out" folder with the compiled JS files + "out": false, // set this to true to hide the "out" folder with the compiled JS files "node_modules": false, "target": true }, diff --git a/vscode-extensions/vscode-boot-java/package.json b/vscode-extensions/vscode-boot-java/package.json index fb9236398..93ce6e1ea 100644 --- a/vscode-extensions/vscode-boot-java/package.json +++ b/vscode-extensions/vscode-boot-java/package.json @@ -22,7 +22,6 @@ "java", "spring-boot" ], "activationEvents": [ - "onLanguage:ini", "onLanguage:java" ], "main": "./out/lib/Main", diff --git a/vscode-extensions/vscode-bosh/README.md b/vscode-extensions/vscode-bosh/README.md index c3fbd6e47..7cc1d4061 100644 --- a/vscode-extensions/vscode-bosh/README.md +++ b/vscode-extensions/vscode-bosh/README.md @@ -1,20 +1,37 @@ -# Concourse Pipeline and Task Editor for Visual Studio Code +# Bosh Deployment Manifest Editor for Visual Studio Code This extension provides validation, content assist and documentation hovers -for editing [Concourse](https://concourse.ci/) Pipeline and Task configuration files. +for editing [Bosh](https://bosh.io/) Deployment Manifest files. ## Usage -The Concourse editor automatically activates when the name of the `.yml` file you are editing +### Activating the Editor + +The Bosh editor automatically activates when the name of the `.yml` file you are editing follows a certain pattern: - - `**/*pipeline*.yml` : activates support for editing pipelines - - `**/tasks/*.yml` : activates support for editing tasks. + - `**/*deployment*.yml` : activates support for bosh manifest file. -You can also define your own patterns and map them to the language-ids `concourse-pipeline-yaml` -or `concourse-task-yaml` by defining `files.associations` in workspace settings. +You can also define your own patterns and map them to the language-id `bosh-deployment-manifest` +by defining `files.associations` in workspace settings. See [vscode documentation](https://code.visualstudio.com/Docs/languages/overview#_adding-a-file-extension-to-a-language) for details. +### Targetting a specific Director + +Some Validation and Content Assist use information dymanically retrieved from an active Bosh director. +For these feature to work it is required that you + +- have the bosh cli V2 installed (information is obtained by executing commands using the V2 cli) +- target a director by setting the `BOSH_ENVIROMENT` variable. + +You can verify that you have set things up right by executing command: + +``` +bosh cloud-config --json +``` + +If setup correctly, it should return information about the cloud-config on your intended bosh director/environment. + ## Functionality ### Validation @@ -27,8 +44,7 @@ an error marker to see an explanation: ### Content assist Having trouble remembering all the names of the attributes, and their spelling? Or can't remember -which resource properties to set in the `get` task params versus its `source` attributes? Or -don't remember what 'special' values are acceptable for a certain property? Content assist +the exact name/version of the stemcell you just uploaded to your bosh environment? Content assist to the rescue: ![Content Assist Screenshot][ca1] @@ -44,11 +60,11 @@ read its detailed documentation: ### Goto Symbol in File -Is your Pipeline yaml file getting larger and is it becoming harder to find a particular Job, Resource or -Resource Type declaration? The "Goto Symbol in File" command helps you quickly jump to a specific +Is your Deployment Manifest getting larger and is it becoming harder to find a particular Instance Group, +Release, or Stemcell definition? The "Goto Symbol in File" command helps you quickly jump to a specific definition. -Type `CTRL-SHIFT-O` to popup a list of all symbols in your current Pipeline file. Start typing a name +Type `CTRL-SHIFT-O` to popup a list of all symbols in your current file. Start typing a name (or portion thereof) to narrow down the list. Select a symbol to jump directly to its location in the file. @@ -56,36 +72,26 @@ file. ### Goto/Peek Definition -Use "Goto Defition" or "Peek Definition" to quickly go (or peek) from a a Job- or Resource name +Use "Goto Defition" or "Peek Definition" to quickly go (or peek) from a Release or Stemcell name to its corresponding definition. ![Peek Definition Screenshot][peek] -## Limitations +### V2 versus V1 Schena -This Vscode Extension is still a work in progress. At the moment only a select few of the [built-in resource-types](https://concourse.ci/resource-types.html) -have been fully defined in the Editor's Schema. +The editor is intended primarily to support editing manifests in the [V2 schema](https://bosh.io/docs/manifest-v2.html). +When you use attributes from the V1 schema the editor will detect this however and switch to 'V1 tolerance' mode. -The resource-types that are already defined in the schema are: - - - git - - docker-image - - s3 - - pool - - semver - - time - -For other resource-types content assist and checking is still very limited. We intend -to grow this list and provide a similar level of support for all of the built-in resource types in -the near future. +In this mode, V1 properties are accepted but marked with deprecation warnings and V2 properties are marked as (unknown property) +errors. ## Issues and Feature Requests Please report bugs, issues and feature requests on the [Github STS4 issue tracker](https://github.com/spring-projects/sts4/issues). -[linting]: https://raw.githubusercontent.com/spring-projects/sts4/98148c08b608ff365fb87b2de955d6833f7ee082/vscode-extensions/vscode-concourse/readme-imgs/linting.png -[ca1]: https://raw.githubusercontent.com/spring-projects/sts4/98148c08b608ff365fb87b2de955d6833f7ee082/vscode-extensions/vscode-concourse/readme-imgs/content-assist-1.png -[ca2]: https://raw.githubusercontent.com/spring-projects/sts4/98148c08b608ff365fb87b2de955d6833f7ee082/vscode-extensions/vscode-concourse/readme-imgs/content-assist-2.png -[hovers]: https://raw.githubusercontent.com/spring-projects/sts4/98148c08b608ff365fb87b2de955d6833f7ee082/vscode-extensions/vscode-concourse/readme-imgs/hover.png -[peek]: https://raw.githubusercontent.com/spring-projects/sts4/98148c08b608ff365fb87b2de955d6833f7ee082/vscode-extensions/vscode-concourse/readme-imgs/peek.png -[goto_symbol]: https://raw.githubusercontent.com/spring-projects/sts4/d095208cfb34b0f129e6b66d41d099955a712f81/vscode-extensions/vscode-concourse/readme-imgs/goto-symbol.png +[linting]: https://raw.githubusercontent.com/spring-projects/sts4/master/vscode-extensions/vscode-bosh/readme-imgs/linting.png +[ca1]: https://raw.githubusercontent.com/spring-projects/sts4/master/vscode-extensions/vscode-bosh/readme-imgs/content-assist-1.png +[ca2]: https://raw.githubusercontent.com/spring-projects/sts4/master/vscode-extensions/vscode-bosh/readme-imgs/content-assist-2.png +[hovers]: https://raw.githubusercontent.com/spring-projects/sts4/master/vscode-extensions/vscode-bosh/readme-imgs/hover.png +[peek]: https://raw.githubusercontent.com/spring-projects/sts4/master/vscode-extensions/vscode-bosh/readme-imgs/peek.png +[goto_symbol]: https://raw.githubusercontent.com/spring-projects/sts4/master/vscode-extensions/vscode-bosh/readme-imgs/goto-symbol.png diff --git a/vscode-extensions/vscode-concourse/readme-imgs/linting.png b/vscode-extensions/vscode-concourse/readme-imgs/linting.png index 93860ed82..8c36b575d 100644 Binary files a/vscode-extensions/vscode-concourse/readme-imgs/linting.png and b/vscode-extensions/vscode-concourse/readme-imgs/linting.png differ