Merge pull request #309 from jca02266/preserve-spaces

Fixed issue 5630: Quotes are missing a space between > and the quoted text
This commit is contained in:
Koji Arai 2013-05-15 21:24:29 -07:00
commit f87ff20556
2 changed files with 174 additions and 51 deletions

View File

@ -211,63 +211,54 @@ public class HtmlConverter {
} }
StringReader reader = new StringReader(text); StringReader reader = new StringReader(text);
StringBuilder buff = new StringBuilder(text.length() + TEXT_TO_HTML_EXTRA_BUFFER_LENGTH); StringBuilder buff = new StringBuilder(text.length() + TEXT_TO_HTML_EXTRA_BUFFER_LENGTH);
boolean isStartOfLine = false; // Are we currently at the start of a line? boolean isStartOfLine = true; // Are we currently at the start of a line?
int spaces = 0;
int quoteDepth = 0; // Number of DIVs deep we are. int quoteDepth = 0; // Number of DIVs deep we are.
int quotesThisLine = 0; // How deep we should be quoting for this line. int quotesThisLine = 0; // How deep we should be quoting for this line.
try { try {
int c; int c;
while ((c = reader.read()) != -1) { while ((c = reader.read()) != -1) {
switch (c) { if (isStartOfLine) {
case '\n': switch (c) {
// pine treats <br> as two newlines, but <br/> as one newline. Use <br/> so our messages aren't case ' ':
// doublespaced. spaces++;
buff.append(HTML_NEWLINE); break;
isStartOfLine = true; case '>':
quotesThisLine = 0;
break;
case '&':
buff.append("&amp;");
break;
case '<':
buff.append("&lt;");
break;
case '>':
if (isStartOfLine) {
quotesThisLine++; quotesThisLine++;
} else { spaces = 0;
// We use a token here which can't occur in htmlified text because &gt; is valid break;
// within links (where > is not), and linkifying links will include it if we case '\n':
// do it here. We'll make another pass and change this back to &gt; after appendbq(buff, quotesThisLine, quoteDepth);
// the linkification is done. quoteDepth = quotesThisLine;
buff.append("<gt>");
} appendsp(buff, spaces);
break; spaces = 0;
case '\r':
break; appendchar(buff, c);
case ' ': isStartOfLine = true;
if (isStartOfLine) { quotesThisLine = 0;
// If we're still in the start of the line and we have spaces, don't output them, since they break;
// may be collapsed by our div-converting magic. default:
isStartOfLine = false;
appendbq(buff, quotesThisLine, quoteDepth);
quoteDepth = quotesThisLine;
appendsp(buff, spaces);
spaces = 0;
appendchar(buff, c);
isStartOfLine = false;
break; break;
} }
default: }
if (isStartOfLine) { else {
// Not a quote character and not a space. Content is starting now. appendchar(buff, c);
isStartOfLine = false; if (c == '\n') {
// Add/remove blockquotes by comparing this line's quotes to the previous line's quotes. isStartOfLine = true;
if (quotesThisLine > quoteDepth) { quotesThisLine = 0;
for (int i = quoteDepth; i < quotesThisLine; i++) {
buff.append(HTML_BLOCKQUOTE_START.replace(HTML_BLOCKQUOTE_COLOR_TOKEN, getQuoteColor(i + 1)));
}
} else if (quotesThisLine < quoteDepth) {
for (int i = quoteDepth; i > quotesThisLine; i--) {
buff.append(HTML_BLOCKQUOTE_END);
}
}
quoteDepth = quotesThisLine;
} }
buff.append((char)c); }
}//switch
} }
} catch (IOException e) { } catch (IOException e) {
//Should never happen //Should never happen
@ -311,6 +302,54 @@ public class HtmlConverter {
return text; return text;
} }
private static void appendchar(StringBuilder buff, int c) {
switch (c) {
case '&':
buff.append("&amp;");
break;
case '<':
buff.append("&lt;");
break;
case '>':
// We use a token here which can't occur in htmlified text because &gt; is valid
// within links (where > is not), and linkifying links will include it if we
// do it here. We'll make another pass and change this back to &gt; after
// the linkification is done.
buff.append("<gt>");
break;
case '\r':
break;
case '\n':
// pine treats <br> as two newlines, but <br/> as one newline. Use <br/> so our messages aren't
// doublespaced.
buff.append(HTML_NEWLINE);
break;
default:
buff.append((char)c);
break;
}
}
private static void appendsp(StringBuilder buff, int spaces) {
while (spaces > 0) {
buff.append(' ');
spaces--;
}
}
private static void appendbq(StringBuilder buff, int quotesThisLine, int quoteDepth) {
// Add/remove blockquotes by comparing this line's quotes to the previous line's quotes.
if (quotesThisLine > quoteDepth) {
for (int i = quoteDepth; i < quotesThisLine; i++) {
buff.append(HTML_BLOCKQUOTE_START.replace(HTML_BLOCKQUOTE_COLOR_TOKEN, getQuoteColor(i + 1)));
}
} else if (quotesThisLine < quoteDepth) {
for (int i = quoteDepth; i > quotesThisLine; i--) {
buff.append(HTML_BLOCKQUOTE_END);
}
}
}
protected static final String QUOTE_COLOR_DEFAULT = "#ccc"; protected static final String QUOTE_COLOR_DEFAULT = "#ccc";
protected static final String QUOTE_COLOR_LEVEL_1 = "#729fcf"; protected static final String QUOTE_COLOR_LEVEL_1 = "#729fcf";
protected static final String QUOTE_COLOR_LEVEL_2 = "#ad7fa8"; protected static final String QUOTE_COLOR_LEVEL_2 = "#ad7fa8";

View File

@ -25,7 +25,27 @@ public class HtmlConverterTest extends TestCase {
">> Guess!"; ">> Guess!";
String result = HtmlConverter.textToHtml(message); String result = HtmlConverter.textToHtml(message);
writeToFile(result); writeToFile(result);
assertEquals("<pre class=\"k9mail\">Panama!<br /><br />Bob Barker &lt;bob@aol.com&gt; wrote:<br /><blockquote class=\"gmail_quote\" style=\"margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #729fcf; padding-left: 1ex;\">a canal<br /><br />Dorothy Jo Gideon &lt;dorothy@aol.com&gt; espoused:<br /><blockquote class=\"gmail_quote\" style=\"margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #ad7fa8; padding-left: 1ex;\">A man, a plan...<br /></blockquote>Too easy!</blockquote><br />Nice job :)<br /><blockquote class=\"gmail_quote\" style=\"margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #729fcf; padding-left: 1ex;\"><blockquote class=\"gmail_quote\" style=\"margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #ad7fa8; padding-left: 1ex;\">Guess!</blockquote></blockquote></pre>", result); assertEquals("<pre class=\"k9mail\">"
+ "Panama!<br />"
+ "<br />"
+ "Bob Barker &lt;bob@aol.com&gt; wrote:<br />"
+ "<blockquote class=\"gmail_quote\" style=\"margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #729fcf; padding-left: 1ex;\">"
+ " a canal<br />"
+ "<br />"
+ " Dorothy Jo Gideon &lt;dorothy@aol.com&gt; espoused:<br />"
+ "<blockquote class=\"gmail_quote\" style=\"margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #ad7fa8; padding-left: 1ex;\">"
+ "A man, a plan...<br />"
+ "</blockquote>"
+ " Too easy!<br />"
+ "</blockquote>"
+ "<br />"
+ "Nice job :)<br />"
+ "<blockquote class=\"gmail_quote\" style=\"margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #729fcf; padding-left: 1ex;\">"
+ "<blockquote class=\"gmail_quote\" style=\"margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #ad7fa8; padding-left: 1ex;\">"
+ " Guess!"
+ "</blockquote>"
+ "</blockquote>"
+ "</pre>", result);
} }
public void testTextQuoteToHtmlBlockquoteIndented() { public void testTextQuoteToHtmlBlockquoteIndented() {
@ -39,7 +59,18 @@ public class HtmlConverterTest extends TestCase {
"> :)"; "> :)";
String result = HtmlConverter.textToHtml(message); String result = HtmlConverter.textToHtml(message);
writeToFile(result); writeToFile(result);
assertEquals("<pre class=\"k9mail\">*facepalm*<br /><br />Bob Barker &lt;bob@aol.com&gt; wrote:<br /><blockquote class=\"gmail_quote\" style=\"margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #729fcf; padding-left: 1ex;\">A wise man once said...<br /><br />LOL F1RST!!!!!<br /><br />:)</blockquote></pre>", result); assertEquals("<pre class=\"k9mail\">"
+ "*facepalm*<br />"
+ "<br />"
+ "Bob Barker &lt;bob@aol.com&gt; wrote:<br />"
+ "<blockquote class=\"gmail_quote\" style=\"margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #729fcf; padding-left: 1ex;\">"
+ " A wise man once said...<br />"
+ "<br />"
+ " LOL F1RST!!!!!<br />"
+ "<br />"
+ " :)"
+ "</blockquote></pre>", result);
} }
public void testQuoteDepthColor() { public void testQuoteDepthColor() {
@ -62,7 +93,27 @@ public class HtmlConverterTest extends TestCase {
">>>>>> six"; ">>>>>> six";
String result = HtmlConverter.textToHtml(message); String result = HtmlConverter.textToHtml(message);
writeToFile(result); writeToFile(result);
assertEquals("<pre class=\"k9mail\">zero<br /><blockquote class=\"gmail_quote\" style=\"margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #729fcf; padding-left: 1ex;\">one<br /><blockquote class=\"gmail_quote\" style=\"margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #ad7fa8; padding-left: 1ex;\">two<br /><blockquote class=\"gmail_quote\" style=\"margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;\">three<br /><blockquote class=\"gmail_quote\" style=\"margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #fcaf3e; padding-left: 1ex;\">four<br /><blockquote class=\"gmail_quote\" style=\"margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #e9b96e; padding-left: 1ex;\">five<br /><blockquote class=\"gmail_quote\" style=\"margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #ccc; padding-left: 1ex;\">six</blockquote></blockquote></blockquote></blockquote></blockquote></blockquote></pre>", result); assertEquals("<pre class=\"k9mail\">"
+ "zero<br />"
+ "<blockquote class=\"gmail_quote\" style=\"margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #729fcf; padding-left: 1ex;\">"
+ " one<br />"
+ "<blockquote class=\"gmail_quote\" style=\"margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #ad7fa8; padding-left: 1ex;\">"
+ " two<br />"
+ "<blockquote class=\"gmail_quote\" style=\"margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;\">"
+ " three<br />"
+ "<blockquote class=\"gmail_quote\" style=\"margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #fcaf3e; padding-left: 1ex;\">"
+ " four<br />"
+ "<blockquote class=\"gmail_quote\" style=\"margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #e9b96e; padding-left: 1ex;\">"
+ " five<br />"
+ "<blockquote class=\"gmail_quote\" style=\"margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #ccc; padding-left: 1ex;\">"
+ " six"
+ "</blockquote>"
+ "</blockquote>"
+ "</blockquote>"
+ "</blockquote>"
+ "</blockquote>"
+ "</blockquote>"
+ "</pre>", result);
} }
private void writeToFile(final String content) { private void writeToFile(final String content) {
@ -83,4 +134,37 @@ public class HtmlConverterTest extends TestCase {
e.printStackTrace(); e.printStackTrace();
} }
} }
public void testPreserveSpacesAtFirst() {
String message = "foo\n"
+ " bar\n"
+ " baz\n";
String result = HtmlConverter.textToHtml(message);
writeToFile(result);
assertEquals("<pre class=\"k9mail\">"
+ "foo<br />"
+ " bar<br />"
+ " baz<br />"
+ "</pre>", result);
}
public void testPreserveSpacesAtFirstForSpecialCharacters() {
String message =
" \n"
+ " &\n"
+ " \r\n"
+ " <\n"
+ " > \n";
String result = HtmlConverter.textToHtml(message);
writeToFile(result);
assertEquals("<pre class=\"k9mail\">"
+ " <br />"
+ " &amp;<br />"
+ " <br />"
+ " &lt;<br />"
+ "<blockquote class=\"gmail_quote\" style=\"margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #729fcf; padding-left: 1ex;\">"
+ " <br />"
+ "</blockquote>"
+ "</pre>", result);
}
} }