From d8e0c7df164b8456747ba467c454dca111b87506 Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Mon, 28 Aug 2023 16:56:45 +0200 Subject: [PATCH] feat: expose Qute server settings Signed-off-by: Fred Bricon --- .../settings/MicroProfileInspectionsInfo.java | 39 ++-- .../UserDefinedMicroProfileSettings.java | 23 ++- .../quarkus/lsp/QuarkusLanguageClient.java | 2 +- .../intellij/quarkus/lsp/QuarkusServer.java | 3 +- .../intellij/qute/lsp/QuteLanguageClient.java | 39 +++- .../intellij/qute/lsp/QuteServer.java | 8 +- .../AbstractDelegateInspection.java | 22 +++ .../QuteUndefinedNamespaceInspection.java | 21 +++ .../QuteUndefinedObjectInspection.java | 21 +++ .../qute/settings/ProblemSeverity.java | 46 +++++ .../qute/settings/QuteInspectionsInfo.java | 71 ++++++++ .../settings/UserDefinedQuteSettings.java | 170 ++++++++++++++++++ src/main/resources/META-INF/lsp4ij-qute.xml | 21 +++ .../QuteUndefinedNamespace.html | 17 ++ .../QuteUndefinedObject.html | 17 ++ .../resources/messages/QuteBundle.properties | 4 + 16 files changed, 487 insertions(+), 37 deletions(-) create mode 100644 src/main/java/com/redhat/devtools/intellij/qute/psi/core/inspections/AbstractDelegateInspection.java create mode 100644 src/main/java/com/redhat/devtools/intellij/qute/psi/core/inspections/QuteUndefinedNamespaceInspection.java create mode 100644 src/main/java/com/redhat/devtools/intellij/qute/psi/core/inspections/QuteUndefinedObjectInspection.java create mode 100644 src/main/java/com/redhat/devtools/intellij/qute/settings/ProblemSeverity.java create mode 100644 src/main/java/com/redhat/devtools/intellij/qute/settings/QuteInspectionsInfo.java create mode 100644 src/main/java/com/redhat/devtools/intellij/qute/settings/UserDefinedQuteSettings.java create mode 100644 src/main/resources/inspectionDescriptions/QuteUndefinedNamespace.html create mode 100644 src/main/resources/inspectionDescriptions/QuteUndefinedObject.html diff --git a/src/main/java/com/redhat/devtools/intellij/lsp4mp4ij/settings/MicroProfileInspectionsInfo.java b/src/main/java/com/redhat/devtools/intellij/lsp4mp4ij/settings/MicroProfileInspectionsInfo.java index da47383a6..fc0dbf048 100644 --- a/src/main/java/com/redhat/devtools/intellij/lsp4mp4ij/settings/MicroProfileInspectionsInfo.java +++ b/src/main/java/com/redhat/devtools/intellij/lsp4mp4ij/settings/MicroProfileInspectionsInfo.java @@ -31,7 +31,6 @@ public class MicroProfileInspectionsInfo { //See https://github.com/eclipse/lsp4mp/blob/6b483c4d292bfebabd13311d6217291da2d5d169/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/settings/MicroProfileValidationSettings.java#L36 - private boolean enabled = true; private ProblemSeverity syntaxSeverity = ProblemSeverity.error; private ProblemSeverity unknownSeverity = ProblemSeverity.warning; private ProblemSeverity duplicateSeverity = ProblemSeverity.warning; @@ -45,30 +44,17 @@ private MicroProfileInspectionsInfo() { public static MicroProfileInspectionsInfo getMicroProfileInspectionInfo(Project project) { MicroProfileInspectionsInfo wrapper = new MicroProfileInspectionsInfo(); InspectionProfile profile = InspectionProfileManager.getInstance(project).getCurrentProfile(); - boolean syntaxEnabled = isInspectionEnabled(MicroProfilePropertiesSyntaxInspection.ID, profile); - boolean unknownEnabled = isInspectionEnabled(MicroProfilePropertiesUnknownInspection.ID, profile); - boolean duplicatedEnabled = isInspectionEnabled(MicroProfilePropertiesDuplicatesInspection.ID, profile); - boolean valueEnabled = isInspectionEnabled(MicroProfilePropertiesValueInspection.ID, profile); - boolean requiredEnabled = isInspectionEnabled(MicroProfilePropertiesRequiredInspection.ID, profile); - boolean expressionsEnabled = isInspectionEnabled(MicroProfilePropertiesExpressionsInspection.ID, profile); - wrapper.enabled = syntaxEnabled - || unknownEnabled - || duplicatedEnabled - || valueEnabled - || requiredEnabled - || expressionsEnabled; - - wrapper.syntaxSeverity = getSeverity(syntaxEnabled, MicroProfilePropertiesSyntaxInspection.ID, profile); - wrapper.unknownSeverity = getSeverity(unknownEnabled, MicroProfilePropertiesUnknownInspection.ID, profile); - wrapper.duplicateSeverity = getSeverity(duplicatedEnabled, MicroProfilePropertiesDuplicatesInspection.ID, profile); - wrapper.valueSeverity = getSeverity(valueEnabled, MicroProfilePropertiesValueInspection.ID, profile); - wrapper.requiredSeverity = getSeverity(requiredEnabled, MicroProfilePropertiesRequiredInspection.ID, profile); - wrapper.expressionSeverity = getSeverity(expressionsEnabled, MicroProfilePropertiesExpressionsInspection.ID, profile); + wrapper.syntaxSeverity = getSeverity(MicroProfilePropertiesSyntaxInspection.ID, profile); + wrapper.unknownSeverity = getSeverity(MicroProfilePropertiesUnknownInspection.ID, profile); + wrapper.duplicateSeverity = getSeverity(MicroProfilePropertiesDuplicatesInspection.ID, profile); + wrapper.valueSeverity = getSeverity(MicroProfilePropertiesValueInspection.ID, profile); + wrapper.requiredSeverity = getSeverity(MicroProfilePropertiesRequiredInspection.ID, profile); + wrapper.expressionSeverity = getSeverity(MicroProfilePropertiesExpressionsInspection.ID, profile); return wrapper; } - private static ProblemSeverity getSeverity(boolean enabled, String inspectionId, InspectionProfile profile) { - if (!enabled) { + private static ProblemSeverity getSeverity(String inspectionId, InspectionProfile profile) { + if (!isInspectionEnabled(inspectionId, profile)) { return ProblemSeverity.none; } return ProblemSeverity.getSeverity(getErrorLevel(inspectionId, profile)); @@ -84,10 +70,6 @@ private static boolean isInspectionEnabled(@NotNull String inspectionId, @NotNul return profile.isToolEnabled(HighlightDisplayKey.find(inspectionId)); } - public boolean enabled() { - return enabled; - } - public ProblemSeverity unknownSeverity() { return unknownSeverity; } @@ -117,15 +99,14 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; MicroProfileInspectionsInfo that = (MicroProfileInspectionsInfo) o; - return enabled == that.enabled - && syntaxSeverity == that.syntaxSeverity && unknownSeverity == that.unknownSeverity + return syntaxSeverity == that.syntaxSeverity && unknownSeverity == that.unknownSeverity && duplicateSeverity == that.duplicateSeverity && valueSeverity == that.valueSeverity && requiredSeverity == that.requiredSeverity && expressionSeverity == that.expressionSeverity; } @Override public int hashCode() { - return Objects.hash(enabled, syntaxSeverity, unknownSeverity, duplicateSeverity, valueSeverity, requiredSeverity, + return Objects.hash(syntaxSeverity, unknownSeverity, duplicateSeverity, valueSeverity, requiredSeverity, expressionSeverity); } } diff --git a/src/main/java/com/redhat/devtools/intellij/lsp4mp4ij/settings/UserDefinedMicroProfileSettings.java b/src/main/java/com/redhat/devtools/intellij/lsp4mp4ij/settings/UserDefinedMicroProfileSettings.java index 750c88029..7bc264188 100644 --- a/src/main/java/com/redhat/devtools/intellij/lsp4mp4ij/settings/UserDefinedMicroProfileSettings.java +++ b/src/main/java/com/redhat/devtools/intellij/lsp4mp4ij/settings/UserDefinedMicroProfileSettings.java @@ -44,6 +44,12 @@ public class UserDefinedMicroProfileSettings implements PersistentStateComponent private volatile MyState myState = new MyState(); + private final Project project; + + public UserDefinedMicroProfileSettings(Project project) { + this.project = project; + } + private final List myChangeHandlers = ContainerUtil.createConcurrentList(); public static @NotNull UserDefinedMicroProfileSettings getInstance(@NotNull Project project) { @@ -63,6 +69,13 @@ public void fireStateChanged() { handler.run(); } } + public boolean isValidationEnabled() { + return myState.myValidationEnabled; + } + + public void setValidationEnabled(boolean validationEnabled) { + myState.myValidationEnabled = validationEnabled; + } // ---------- Properties @@ -103,8 +116,8 @@ public void loadState(@NotNull MyState state) { * * @return the proper settings expected by the MicroProfile language server. */ - public Map toSettingsForMicroProfileLS(MicroProfileInspectionsInfo inspectionsInfo) { - + public Map toSettingsForMicroProfileLS() { + MicroProfileInspectionsInfo inspectionsInfo = MicroProfileInspectionsInfo.getMicroProfileInspectionInfo(project); Map settings = new HashMap<>(); Map microprofile = new HashMap<>(); settings.put("microprofile", microprofile); @@ -125,7 +138,7 @@ public Map toSettingsForMicroProfileLS(MicroProfileInspectionsIn Map validation = new HashMap<>(); tools.put("validation", validation); - validation.put("enabled", inspectionsInfo.enabled()); + validation.put("enabled", isValidationEnabled()); validation.put("syntax", getSeverityNode(inspectionsInfo.syntaxSeverity())); validation.put("unknown", getSeverityNode(inspectionsInfo.unknownSeverity())); validation.put("duplicate", getSeverityNode(inspectionsInfo.duplicateSeverity())); @@ -141,6 +154,10 @@ private Map getSeverityNode(ProblemSeverity severity) { public static class MyState { + + @Tag("validationEnabled") + public boolean myValidationEnabled = true; + @Tag("inlayHintEnabled") public boolean myInlayHintEnabled = true; diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/lsp/QuarkusLanguageClient.java b/src/main/java/com/redhat/devtools/intellij/quarkus/lsp/QuarkusLanguageClient.java index f453f86fa..ca4020279 100644 --- a/src/main/java/com/redhat/devtools/intellij/quarkus/lsp/QuarkusLanguageClient.java +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/lsp/QuarkusLanguageClient.java @@ -74,7 +74,7 @@ public void dispose() { @Override protected Object createSettings() { - return UserDefinedMicroProfileSettings.getInstance(getProject()).toSettingsForMicroProfileLS(inspectionsInfo); + return UserDefinedMicroProfileSettings.getInstance(getProject()).toSettingsForMicroProfileLS(); } private void sendPropertiesChangeEvent(List scope, Set uris) { diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/lsp/QuarkusServer.java b/src/main/java/com/redhat/devtools/intellij/quarkus/lsp/QuarkusServer.java index 12c025e5e..8854529ec 100644 --- a/src/main/java/com/redhat/devtools/intellij/quarkus/lsp/QuarkusServer.java +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/lsp/QuarkusServer.java @@ -53,8 +53,7 @@ public QuarkusServer(Project project) { @Override public Object getInitializationOptions(URI rootUri) { Map root = new HashMap<>(); - MicroProfileInspectionsInfo inspectionsInfo = MicroProfileInspectionsInfo.getMicroProfileInspectionInfo(project); - Map settings = UserDefinedMicroProfileSettings.getInstance(project).toSettingsForMicroProfileLS(inspectionsInfo); + Map settings = UserDefinedMicroProfileSettings.getInstance(project).toSettingsForMicroProfileLS(); root.put("settings", settings); Map extendedClientCapabilities = new HashMap<>(); diff --git a/src/main/java/com/redhat/devtools/intellij/qute/lsp/QuteLanguageClient.java b/src/main/java/com/redhat/devtools/intellij/qute/lsp/QuteLanguageClient.java index 741067acb..fdf5e8225 100644 --- a/src/main/java/com/redhat/devtools/intellij/qute/lsp/QuteLanguageClient.java +++ b/src/main/java/com/redhat/devtools/intellij/qute/lsp/QuteLanguageClient.java @@ -10,19 +10,28 @@ ******************************************************************************/ package com.redhat.devtools.intellij.qute.lsp; +import com.intellij.codeInspection.InspectionProfile; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.module.Module; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.profile.ProfileChangeAdapter; import com.intellij.util.messages.MessageBusConnection; import com.redhat.devtools.intellij.lsp4ij.client.CoalesceByKey; import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.project.PsiMicroProfileProjectManager; import com.redhat.devtools.intellij.lsp4mp4ij.psi.internal.core.ls.PsiUtilsLSImpl; import com.redhat.devtools.intellij.lsp4ij.client.IndexAwareLanguageClient; import com.redhat.devtools.intellij.lsp4mp4ij.classpath.ClasspathResourceChangedManager; +import com.redhat.devtools.intellij.lsp4mp4ij.settings.UserDefinedMicroProfileSettings; import com.redhat.devtools.intellij.qute.psi.QuteSupportForJava; import com.redhat.devtools.intellij.qute.psi.QuteSupportForTemplate; import com.redhat.devtools.intellij.qute.psi.utils.PsiQuteProjectUtils; +import com.redhat.devtools.intellij.qute.settings.QuteInspectionsInfo; +import com.redhat.devtools.intellij.qute.settings.UserDefinedQuteSettings; import com.redhat.qute.commons.GenerateMissingJavaMemberParams; import com.redhat.qute.commons.JavaTypeInfo; import com.redhat.qute.commons.ProjectInfo; @@ -49,11 +58,13 @@ import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.PublishDiagnosticsParams; import org.eclipse.lsp4j.WorkspaceEdit; +import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; @@ -61,13 +72,17 @@ /** * Qute language client. */ -public class QuteLanguageClient extends IndexAwareLanguageClient implements QuteLanguageClientAPI, ClasspathResourceChangedManager.Listener { +public class QuteLanguageClient extends IndexAwareLanguageClient implements QuteLanguageClientAPI, ClasspathResourceChangedManager.Listener, ProfileChangeAdapter { private final MessageBusConnection connection; + private QuteInspectionsInfo inspectionsInfo; + public QuteLanguageClient(Project project) { super(project); connection = project.getMessageBus().connect(project); connection.subscribe(ClasspathResourceChangedManager.TOPIC, this); + inspectionsInfo = QuteInspectionsInfo.getQuteInspectionsInfo(project); + connection.subscribe(ProfileChangeAdapter.TOPIC, this); } @Override @@ -91,6 +106,28 @@ private void notifyQuteDataModelChanged(Set uris) { } } + @Override + protected Object createSettings() { + return UserDefinedQuteSettings.getInstance(getProject()).toSettingsForQuteLS(); + } + + @Override + public void profileChanged(@NotNull InspectionProfile profile) { + // Track Qute inspections settings (declared in Editor/Inspection/Qute UI settings) changed, + // convert them to matching Qute configuration and push them via 'workspace/didChangeConfiguration'. + QuteInspectionsInfo newInspectionState = QuteInspectionsInfo.getQuteInspectionsInfo(getProject()); + if (!Objects.equals(newInspectionState, inspectionsInfo)) { + inspectionsInfo = newInspectionState; + ApplicationManager.getApplication().invokeLater(() -> { + new Task.Backgroundable(getProject(), "Updating Qute LS configuration...", true) { + @Override + public void run(@NotNull ProgressIndicator progressIndicator) { + triggerChangeConfiguration(); + } + }.queue(); + }, ModalityState.defaultModalityState(), getProject().getDisposed()); + } + } @Override public void librariesChanged() { if (isDisposed()) { diff --git a/src/main/java/com/redhat/devtools/intellij/qute/lsp/QuteServer.java b/src/main/java/com/redhat/devtools/intellij/qute/lsp/QuteServer.java index a999a8a12..fcd5c49fb 100644 --- a/src/main/java/com/redhat/devtools/intellij/qute/lsp/QuteServer.java +++ b/src/main/java/com/redhat/devtools/intellij/qute/lsp/QuteServer.java @@ -14,9 +14,12 @@ import com.intellij.ide.plugins.PluginManager; import com.intellij.openapi.extensions.PluginId; import com.intellij.openapi.project.Project; +import com.redhat.devtools.intellij.lsp4mp4ij.settings.UserDefinedMicroProfileSettings; import com.redhat.devtools.intellij.quarkus.TelemetryService; import com.redhat.devtools.intellij.lsp4ij.server.JavaProcessCommandBuilder; import com.redhat.devtools.intellij.lsp4ij.server.ProcessStreamConnectionProvider; +import com.redhat.devtools.intellij.qute.settings.QuteInspectionsInfo; +import com.redhat.devtools.intellij.qute.settings.UserDefinedQuteSettings; import java.io.File; import java.net.URI; @@ -30,7 +33,10 @@ */ public class QuteServer extends ProcessStreamConnectionProvider { + private final Project project; + public QuteServer(Project project) { + this.project = project; IdeaPluginDescriptor descriptor = PluginManager.getPlugin(PluginId.getId("com.redhat.devtools.intellij.quarkus")); File quteServerPath = new File(descriptor.getPath(), "lib/server/com.redhat.qute.ls-uber.jar"); @@ -46,7 +52,7 @@ public QuteServer(Project project) { @Override public Object getInitializationOptions(URI rootUri) { Map root = new HashMap<>(); - Map settings = QuteUtils.getQuteSettings(); + Map settings = UserDefinedQuteSettings.getInstance(project).toSettingsForQuteLS(); Map extendedClientCapabilities = new HashMap<>(); Map commands = new HashMap<>(); Map commandsKind = new HashMap<>(); diff --git a/src/main/java/com/redhat/devtools/intellij/qute/psi/core/inspections/AbstractDelegateInspection.java b/src/main/java/com/redhat/devtools/intellij/qute/psi/core/inspections/AbstractDelegateInspection.java new file mode 100644 index 000000000..6e248a850 --- /dev/null +++ b/src/main/java/com/redhat/devtools/intellij/qute/psi/core/inspections/AbstractDelegateInspection.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2023 Red Hat Inc. and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + *******************************************************************************/ +package com.redhat.devtools.intellij.qute.psi.core.inspections; + +import com.intellij.codeInspection.LocalInspectionTool; + +/** + * No-op {@link LocalInspectionTool} used as a basis for mapping inspection severities to matching LSP severities. + */ +public abstract class AbstractDelegateInspection extends LocalInspectionTool { +} diff --git a/src/main/java/com/redhat/devtools/intellij/qute/psi/core/inspections/QuteUndefinedNamespaceInspection.java b/src/main/java/com/redhat/devtools/intellij/qute/psi/core/inspections/QuteUndefinedNamespaceInspection.java new file mode 100644 index 000000000..29a3ea16e --- /dev/null +++ b/src/main/java/com/redhat/devtools/intellij/qute/psi/core/inspections/QuteUndefinedNamespaceInspection.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2023 Red Hat Inc. and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + *******************************************************************************/ +package com.redhat.devtools.intellij.qute.psi.core.inspections; + +/** + * Dummy inspection for undefined namespaces in Qute templates + */ +public class QuteUndefinedNamespaceInspection extends AbstractDelegateInspection { + public static final String ID = getShortName(QuteUndefinedNamespaceInspection.class.getSimpleName()); +} diff --git a/src/main/java/com/redhat/devtools/intellij/qute/psi/core/inspections/QuteUndefinedObjectInspection.java b/src/main/java/com/redhat/devtools/intellij/qute/psi/core/inspections/QuteUndefinedObjectInspection.java new file mode 100644 index 000000000..1fce8e42f --- /dev/null +++ b/src/main/java/com/redhat/devtools/intellij/qute/psi/core/inspections/QuteUndefinedObjectInspection.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2023 Red Hat Inc. and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + *******************************************************************************/ +package com.redhat.devtools.intellij.qute.psi.core.inspections; + +/** + * Dummy inspection for undefined objects in Qute templates + */ +public class QuteUndefinedObjectInspection extends AbstractDelegateInspection { + public static final String ID = getShortName(QuteUndefinedObjectInspection.class.getSimpleName()); +} diff --git a/src/main/java/com/redhat/devtools/intellij/qute/settings/ProblemSeverity.java b/src/main/java/com/redhat/devtools/intellij/qute/settings/ProblemSeverity.java new file mode 100644 index 000000000..3a5589176 --- /dev/null +++ b/src/main/java/com/redhat/devtools/intellij/qute/settings/ProblemSeverity.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2023 Red Hat Inc. and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + *******************************************************************************/ +package com.redhat.devtools.intellij.qute.settings; + +import com.intellij.lang.annotation.HighlightSeverity; +import org.jetbrains.annotations.NotNull; + +/** + * Problem severity levels used by Qute LS + */ +//TODO move to lsp4ij? +public enum ProblemSeverity { + none, warning, error; + + /** + * Maps {@link HighlightSeverity} to {@link ProblemSeverity} levels used by LSP4MP. + *
    + *
  • Any severity below HighlightSeverity.WEAK_WARNING is mapped to ProblemSeverity.none
  • + *
  • Any severity below HighlightSeverity.ERROR is mapped to ProblemSeverity.warning
  • + *
  • Any other severity is mapped to ProblemSeverity.error
  • + *
+ * + * @param highlightSeverity the severity to map to a {@link ProblemSeverity} + * @return the matching {@link ProblemSeverity} + */ + public static @NotNull ProblemSeverity getSeverity(@NotNull HighlightSeverity highlightSeverity) { + if (HighlightSeverity.WEAK_WARNING.compareTo(highlightSeverity) > 0) { + return none; + } + if (HighlightSeverity.ERROR.compareTo(highlightSeverity) > 0) { + return warning; + } + return error; + } +} diff --git a/src/main/java/com/redhat/devtools/intellij/qute/settings/QuteInspectionsInfo.java b/src/main/java/com/redhat/devtools/intellij/qute/settings/QuteInspectionsInfo.java new file mode 100644 index 000000000..77c063904 --- /dev/null +++ b/src/main/java/com/redhat/devtools/intellij/qute/settings/QuteInspectionsInfo.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2023 Red Hat Inc. and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + *******************************************************************************/ +package com.redhat.devtools.intellij.qute.settings; + +import com.intellij.codeHighlighting.HighlightDisplayLevel; +import com.intellij.codeInsight.daemon.HighlightDisplayKey; +import com.intellij.codeInspection.InspectionProfile; +import com.intellij.lang.annotation.HighlightSeverity; +import com.intellij.openapi.project.Project; +import com.intellij.profile.codeInspection.InspectionProfileManager; +import com.redhat.devtools.intellij.qute.psi.core.inspections.QuteUndefinedNamespaceInspection; +import com.redhat.devtools.intellij.qute.psi.core.inspections.QuteUndefinedObjectInspection; +import org.jetbrains.annotations.NotNull; + +/** + * Contains Qute inspection settings relevant to Qute LS configuration + */ +//TODO switch to a record, when Java 17 is required +public class QuteInspectionsInfo { + + private ProblemSeverity undefinedObjectSeverity = ProblemSeverity.warning; + private ProblemSeverity undefinedNamespaceSeverity = ProblemSeverity.warning; + + private QuteInspectionsInfo() { + } + + public static QuteInspectionsInfo getQuteInspectionsInfo(Project project) { + QuteInspectionsInfo wrapper = new QuteInspectionsInfo(); + InspectionProfile profile = InspectionProfileManager.getInstance(project).getCurrentProfile(); + wrapper.undefinedObjectSeverity = getSeverity(QuteUndefinedObjectInspection.ID, profile); + wrapper.undefinedNamespaceSeverity = getSeverity(QuteUndefinedNamespaceInspection.ID, profile); + return wrapper; + } + + private static ProblemSeverity getSeverity(String inspectionId, InspectionProfile profile) { + if (!isInspectionEnabled(inspectionId, profile)) { + return ProblemSeverity.none; + } + return ProblemSeverity.getSeverity(getErrorLevel(inspectionId, profile)); + + } + + private static @NotNull HighlightSeverity getErrorLevel(String inspectionId, InspectionProfile profile) { + HighlightDisplayLevel level = profile.getErrorLevel(HighlightDisplayKey.find(inspectionId), null); + return level.getSeverity(); + } + + private static boolean isInspectionEnabled(@NotNull String inspectionId, @NotNull InspectionProfile profile) { + return profile.isToolEnabled(HighlightDisplayKey.find(inspectionId)); + } + + public ProblemSeverity undefinedObjectSeverity() { + return undefinedObjectSeverity; + } + + public ProblemSeverity undefinedNamespaceSeverity() { + return undefinedNamespaceSeverity; + } + +} diff --git a/src/main/java/com/redhat/devtools/intellij/qute/settings/UserDefinedQuteSettings.java b/src/main/java/com/redhat/devtools/intellij/qute/settings/UserDefinedQuteSettings.java new file mode 100644 index 000000000..bafda9575 --- /dev/null +++ b/src/main/java/com/redhat/devtools/intellij/qute/settings/UserDefinedQuteSettings.java @@ -0,0 +1,170 @@ +/******************************************************************************* + * Copyright (c) 2023 Red Hat Inc. and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + *******************************************************************************/ +package com.redhat.devtools.intellij.qute.settings; + +import com.intellij.openapi.components.PersistentStateComponent; +import com.intellij.openapi.components.State; +import com.intellij.openapi.components.Storage; +import com.intellij.openapi.project.Project; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.xmlb.annotations.Tag; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * User defined Qute settings + * + *
    + *
  • validation
  • + *
