From 049cfe4d92d4ccfcf1730a46fb8ae2466bee549f Mon Sep 17 00:00:00 2001 From: David Kwon Date: Mon, 27 Jul 2020 13:41:04 -0400 Subject: [PATCH] Escape special characters within LSP snippets Signed-off-by: David Kwon --- .../lsp4mp/ls/commons/SnippetsBuilder.java | 6 ++- .../ApplicationPropertiesCompletionTest.java | 53 ++++++++++++++++--- .../lsp4mp/services/MicroProfileAssert.java | 7 ++- 3 files changed, 57 insertions(+), 9 deletions(-) diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/commons/SnippetsBuilder.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/commons/SnippetsBuilder.java index 9eadaa671..d27e6ee93 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/commons/SnippetsBuilder.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/commons/SnippetsBuilder.java @@ -39,7 +39,7 @@ public static void placeholders(int index, String text, StringBuilder snippets) snippets.append("${"); snippets.append(index); snippets.append(":"); - snippets.append(text); + snippets.append(escape(text)); snippets.append("}"); } @@ -67,4 +67,8 @@ public static void choice(int index, Collection values, StringBuilder sn snippets.append("}"); } + private static String escape(String text) { + return text.replace("$", "\\$").replace("}", "\\}"); + } + } diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/test/java/org/eclipse/lsp4mp/services/ApplicationPropertiesCompletionTest.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/test/java/org/eclipse/lsp4mp/services/ApplicationPropertiesCompletionTest.java index 9920665d8..e968084da 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/test/java/org/eclipse/lsp4mp/services/ApplicationPropertiesCompletionTest.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/test/java/org/eclipse/lsp4mp/services/ApplicationPropertiesCompletionTest.java @@ -14,6 +14,7 @@ import static org.eclipse.lsp4mp.services.MicroProfileAssert.testCompletionFor; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import org.eclipse.lsp4mp.commons.MicroProfileProjectInfo; @@ -211,13 +212,13 @@ public void noCompletionForExistingProperties() throws BadLocationException { projectInfo.setProperties(properties); - testCompletionFor(value, false, null, 2, projectInfo, c("quarkus.http.cors", "quarkus.http.cors=", r(0, 0, 0)), + testCompletionFor(value, false, 2, projectInfo, c("quarkus.http.cors", "quarkus.http.cors=", r(0, 0, 0)), c("quarkus.application.name", "quarkus.application.name=", r(0, 0, 0))); value = "quarkus.http.cors=false\r\n" + // "|"; - testCompletionFor(value, false, null, 1, projectInfo, + testCompletionFor(value, false, 1, projectInfo, c("quarkus.application.name", "quarkus.application.name=", r(1, 0, 0))); } @@ -240,7 +241,7 @@ public void noCompletionForExistingPropertiesWithProfile() throws BadLocationExc projectInfo.setProperties(properties); - testCompletionFor(value, false, null, 1, projectInfo, + testCompletionFor(value, false, 1, projectInfo, c("quarkus.http.cors", "%prod.quarkus.http.cors=", r(1, 0, 6))); } @@ -260,13 +261,13 @@ public void completionForExistingPropertiesDifferentProfile() throws BadLocation projectInfo.setProperties(properties); - testCompletionFor(value, false, null, 2, projectInfo, c("quarkus.http.cors", "quarkus.http.cors=", r(0, 0, 0)), + testCompletionFor(value, false, 2, projectInfo, c("quarkus.http.cors", "quarkus.http.cors=", r(0, 0, 0)), c("quarkus.application.name", "quarkus.application.name=", r(0, 0, 0))); value = "quarkus.http.cors=false\r\n" + // "%dev.|"; - testCompletionFor(value, false, null, 2, projectInfo, + testCompletionFor(value, false, 2, projectInfo, c("quarkus.http.cors", "%dev.quarkus.http.cors=", r(1, 0, 5)), c("quarkus.application.name", "%dev.quarkus.application.name=", r(1, 0, 5))); @@ -274,7 +275,7 @@ public void completionForExistingPropertiesDifferentProfile() throws BadLocation "%dev.quarkus.application.name\r\n" + // "%prod.|"; - testCompletionFor(value, false, null, 2, projectInfo, + testCompletionFor(value, false, 2, projectInfo, c("quarkus.http.cors", "%prod.quarkus.http.cors=", r(2, 0, 6)), c("quarkus.application.name", "%prod.quarkus.application.name=", r(2, 0, 6))); @@ -297,4 +298,42 @@ public void completionSpacingSurroundingEquals() throws BadLocationException { c("quarkus.http.cors", "quarkus.http.cors = ${1|false,true|}", r(0, 0, 0))); } -} + @Test + public void completionDefaultValueContainsDollarSign() throws BadLocationException { + MicroProfileProjectInfo projectInfo = new MicroProfileProjectInfo(); + ItemMetadata metadata = new ItemMetadata(); + metadata.setName("price.string"); + metadata.setDefaultValue("Price: $10"); + projectInfo.setProperties(Collections.singletonList(metadata)); + + String value = "|"; + testCompletionFor(value, true, 1, projectInfo, c("price.string", "price.string=${0:Price: \\$10}", r(0, 0, 0))); + testCompletionFor(value, false, 1, projectInfo, c("price.string", "price.string=Price: $10", r(0, 0, 0))); + } + + @Test + public void completionDefaultValueContainsBraces() throws BadLocationException { + MicroProfileProjectInfo projectInfo = new MicroProfileProjectInfo(); + ItemMetadata metadata = new ItemMetadata(); + metadata.setName("price.string"); + metadata.setDefaultValue("Price: {10}"); + projectInfo.setProperties(Collections.singletonList(metadata)); + + String value = "|"; + testCompletionFor(value, true, 1, projectInfo, c("price.string", "price.string=${0:Price: {10\\}}", r(0, 0, 0))); + testCompletionFor(value, false, 1, projectInfo, c("price.string", "price.string=Price: {10}", r(0, 0, 0))); + } + + @Test + public void completionDefaultValueContainsDollarSignAndBraces() throws BadLocationException { + MicroProfileProjectInfo projectInfo = new MicroProfileProjectInfo(); + ItemMetadata metadata = new ItemMetadata(); + metadata.setName("price.string"); + metadata.setDefaultValue("Price: ${price}"); + projectInfo.setProperties(Collections.singletonList(metadata)); + + String value = "|"; + testCompletionFor(value, true, 1, projectInfo, c("price.string", "price.string=${0:Price: \\${price\\}}", r(0, 0, 0))); + testCompletionFor(value, false, 1, projectInfo, c("price.string", "price.string=Price: ${price}", r(0, 0, 0))); + } +} \ No newline at end of file diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/test/java/org/eclipse/lsp4mp/services/MicroProfileAssert.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/test/java/org/eclipse/lsp4mp/services/MicroProfileAssert.java index e814b9c73..e80fe8b60 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/test/java/org/eclipse/lsp4mp/services/MicroProfileAssert.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/test/java/org/eclipse/lsp4mp/services/MicroProfileAssert.java @@ -135,11 +135,16 @@ public static void testCompletionFor(String value, boolean snippetSupport, boole getDefaultMicroProfileProjectInfo(), expectedItems); } - public static void testCompletionFor(String value, boolean snippetSupport, String fileURI, Integer expectedCount, + public static void testCompletionFor(String value, boolean snippetSupport, Integer expectedCount, MicroProfileProjectInfo projectInfo, CompletionItem... expectedItems) throws BadLocationException { testCompletionFor(value, snippetSupport, false, null, expectedCount, projectInfo, expectedItems); } + public static void testCompletionFor(String value, boolean snippetSupport, String fileURI, Integer expectedCount, + MicroProfileProjectInfo projectInfo, CompletionItem... expectedItems) throws BadLocationException { + testCompletionFor(value, snippetSupport, false, fileURI, expectedCount, projectInfo, expectedItems); + } + public static void testCompletionFor(String value, boolean snippetSupport, boolean insertSpacing, String fileURI, Integer expectedCount, MicroProfileProjectInfo projectInfo, CompletionItem... expectedItems) throws BadLocationException {