diff --git a/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/application/properties/metadata/completions/PropertyCompletionFactory.java b/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/application/properties/metadata/completions/PropertyCompletionFactory.java index 87c75fde5..f585e2b2e 100644 --- a/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/application/properties/metadata/completions/PropertyCompletionFactory.java +++ b/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/application/properties/metadata/completions/PropertyCompletionFactory.java @@ -26,7 +26,6 @@ import org.springframework.ide.vscode.commons.languageserver.util.IDocument; import org.springframework.ide.vscode.commons.yaml.schema.YType; public class PropertyCompletionFactory { - public ICompletionProposal valueProposal(String value, String query, Type type, double score, DocumentEdits edits, ValueHintHoverInfo info) { return new ScoreableProposal() { diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/VscodeCompletionEngineAdapter.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/VscodeCompletionEngineAdapter.java index a2f6ffc36..7724c062f 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/VscodeCompletionEngineAdapter.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/VscodeCompletionEngineAdapter.java @@ -51,8 +51,6 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine { return getCompletionsMono(params).toFuture(); } - - private Mono getCompletionsMono(TextDocumentPositionParams params) { SimpleTextDocumentService documents = server.getTextDocumentService(); TextDocument doc = documents.get(params); diff --git a/vscode-extensions/pom.xml b/vscode-extensions/pom.xml index c71425479..842ae7e1c 100644 --- a/vscode-extensions/pom.xml +++ b/vscode-extensions/pom.xml @@ -11,6 +11,7 @@ commons + vscode-boot-properties vscode-application-properties vscode-application-yaml vscode-manifest-yaml diff --git a/vscode-extensions/vscode-application-properties/pom.xml b/vscode-extensions/vscode-application-properties/pom.xml index 9d5490db2..384d98dd9 100644 --- a/vscode-extensions/vscode-application-properties/pom.xml +++ b/vscode-extensions/vscode-application-properties/pom.xml @@ -89,7 +89,7 @@ 1.8 - + diff --git a/vscode-extensions/vscode-application-properties/src/main/java/org/springframework/ide/vscode/application/properties/ApplicationPropertiesLanguageServer.java b/vscode-extensions/vscode-application-properties/src/main/java/org/springframework/ide/vscode/application/properties/ApplicationPropertiesLanguageServer.java index 1c4b66ab2..e0e075f3b 100644 --- a/vscode-extensions/vscode-application-properties/src/main/java/org/springframework/ide/vscode/application/properties/ApplicationPropertiesLanguageServer.java +++ b/vscode-extensions/vscode-application-properties/src/main/java/org/springframework/ide/vscode/application/properties/ApplicationPropertiesLanguageServer.java @@ -70,10 +70,6 @@ public class ApplicationPropertiesLanguageServer extends SimpleLanguageServer { completionEngine.setMaxCompletionsNumber(number); } - public void setRecordSyntaxErrors(boolean record) { - reconcileEngine.setRecordSyntaxErrors(record); - } - public void setHoverType(HoverType type) { hoverEngine.setHoverType(type); } diff --git a/vscode-extensions/vscode-application-properties/src/main/java/org/springframework/ide/vscode/application/properties/reconcile/SpringPropertiesReconcileEngine.java b/vscode-extensions/vscode-application-properties/src/main/java/org/springframework/ide/vscode/application/properties/reconcile/SpringPropertiesReconcileEngine.java index bd76e8b84..26acc6de9 100644 --- a/vscode-extensions/vscode-application-properties/src/main/java/org/springframework/ide/vscode/application/properties/reconcile/SpringPropertiesReconcileEngine.java +++ b/vscode-extensions/vscode-application-properties/src/main/java/org/springframework/ide/vscode/application/properties/reconcile/SpringPropertiesReconcileEngine.java @@ -69,16 +69,9 @@ public class SpringPropertiesReconcileEngine implements IReconcileEngine { private final DelimitedListReconciler commaListReconciler = new DelimitedListReconciler(COMMA, this::reconcileType); private Parser parser = new AntlrParser(); - private boolean recordSyntaxErrors; - public SpringPropertiesReconcileEngine(SpringPropertyIndexProvider provider, TypeUtilProvider typeUtilProvider) { - this(provider, typeUtilProvider, true); - } - - public SpringPropertiesReconcileEngine(SpringPropertyIndexProvider provider, TypeUtilProvider typeUtilProvider, boolean recordSyntaxErrors) { this.fIndexProvider = provider; this.typeUtilProvider = typeUtilProvider; - this.recordSyntaxErrors = recordSyntaxErrors; } public void reconcile(IDocument doc, IProblemCollector problemCollector) { @@ -88,12 +81,10 @@ public class SpringPropertiesReconcileEngine implements IReconcileEngine { ParseResults results = parser.parse(doc.get()); DuplicateNameChecker duplicateNameChecker = new DuplicateNameChecker(problemCollector); - if (recordSyntaxErrors) { - results.syntaxErrors.forEach(syntaxError -> { - problemCollector.accept(problem(PROP_SYNTAX_ERROR, syntaxError.getMessage(), syntaxError.getOffset(), - syntaxError.getLength())); - }); - } + results.syntaxErrors.forEach(syntaxError -> { + problemCollector.accept(problem(PROP_SYNTAX_ERROR, syntaxError.getMessage(), syntaxError.getOffset(), + syntaxError.getLength())); + }); if (index==null || index.isEmpty()) { //don't report errors when index is empty, simply don't check (otherwise we will just reprot @@ -138,14 +129,6 @@ public class SpringPropertiesReconcileEngine implements IReconcileEngine { } } - public void setRecordSyntaxErrors(boolean recordSyntaxErrors) { - this.recordSyntaxErrors = recordSyntaxErrors; - } - - public boolean isRecordSyntaxErrors() { - return recordSyntaxErrors ; - } - protected SpringPropertyProblem problemDeprecated(DocumentRegion region, PropertyInfo property) { SpringPropertyProblem p = problem(PROP_DEPRECATED, TypeUtil.deprecatedPropertyMessage( diff --git a/vscode-extensions/vscode-application-yaml/pom.xml b/vscode-extensions/vscode-application-yaml/pom.xml index 381a717c1..1581b2ffc 100644 --- a/vscode-extensions/vscode-application-yaml/pom.xml +++ b/vscode-extensions/vscode-application-yaml/pom.xml @@ -101,7 +101,7 @@ 1.8 - + diff --git a/vscode-extensions/vscode-boot-properties/.classpath b/vscode-extensions/vscode-boot-properties/.classpath new file mode 100644 index 000000000..d46faf10e --- /dev/null +++ b/vscode-extensions/vscode-boot-properties/.classpath @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vscode-extensions/vscode-boot-properties/.gitignore b/vscode-extensions/vscode-boot-properties/.gitignore new file mode 100644 index 000000000..8c44546ea --- /dev/null +++ b/vscode-extensions/vscode-boot-properties/.gitignore @@ -0,0 +1,12 @@ +out +node_modules +target +*.log +*.log.* +classpath.txt +*.vsix +repo +.idea +*.iml +.DS_Store +**/.DS_Store \ No newline at end of file diff --git a/vscode-extensions/vscode-boot-properties/.project b/vscode-extensions/vscode-boot-properties/.project new file mode 100644 index 000000000..2a069378f --- /dev/null +++ b/vscode-extensions/vscode-boot-properties/.project @@ -0,0 +1,23 @@ + + + vscode-application-properties + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/vscode-extensions/vscode-boot-properties/.settings/org.eclipse.jdt.core.prefs b/vscode-extensions/vscode-boot-properties/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..714351aec --- /dev/null +++ b/vscode-extensions/vscode-boot-properties/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/vscode-extensions/vscode-boot-properties/.settings/org.eclipse.m2e.core.prefs b/vscode-extensions/vscode-boot-properties/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 000000000..f897a7f1c --- /dev/null +++ b/vscode-extensions/vscode-boot-properties/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/vscode-extensions/vscode-boot-properties/.vscode/launch.json b/vscode-extensions/vscode-boot-properties/.vscode/launch.json new file mode 100644 index 000000000..52ebf9f9e --- /dev/null +++ b/vscode-extensions/vscode-boot-properties/.vscode/launch.json @@ -0,0 +1,28 @@ +// A launch configuration that compiles the extension and then opens it inside a new window +{ + "version": "0.1.0", + "configurations": [ + { + "name": "Launch Extension", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": ["--extensionDevelopmentPath=${workspaceRoot}" ], + "stopOnEntry": false, + "sourceMaps": true, + "outDir": "${workspaceRoot}/out/lib", + "preLaunchTask": "npm" + }, + { + "name": "Launch Tests", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test" ], + "stopOnEntry": false, + "sourceMaps": true, + "outDir": "${workspaceRoot}/out/test", + "preLaunchTask": "npm" + } + ] +} diff --git a/vscode-extensions/vscode-boot-properties/.vscode/settings.json b/vscode-extensions/vscode-boot-properties/.vscode/settings.json new file mode 100644 index 000000000..c5592bee9 --- /dev/null +++ b/vscode-extensions/vscode-boot-properties/.vscode/settings.json @@ -0,0 +1,12 @@ +// 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 + "node_modules": false, + "target": true + }, + "search.exclude": { + "out": true // set this to false to include "out" folder in search results + }, + "typescript.tsdk": "./node_modules/typescript/lib" // we want to use the TS server from our node_modules folder to control its version +} \ No newline at end of file diff --git a/vscode-extensions/vscode-boot-properties/.vscode/tasks.json b/vscode-extensions/vscode-boot-properties/.vscode/tasks.json new file mode 100644 index 000000000..1cbb9fd45 --- /dev/null +++ b/vscode-extensions/vscode-boot-properties/.vscode/tasks.json @@ -0,0 +1,30 @@ +// Available variables which can be used inside of strings. +// ${workspaceRoot}: the root folder of the team +// ${file}: the current opened file +// ${fileBasename}: the current opened file's basename +// ${fileDirname}: the current opened file's dirname +// ${fileExtname}: the current opened file's extension +// ${cwd}: the current working directory of the spawned process + +// A task runner that calls a custom npm script that compiles the extension. +{ + "version": "0.1.0", + + // we want to run npm + "command": "npm", + + // the command is a shell script + "isShellCommand": true, + + // show the output window only if unrecognized errors occur. + "showOutput": "silent", + + // we run the custom script "compile" as defined in package.json + "args": ["run", "compile"], //, "--loglevel", "silent"], + + // The tsc compiler is started in watching mode + "isWatching": true, + + // use the standard tsc in watch mode problem matcher to find compile problems in the output. + "problemMatcher": "$tsc-watch" +} \ No newline at end of file diff --git a/vscode-extensions/vscode-boot-properties/.vscodeignore b/vscode-extensions/vscode-boot-properties/.vscodeignore new file mode 100644 index 000000000..37a538825 --- /dev/null +++ b/vscode-extensions/vscode-boot-properties/.vscodeignore @@ -0,0 +1,30 @@ +# IDE configs +.vscode/** +.idea/** +*.iml +javaconfig.json +classpath.txt +tsconfig.json +tsd.json +*.xml + +# Logs +*.log* + +# Sources +typings/** +src/** +test/** +lib/** +!lib/javaconfig.schema.json +repo/** +scripts/** + +# Compiler output +out/test/** +target/** +!target/vscode-boot-properties-*.jar + +# Extensions +.gitignore +**/*.map diff --git a/vscode-extensions/vscode-boot-properties/README.md b/vscode-extensions/vscode-boot-properties/README.md new file mode 100644 index 000000000..b30e3db57 --- /dev/null +++ b/vscode-extensions/vscode-boot-properties/README.md @@ -0,0 +1,75 @@ +# VS Code Language Server for Spring Boot Application Properties + +VSCode extension and Language Server providing support for editing `application.properties` +and `application.yml` files containing Spring Boot configuration properties. + +## Installation: + +Currently this plugin is not distributed via vscode marketplace. You can only install +it from a .vsix file. You can download it here: + + TODO: add link + +To install it: + +- open vscode. +- press `CTRL-SHIFT-P` and search for VSIX +- select `Extension: Install from VSIX` + +## Usage: + +The extension will automatically activate when you edit files with the following +name patterns: + + - `application*.properties` => activates support for .properties file format. + - `application*.yml` => activates support for .yml file format. + +# Developer notes + +## Bulding and Running + +This project consists of three pieces: + + - a vscode-extension which is a language-server client implemented in TypeScript. + - commons-vscode: a local npm module with some utilities implemented in TypeScript. + - a language server implemented in Java. + +To build all these pieces you normally only need to run: + + npm install + +**However, the first time you build** it might fail trying to +find the `commons-vscode` module on npm central. Once we publish a stable +version of that module on npm central that will no longer be a problem. +Until that time, you can work around this by doing a one time manual +run of the `preinstall` script prior to running `npm install`: + + ./scripts/preinstall.sh + npm install + +Now you can open the client-app in vscode. From the root of this project. + + code . + +To launch the language server in a vscode runtime, press F5. + +## Debugging + +To debug the language server, open `lib/Main.ts` and edit to set the +`DEBUG` option to `true`. When you laucnh the app next by pressing +`F5` it will launch with debug options being passed to the JVM. + +You can then connect a 'Remote Java' Eclipse debugger on port 8000. + +## Packaging as a vscode extension + +First make sure the stuff is all built locally: + + ./scripts/preinstall.sh # only needed if this is the first build. + npm install + +Then package it: + + npm run vsce-package + +This produces a `.vsix` file which you can install directly into vscode. \ No newline at end of file diff --git a/vscode-extensions/vscode-boot-properties/lib/.gitignore b/vscode-extensions/vscode-boot-properties/lib/.gitignore new file mode 100644 index 000000000..a6c7c2852 --- /dev/null +++ b/vscode-extensions/vscode-boot-properties/lib/.gitignore @@ -0,0 +1 @@ +*.js diff --git a/vscode-extensions/vscode-boot-properties/lib/Main.ts b/vscode-extensions/vscode-boot-properties/lib/Main.ts new file mode 100644 index 000000000..c986e3a55 --- /dev/null +++ b/vscode-extensions/vscode-boot-properties/lib/Main.ts @@ -0,0 +1,48 @@ +'use strict'; +// The module 'vscode' contains the VS Code extensibility API +// Import the module and reference it with the alias vscode in your code below + +import * as VSCode from 'vscode'; +import * as Path from 'path'; +import * as FS from 'fs'; +import * as Net from 'net'; +import * as ChildProcess from 'child_process'; +import {LanguageClient, LanguageClientOptions, SettingMonitor, ServerOptions, StreamInfo} from 'vscode-languageclient'; +import {TextDocument} from 'vscode'; + +import * as commons from 'commons-vscode'; + +/** Called when extension is activated */ +export function activate(context: VSCode.ExtensionContext) { + let options : commons.ActivatorOptions = { + DEBUG: false, + extensionId: 'vscode-boot-properties', + fatJarFile: 'target/vscode-boot-properties-0.0.1-SNAPSHOT.jar', + clientOptions: { + // HACK!!! documentSelector only takes string|string[] where string is language id, but DocumentFilter object is passed instead + // Reasons: + // 1. documentSelector is just passed over to functions like #registerHoverProvider(documentSelector, ...) that take documentSelector + // parameter in string | DocumentFilter | string[] | DocumentFilter[] format + // 2. Combination of non string|string[] documentSelector parameter and synchronize.textDocumentFilter function makes doc synchronization + // events pass on to Language Server only for documents for which function passed via textDocumentFilter property return true + + // TODO: Remove cast ones https://github.com/Microsoft/vscode-languageserver-node/issues/9 is resolved + documentSelector: [ + // for application.properties files + {language: 'ini', pattern: '**/application*.properties'}, + {language: 'java-properties', pattern: '**/application*.properties'}, + {language: 'properties', pattern: '**/application*.properties'}, + // for application.yml files + {language: 'yaml', pattern: '**/application*.yml'} + + ], + synchronize: { + // TODO: Remove textDocumentFilter property ones https://github.com/Microsoft/vscode-languageserver-node/issues/9 is resolved + textDocumentFilter: function(textDocument : TextDocument) : boolean { + return /^(.*\/)?application[^\s\\/]*.(yml|properties)$/i.test(textDocument.fileName); + } + } + } + }; + commons.activate(options, context); +} diff --git a/vscode-extensions/vscode-boot-properties/package.json b/vscode-extensions/vscode-boot-properties/package.json new file mode 100644 index 000000000..ebd1c124e --- /dev/null +++ b/vscode-extensions/vscode-boot-properties/package.json @@ -0,0 +1,50 @@ +{ + "name": "vscode-boot-properties", + "displayName": "Spring Boot Application Properties Support", + "description": "Provides validation and content assist for Spring Boot application.properties and application.yml file", + "icon": "spring-boot-logo.png", + "version": "0.0.1", + "publisher": "Pivotal", + "repository": { + "type": "git", + "url": "https://github.com/spring-projects/sts4.git" + }, + "license": "EPL-1.0", + "engines": { + "npm": "^3.0.0", + "vscode": "^1.5.0" + }, + "categories": [ + "Languages", + "Linters" + ], + "keywords": [ + "java-properties", "spring-boot", "application-properties", "application-yaml" + ], + "activationEvents": [ + "onLanguage:ini", + "onLanguage:java-properties", + "onLanguage:properties", + "onLanguage:yaml" + ], + "main": "./out/lib/Main", + "preview": true, + "scripts": { + "prepublish": "tsc -p .", + "clean": "rm -fr node_modules out *.vsix", + "compile": "tsc -watch -p ./", + "preinstall": "./scripts/preinstall.sh", + "postinstall": "node ./node_modules/vscode/bin/install", + "vsce-package": "vsce package" + }, + "dependencies": { + "vscode-languageclient": "2.5.x", + "commons-vscode": "^0.0.1" + }, + "devDependencies": { + "vsce": "^1.17.0", + "typescript": "^2.0.x", + "@types/node": "^6.0.40", + "vscode": "^1.0.0" + } +} diff --git a/vscode-extensions/vscode-boot-properties/pom.xml b/vscode-extensions/vscode-boot-properties/pom.xml new file mode 100644 index 000000000..a77de5c99 --- /dev/null +++ b/vscode-extensions/vscode-boot-properties/pom.xml @@ -0,0 +1,74 @@ + + + 4.0.0 + vscode-boot-properties + jar + + + org.springframework.ide.vscode + commons-parent + 0.0.1-SNAPSHOT + ../commons/pom.xml + + + + + + oss-sonatype + oss-sonatype + https://oss.sonatype.org/content/repositories/snapshots/ + + true + + + + + + + distribution-repository + Temporary Staging Repository + file://${basedir}/dist + + + + + + org.springframework.ide.vscode + vscode-application-properties + ${project.version} + + + org.springframework.ide.vscode + vscode-application-yaml + ${project.version} + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.3 + + 1.8 + 1.8 + + + + + org.springframework.boot + spring-boot-maven-plugin + 1.4.1.RELEASE + + + + repackage + + + + + + + diff --git a/vscode-extensions/vscode-boot-properties/scripts/preinstall.sh b/vscode-extensions/vscode-boot-properties/scripts/preinstall.sh new file mode 100755 index 000000000..f69d40a09 --- /dev/null +++ b/vscode-extensions/vscode-boot-properties/scripts/preinstall.sh @@ -0,0 +1,5 @@ +#!/bin/bash +set -e +(cd ../commons-vscode ; npm install) +npm install ../commons-vscode +../mvnw -f ../pom.xml -pl vscode-boot-properties -am clean package diff --git a/vscode-extensions/vscode-boot-properties/spring-boot-logo.png b/vscode-extensions/vscode-boot-properties/spring-boot-logo.png new file mode 100644 index 000000000..0ccdef63a Binary files /dev/null and b/vscode-extensions/vscode-boot-properties/spring-boot-logo.png differ diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/BootPropertiesLanguageServer.java b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/BootPropertiesLanguageServer.java new file mode 100644 index 000000000..a8728618d --- /dev/null +++ b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/BootPropertiesLanguageServer.java @@ -0,0 +1,190 @@ +/******************************************************************************* + * Copyright (c) 2016 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; + +import static org.springframework.ide.vscode.commons.util.Providers.lazy; + +import javax.inject.Provider; + +import org.eclipse.lsp4j.CompletionOptions; +import org.eclipse.lsp4j.ServerCapabilities; +import org.eclipse.lsp4j.TextDocumentSyncKind; +import org.springframework.ide.vscode.application.properties.completions.SpringPropertiesCompletionEngine; +import org.springframework.ide.vscode.application.properties.hover.PropertiesHoverInfoProvider; +import org.springframework.ide.vscode.application.properties.metadata.PropertyInfo; +import org.springframework.ide.vscode.application.properties.metadata.SpringPropertyIndexProvider; +import org.springframework.ide.vscode.application.properties.metadata.completions.PropertyCompletionFactory; +import org.springframework.ide.vscode.application.properties.metadata.completions.RelaxedNameConfig; +import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtilProvider; +import org.springframework.ide.vscode.application.properties.metadata.util.FuzzyMap; +import org.springframework.ide.vscode.application.properties.reconcile.SpringPropertiesReconcileEngine; +import org.springframework.ide.vscode.application.yaml.completions.ApplicationYamlAssistContext; +import org.springframework.ide.vscode.application.yaml.reconcile.ApplicationYamlReconcileEngine; +import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine; +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; +import org.springframework.ide.vscode.commons.languageserver.hover.VscodeHoverEngineAdapter.HoverType; +import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; +import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcileEngine; +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; +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.TextDocument; +import org.springframework.ide.vscode.commons.yaml.ast.YamlASTProvider; +import org.springframework.ide.vscode.commons.yaml.ast.YamlParser; +import org.springframework.ide.vscode.commons.yaml.completion.YamlAssistContext; +import org.springframework.ide.vscode.commons.yaml.completion.YamlAssistContextProvider; +import org.springframework.ide.vscode.commons.yaml.completion.YamlCompletionEngine; +import org.springframework.ide.vscode.commons.yaml.hover.YamlHoverInfoProvider; +import org.springframework.ide.vscode.commons.yaml.structure.YamlDocument; +import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureProvider; +import org.yaml.snakeyaml.Yaml; + +import com.google.common.collect.ImmutableList; + +/** + * Language Server for Spring Boot Application Properties files + * + * @author Alex Boyko + * + */ +public class BootPropertiesLanguageServer extends SimpleLanguageServer { + + private static final String YML = ".yml"; + private static final String PROPERTIES = ".properties"; + // Shared: + private final JavaProjectFinder javaProjectFinder; + private final SpringPropertyIndexProvider indexProvider; + private final TypeUtilProvider typeUtilProvider; + private final VscodeCompletionEngineAdapter completionEngine; + private final VscodeHoverEngineAdapter hoverEngine; + private final RelaxedNameConfig relaxedNameConfig = RelaxedNameConfig.COMPLETION_DEFAULTS; + + private final PropertyCompletionFactory completionFactory; + + // For yaml + private final Yaml yaml = new Yaml(); + private final YamlASTProvider parser = new YamlParser(yaml); + private final YamlStructureProvider yamlStructureProvider= YamlStructureProvider.DEFAULT; + private YamlAssistContextProvider yamlAssistContextProvider; + + public BootPropertiesLanguageServer(SpringPropertyIndexProvider indexProvider, TypeUtilProvider typeUtilProvider, JavaProjectFinder javaProjectFinder) { + this.indexProvider = indexProvider; + this.typeUtilProvider = typeUtilProvider; + this.javaProjectFinder = javaProjectFinder; + this.completionFactory = new PropertyCompletionFactory(javaProjectFinder); + this.yamlAssistContextProvider = new YamlAssistContextProvider() { + @Override + public YamlAssistContext getGlobalAssistContext(YamlDocument ydoc) { + IDocument doc = ydoc.getDocument(); + FuzzyMap index = indexProvider.getIndex(doc); + return ApplicationYamlAssistContext.global(index, completionFactory, typeUtilProvider.getTypeUtil(doc), relaxedNameConfig); + } + }; + + SimpleTextDocumentService documents = getTextDocumentService(); + + IReconcileEngine reconcileEngine = getReconcileEngine(); + documents.onDidChangeContent(params -> { + TextDocument doc = params.getDocument(); + validateWith(doc, reconcileEngine); + }); + + ICompletionEngine propertiesCompletionEngine = getCompletionEngine(); + completionEngine = new VscodeCompletionEngineAdapter(this, propertiesCompletionEngine); + completionEngine.setMaxCompletionsNumber(100); + documents.onCompletion(completionEngine::getCompletions); + documents.onCompletionResolve(completionEngine::resolveCompletion); + + HoverInfoProvider hoverInfoProvider = getHoverProvider(); + hoverEngine = new VscodeHoverEngineAdapter(this, hoverInfoProvider); + documents.onHover(hoverEngine::getHover); + } + + private ICompletionEngine getCompletionEngine() { + ICompletionEngine propertiesCompletions = new SpringPropertiesCompletionEngine(indexProvider, typeUtilProvider, javaProjectFinder); + ICompletionEngine yamlCompletions = new YamlCompletionEngine(yamlStructureProvider, yamlAssistContextProvider); + return (IDocument document, int offset) -> { + String uri = document.getUri(); + if (uri!=null) { + if (uri.endsWith(PROPERTIES)) { + return propertiesCompletions.getCompletions(document, offset); + } else if (uri.endsWith(YML)) { + return yamlCompletions.getCompletions(document, offset); + } + } + return ImmutableList.of(); + }; + } + + protected HoverInfoProvider getHoverProvider() { + HoverInfoProvider propertiesHovers = new PropertiesHoverInfoProvider(indexProvider, typeUtilProvider, javaProjectFinder); + HoverInfoProvider ymlHovers = new YamlHoverInfoProvider(parser, yamlStructureProvider, yamlAssistContextProvider); + + return (IDocument document, int offset) -> { + String uri = document.getUri(); + if (uri!=null) { + if (uri.endsWith(PROPERTIES)) { + return propertiesHovers.getHoverInfo(document, offset); + } else if (uri.endsWith(YML)) { + return ymlHovers.getHoverInfo(document, offset); + } + } + return null; + }; + } + + public void setMaxCompletionsNumber(int number) { + completionEngine.setMaxCompletionsNumber(number); + } + + public void setHoverType(HoverType type) { + hoverEngine.setHoverType(type); + } + + @Override + protected ServerCapabilities getServerCapabilities() { + ServerCapabilities c = new ServerCapabilities(); + + c.setTextDocumentSync(TextDocumentSyncKind.Full); + CompletionOptions completionProvider = new CompletionOptions(); + completionProvider.setResolveProvider(false); + c.setCompletionProvider(completionProvider); + + c.setHoverProvider(true); + + return c; + } + + protected IReconcileEngine getReconcileEngine() { + IReconcileEngine propertiesReconciler = new SpringPropertiesReconcileEngine(indexProvider, typeUtilProvider); + IReconcileEngine ymlReconciler = new ApplicationYamlReconcileEngine(parser, indexProvider, typeUtilProvider); + + return (doc, problemCollector) -> { + String uri = doc.getUri(); + if (uri!=null) { + if (uri.endsWith(PROPERTIES)) { + propertiesReconciler.reconcile(doc, problemCollector); + return; + } else if (uri.endsWith(YML)) { + ymlReconciler.reconcile(doc, problemCollector); + return; + } + } + //No real reconciler is applicable. So tell the problemCollector there are no problems. + problemCollector.beginCollecting(); + problemCollector.endCollecting(); + }; + } + + +} diff --git a/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/Main.java b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/Main.java new file mode 100644 index 000000000..b2def0eb4 --- /dev/null +++ b/vscode-extensions/vscode-boot-properties/src/main/java/org/springframework/ide/vscode/boot/Main.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2016 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; + +import java.io.IOException; + +import org.eclipse.lsp4j.services.LanguageServer; +import org.springframework.ide.vscode.application.properties.metadata.DefaultSpringPropertyIndexProvider; +import org.springframework.ide.vscode.application.properties.metadata.SpringPropertyIndexProvider; +import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtil; +import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtilProvider; +import org.springframework.ide.vscode.commons.languageserver.LaunguageServerApp; +import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; + +/** + * Starts up Language Server process + * + * @author Alex Boyko + * @author Kris De Volder + * + */ +public class Main { + + public static void main(String[] args) throws IOException { + LaunguageServerApp.start(() -> { + JavaProjectFinder javaProjectFinder = JavaProjectFinder.DEFAULT; + SpringPropertyIndexProvider indexProvider = new DefaultSpringPropertyIndexProvider(javaProjectFinder); + TypeUtilProvider typeUtilProvider = (IDocument doc) -> new TypeUtil(javaProjectFinder.find(doc)); + LanguageServer server = new BootPropertiesLanguageServer(indexProvider, typeUtilProvider, javaProjectFinder); + return server; + }); + } + +} diff --git a/vscode-extensions/vscode-boot-properties/src/test/resources/workspace/application.properties b/vscode-extensions/vscode-boot-properties/src/test/resources/workspace/application.properties new file mode 100644 index 000000000..3a87ccd5f --- /dev/null +++ b/vscode-extensions/vscode-boot-properties/src/test/resources/workspace/application.properties @@ -0,0 +1,3 @@ +#Bar role +app=foo +bad diff --git a/vscode-extensions/vscode-boot-properties/tsconfig.json b/vscode-extensions/vscode-boot-properties/tsconfig.json new file mode 100644 index 000000000..1905ffea7 --- /dev/null +++ b/vscode-extensions/vscode-boot-properties/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "module": "commonjs", + "moduleResolution": "node", + "target": "es6", + "lib": [ + "es6" + ], + "declaration": true, + "outDir": "out", + "sourceMap": true, + "rootDir": "." + }, + "include": [ + "typings/*.d.ts", + "lib/**/*.ts" + ], + "exclude": [ + "node_modules" + ] +} \ No newline at end of file