From 389c18411e849a6edf6b3727d60243f2bf8f030e Mon Sep 17 00:00:00 2001 From: azerr Date: Wed, 8 Apr 2020 11:49:18 +0200 Subject: [PATCH] Filter for Java (server) snippet Fixes #265 Signed-off-by: azerr --- .../MicroProfileJavaProjectLabelsParams.java | 28 ++++++ .../jdt/core/ProjectLabelManager.java | 31 +++++- .../ls/JavaProjectDelegateCommandHandler.java | 3 + microprofile.ls/README.md | 24 ++++- .../MicroProfileJavaProjectLabelsParams.java | 28 ++++++ .../ls/JavaTextDocumentService.java | 64 ++++++------ .../ls/JavaTextDocumentSnippetRegistry.java | 42 ++++++++ .../microprofile/ls/JavaTextDocuments.java | 18 +++- .../commons/snippets/SnippetDeserializer.java | 9 +- .../ls/commons/snippets/SnippetRegistry.java | 11 +-- .../services/MicroProfileCompletions.java | 6 +- ...MicroProfileJavaSnippetRegistryLoader.java | 6 +- .../snippets/SnippetContextForJava.java | 99 +++++++++++++++++++ .../snippets/SnippetContextForProperties.java | 94 ++++++++++++++++++ .../QuarkusJavaSnippetRegistryLoader.java | 5 +- ...uarkusPropertiesSnippetRegistryLoader.java | 4 +- .../microprofile/snippets/mp-openapi.json | 18 ++-- .../redhat/quarkus/snippets/quarkus-java.json | 20 +++- .../quarkus/snippets/quarkus-properties.json | 4 +- .../ls/JavaTextDocumentsTest.java | 4 +- .../commons/snippets/SnippetRegistryTest.java | 10 +- 21 files changed, 446 insertions(+), 82 deletions(-) create mode 100644 microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/ls/JavaTextDocumentSnippetRegistry.java create mode 100644 microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/snippets/SnippetContextForJava.java create mode 100644 microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/snippets/SnippetContextForProperties.java diff --git a/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/commons/MicroProfileJavaProjectLabelsParams.java b/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/commons/MicroProfileJavaProjectLabelsParams.java index ba14d9862..4add30e97 100644 --- a/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/commons/MicroProfileJavaProjectLabelsParams.java +++ b/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/commons/MicroProfileJavaProjectLabelsParams.java @@ -11,6 +11,8 @@ *******************************************************************************/ package com.redhat.microprofile.commons; +import java.util.List; + /** * MicroProfile Java Project labels * @@ -21,6 +23,8 @@ public class MicroProfileJavaProjectLabelsParams { private String uri; + private List types; + /** * Returns the Java file uri. * @@ -38,4 +42,28 @@ public String getUri() { public void setUri(String uri) { this.uri = uri; } + + /** + * Returns the Java types list to check. + * + *

