IDEA-54829 When editing a resource bundle, IntelliJ generates spurious double backslashes

Corrected property values (un)escaping processing
This commit is contained in:
Denis.Zhdanov
2011-10-13 17:11:09 +04:00
parent 01ef0331be
commit 0551f18acb
3 changed files with 135 additions and 19 deletions
@@ -318,7 +318,14 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit
if (editor == null) continue;
reinitSettings(editor);
IProperty property = propertiesFile.findPropertyByKey(propertyName);
final String value = property == null ? "" : property.getValue();
final String value;
if (property == null) {
value = "";
}
else {
String rawValue = property.getValue();
value = rawValue == null ? "" : ResourceBundleUtil.fromPropertyValueToValueEditor(rawValue);
}
final Document document = editor.getDocument();
CommandProcessor.getInstance().executeCommand(null, new Runnable() {
public void run() {
@@ -362,7 +369,7 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit
else {
myBackSlashPressed.remove(propertiesFile);
}
String value = getPropertyValueFromText(text);
String value = ResourceBundleUtil.fromValueEditorToPropertyValue(text);
IProperty property = propertiesFile.findPropertyByKey(propertyName);
try {
if (property == null) {
@@ -377,23 +384,6 @@ public class ResourceBundleEditor extends UserDataHolderBase implements FileEdit
}
}
private static String getPropertyValueFromText(final String text) {
StringBuilder value = new StringBuilder();
for (int i=0; i<text.length();i++) {
char c = text.charAt(i);
if (c == '\n') {
if (!PropertiesUtil.isUnescapedBackSlashAtTheEnd(value.toString())) {
value.append("\\");
}
value.append("\n");
}
else {
value.append(c);
}
}
return value.toString();
}
private void installDocumentListeners() {
List<PropertiesFile> propertiesFiles = myResourceBundle.getPropertiesFiles(myProject);
for (final PropertiesFile propertiesFile : propertiesFiles) {
@@ -0,0 +1,68 @@
package com.intellij.lang.properties.editor;
import gnu.trove.TIntHashSet;
import org.jetbrains.annotations.NotNull;
import java.io.Reader;
import java.util.Properties;
/**
* @author Denis Zhdanov
* @since 10/5/11 2:35 PM
*/
public class ResourceBundleUtil {
private static final TIntHashSet SYMBOLS_TO_ESCAPE = new TIntHashSet(new int[]{'#', '!', '=', ':'});
private static final char ESCAPE_SYMBOL = '\\';
private ResourceBundleUtil() {
}
/**
* Allows to map given 'raw' property value text to the 'user-friendly' text to show at the resource bundle editor.
* <p/>
* <b>Note:</b> please refer to {@link Properties#load(Reader)} contract for the property value escape rules.
*
* @param text 'raw' property value text
* @return 'user-friendly' text to show at the resource bundle editor
*/
@NotNull
public static String fromPropertyValueToValueEditor(@NotNull String text) {
StringBuilder buffer = new StringBuilder();
boolean escaped = false;
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
if (c == ESCAPE_SYMBOL && !escaped) {
escaped = true;
continue;
}
buffer.append(c);
escaped = false;
}
return buffer.toString();
}
/**
* Perform reverse operation to {@link #fromPropertyValueToValueEditor(String)}.
*
* @param text 'user-friendly' text shown to the user at the resource bundle editor
* @return 'raw' value to store at the *.properties file
*/
@NotNull
public static String fromValueEditorToPropertyValue(@NotNull String text) {
StringBuilder buffer = new StringBuilder();
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
if ((i == 0 && (c == ' ' || c == '\t')) // Leading white space
|| c == '\n' // Multi-line value
|| c == ESCAPE_SYMBOL // Escaped 'escape' symbol
|| SYMBOLS_TO_ESCAPE.contains(c)) // Special symbol
{
buffer.append(ESCAPE_SYMBOL);
}
buffer.append(c);
}
return buffer.toString();
}
}
@@ -0,0 +1,58 @@
package com.intellij.lang.properties.editor;
import gnu.trove.TIntHashSet;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
/**
* @author Denis Zhdanov
* @since 10/5/11 2:37 PM
*/
public class ResourceBundleUtilTest {
/**
* Holds pairs like <code>('property value'; 'value editor text')</code>.
*/
private static final String[][] TEST_DATA = {
// Common.
{ "", "" },
{ "as-is", "as-is" },
{ "with escaped escape symbol - \\\\", "with escaped escape symbol - \\" },
// Special symbols.
{ "special symbols - \\# and \\! and \\= and \\:", "special symbols - # and ! and = and :" },
// White spaces.
{ "trailing white space ", "trailing white space " },
{ "trailing white spaces ", "trailing white spaces " },
{ "trailing tab\t", "trailing tab\t" },
{ "trailing tabs\t\t\t", "trailing tabs\t\t\t" },
{ "\\\tstarting from tab", "\tstarting from tab" },
{ "\\\t\t\tstarting from tabs", "\t\t\tstarting from tabs" },
{ "\\ starting from white space", " starting from white space" },
{ "\\ starting from white spaces", " starting from white spaces" },
{ "\\ \t starting from white spaces and tabs", " \t starting from white spaces and tabs" },
{ "first line \\\nsecond line", "first line \nsecond line" },
// All together.
{ "\\\t text with \\\nspecial symbols\\:\\\n\\#", "\t text with \nspecial symbols:\n#" }
};
@Test
public void checkAllTestData() {
for (String[] entry : TEST_DATA) {
assertEquals(
"Expected property value differs from the one converted from value editor text",
entry[0],
ResourceBundleUtil.fromValueEditorToPropertyValue(entry[1])
);
assertEquals(
"Expected value editor text differs from the one converted from property value",
entry[1],
ResourceBundleUtil.fromPropertyValueToValueEditor(entry[0])
);
}
}
}