From e4bedb87d125fb7234720a47523f9e3b4b117111 Mon Sep 17 00:00:00 2001 From: Mickael Istria Date: Thu, 21 Jan 2021 17:30:43 +0100 Subject: Bug 570519 - Fix VariableTemplate offset/buffer In case the default value is different from name, the insertion would potentially behave incorrectly, showing variable name where default value is expected, or inserting at wrong offset, erasing or keeping some extra characters. Change-Id: Ia5d4e47841a2272ce66e7e5a61b630eeadeaf13b Also-By: Christoph Läubrich Signed-off-by: Mickael Istria --- org.eclipse.text.tests/META-INF/MANIFEST.MF | 2 +- org.eclipse.text.tests/pom.xml | 2 +- .../TemplateVariablesWordSelectionTest.java | 24 +++++++++++++ org.eclipse.text/META-INF/MANIFEST.MF | 2 +- .../jface/text/templates/TemplateTranslator.java | 41 ++++++++++++++++++++-- 5 files changed, 66 insertions(+), 5 deletions(-) diff --git a/org.eclipse.text.tests/META-INF/MANIFEST.MF b/org.eclipse.text.tests/META-INF/MANIFEST.MF index 40ec27473bd..05f4275457f 100644 --- a/org.eclipse.text.tests/META-INF/MANIFEST.MF +++ b/org.eclipse.text.tests/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Plugin.name Bundle-SymbolicName: org.eclipse.text.tests -Bundle-Version: 3.12.700.qualifier +Bundle-Version: 3.12.800.qualifier Bundle-Vendor: %Plugin.providerName Bundle-Localization: plugin Export-Package: diff --git a/org.eclipse.text.tests/pom.xml b/org.eclipse.text.tests/pom.xml index c83c53954f1..0df48e1a2b6 100644 --- a/org.eclipse.text.tests/pom.xml +++ b/org.eclipse.text.tests/pom.xml @@ -19,7 +19,7 @@ org.eclipse.text org.eclipse.text.tests - 3.12.700-SNAPSHOT + 3.12.800-SNAPSHOT eclipse-test-plugin ${project.artifactId} diff --git a/org.eclipse.text.tests/src/org/eclipse/text/tests/templates/TemplateVariablesWordSelectionTest.java b/org.eclipse.text.tests/src/org/eclipse/text/tests/templates/TemplateVariablesWordSelectionTest.java index df8be90928f..efbb97a54d9 100644 --- a/org.eclipse.text.tests/src/org/eclipse/text/tests/templates/TemplateVariablesWordSelectionTest.java +++ b/org.eclipse.text.tests/src/org/eclipse/text/tests/templates/TemplateVariablesWordSelectionTest.java @@ -26,6 +26,7 @@ import org.eclipse.jface.text.templates.TemplateBuffer; import org.eclipse.jface.text.templates.TemplateContextType; import org.eclipse.jface.text.templates.TemplateTranslator; import org.eclipse.jface.text.templates.TemplateVariable; +import org.eclipse.jface.text.templates.TemplateVariableType; public class TemplateVariablesWordSelectionTest { @@ -65,6 +66,29 @@ public class TemplateVariablesWordSelectionTest { assertBufferStringAndVariables(expected.toString(), buffer); } + @Test + public void testMulti() throws Exception { + TemplateBuffer buffer = new TemplateTranslator() { + + @Override + protected TemplateVariable createVariable(TemplateVariableType type, String name, int[] offsets) { + if ("petType".equals(name)) { + String[] pets = new String[] { "cat", "dog", "other" }; + TemplateVariable variable = new TemplateVariable(type.getName(), name, pets, offsets); + variable.setUnambiguous(true); + return variable; + } + return super.createVariable(type, name, offsets); + } + }.translate("My favorite pet is a ${petType:String}, I love my ${petType}."); + assertEquals("My favorite pet is a cat, I love my cat.", buffer.getString()); + fType.resolve(buffer, fContext); + + StringBuilder expected = new StringBuilder(); + expected.append("My favorite pet is a cat, I love my cat."); + assertBufferStringAndVariables(expected.toString(), buffer); + } + /** * Ensures that {@link TemplateBuffer#getString()} equals the expected String and that all * {@link TemplateBuffer#getVariables()} are resolved and unambiguous. diff --git a/org.eclipse.text/META-INF/MANIFEST.MF b/org.eclipse.text/META-INF/MANIFEST.MF index c67cfa9b713..fbcad6f8538 100644 --- a/org.eclipse.text/META-INF/MANIFEST.MF +++ b/org.eclipse.text/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.text -Bundle-Version: 3.10.400.qualifier +Bundle-Version: 3.10.500.qualifier Bundle-Vendor: %providerName Bundle-Localization: plugin Export-Package: diff --git a/org.eclipse.text/src/org/eclipse/jface/text/templates/TemplateTranslator.java b/org.eclipse.text/src/org/eclipse/jface/text/templates/TemplateTranslator.java index dcb00151040..c56d826edb7 100644 --- a/org.eclipse.text/src/org/eclipse/jface/text/templates/TemplateTranslator.java +++ b/org.eclipse.text/src/org/eclipse/jface/text/templates/TemplateTranslator.java @@ -14,10 +14,15 @@ package org.eclipse.jface.text.templates; import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.SortedMap; +import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -221,9 +226,39 @@ public class TemplateTranslator { buffer.append(string.substring(complete)); TemplateVariable[] vars= createVariables(variables); + fixOffsetsAndBuffer(buffer, vars); return new TemplateBuffer(buffer.toString(), vars); } + /** + * In cases default value is provided dynamically when instantiating the variable (so not part + * of the {@link VariableDescription}), the buffer would actually contain incorrect text (name instead + * of default value) and offsets can also be inconsistent if variable name and default value have different + * length. This methods fix both buffer and variable offsets to ensure default value is used. + * @param buffer the default template string + * @param vars variables + */ + private void fixOffsetsAndBuffer(StringBuilder buffer, TemplateVariable[] vars) { + SortedMap varsByOffset = new TreeMap<>(); + for (TemplateVariable var : vars) { + for (int offset : var.getOffsets()) { + varsByOffset.put(Integer.valueOf(offset), var); + } + } + int totalOffsetDelta = 0; + Map> fixedOffsets = new HashMap<>(vars.length, 1.f); + for (Entry entry : varsByOffset.entrySet()) { + final int initialOffset = entry.getKey().intValue(); + TemplateVariable variable = entry.getValue(); + final int fixedOffset = initialOffset + totalOffsetDelta; + fixedOffsets.computeIfAbsent(variable, v -> new ArrayList<>(v.getOffsets().length)).add(Integer.valueOf(fixedOffset)); + int currentOffsetDelta = variable.getDefaultValue().length() - variable.getName().length(); + buffer.replace(fixedOffset, fixedOffset + variable.getName().length(), variable.getDefaultValue()); + totalOffsetDelta += currentOffsetDelta; + } + fixedOffsets.forEach((variable, fixs) -> variable.setOffsets(fixs.stream().mapToInt(Integer::valueOf).toArray())); + } + private TemplateVariableType createType(String typeName, String paramString) { if (typeName == null) return null; @@ -237,7 +272,7 @@ public class TemplateTranslator { String argument= matcher.group(); if (argument.charAt(0) == '\'') { // argumentText - argument= argument.substring(1, argument.length() - 1).replaceAll("''", "'"); //$NON-NLS-1$ //$NON-NLS-2$ + argument= argument.substring(1, argument.length() - 1).replace("''", "'"); //$NON-NLS-1$ //$NON-NLS-2$ } params.add(argument); @@ -260,10 +295,11 @@ public class TemplateTranslator { * @param name the name of the variable * @param type the variable type, null for not defined * @param offset the buffer offset of the variable + * @return the variable description found or created for that name * @throws TemplateException if merging the type fails * @since 3.3 */ - private void updateOrCreateVariable(Map variables, String name, TemplateVariableType type, int offset) throws TemplateException { + private VariableDescription updateOrCreateVariable(Map variables, String name, TemplateVariableType type, int offset) throws TemplateException { VariableDescription varDesc= variables.get(name); if (varDesc == null) { varDesc= new VariableDescription(name, type); @@ -272,6 +308,7 @@ public class TemplateTranslator { varDesc.mergeType(type); } varDesc.fOffsets.add(Integer.valueOf(offset)); + return varDesc; } /** -- cgit v1.2.3