From 045bb6ac94fe13e643912d9e6c712277f97aa036 Mon Sep 17 00:00:00 2001 From: marhali Date: Fri, 1 Jul 2022 12:33:21 +0200 Subject: [PATCH] optimize line breaks and value parsing --- .../properties/PropertiesParserStrategy.java | 5 +- .../parser/properties/SortableProperties.java | 96 +++++++++++++++++++ .../easyi18n/util/IntelliJBufferedWriter.java | 27 ++++++ 3 files changed, 125 insertions(+), 3 deletions(-) create mode 100644 src/main/java/de/marhali/easyi18n/util/IntelliJBufferedWriter.java diff --git a/src/main/java/de/marhali/easyi18n/io/parser/properties/PropertiesParserStrategy.java b/src/main/java/de/marhali/easyi18n/io/parser/properties/PropertiesParserStrategy.java index f5ad136..82b5832 100644 --- a/src/main/java/de/marhali/easyi18n/io/parser/properties/PropertiesParserStrategy.java +++ b/src/main/java/de/marhali/easyi18n/io/parser/properties/PropertiesParserStrategy.java @@ -52,9 +52,8 @@ public class PropertiesParserStrategy extends ParserStrategy { PropertiesMapper.write(file.getLocale(), output, targetData, converter); try(StringWriter writer = new StringWriter()) { - output.store(writer, null); - // Current implementation only works with \n line separators (IntelliJ Document Formatting) - return writer.toString().replaceAll("\r\n", "\n"); + output.store(writer); + return writer.toString(); } } } diff --git a/src/main/java/de/marhali/easyi18n/io/parser/properties/SortableProperties.java b/src/main/java/de/marhali/easyi18n/io/parser/properties/SortableProperties.java index f4bc3be..0ff7819 100644 --- a/src/main/java/de/marhali/easyi18n/io/parser/properties/SortableProperties.java +++ b/src/main/java/de/marhali/easyi18n/io/parser/properties/SortableProperties.java @@ -1,5 +1,12 @@ package de.marhali.easyi18n.io.parser.properties; +import de.marhali.easyi18n.util.IntelliJBufferedWriter; + +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; import java.util.*; /** @@ -38,6 +45,95 @@ public class SortableProperties extends Properties { return this.properties.put(key, value); } + @Override + @Deprecated + public void store(OutputStream out, @Nullable String comments) throws IOException { + throw new UnsupportedOperationException("Not implemented"); + } + + @Override + @Deprecated + public void store(Writer writer, String comments) throws IOException { + throw new UnsupportedOperationException("Not implemented"); + } + + public void store(Writer writer) throws IOException { + IntelliJBufferedWriter bw = new IntelliJBufferedWriter(writer); + boolean escUnicode = false; + + synchronized (this) { + for (Map.Entry e : entrySet()) { + String key = String.valueOf(e.getKey()); + String val = String.valueOf(e.getValue()); + key = saveConvert(key, true, escUnicode); + /* No need to escape embedded and trailing spaces for value, hence + * pass false to flag. + */ + val = saveConvert(val, false, escUnicode); + bw.write(key + "=" + val); + bw.newLine(); + } + } + bw.flush(); + } + + /* + * Converts unicodes to encoded \uxxxx and escapes + * special characters with a preceding slash + */ + private String saveConvert(String theString, + boolean escapeSpace, + boolean escapeUnicode) { + int len = theString.length(); + int bufLen = len * 2; + if (bufLen < 0) { + bufLen = Integer.MAX_VALUE; + } + StringBuilder outBuffer = new StringBuilder(bufLen); + for(int x=0; x 61) && (aChar < 127)) { + if (aChar == '\\') { + outBuffer.append('\\'); outBuffer.append('\\'); + continue; + } + outBuffer.append(aChar); + continue; + } + switch(aChar) { + case ' ': + if (x == 0 || escapeSpace) + outBuffer.append('\\'); + outBuffer.append(' '); + break; + case '\t':outBuffer.append('\\'); outBuffer.append('t'); + break; + case '\n':outBuffer.append('\\'); outBuffer.append('n'); + break; + case '\r':outBuffer.append('\\'); outBuffer.append('r'); + break; + case '\f':outBuffer.append('\\'); outBuffer.append('f'); + break; + case '=': // Fall through + case ':': // Fall through + case '#': // Fall through + case '!': + outBuffer.append('\\'); outBuffer.append(aChar); + break; + default: + if (((aChar < 0x0020) || (aChar > 0x007e)) & escapeUnicode ) { + outBuffer.append("\\u"); + outBuffer.append(Integer.toHexString(aChar)); + } else { + outBuffer.append(aChar); + } + } + } + return outBuffer.toString(); + } + @Override public synchronized String toString() { return this.properties.toString(); diff --git a/src/main/java/de/marhali/easyi18n/util/IntelliJBufferedWriter.java b/src/main/java/de/marhali/easyi18n/util/IntelliJBufferedWriter.java new file mode 100644 index 0000000..41e28dd --- /dev/null +++ b/src/main/java/de/marhali/easyi18n/util/IntelliJBufferedWriter.java @@ -0,0 +1,27 @@ +package de.marhali.easyi18n.util; + +import org.jetbrains.annotations.NotNull; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.Writer; + +/** + * IntelliJ aware BufferedWriter implementation. + * (Document PSI uses \n as line separator) + * @author marhali + */ +public class IntelliJBufferedWriter extends BufferedWriter { + public IntelliJBufferedWriter(@NotNull Writer out) { + super(out); + } + + public IntelliJBufferedWriter(@NotNull Writer out, int sz) { + super(out, sz); + } + + @Override + public void newLine() throws IOException { + write("\n"); + } +}