+ */ +@State( + name = "QuteSettingsState", + storages = {@Storage("quteSettings.xml")} +) +public class UserDefinedQuteSettings implements PersistentStateComponent { + + private volatile MyState myState = new MyState(); + + private final Project project; + + public UserDefinedQuteSettings(Project project) { + this.project = project; + } + + private final List myChangeHandlers = ContainerUtil.createConcurrentList(); + + public static @NotNull UserDefinedQuteSettings getInstance(@NotNull Project project) { + return project.getService(UserDefinedQuteSettings.class); + } + + public void addChangeHandler(Runnable runnable) { + myChangeHandlers.add(runnable); + } + + public void removeChangeHandler(Runnable runnable) { + myChangeHandlers.remove(runnable); + } + + public void fireStateChanged() { + for (Runnable handler : myChangeHandlers) { + handler.run(); + } + } + + public boolean isValidationEnabled() { + return myState.myValidationEnabled; + } + + public void setValidationEnabled(boolean validationEnabled) { + myState.myValidationEnabled = validationEnabled; + } + + @Nullable + @Override + public MyState getState() { + return myState; + } + + @Override + public void loadState(@NotNull MyState state) { + myState = state; + for (Runnable handler : myChangeHandlers) { + handler.run(); + } + } + + /** + * Returns the proper settings expected by the Qute language server. + * + * @return the proper settings expected by the Qute language server. + */ + public Map toSettingsForQuteLS() { + /* + "settings": { + "qute": { + "server": { + "vmargs": "-Xmx100M -XX:+UseG1GC -XX:+UseStringDeduplication -Xlog:disable" + }, + "templates": { + "languageMismatch": "force" + }, + "trace": { + "server": "verbose" + }, + "codeLens": { + "enabled": true + }, + "inlayHint": { + "enabled": true, + "showSectionParameterType": true, + "showSectionParameterDefaultValue": true + }, + "native": { + "enabled": false + }, + "validation": { + "enabled": true, + "excluded": [], + "undefinedObject": { + "severity": "warning" + }, + "undefinedNamespace": { + "severity": "warning" + } + } + } + */ + QuteInspectionsInfo inspectionsInfo = QuteInspectionsInfo.getQuteInspectionsInfo(project); + Map settings = new HashMap<>(); + + Map qute = new HashMap<>(); + settings.put("qute", qute); + qute.put("workspaceFolders", new HashMap()); + + // Inlay hint + qute.put("inlayHint", Collections.singletonMap("enabled", true)); + + //Code lens + qute.put("codelens", Collections.singletonMap("enabled", true)); + + // Validation + Map validation = new HashMap<>(); + qute.put("validation", validation); + validation.put("enabled", isValidationEnabled()); + validation.put("undefinedObject", getSeverityNode(inspectionsInfo.undefinedObjectSeverity())); + validation.put("undefinedNamespace", getSeverityNode(inspectionsInfo.undefinedNamespaceSeverity())); + return settings; + } + + private Map getSeverityNode(ProblemSeverity severity) { + return Collections.singletonMap("severity", severity.name()); + } + + public static class MyState { + + @Tag("validationEnabled") + public boolean myValidationEnabled = true; + + MyState() { + } + + } + +} diff --git a/src/main/resources/META-INF/lsp4ij-qute.xml b/src/main/resources/META-INF/lsp4ij-qute.xml index 2e2e43b31..93bc73aa7 100644 --- a/src/main/resources/META-INF/lsp4ij-qute.xml +++ b/src/main/resources/META-INF/lsp4ij-qute.xml @@ -45,6 +45,27 @@ implementationClass="com.redhat.devtools.intellij.lsp4ij.operations.documentLink.LSPDocumentLinkAnnotator"/> + + + + diff --git a/src/main/resources/inspectionDescriptions/QuteUndefinedNamespace.html b/src/main/resources/inspectionDescriptions/QuteUndefinedNamespace.html new file mode 100644 index 000000000..927a10935 --- /dev/null +++ b/src/main/resources/inspectionDescriptions/QuteUndefinedNamespace.html @@ -0,0 +1,17 @@ + + +Reports undefined namespaces in Qute templates files. +

+
+

+ ⚠ This inspection is used to configure the Qute support server in Settings | Languages & Frameworks | Language Servers.

+ Consequently, some limitations apply: +

+
    +
  • Scope: values are ignored
  • +
  • Severity: only Error and (Weak) Warning are respected. Other values mean no errors will be reported
  • +
  • Highlighting in Editor: values are ignored
  • +
+
+ + \ No newline at end of file diff --git a/src/main/resources/inspectionDescriptions/QuteUndefinedObject.html b/src/main/resources/inspectionDescriptions/QuteUndefinedObject.html new file mode 100644 index 000000000..b115d3f78 --- /dev/null +++ b/src/main/resources/inspectionDescriptions/QuteUndefinedObject.html @@ -0,0 +1,17 @@ + + +Reports undefined objects in Qute templates files. +

+
+

+ ⚠ This inspection is used to configure the Qute support server in Settings | Languages & Frameworks | Language Servers.

+ Consequently, some limitations apply: +

+
    +
  • Scope: values are ignored
  • +
  • Severity: only Error and (Weak) Warning are respected. Other values mean no errors will be reported
  • +
  • Highlighting in Editor: values are ignored
  • +
+
+ + \ No newline at end of file diff --git a/src/main/resources/messages/QuteBundle.properties b/src/main/resources/messages/QuteBundle.properties index 95fb60633..c34ce0d94 100644 --- a/src/main/resources/messages/QuteBundle.properties +++ b/src/main/resources/messages/QuteBundle.properties @@ -20,3 +20,7 @@ options.qute.attribute.descriptor.string=String options.qute.attribute.descriptor.numeric=Numeric options.qute.attribute.descriptor.boolean=Boolean options.qute.attribute.descriptor.keyword=Keyword +qute.inspection.group.name=Qute +qute.templates.inspection.group.name=Templates +qute.templates.validation.undefinedNamespace=Undefined namespaces +qute.templates.validation.undefinedObject=Undefined objects