diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/profiles/ActiveProfilesProvider.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/profiles/ActiveProfilesProvider.java index 8c64296d0..73e3d275d 100644 --- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/profiles/ActiveProfilesProvider.java +++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/profiles/ActiveProfilesProvider.java @@ -12,22 +12,26 @@ package org.springframework.ide.vscode.boot.java.profiles; import java.util.Collection; import java.util.List; +import java.util.Optional; +import java.util.Set; import java.util.concurrent.CompletableFuture; import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.ASTVisitor; import org.eclipse.jdt.core.dom.Annotation; import org.eclipse.jdt.core.dom.ITypeBinding; -import org.eclipse.jdt.core.dom.Name; +import org.eclipse.jdt.core.dom.StringLiteral; import org.eclipse.lsp4j.Hover; import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.springframework.ide.vscode.boot.java.handlers.HoverProvider; import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp; -import org.springframework.ide.vscode.commons.util.BadLocationException; import org.springframework.ide.vscode.commons.util.Log; import org.springframework.ide.vscode.commons.util.text.TextDocument; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableList.Builder; +import com.google.common.collect.ImmutableSet; /** * @author Kris De Volder @@ -74,14 +78,65 @@ public class ActiveProfilesProvider implements HoverProvider { @Override public Collection getLiveHoverHints(Annotation annotation, TextDocument doc, SpringBootApp[] runningApps) { - try { - if (runningApps.length > 0) { - Name node = annotation.getTypeName(); - return ImmutableList.of(doc.toRange(node.getStartPosition(), node.getLength())); - } - } catch (BadLocationException e) { - Log.log(e); + if (runningApps.length > 0) { + Builder ranges = ImmutableList.builder(); + nameRange(doc, annotation).ifPresent(ranges::add); + + Set allActiveProfiles = getAllActiveProfiles(runningApps); + annotation.accept(new ASTVisitor() { + @Override + public boolean visit(StringLiteral node) { + String value = node.getLiteralValue(); + if (value!=null && allActiveProfiles.contains(value)) { + rangeOf(doc, node).ifPresent(ranges::add); + } + return true; + } + }); + return ranges.build(); } return ImmutableList.of(); } + + private static Set getAllActiveProfiles(SpringBootApp[] runningApps) { + ImmutableSet.Builder builder = ImmutableSet.builder(); + for (SpringBootApp app : runningApps) { + List profiles = app.getActiveProfiles(); + if (profiles!=null) { + builder.addAll(app.getActiveProfiles()); + } + } + return builder.build(); + } + + private static Optional nameRange(TextDocument doc, Annotation annotation) { + try { + int start = annotation.getTypeName().getStartPosition(); + int len = annotation.getTypeName().getLength(); + if (doc.getSafeChar(start-1)=='@') { + start--; len++; + } + return Optional.of(doc.toRange(start, len)); + } catch (Exception e) { + Log.log(e); + return Optional.empty(); + } + } + + private static Optional rangeOf(TextDocument doc, StringLiteral node) { + try { + int start = node.getStartPosition(); + int end = start + node.getLength(); + if (doc.getSafeChar(start)=='"') { + start++; + } + if (doc.getSafeChar(end-1)=='"') { + end--; + } + return Optional.of(doc.toRange(start, end-start)); + } catch (Exception e) { + Log.log(e); + return Optional.empty(); + } + } } diff --git a/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/profile/ActiveProfilesHoverTest.java b/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/profile/ActiveProfilesHoverTest.java index 016ba1bfb..97d70543b 100644 --- a/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/profile/ActiveProfilesHoverTest.java +++ b/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/profile/ActiveProfilesHoverTest.java @@ -60,18 +60,21 @@ public class ActiveProfilesHoverTest { "public class LocalConfig {\n" + "}" ); - editor.assertHoverContains("@Profile", "testing-profile"); - editor.assertHoverContains("@Profile", "local-profile"); - editor.assertHoverContains("@Profile", "foo.bar.RunningApp"); - editor.assertHoverContains("@Profile", "22022"); - //TODO: -// editor.assertHighlights( -// "@Profile", "local-profile", "testing-profile" -// ); + String[] hoverSites = { + "@Profile", "local-profile", "testing-profile" + }; + editor.assertHighlights( + hoverSites + ); + for (String hoverOver : hoverSites) { + editor.assertHoverContains(hoverOver, "testing-profile"); + editor.assertHoverContains(hoverOver, "local-profile"); + editor.assertHoverContains(hoverOver, "foo.bar.RunningApp"); + editor.assertHoverContains(hoverOver, "22022"); + } } - @Test public void testActiveProfileHover_Unknown() throws Exception { //Sometimes its not possible to determine active profiles for an app (e.g. no actuator dependency). @@ -97,6 +100,41 @@ public class ActiveProfilesHoverTest { "}" ); editor.assertHoverContains("@Profile", "Process [PID=22022, name=`foo.bar.RunningApp`] : _Unknown_"); + editor.assertHighlights("@Profile"); + } + + @Test + public void testActiveProfileHoverMixedKnownAndUnknown() throws Exception { + mockAppProvider.builder() + .isSpringBootApp(true) + .processId("22022") + .processName("foo.bar.NoActuatorApp") + .profilesUnknown() + .build(); + + mockAppProvider.builder() + .isSpringBootApp(true) + .processId("3456") + .processName("foo.bar.NormalApp") + .profiles("fancy") + .build(); + + Editor editor = harness.newEditor(LanguageId.JAVA, + "package hello;\n" + + "\n" + + "import org.springframework.context.annotation.Configuration;\n" + + "import org.springframework.context.annotation.Profile;\n" + + "\n" + + "@Configuration\n" + + "@Profile({\"unknown\", \"inactive\", \"fancy\"})\n" + + "public class LocalConfig {\n" + + "\n" + + "}" + ); + + editor.assertHighlights("@Profile", "fancy"); + editor.assertHoverContains("@Profile", "Unknown"); + editor.assertHoverContains("@Profile", "fancy"); } @Test @@ -114,5 +152,6 @@ public class ActiveProfilesHoverTest { "}" ); editor.assertNoHover("@Profile"); + editor.assertHighlights(/*NONE*/); } }