Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin de Vlaming2018-12-14 00:06:26 +0000
committerKevin de Vlaming2018-12-14 01:12:21 +0000
commitb08f6820b35251ff6e2d784f77562dae27e1f409 (patch)
treeebac44a62b662744ca5e18748bb08cbc5033181d
parent372e02c209c8cf666f1cc93f96ab5a25be8c8979 (diff)
downloadorg.eclipse.mylyn.docs-b08f6820b35251ff6e2d784f77562dae27e1f409.tar.gz
org.eclipse.mylyn.docs-b08f6820b35251ff6e2d784f77562dae27e1f409.tar.xz
org.eclipse.mylyn.docs-b08f6820b35251ff6e2d784f77562dae27e1f409.zip
542496: Fix escape behavior in Creole Document Builder
- The previous approach of replacing the tilde literal with its entity reference when writing to Creole was incorrect, as it would not be converted back to a literal when parsed via Creole Language - A better approach is to escape any literal tildes by adding a preceding tilde. Ie., '~' will be written to Creole as '~~'. - CreoleLanguage is capable of detecting the first of these two tildes as an escape then reading the second as a literal, thus ensuring that during the round trip the tilde is kept intact - Also added some additional special characters that should be escaped with a tilde Change-Id: If0ed1c10ed6ff961f1f15a02ec36fa693b2c6ee3 Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=542496 Signed-off-by: Kevin de Vlaming <kevin.devlaming@tasktop.com>
-rw-r--r--wikitext/core/org.eclipse.mylyn.wikitext.creole/src/main/java/org/eclipse/mylyn/wikitext/creole/internal/CreoleDocumentBuilder.java68
-rw-r--r--wikitext/core/org.eclipse.mylyn.wikitext.creole/src/test/java/org/eclipse/mylyn/internal/wikitext/creole/tests/CreoleLanguageIntegrationTest.java26
-rw-r--r--wikitext/core/org.eclipse.mylyn.wikitext.creole/src/test/java/org/eclipse/mylyn/internal/wikitext/creole/tests/CreoleLanguageTest.java6
-rw-r--r--wikitext/core/org.eclipse.mylyn.wikitext.creole/src/test/java/org/eclipse/mylyn/internal/wikitext/creole/tests/documentbuilder/CreoleDocumentBuilderTest.java2
4 files changed, 73 insertions, 29 deletions
diff --git a/wikitext/core/org.eclipse.mylyn.wikitext.creole/src/main/java/org/eclipse/mylyn/wikitext/creole/internal/CreoleDocumentBuilder.java b/wikitext/core/org.eclipse.mylyn.wikitext.creole/src/main/java/org/eclipse/mylyn/wikitext/creole/internal/CreoleDocumentBuilder.java
index fef3c23f2..ceb4463e8 100644
--- a/wikitext/core/org.eclipse.mylyn.wikitext.creole/src/main/java/org/eclipse/mylyn/wikitext/creole/internal/CreoleDocumentBuilder.java
+++ b/wikitext/core/org.eclipse.mylyn.wikitext.creole/src/main/java/org/eclipse/mylyn/wikitext/creole/internal/CreoleDocumentBuilder.java
@@ -50,17 +50,20 @@ public class CreoleDocumentBuilder extends AbstractMarkupDocumentBuilder {
private final boolean emitWhenEmpty;
+ private final boolean escaping;
+
public ContentBlock(BlockType blockType, String prefix, String suffix, int precedingNewlineCount,
- int trailingNewlineCount, boolean emitWhenEmpty) {
+ int trailingNewlineCount, boolean emitWhenEmpty, boolean escaping) {
super(blockType, precedingNewlineCount, trailingNewlineCount);
this.prefix = prefix;
this.suffix = suffix;
this.emitWhenEmpty = emitWhenEmpty;
+ this.escaping = escaping;
}
public ContentBlock(BlockType blockType, String prefix, String suffix, int precedingNewlineCount,
int trailingNewlineCount) {
- this(blockType, prefix, suffix, precedingNewlineCount, trailingNewlineCount, false);
+ this(blockType, prefix, suffix, precedingNewlineCount, trailingNewlineCount, false, true);
}
public ContentBlock(String prefix, String suffix, int precedingNewlineCount, int trailingNewlineCount) {
@@ -73,12 +76,20 @@ public class CreoleDocumentBuilder extends AbstractMarkupDocumentBuilder {
@Override
public void write(int c) throws IOException {
- CreoleDocumentBuilder.this.emitContent(c);
+ if (escaping) {
+ CreoleDocumentBuilder.this.emitEscapedContent(c);
+ } else {
+ CreoleDocumentBuilder.this.emitContent(c);
+ }
}
@Override
public void write(String s) throws IOException {
- CreoleDocumentBuilder.this.emitContent(s);
+ if (escaping) {
+ CreoleDocumentBuilder.this.emitEscapedContent(s);
+ } else {
+ CreoleDocumentBuilder.this.emitContent(s);
+ }
}
@Override
@@ -128,7 +139,7 @@ public class CreoleDocumentBuilder extends AbstractMarkupDocumentBuilder {
private final LinkAttributes attributes;
LinkBlock(LinkAttributes attributes) {
- super(null, "", "", 0, 0, true);
+ super(null, "", "", 0, 0, true, true);
this.attributes = attributes;
}
@@ -154,7 +165,7 @@ public class CreoleDocumentBuilder extends AbstractMarkupDocumentBuilder {
private class TableCellBlock extends ContentBlock {
public TableCellBlock(BlockType blockType) {
- super(blockType, blockType == BlockType.TABLE_CELL_NORMAL ? "|" : "|=", "", 0, 0, true);
+ super(blockType, blockType == BlockType.TABLE_CELL_NORMAL ? "|" : "|=", "", 0, 0, true, true);
}
@Override
@@ -183,7 +194,7 @@ public class CreoleDocumentBuilder extends AbstractMarkupDocumentBuilder {
return new ContentBlock(type, "", "", 2, 2); //$NON-NLS-1$ //$NON-NLS-2$
case PREFORMATTED:
case CODE:
- return new ContentBlock(type, "{{{\n", "\n}}}", 2, 2); //$NON-NLS-1$ //$NON-NLS-2$
+ return new ContentBlock(type, "{{{\n", "\n}}}", 2, 2, false, false); //$NON-NLS-1$ //$NON-NLS-2$
case TABLE:
return new SuffixBlock(type, "\n"); //$NON-NLS-1$
case TABLE_CELL_HEADER:
@@ -226,7 +237,7 @@ public class CreoleDocumentBuilder extends AbstractMarkupDocumentBuilder {
case DELETED:
return new ContentBlock("--", "--"); //$NON-NLS-1$ //$NON-NLS-2$
case CODE:
- return new ContentBlock("{{{", "}}}"); //$NON-NLS-1$ //$NON-NLS-2$
+ return new ContentBlock(null, "{{{", "}}}", 0, 0, false, false); //$NON-NLS-1$ //$NON-NLS-2$
case UNDERLINED:
return new ContentBlock("__", "__"); //$NON-NLS-1$ //$NON-NLS-2$
default:
@@ -243,19 +254,14 @@ public class CreoleDocumentBuilder extends AbstractMarkupDocumentBuilder {
@Override
public void characters(String text) {
- String escapedText = escapeTilde(text);
assertOpenBlock();
try {
- currentBlock.write(escapedText);
+ currentBlock.write(text);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
- private String escapeTilde(String text) {
- return text != null ? text.replace("~", "&tilde;") : null;
- }
-
@Override
public void entityReference(String entity) {
assertOpenBlock();
@@ -275,24 +281,25 @@ public class CreoleDocumentBuilder extends AbstractMarkupDocumentBuilder {
if (url != null) {
assertOpenBlock();
try {
- currentBlock.write("{{");
- currentBlock.write(url);
- writeImageAttributes(attributes);
- currentBlock.write("}}");
+ Block imageBlock = new ContentBlock(null, "{{", "}}", 0, 0, false, false);
+ imageBlock.open();
+ imageBlock.write(url);
+ writeImageAttributes(imageBlock, attributes);
+ imageBlock.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
- private void writeImageAttributes(Attributes attributes) throws IOException {
+ private void writeImageAttributes(Block imageBlock, Attributes attributes) throws IOException {
if (attributes instanceof ImageAttributes) {
if (!Strings.isNullOrEmpty(((ImageAttributes) attributes).getAlt())) {
- currentBlock.write('|');
- currentBlock.write(((ImageAttributes) attributes).getAlt());
+ imageBlock.write('|');
+ imageBlock.write(((ImageAttributes) attributes).getAlt());
} else if (!Strings.isNullOrEmpty(((ImageAttributes) attributes).getTitle())) {
- currentBlock.write('|');
- currentBlock.write(((ImageAttributes) attributes).getTitle());
+ imageBlock.write('|');
+ imageBlock.write(((ImageAttributes) attributes).getTitle());
}
}
}
@@ -345,6 +352,21 @@ public class CreoleDocumentBuilder extends AbstractMarkupDocumentBuilder {
}
}
+ void emitEscapedContent(String s) throws IOException {
+ if (s != null) {
+ for (int x = 0; x < s.length(); ++x) {
+ emitEscapedContent(s.charAt(x));
+ }
+ }
+ }
+
+ void emitEscapedContent(int c) throws IOException {
+ if (c == '~' || c == '*' || c == '#' || c == '|' || c == '=') {
+ super.emitContent('~');
+ }
+ super.emitContent(c);
+ }
+
@Override
protected Block createImplicitParagraphBlock() {
return new ImplicitParagraphBlock();
diff --git a/wikitext/core/org.eclipse.mylyn.wikitext.creole/src/test/java/org/eclipse/mylyn/internal/wikitext/creole/tests/CreoleLanguageIntegrationTest.java b/wikitext/core/org.eclipse.mylyn.wikitext.creole/src/test/java/org/eclipse/mylyn/internal/wikitext/creole/tests/CreoleLanguageIntegrationTest.java
index 0e3c8a6b3..1a19e1261 100644
--- a/wikitext/core/org.eclipse.mylyn.wikitext.creole/src/test/java/org/eclipse/mylyn/internal/wikitext/creole/tests/CreoleLanguageIntegrationTest.java
+++ b/wikitext/core/org.eclipse.mylyn.wikitext.creole/src/test/java/org/eclipse/mylyn/internal/wikitext/creole/tests/CreoleLanguageIntegrationTest.java
@@ -55,11 +55,6 @@ public class CreoleLanguageIntegrationTest extends TestCase {
assertRoundTripExact("# item 1\n## item 1.A.\n# item 2\n## item 2.A.\n### item 2.A.i.\n### item 2.A.ii.\n");
}
- public void testImageLink() {
- assertRoundTripExact(
- "This is an image: {{/path/to/img.jpg|An image}}\nThis is an image link: [[http://example.net/|{{/path/to/img.jpg}}]]\nThis is a link: [[http://example.com/|inline link]]\n\n");
- }
-
public void testTable() {
assertRoundTripExact("|=H Col 1|=H Col 2|\n|Cell 1 line 1\\\\Cell 1 line 2|Cell 2|\n\n");
}
@@ -237,6 +232,27 @@ public class CreoleLanguageIntegrationTest extends TestCase {
out.toString());
}
+ public void testEscapedCharacters() {
+ StringWriter out = new StringWriter();
+ DocumentBuilder builder = new CreoleDocumentBuilder(out);
+ builder.beginDocument();
+ builder.characters("~ Tilde ~ * Asterix * # Number # | Pipe |");
+ builder.endDocument();
+ assertParsedHtmlMatchesRoundTrip("<p>~ Tilde ~ * Asterix * # Number # | Pipe |</p>", out.toString());
+ }
+
+ public void testEscapedCharactersInCodeSpan() {
+ StringWriter out = new StringWriter();
+ DocumentBuilder builder = new CreoleDocumentBuilder(out);
+ builder.beginDocument();
+ builder.beginSpan(SpanType.CODE, new Attributes());
+ builder.characters("~ Tilde ~ * Asterix * # Number # | Pipe |");
+ builder.endSpan();
+ builder.endDocument();
+ assertParsedHtmlMatchesRoundTrip("<p><code>~ Tilde ~ * Asterix * # Number # | Pipe |</code></p>",
+ out.toString());
+ }
+
private void assertRoundTripExact(String textile) {
assertRoundTrip(textile, textile);
}
diff --git a/wikitext/core/org.eclipse.mylyn.wikitext.creole/src/test/java/org/eclipse/mylyn/internal/wikitext/creole/tests/CreoleLanguageTest.java b/wikitext/core/org.eclipse.mylyn.wikitext.creole/src/test/java/org/eclipse/mylyn/internal/wikitext/creole/tests/CreoleLanguageTest.java
index 0bfa040aa..9de3f2b32 100644
--- a/wikitext/core/org.eclipse.mylyn.wikitext.creole/src/test/java/org/eclipse/mylyn/internal/wikitext/creole/tests/CreoleLanguageTest.java
+++ b/wikitext/core/org.eclipse.mylyn.wikitext.creole/src/test/java/org/eclipse/mylyn/internal/wikitext/creole/tests/CreoleLanguageTest.java
@@ -208,6 +208,12 @@ public class CreoleLanguageTest extends TestCase {
content(html));
}
+ public void testTildeEscape() {
+ String html = parser.parseToHtml("~~ escape ~* escape ~= escape ~| escape ~# escape");
+
+ assertEquals("<p>~ escape * escape = escape | escape # escape</p>", content(html));
+ }
+
private String repeat(int i, String string) {
StringBuilder buf = new StringBuilder(string.length() * i);
for (int x = 0; x < i; ++x) {
diff --git a/wikitext/core/org.eclipse.mylyn.wikitext.creole/src/test/java/org/eclipse/mylyn/internal/wikitext/creole/tests/documentbuilder/CreoleDocumentBuilderTest.java b/wikitext/core/org.eclipse.mylyn.wikitext.creole/src/test/java/org/eclipse/mylyn/internal/wikitext/creole/tests/documentbuilder/CreoleDocumentBuilderTest.java
index 752ce4c57..90d58821a 100644
--- a/wikitext/core/org.eclipse.mylyn.wikitext.creole/src/test/java/org/eclipse/mylyn/internal/wikitext/creole/tests/documentbuilder/CreoleDocumentBuilderTest.java
+++ b/wikitext/core/org.eclipse.mylyn.wikitext.creole/src/test/java/org/eclipse/mylyn/internal/wikitext/creole/tests/documentbuilder/CreoleDocumentBuilderTest.java
@@ -74,7 +74,7 @@ public class CreoleDocumentBuilderTest extends AbstractCreoleDocumentBuilderTest
builder.characters("this ~ is interpreted as an escape");
builder.endBlock();
builder.endDocument();
- assertMarkup("this &tilde; is interpreted as an escape\n\n");
+ assertMarkup("this ~~ is interpreted as an escape\n\n");
}
public void testEntityReference() {

Back to the top