From eaa1061e6e89df8a53c35344464bc92a9b43f84e Mon Sep 17 00:00:00 2001 From: Arun Venmany Date: Mon, 2 Dec 2024 15:18:08 +0530 Subject: [PATCH] Code completion for variable on attribute value Signed-off-by: Arun Venmany --- .../lemminx/LibertyCompletionParticipant.java | 26 +++++ .../lemminx/LibertyHoverParticipant.java | 3 +- .../io/openliberty/LibertyCompletionTest.java | 103 ++++++++++++++++++ 3 files changed, 130 insertions(+), 2 deletions(-) diff --git a/lemminx-liberty/src/main/java/io/openliberty/tools/langserver/lemminx/LibertyCompletionParticipant.java b/lemminx-liberty/src/main/java/io/openliberty/tools/langserver/lemminx/LibertyCompletionParticipant.java index 83c9dc6..9226cc8 100644 --- a/lemminx-liberty/src/main/java/io/openliberty/tools/langserver/lemminx/LibertyCompletionParticipant.java +++ b/lemminx-liberty/src/main/java/io/openliberty/tools/langserver/lemminx/LibertyCompletionParticipant.java @@ -16,6 +16,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.Properties; import java.util.Set; import java.util.stream.Collectors; @@ -28,6 +29,7 @@ import org.eclipse.lemminx.services.extensions.completion.ICompletionResponse; import org.eclipse.lemminx.utils.XMLPositionUtility; import org.eclipse.lsp4j.CompletionItem; +import org.eclipse.lsp4j.CompletionItemKind; import org.eclipse.lsp4j.InsertReplaceEdit; import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.TextEdit; @@ -43,6 +45,30 @@ public class LibertyCompletionParticipant extends CompletionParticipantAdapter { + + @Override + public void onAttributeValue(String valuePrefix, ICompletionRequest request, ICompletionResponse response, CancelChecker cancelChecker) throws Exception { + if (!LibertyUtils.isConfigXMLFile(request.getXMLDocument())) + return; + Properties variableProps = SettingsService.getInstance().getVariables(); + String variableName = valuePrefix.replace("$", "") + .replace("{", "") + .replace("}", ""); + variableProps.entrySet().stream().filter(it -> it.getKey().toString().contains(variableName)) + .forEach(variableProp -> { + String varValue = String.format("${%s}", variableProp.getKey()); + + Either edit = Either.forLeft(new + TextEdit(request.getReplaceRange(), varValue)); + CompletionItem completionItem = new CompletionItem(); + completionItem.setLabel(variableProp.getKey().toString()); + completionItem.setTextEdit(edit); + completionItem.setFilterText(variableProp.getKey().toString()); + completionItem.setKind(CompletionItemKind.Value); + response.addCompletionItem(completionItem); + }); + } + @Override public void onXMLContent(ICompletionRequest request, ICompletionResponse response, CancelChecker cancelChecker) throws IOException, BadLocationException { diff --git a/lemminx-liberty/src/main/java/io/openliberty/tools/langserver/lemminx/LibertyHoverParticipant.java b/lemminx-liberty/src/main/java/io/openliberty/tools/langserver/lemminx/LibertyHoverParticipant.java index b19f96d..c61d5ab 100644 --- a/lemminx-liberty/src/main/java/io/openliberty/tools/langserver/lemminx/LibertyHoverParticipant.java +++ b/lemminx-liberty/src/main/java/io/openliberty/tools/langserver/lemminx/LibertyHoverParticipant.java @@ -45,8 +45,7 @@ public Hover onAttributeName(IHoverRequest request, CancelChecker cancelChecker) } @Override - public Hover onAttributeValue(IHoverRequest request, CancelChecker cancelChecker) { - List variables = LibertyUtils.getVariablesFromTextContent(request.getNode().getTextContent()); + public Hover onAttributeValue(IHoverRequest request, CancelChecker cancelChecker) {List variables = LibertyUtils.getVariablesFromTextContent(request.getNode().getTextContent()); if(variables.size() == 1){ Properties variableMap = SettingsService.getInstance().getVariables(); diff --git a/lemminx-liberty/src/test/java/io/openliberty/LibertyCompletionTest.java b/lemminx-liberty/src/test/java/io/openliberty/LibertyCompletionTest.java index 0663f4f..568f301 100644 --- a/lemminx-liberty/src/test/java/io/openliberty/LibertyCompletionTest.java +++ b/lemminx-liberty/src/test/java/io/openliberty/LibertyCompletionTest.java @@ -1,17 +1,47 @@ package io.openliberty; +import io.openliberty.tools.langserver.lemminx.services.SettingsService; import org.eclipse.lemminx.XMLAssert; import org.eclipse.lemminx.commons.BadLocationException; import org.eclipse.lsp4j.CompletionItem; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; import static org.eclipse.lemminx.XMLAssert.*; +import static org.mockito.Mockito.when; +@ExtendWith(MockitoExtension.class) public class LibertyCompletionTest { + @Mock + SettingsService settingsService; + + MockedStatic settings; static String newLine = System.lineSeparator(); static String serverXMLURI = "test/server.xml"; + @BeforeEach + public void setup(){ + settings= Mockito.mockStatic(SettingsService.class); + settings.when(SettingsService::getInstance).thenReturn(settingsService); + } + + @AfterEach + public void cleanup(){ + settings.close(); + } + + // Tests the availability of completion of XML elements provided by the // server.xsd file @Test @@ -264,4 +294,77 @@ public void testFeatureRepetitionCompletionItem() throws BadLocationException { XMLAssert.testCompletionFor(serverXML, null, serverXMLURI, 3, sipServletCompletionItem); } + // Tests the + // availability of feature completion + @Test + public void testVariableCompletionItem() throws BadLocationException { + String serverXML = String.join(newLine, // + "", // + " ", // + " javaee-6.0", // + " acmeCA-2.0", // + " ", // + " ",// + "" // + ); + Map propsMap=new HashMap<>(); + propsMap.put("default.http.port","9080"); + propsMap.put("default.https.port","9443"); + propsMap.put("testVar","false"); + propsMap.put("testVar2","true"); + Properties props = new Properties(); + props.putAll(propsMap); + + when(settingsService.getVariables()).thenReturn(props); + CompletionItem httpCompletion = c("default.http.port", "${default.http.port}"); + CompletionItem httpsCompletion = c("default.https.port", "${default.https.port}"); + final int TOTAL_ITEMS = 2; // total number of available completion items + + XMLAssert.testCompletionFor(serverXML, null, serverXMLURI, TOTAL_ITEMS, httpCompletion, + httpsCompletion); + + serverXML = String.join(newLine, // + "", // + " ", // + " javaee-6.0", // + " acmeCA-2.0", // + " ", // + " ",// + "" // + ); + XMLAssert.testCompletionFor(serverXML, null, serverXMLURI, 0); + } + + @Test + public void testVariableCompletionItemWithDefaultXsdValues() throws BadLocationException { + String serverXML = String.join(newLine, // + "", // + " ", // + " javaee-6.0", // + " acmeCA-2.0", // + " ", // + " ",// + "" // + ); + Map propsMap=new HashMap<>(); + propsMap.put("default.http.port","9080"); + propsMap.put("default.https.port","9443"); + propsMap.put("testVar","false"); + propsMap.put("testVar2","true"); + Properties props = new Properties(); + props.putAll(propsMap); + + when(settingsService.getVariables()).thenReturn(props); + CompletionItem httpCompletion = c("default.http.port", "${default.http.port}"); + CompletionItem httpsCompletion = c("default.https.port", "${default.https.port}"); + final int TOTAL_ITEMS = 4; // total number of available completion items + // variables values -> default.http.port, default.https.port + // default schema provided value, this is not being filtered -> true, false + + XMLAssert.testCompletionFor(serverXML, null, serverXMLURI, TOTAL_ITEMS, httpCompletion, + httpsCompletion); + } + }