+ * If the owner Java project of the Java file URI contains some type in the + * classpath, it will return the type as label in + * {@link ProjectLabelInfoEntry#getLabels()} + *

+ * + * @return the Java types list to check + */ + public List getTypes() { + return types; + } + + /** + * Set the Java types list to check. + * + * @param types the Java types list to check. + */ + public void setTypes(List types) { + this.types = types; + } } diff --git a/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/jdt/core/ProjectLabelManager.java b/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/jdt/core/ProjectLabelManager.java index 626c58749..065b2b086 100644 --- a/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/jdt/core/ProjectLabelManager.java +++ b/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/jdt/core/ProjectLabelManager.java @@ -26,6 +26,7 @@ import com.redhat.microprofile.commons.ProjectLabelInfoEntry; import com.redhat.microprofile.jdt.core.utils.IJDTUtils; import com.redhat.microprofile.jdt.core.utils.JDTMicroProfileUtils; +import com.redhat.microprofile.jdt.core.utils.JDTTypeUtils; import com.redhat.microprofile.jdt.internal.core.ProjectLabelRegistry; /** @@ -54,7 +55,7 @@ public List getProjectLabelInfo() { IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); for (IProject project : projects) { - ProjectLabelInfoEntry info = getProjectLabelInfo(project); + ProjectLabelInfoEntry info = getProjectLabelInfo(project, null); if (info != null) { results.add(info); } @@ -66,12 +67,13 @@ public List getProjectLabelInfo() { * Returns project label results for the given Eclipse project. * * @param project Eclipse project. + * @param types the Java type list to check. * @return project label results for the given Eclipse project. */ - private ProjectLabelInfoEntry getProjectLabelInfo(IProject project) { + private ProjectLabelInfoEntry getProjectLabelInfo(IProject project, List types) { String uri = JDTMicroProfileUtils.getProjectURI(project); if (uri != null) { - return new ProjectLabelInfoEntry(uri, getProjectLabels(project)); + return new ProjectLabelInfoEntry(uri, getProjectLabels(project, types)); } return null; } @@ -91,21 +93,40 @@ public ProjectLabelInfoEntry getProjectLabelInfo(MicroProfileJavaProjectLabelsPa // The uri doesn't belong to an Eclipse project return ProjectLabelInfoEntry.EMPTY_PROJECT_INFO; } - return getProjectLabelInfo(file.getProject()); + return getProjectLabelInfo(file.getProject(), params.getTypes()); } - private List getProjectLabels(IProject project) { + /** + * Returns the project labels for the given project. + * + * @param project the Eclipse project. + * @param types the Java type list to check. + * @return the project labels for the given project. + */ + private List getProjectLabels(IProject project, List types) { IJavaProject javaProject = JavaCore.create(project); if (javaProject == null) { return Collections.emptyList(); } + // Update labels by using the + // "com.redhat.microprofile.jdt.core.projectLabelProviders" extension point (ex + // : "maven", "gradle", "quarkus", "microprofile"). List projectLabels = new ArrayList<>(); List definitions = ProjectLabelRegistry.getInstance().getProjectLabelDefinitions(); for (ProjectLabelDefinition definition : definitions) { projectLabels.addAll(definition.getProjectLabels(javaProject)); } + // Update labels by checking if some Java types are in the classpath of the Java + // project. + if (types != null) { + for (String type : types) { + if (JDTTypeUtils.findType(javaProject, type) != null) { + projectLabels.add(type); + } + } + } return projectLabels; } diff --git a/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/jdt/internal/core/ls/JavaProjectDelegateCommandHandler.java b/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/jdt/internal/core/ls/JavaProjectDelegateCommandHandler.java index c47987496..e2643fbe3 100644 --- a/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/jdt/internal/core/ls/JavaProjectDelegateCommandHandler.java +++ b/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/jdt/internal/core/ls/JavaProjectDelegateCommandHandler.java @@ -11,6 +11,7 @@ import static com.redhat.microprofile.jdt.internal.core.ls.ArgumentUtils.getFirst; import static com.redhat.microprofile.jdt.internal.core.ls.ArgumentUtils.getString; +import static com.redhat.microprofile.jdt.internal.core.ls.ArgumentUtils.getStringList; import java.util.List; import java.util.Map; @@ -57,8 +58,10 @@ private static Object getProjectLabelInfo(List arguments, String command "Command '%s' must be called with required MicroProfileJavaProjectLabelsParams.uri (java file URI)!", commandId)); } + List types = getStringList(obj, "types"); MicroProfileJavaProjectLabelsParams params = new MicroProfileJavaProjectLabelsParams(); params.setUri(javaFileUri); + params.setTypes(types); return ProjectLabelManager.getInstance().getProjectLabelInfo(params, JDTUtilsLSImpl.getInstance(), monitor); } } diff --git a/microprofile.ls/README.md b/microprofile.ls/README.md index 2c8bcb5a0..342570793 100644 --- a/microprofile.ls/README.md +++ b/microprofile.ls/README.md @@ -62,23 +62,39 @@ Java and properties completion snippets are managed by the MicroProfile LS (snip The `"context"` key can be provided to specify the condition in which the snippet should appear: - * for `properties files`: the context/extension can be declared in the snippet to show the snippet only if the extension belongs to the project. + * for `properties files`: the context/dependency can be declared in the snippet to show the snippet only if the extension belongs to the project. ```json -"Add datasource properties": { + "Add datasource properties": { "prefix": "qds", "body": [ ... ], "context": { - "extension": "quarkus-agroal" + "dependency": "quarkus-agroal" } } ``` means that the snippet is shown only if the project has the `quarkus-agroal` dependency. - * for `Java files` (not available for the moment) + * for `Java files`: the context/type can be declared in the snippet to show the snippet only if the Java type belongs to the project. + +```json + "@Operation": { + "prefix": [ + "@Operation" + ], + "body": [ + ... + ], + "context": { + "type": "org.eclipse.microprofile.openapi.annotations.Operation" + } + } +``` + +means that the snippet is shown only if the project has the `org.eclipse.microprofile.openapi.annotations.Operation` Java Annotation in the classpath. In otherwords, only when the Java project have a dependency to the MicroProfile Open API. ## Adding new internal snippets diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/commons/MicroProfileJavaProjectLabelsParams.java b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/commons/MicroProfileJavaProjectLabelsParams.java index ba14d9862..4add30e97 100644 --- a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/commons/MicroProfileJavaProjectLabelsParams.java +++ b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/commons/MicroProfileJavaProjectLabelsParams.java @@ -11,6 +11,8 @@ *******************************************************************************/ package com.redhat.microprofile.commons; +import java.util.List; + /** * MicroProfile Java Project labels * @@ -21,6 +23,8 @@ public class MicroProfileJavaProjectLabelsParams { private String uri; + private List types; + /** * Returns the Java file uri. * @@ -38,4 +42,28 @@ public String getUri() { public void setUri(String uri) { this.uri = uri; } + + /** + * Returns the Java types list to check. + * + *

+ * If the owner Java project of the Java file URI contains some type in the + * classpath, it will return the type as label in + * {@link ProjectLabelInfoEntry#getLabels()} + *

+ * + * @return the Java types list to check + */ + public List getTypes() { + return types; + } + + /** + * Set the Java types list to check. + * + * @param types the Java types list to check. + */ + public void setTypes(List types) { + this.types = types; + } } diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/ls/JavaTextDocumentService.java b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/ls/JavaTextDocumentService.java index 1ed5091a0..bbb967024 100644 --- a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/ls/JavaTextDocumentService.java +++ b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/ls/JavaTextDocumentService.java @@ -54,7 +54,7 @@ import com.redhat.microprofile.ls.commons.snippets.TextDocumentSnippetRegistry; import com.redhat.microprofile.settings.MicroProfileCodeLensSettings; import com.redhat.microprofile.settings.SharedSettings; -import com.redhat.microprofile.snippets.LanguageId; +import com.redhat.microprofile.snippets.SnippetContextForJava; /** * LSP text document service for Java file. @@ -80,7 +80,8 @@ public JavaTextDocumentService(MicroProfileLanguageServer microprofileLanguageSe this.documents = new JavaTextDocuments(microprofileLanguageServer); } - // ------------------------------ did* for Java file ------------------------------ + // ------------------------------ did* for Java file + // ------------------------------ @Override public void didOpen(DidOpenTextDocumentParams params) { @@ -110,32 +111,31 @@ public void didSave(DidSaveTextDocumentParams params) { @Override public CompletableFuture, CompletionList>> completion(CompletionParams params) { - return CompletableFutures.computeAsync(cancel -> { - try { - // Returns java snippets - TextDocument document = documents.get(params.getTextDocument().getUri()); - int completionOffset = document.offsetAt(params.getPosition()); - boolean canSupportMarkdown = true; - CompletionList list = new CompletionList(); - list.setItems(new ArrayList<>()); - getSnippetRegistry().getCompletionItems(document, completionOffset, canSupportMarkdown, context -> { - return true; - }).forEach(item -> { - list.getItems().add(item); - }); - return Either.forRight(list); - } catch (BadLocationException e) { - LOGGER.log(Level.SEVERE, "Error while getting java completions", e); - return Either.forRight(null); - } - }); - } - - private TextDocumentSnippetRegistry getSnippetRegistry() { - if (snippetRegistry == null) { - snippetRegistry = new TextDocumentSnippetRegistry(LanguageId.java.name()); - } - return snippetRegistry; + JavaTextDocument document = documents.get(params.getTextDocument().getUri()); + return document.executeIfInMicroProfileProject((projectInfo) -> { + return CompletableFutures.computeAsync(cancel -> { + try { + // Returns java snippets + int completionOffset = document.offsetAt(params.getPosition()); + boolean canSupportMarkdown = true; + CompletionList list = new CompletionList(); + list.setItems(new ArrayList<>()); + documents.getSnippetRegistry() + .getCompletionItems(document, completionOffset, canSupportMarkdown, context -> { + if (context != null && context instanceof SnippetContextForJava) { + return ((SnippetContextForJava) context).isMatch(projectInfo); + } + return true; + }).forEach(item -> { + list.getItems().add(item); + }); + return Either.forRight(list); + } catch (BadLocationException e) { + LOGGER.log(Level.SEVERE, "Error while getting java completions", e); + return Either.forRight(null); + } + }); + }, Either.forRight(null)); } // ------------------------------ Code Lens ------------------------------ @@ -152,7 +152,7 @@ public CompletableFuture> codeLens(CodeLensParams param return CompletableFuture.completedFuture(Collections.emptyList()); } JavaTextDocument document = documents.get(params.getTextDocument().getUri()); - return document.executeIfInMicroProfileProject(() -> { + return document.executeIfInMicroProfileProject((projectInfo) -> { MicroProfileJavaCodeLensParams javaParams = new MicroProfileJavaCodeLensParams( params.getTextDocument().getUri()); if (sharedSettings.getCommandCapabilities().isCommandSupported(CommandKind.COMMAND_OPEN_URI)) { @@ -171,7 +171,7 @@ public CompletableFuture> codeLens(CodeLensParams param @Override public CompletableFuture>> codeAction(CodeActionParams params) { JavaTextDocument document = documents.get(params.getTextDocument().getUri()); - return document.executeIfInMicroProfileProject(() -> { + return document.executeIfInMicroProfileProject((projectInfo) -> { MicroProfileJavaCodeActionParams javaParams = new MicroProfileJavaCodeActionParams(); javaParams.setTextDocument(params.getTextDocument()); javaParams.setRange(params.getRange()); @@ -195,7 +195,7 @@ public CompletableFuture>> codeAction(CodeActio @Override public CompletableFuture hover(HoverParams params) { JavaTextDocument document = documents.get(params.getTextDocument().getUri()); - return document.executeIfInMicroProfileProject(() -> { + return document.executeIfInMicroProfileProject((projectinfo) -> { boolean markdownSupported = sharedSettings.getHoverSettings().isContentFormatSupported(MarkupKind.MARKDOWN); DocumentFormat documentFormat = markdownSupported ? DocumentFormat.Markdown : DocumentFormat.PlainText; MicroProfileJavaHoverParams javaParams = new MicroProfileJavaHoverParams(params.getTextDocument().getUri(), @@ -212,7 +212,7 @@ public CompletableFuture hover(HoverParams params) { * @param document the opened Java file. */ private void triggerValidationFor(JavaTextDocument document) { - document.executeIfInMicroProfileProject(() -> { + document.executeIfInMicroProfileProject((projectinfo) -> { String uri = document.getUri(); triggerValidationFor(Arrays.asList(uri)); return null; diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/ls/JavaTextDocumentSnippetRegistry.java b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/ls/JavaTextDocumentSnippetRegistry.java new file mode 100644 index 000000000..ebd107c72 --- /dev/null +++ b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/ls/JavaTextDocumentSnippetRegistry.java @@ -0,0 +1,42 @@ +package com.redhat.microprofile.ls; + +import java.util.ArrayList; +import java.util.List; + +import com.redhat.microprofile.ls.commons.snippets.Snippet; +import com.redhat.microprofile.ls.commons.snippets.TextDocumentSnippetRegistry; +import com.redhat.microprofile.snippets.LanguageId; +import com.redhat.microprofile.snippets.SnippetContextForJava; + +public class JavaTextDocumentSnippetRegistry extends TextDocumentSnippetRegistry { + + private List types; + + public JavaTextDocumentSnippetRegistry() { + super(LanguageId.java.name()); + } + + public List getTypes() { + if (types != null) { + return types; + } + types = collectTypes(); + return types; + } + + private synchronized List collectTypes() { + if (types != null) { + return types; + } + List types = new ArrayList<>(); + for (Snippet snippet : getSnippets()) { + if (snippet.getContext() != null && snippet.getContext() instanceof SnippetContextForJava) { + List t = ((SnippetContextForJava) snippet.getContext()).getTypes(); + if (t != null) { + types.addAll(t); + } + } + } + return types; + } +} diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/ls/JavaTextDocuments.java b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/ls/JavaTextDocuments.java index c9ff5a87b..92b7ce3ca 100644 --- a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/ls/JavaTextDocuments.java +++ b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/ls/JavaTextDocuments.java @@ -16,7 +16,7 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Supplier; +import java.util.function.Function; import java.util.logging.Level; import java.util.logging.Logger; @@ -49,6 +49,8 @@ class JavaTextDocuments extends TextDocuments { private final MicroProfileJavaProjectLabelsProvider provider; + private JavaTextDocumentSnippetRegistry snippetRegistry; + /** * Opened Java file. * @@ -80,13 +82,13 @@ public void setProjectURI(String projectURI) { * @return the given code only if the Java file belongs to a MicroProfile * project. */ - public CompletableFuture executeIfInMicroProfileProject(Supplier> code, - T defaultValue) { + public CompletableFuture executeIfInMicroProfileProject( + Function> code, T defaultValue) { return getProjectInfo(this).thenComposeAsync(projectInfo -> { if (!isMicroProfileProject(projectInfo)) { return CompletableFuture.completedFuture(defaultValue); } - return code.get(); + return code.apply(projectInfo); }); } @@ -150,6 +152,7 @@ CompletableFuture getProjectInfoFromCache(JavaTextDocumen // not found in the cache, load the project info from the JDT LS Extension MicroProfileJavaProjectLabelsParams params = new MicroProfileJavaProjectLabelsParams(); params.setUri(documentURI); + params.setTypes(getSnippetRegistry().getTypes()); final CompletableFuture future = provider.getJavaProjectlabels(params); future.thenApply(entry -> { if (entry != null) { @@ -200,4 +203,11 @@ private void classpathChanged(Set projectURIs) { private static boolean isMicroProfileProject(ProjectLabelInfoEntry projectInfo) { return projectInfo != null && projectInfo.hasLabel(MICROPROFILE_PROJECT_LABEL); } + + public JavaTextDocumentSnippetRegistry getSnippetRegistry() { + if (snippetRegistry == null) { + snippetRegistry = new JavaTextDocumentSnippetRegistry(); + } + return snippetRegistry; + } } diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/ls/commons/snippets/SnippetDeserializer.java b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/ls/commons/snippets/SnippetDeserializer.java index 59a5afb13..f07f1c9f5 100644 --- a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/ls/commons/snippets/SnippetDeserializer.java +++ b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/ls/commons/snippets/SnippetDeserializer.java @@ -21,6 +21,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapter; /** * GSON deserializer to build Snippet from vscode JSON snippet. @@ -36,9 +37,9 @@ class SnippetDeserializer implements JsonDeserializer { private static final String BODY_ELT = "body"; private static final String CONTEXT_ELT = "context"; - private final JsonDeserializer> contextDeserializer; + private final TypeAdapter> contextDeserializer; - public SnippetDeserializer(JsonDeserializer> contextDeserializer) { + public SnippetDeserializer(TypeAdapter> contextDeserializer) { this.contextDeserializer = contextDeserializer; } @@ -96,7 +97,7 @@ public Snippet deserialize(JsonElement json, Type typeOfT, JsonDeserializationCo if (contextDeserializer != null) { JsonElement contextElt = snippetObj.get(CONTEXT_ELT); if (contextElt != null) { - ISnippetContext snippetContext = contextDeserializer.deserialize(contextElt, typeOfT, context); + ISnippetContext snippetContext = contextDeserializer.fromJsonTree(contextElt); snippet.setContext(snippetContext); } } @@ -104,4 +105,4 @@ public Snippet deserialize(JsonElement json, Type typeOfT, JsonDeserializationCo return snippet; } -} +} \ No newline at end of file diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/ls/commons/snippets/SnippetRegistry.java b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/ls/commons/snippets/SnippetRegistry.java index 4fee72d18..9402f7d59 100644 --- a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/ls/commons/snippets/SnippetRegistry.java +++ b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/ls/commons/snippets/SnippetRegistry.java @@ -36,9 +36,9 @@ import org.eclipse.lsp4j.jsonrpc.messages.Either; import com.google.gson.GsonBuilder; -import com.google.gson.JsonDeserializer; import com.google.gson.JsonIOException; import com.google.gson.JsonSyntaxException; +import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; /** @@ -106,7 +106,7 @@ public void registerSnippets(InputStream in) throws IOException { * context. * @throws IOException */ - public void registerSnippets(InputStream in, JsonDeserializer> contextDeserializer) + public void registerSnippets(InputStream in, TypeAdapter> contextDeserializer) throws IOException { registerSnippets(new InputStreamReader(in, StandardCharsets.UTF_8.name()), contextDeserializer); } @@ -130,7 +130,7 @@ public void registerSnippets(Reader in) throws IOException { * context. * @throws IOException */ - public void registerSnippets(Reader in, JsonDeserializer> contextDeserializer) + public void registerSnippets(Reader in, TypeAdapter> contextDeserializer) throws IOException { JsonReader reader = new JsonReader(in); reader.beginObject(); @@ -146,8 +146,7 @@ public void registerSnippets(Reader in, JsonDeserializer> contextDeserializer) - throws JsonIOException, JsonSyntaxException { + TypeAdapter> contextDeserializer) throws JsonIOException, JsonSyntaxException { GsonBuilder builder = new GsonBuilder(); builder.registerTypeAdapter(Snippet.class, new SnippetDeserializer(contextDeserializer)); return builder.create().fromJson(reader, Snippet.class); @@ -309,4 +308,4 @@ protected static String findExprBeforeAt(String text, int offset) { return expr.toString(); } -} +} \ No newline at end of file diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/services/MicroProfileCompletions.java b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/services/MicroProfileCompletions.java index 4010938c7..6db35dd5b 100644 --- a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/services/MicroProfileCompletions.java +++ b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/services/MicroProfileCompletions.java @@ -48,7 +48,7 @@ import com.redhat.microprofile.settings.MicroProfileCompletionSettings; import com.redhat.microprofile.settings.MicroProfileFormattingSettings; import com.redhat.microprofile.snippets.LanguageId; -import com.redhat.microprofile.snippets.SnippetContextProperties; +import com.redhat.microprofile.snippets.SnippetContextForProperties; import com.redhat.microprofile.utils.DocumentationUtils; import com.redhat.microprofile.utils.MicroProfilePropertiesUtils; import com.redhat.microprofile.utils.MicroProfilePropertiesUtils.FormattedPropertyResult; @@ -420,8 +420,8 @@ private static void collectSnippetSuggestions(int completionOffset, Node node, P boolean markdownSupported = completionSettings.isDocumentationFormatSupported(MarkupKind.MARKDOWN); snippetRegistry.getCompletionItems(document.getDocument(), completionOffset, markdownSupported, context -> { - if (context instanceof SnippetContextProperties) { - SnippetContextProperties contextProperties = (SnippetContextProperties) context; + if (context instanceof SnippetContextForProperties) { + SnippetContextForProperties contextProperties = (SnippetContextForProperties) context; return contextProperties.isMatch(extensions); } return false; diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/snippets/MicroProfileJavaSnippetRegistryLoader.java b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/snippets/MicroProfileJavaSnippetRegistryLoader.java index ca257a785..4f3a2b6da 100644 --- a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/snippets/MicroProfileJavaSnippetRegistryLoader.java +++ b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/snippets/MicroProfileJavaSnippetRegistryLoader.java @@ -26,8 +26,10 @@ public class MicroProfileJavaSnippetRegistryLoader implements ISnippetRegistryLo @Override public void load(SnippetRegistry registry) throws IOException { - registry.registerSnippets(MicroProfileJavaSnippetRegistryLoader.class.getResourceAsStream("mp-metrics.json")); - registry.registerSnippets(MicroProfileJavaSnippetRegistryLoader.class.getResourceAsStream("mp-openapi.json")); + registry.registerSnippets(MicroProfileJavaSnippetRegistryLoader.class.getResourceAsStream("mp-metrics.json"), + SnippetContextForJava.TYPE_ADAPTER); + registry.registerSnippets(MicroProfileJavaSnippetRegistryLoader.class.getResourceAsStream("mp-openapi.json"), + SnippetContextForJava.TYPE_ADAPTER); } @Override diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/snippets/SnippetContextForJava.java b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/snippets/SnippetContextForJava.java new file mode 100644 index 000000000..8082ace58 --- /dev/null +++ b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/snippets/SnippetContextForJava.java @@ -0,0 +1,99 @@ +/******************************************************************************* +* Copyright (c) 2020 Red Hat Inc. and others. +* All rights reserved. This program and the accompanying materials +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v20.html +* +* SPDX-License-Identifier: EPL-2.0 +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package com.redhat.microprofile.snippets; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import com.redhat.microprofile.commons.ProjectLabelInfoEntry; +import com.redhat.microprofile.ls.commons.snippets.ISnippetContext; + +/** + * A snippet context for Java files which matches java scope and dependency. + * + * @author Angelo ZERR + * + */ +public class SnippetContextForJava implements ISnippetContext { + + public static final TypeAdapter TYPE_ADAPTER = new SnippetContextForJavaAdapter(); + private List types; + + public SnippetContextForJava(List types) { + this.types = types; + } + + public List getTypes() { + return types; + } + + @Override + public boolean isMatch(ProjectLabelInfoEntry context) { + if (context == null) { + return true; + } + if (types == null || types.isEmpty()) { + return true; + } + for (String type : types) { + if (context.hasLabel(type)) { + return true; + } + } + return false; + } + + private static class SnippetContextForJavaAdapter extends TypeAdapter { + + @Override + public SnippetContextForJava read(final JsonReader in) throws IOException { + JsonToken nextToken = in.peek(); + if (nextToken == JsonToken.NULL) { + return null; + } + + List types = new ArrayList<>(); + in.beginObject(); + while (in.hasNext()) { + String name = in.nextName(); + switch (name) { + case "type": + if (in.peek() == JsonToken.BEGIN_ARRAY) { + in.beginArray(); + while (in.peek() != JsonToken.END_ARRAY) { + types.add(in.nextString()); + } + in.endArray(); + } else { + types.add(in.nextString()); + } + break; + default: + in.skipValue(); + } + } + in.endObject(); + return new SnippetContextForJava(types); + } + + @Override + public void write(JsonWriter out, SnippetContextForJava value) throws IOException { + // Do nothing + } + } + +} \ No newline at end of file diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/snippets/SnippetContextForProperties.java b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/snippets/SnippetContextForProperties.java new file mode 100644 index 000000000..dc7c672b6 --- /dev/null +++ b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/snippets/SnippetContextForProperties.java @@ -0,0 +1,94 @@ +/******************************************************************************* +* Copyright (c) 2020 Red Hat Inc. and others. +* All rights reserved. This program and the accompanying materials +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v20.html +* +* SPDX-License-Identifier: EPL-2.0 +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package com.redhat.microprofile.snippets; + +import java.io.IOException; +import java.util.Set; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import com.redhat.microprofile.ls.commons.snippets.ISnippetContext; + +/** + * A snippet context properties which matches dependency. You can write a vscode + * snippet that declares a context like this: + * + * + * + * "Add datasource properties": { + "prefix": "qds", + "body": [ + "quarkus.datasource.url=${1|jdbc:mariadb://localhost:3306/mydb,jdbc:mysql://localhost:3306/test,jdbc:h2:mem:mydb,jdbc:postgresql://localhost/mydb,jdbc:sqlserver://localhost:1433;databaseName=mydb|}", + "quarkus.datasource.driver=${2|org.mariadb.jdbc.Driver,org.mysql.jdbc.Driver,org.h2.Driver,org.postgresql.Driver,com.microsoft.sqlserver.jdbc.SQLServerDriver|}", + "quarkus.datasource.username=${3:developer}", + "quarkus.datasource.password=${4:developer}", + "quarkus.hibernate-orm.database.generation=${5|update,drop-and-create,create,drop,none|}" + ], + "description": "Configure Quarkus datasource", + "context": { + "dependency": "quarkus-agroal" + } + } + + * + * + * This snippet will be available only if "quarkus-agroal" is present as + * dependency in the project. + * + * @author Angelo ZERR + * + */ +public class SnippetContextForProperties implements ISnippetContext> { + + public static final TypeAdapter TYPE_ADAPTER = new SnippetContextForPropertiesAdapter(); + + private String dependency; + + public SnippetContextForProperties(String dependency) { + this.dependency = dependency; + } + + @Override + public boolean isMatch(Set dependencys) { + return dependencys.contains(dependency); + } + + private static class SnippetContextForPropertiesAdapter extends TypeAdapter { + public SnippetContextForProperties read(JsonReader in) throws IOException { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + return null; + } + String dependency = null; + in.beginObject(); + while (in.hasNext()) { + String name = in.nextName(); + switch (name) { + case "dependency": + dependency = in.nextString(); + break; + default: + in.skipValue(); + } + } + in.endObject(); + return new SnippetContextForProperties(dependency); + } + + public void write(JsonWriter writer, SnippetContextForProperties value) throws IOException { + // Do nothing + } + } + +} \ No newline at end of file diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/quarkus/snippets/QuarkusJavaSnippetRegistryLoader.java b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/quarkus/snippets/QuarkusJavaSnippetRegistryLoader.java index 28bf07019..f78c22f23 100644 --- a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/quarkus/snippets/QuarkusJavaSnippetRegistryLoader.java +++ b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/quarkus/snippets/QuarkusJavaSnippetRegistryLoader.java @@ -16,7 +16,7 @@ import com.redhat.microprofile.ls.commons.snippets.ISnippetRegistryLoader; import com.redhat.microprofile.ls.commons.snippets.SnippetRegistry; import com.redhat.microprofile.snippets.LanguageId; - +import com.redhat.microprofile.snippets.SnippetContextForJava; /** * Snippet loader for Quarkus in java files. @@ -28,7 +28,8 @@ public class QuarkusJavaSnippetRegistryLoader implements ISnippetRegistryLoader @Override public void load(SnippetRegistry registry) throws IOException { - registry.registerSnippets(QuarkusJavaSnippetRegistryLoader.class.getResourceAsStream("quarkus-java.json")); + registry.registerSnippets(QuarkusJavaSnippetRegistryLoader.class.getResourceAsStream("quarkus-java.json"), + SnippetContextForJava.TYPE_ADAPTER); } @Override diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/quarkus/snippets/QuarkusPropertiesSnippetRegistryLoader.java b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/quarkus/snippets/QuarkusPropertiesSnippetRegistryLoader.java index be415e065..688490e23 100644 --- a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/quarkus/snippets/QuarkusPropertiesSnippetRegistryLoader.java +++ b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/quarkus/snippets/QuarkusPropertiesSnippetRegistryLoader.java @@ -14,7 +14,7 @@ import com.redhat.microprofile.ls.commons.snippets.ISnippetRegistryLoader; import com.redhat.microprofile.ls.commons.snippets.SnippetRegistry; import com.redhat.microprofile.snippets.LanguageId; -import com.redhat.microprofile.snippets.SnippetContextPropertiesDeserializer; +import com.redhat.microprofile.snippets.SnippetContextForProperties; /** * Snippet loader for Quarkus in properties files. @@ -28,7 +28,7 @@ public class QuarkusPropertiesSnippetRegistryLoader implements ISnippetRegistryL public void load(SnippetRegistry registry) throws Exception { registry.registerSnippets( QuarkusPropertiesSnippetRegistryLoader.class.getResourceAsStream("quarkus-properties.json"), - new SnippetContextPropertiesDeserializer()); + SnippetContextForProperties.TYPE_ADAPTER); } @Override diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/main/resources/com/redhat/microprofile/snippets/mp-openapi.json b/microprofile.ls/com.redhat.microprofile.ls/src/main/resources/com/redhat/microprofile/snippets/mp-openapi.json index 60aaff4cd..e212e7098 100644 --- a/microprofile.ls/com.redhat.microprofile.ls/src/main/resources/com/redhat/microprofile/snippets/mp-openapi.json +++ b/microprofile.ls/com.redhat.microprofile.ls/src/main/resources/com/redhat/microprofile/snippets/mp-openapi.json @@ -24,7 +24,7 @@ ], "description": "Provides media type", "context": { - "type": "org.eclipse.microprofile.openapi.annotations.Content" + "type": "org.eclipse.microprofile.openapi.annotations.media.Content" } }, "@Content with Schema": { @@ -39,7 +39,7 @@ ], "description": "Provides schema and examples for a particular media type.", "context": { - "type": "org.eclipse.microprofile.openapi.annotations.Content" + "type": "org.eclipse.microprofile.openapi.annotations.media.Content" } }, "@Schema with implementation": { @@ -51,7 +51,7 @@ ], "description": "Allows the definition of input and output data types.", "context": { - "type": "org.eclipse.microprofile.openapi.annotations.Schema" + "type": "org.eclipse.microprofile.openapi.annotations.media.Schema" } }, "@Schema with type": { @@ -63,7 +63,7 @@ ], "description": "Allows the definition of input and output data types.", "context": { - "type": "org.eclipse.microprofile.openapi.annotations.Schema" + "type": "org.eclipse.microprofile.openapi.annotations.media.Schema" } }, "@Schema with implementation and type": { @@ -78,7 +78,7 @@ ], "description": "Allows the definition of input and output data types.", "context": { - "type": "org.eclipse.microprofile.openapi.annotations.Schema" + "type": "org.eclipse.microprofile.openapi.annotations.media.Schema" } }, "@Parameters": { @@ -93,7 +93,7 @@ ], "description": "Encapsulates input parameters.", "context": { - "type": "org.eclipse.microprofile.openapi.annotations.Parameters" + "type": "org.eclipse.microprofile.openapi.annotations.parameters.Parameters.Parameters" } }, "@Parameter": { @@ -110,7 +110,7 @@ ], "description": "Describes a single operation parameter.", "context": { - "type": "org.eclipse.microprofile.openapi.annotations.Parameter" + "type": "org.eclipse.microprofile.openapi.annotations.parameters.Parameter" } }, "@APIResponses": { @@ -125,7 +125,7 @@ ], "description": "A container for multiple responses from an API operation.", "context": { - "type": "org.eclipse.microprofile.openapi.annotations.APIResponses" + "type": "org.eclipse.microprofile.openapi.annotations.responses.APIResponses" } }, "@APIResponse": { @@ -142,7 +142,7 @@ ], "description": "Describes a single response from an API operation.", "context": { - "type": "org.eclipse.microprofile.openapi.annotations.APIResponse" + "type": "org.eclipse.microprofile.openapi.annotations.responses.APIResponse" } } } \ No newline at end of file diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/main/resources/com/redhat/quarkus/snippets/quarkus-java.json b/microprofile.ls/com.redhat.microprofile.ls/src/main/resources/com/redhat/quarkus/snippets/quarkus-java.json index 8f73466a4..3bd79b38d 100644 --- a/microprofile.ls/com.redhat.microprofile.ls/src/main/resources/com/redhat/quarkus/snippets/quarkus-java.json +++ b/microprofile.ls/com.redhat.microprofile.ls/src/main/resources/com/redhat/quarkus/snippets/quarkus-java.json @@ -19,7 +19,10 @@ "\t}", "}" ], - "description": "Quarkus REST resource class" + "description": "Quarkus REST resource class", + "context": { + "type": "javax.ws.rs.GET" + } }, "Quarkus - new resource method": { "prefix": "qrm", @@ -30,7 +33,10 @@ "\treturn \"hello\";", "}" ], - "description": "Quarkus REST resource method" + "description": "Quarkus REST resource method", + "context": { + "type": "javax.ws.rs.GET" + } }, "Quarkus - new test resource class": { "prefix": "qtrc", @@ -57,7 +63,10 @@ "", "}" ], - "description": "Quarkus test resource class" + "description": "Quarkus test resource class", + "context": { + "type": "io.quarkus.test.junit.QuarkusTest" + } }, "Quarkus - new native test resource class": { "prefix": "qntrc", @@ -72,6 +81,9 @@ "\t// Execute the same tests, but in native mode.", "}" ], - "description": "Quarkus native test resource class" + "description": "Quarkus native test resource class", + "context": { + "type": "io.quarkus.test.junit.SubstrateTest" + } } } \ No newline at end of file diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/main/resources/com/redhat/quarkus/snippets/quarkus-properties.json b/microprofile.ls/com.redhat.microprofile.ls/src/main/resources/com/redhat/quarkus/snippets/quarkus-properties.json index c2a142970..c26b18f5d 100644 --- a/microprofile.ls/com.redhat.microprofile.ls/src/main/resources/com/redhat/quarkus/snippets/quarkus-properties.json +++ b/microprofile.ls/com.redhat.microprofile.ls/src/main/resources/com/redhat/quarkus/snippets/quarkus-properties.json @@ -10,7 +10,7 @@ ], "description": "Configure Quarkus datasource", "context": { - "extension": "quarkus-agroal" + "dependency": "quarkus-agroal" } }, "Add Jaeger properties": { @@ -23,7 +23,7 @@ ], "description": "Configure Jaeger tracer", "context": { - "extension": "quarkus-jaeger" + "dependency": "quarkus-jaeger" } } } diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/ls/JavaTextDocumentsTest.java b/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/ls/JavaTextDocumentsTest.java index b71408e01..2e2938f96 100644 --- a/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/ls/JavaTextDocumentsTest.java +++ b/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/ls/JavaTextDocumentsTest.java @@ -58,7 +58,7 @@ public void inMicroProfileProject() throws InterruptedException, ExecutionExcept JavaTextDocuments documents = new JavaTextDocuments(PROVIDER); JavaTextDocument document1 = documents .createDocument(new TextDocumentItem(MP_PROJECT + "/file1.java", "", 0, "")); - CompletableFuture result = document1.executeIfInMicroProfileProject(() -> { + CompletableFuture result = document1.executeIfInMicroProfileProject((projectInfo) -> { // return the result of the execute return CompletableFuture.completedFuture(true); }, DEFAULT_VALUE); @@ -72,7 +72,7 @@ public void inNonMicroProfileProject() throws InterruptedException, ExecutionExc JavaTextDocuments documents = new JavaTextDocuments(PROVIDER); JavaTextDocument document1 = documents .createDocument(new TextDocumentItem(NOMP_PROJECT + "/file1.java", "", 0, "")); - CompletableFuture result = document1.executeIfInMicroProfileProject(() -> { + CompletableFuture result = document1.executeIfInMicroProfileProject((projectInfo) -> { // return the result of the execute return CompletableFuture.completedFuture(true); }, DEFAULT_VALUE); diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/ls/commons/snippets/SnippetRegistryTest.java b/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/ls/commons/snippets/SnippetRegistryTest.java index 550588360..1169b92e8 100644 --- a/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/ls/commons/snippets/SnippetRegistryTest.java +++ b/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/ls/commons/snippets/SnippetRegistryTest.java @@ -22,6 +22,8 @@ import org.junit.Assert; import org.junit.Test; +import com.redhat.microprofile.snippets.LanguageId; + /** * Test for snippet registry. * @@ -145,4 +147,10 @@ public void prefixCompletion() { assertCompletion("m |", registry, c("mp", "", r(0, 2, 2)), c("quarkus", "", r(0, 2, 2))); assertCompletion("m|", registry, c("mp", "", r(0, 0, 1)), c("quarkus", "", r(0, 0, 1))); } -} + + @Test + public void javaSnippets() { + TextDocumentSnippetRegistry registry = new TextDocumentSnippetRegistry(LanguageId.java.name()); + + } +} \ No newline at end of file