diff options
author | Ryan Nosworthy | 2018-10-17 21:21:49 +0000 |
---|---|---|
committer | Ryan Nosworthy | 2018-10-17 23:30:31 +0000 |
commit | b643f7d1d505b4f979b178a2cba99b17bec8a748 (patch) | |
tree | c7487988c43e675cd56f7944f84f7f7a231b5ab4 | |
parent | 1d7c17eca3001f4d96e5653ca13a139933bf5e9e (diff) | |
download | org.eclipse.mylyn.docs-b643f7d1d505b4f979b178a2cba99b17bec8a748.tar.gz org.eclipse.mylyn.docs-b643f7d1d505b4f979b178a2cba99b17bec8a748.tar.xz org.eclipse.mylyn.docs-b643f7d1d505b4f979b178a2cba99b17bec8a748.zip |
540235: ExtendedQuoteBlock supports nested blocks over multiple lines
* Override the three functions necessary for nested block supported as
specified in the Block javadocs: beginNesting(), findClosedOffset(), and
canResume(). This way we can leverage the logic within
AbstractMarkupLanguage that manages the state of nested blocks.
* Further in order for AbstractMarkupLanguage to supported
ExtendedQuoteBlock and its nested blocks it needs to know what the
offset is for the current line being processed. Currently the abstract
function in AbstractConfluenceDelimitedBlock assumes the whole line
being processed and has a void return. This is not the case so we should
return an offset when calling handleBlockContent().
* Added tests for the transformation of Confluence markup to HTML
* Added tests for the transformation of HTML document building blocks to
Confluence markup
https://bugs.eclipse.org/bugs/show_bug.cgi?id=540235
Change-Id: Ic11a7605fc0bbca3c97a6e432a4036834faafd33
Signed-off-by: Ryan Nosworthy <ryan.nosworthy@tasktop.com>
7 files changed, 139 insertions, 24 deletions
diff --git a/wikitext/core/org.eclipse.mylyn.wikitext.confluence/src/main/java/org/eclipse/mylyn/wikitext/confluence/internal/block/AbstractConfluenceDelimitedBlock.java b/wikitext/core/org.eclipse.mylyn.wikitext.confluence/src/main/java/org/eclipse/mylyn/wikitext/confluence/internal/block/AbstractConfluenceDelimitedBlock.java index 21c347f00..b6cfbf1a6 100644 --- a/wikitext/core/org.eclipse.mylyn.wikitext.confluence/src/main/java/org/eclipse/mylyn/wikitext/confluence/internal/block/AbstractConfluenceDelimitedBlock.java +++ b/wikitext/core/org.eclipse.mylyn.wikitext.confluence/src/main/java/org/eclipse/mylyn/wikitext/confluence/internal/block/AbstractConfluenceDelimitedBlock.java @@ -40,38 +40,57 @@ public abstract class AbstractConfluenceDelimitedBlock extends ParameterizedBloc beginBlock(); } - int end = line.length(); - int segmentEnd = end; + int endOfContent = line.length(); + int segmentEnd = endOfContent; boolean terminating = false; - if (offset < end) { + if (offset < endOfContent) { Matcher endMatcher = endPattern.matcher(line); if (blockLineCount == 0) { - endMatcher.region(offset, end); + endMatcher.region(offset, endOfContent); } if (endMatcher.find()) { terminating = true; - end = endMatcher.start(2); + endOfContent = endMatcher.start(2); segmentEnd = endMatcher.start(1); } } - if (end < line.length()) { - state.setLineSegmentEndOffset(end); + if (endOfContent < line.length()) { + state.setLineSegmentEndOffset(endOfContent); } ++blockLineCount; final String content = line.substring(offset, segmentEnd); - handleBlockContent(content); + int contentOffset = handleBlockContent(content); if (terminating) { setClosed(true); } - return end == line.length() ? -1 : end; + + return finalOffset(line.length(), endOfContent, contentOffset); + } + + private int finalOffset(int lineLength, int endOfContent, int contentOffset) { + int finalOffset = contentOffset; + if (contentOffset == lineLength) { + finalOffset = -1; + } else if (endOfContent != lineLength) { + finalOffset = endOfContent; + } + return finalOffset; } - protected abstract void handleBlockContent(String content); + /** + * Process the given line of markup starting at the provided offset. + * + * @param line + * the markup line to process + * @return a non-negative integer to indicate that processing of the block completed before the end of the line, or + * -1 if the entire line was processed. + */ + protected abstract int handleBlockContent(String content); protected abstract void beginBlock(); diff --git a/wikitext/core/org.eclipse.mylyn.wikitext.confluence/src/main/java/org/eclipse/mylyn/wikitext/confluence/internal/block/CodeBlock.java b/wikitext/core/org.eclipse.mylyn.wikitext.confluence/src/main/java/org/eclipse/mylyn/wikitext/confluence/internal/block/CodeBlock.java index ce6cd315f..ff824b93c 100644 --- a/wikitext/core/org.eclipse.mylyn.wikitext.confluence/src/main/java/org/eclipse/mylyn/wikitext/confluence/internal/block/CodeBlock.java +++ b/wikitext/core/org.eclipse.mylyn.wikitext.confluence/src/main/java/org/eclipse/mylyn/wikitext/confluence/internal/block/CodeBlock.java @@ -44,15 +44,16 @@ public class CodeBlock extends AbstractConfluenceDelimitedBlock { } @Override - protected void handleBlockContent(String content) { + protected int handleBlockContent(String content) { builder.characters(content); builder.characters("\n"); //$NON-NLS-1$ + return -1; } @Override protected void endBlock() { if (title != null) { - builder.endBlock(); // panel + builder.endBlock(); // panel } builder.endBlock(); // code } diff --git a/wikitext/core/org.eclipse.mylyn.wikitext.confluence/src/main/java/org/eclipse/mylyn/wikitext/confluence/internal/block/ExtendedPreformattedBlock.java b/wikitext/core/org.eclipse.mylyn.wikitext.confluence/src/main/java/org/eclipse/mylyn/wikitext/confluence/internal/block/ExtendedPreformattedBlock.java index 152825362..9eef784ae 100644 --- a/wikitext/core/org.eclipse.mylyn.wikitext.confluence/src/main/java/org/eclipse/mylyn/wikitext/confluence/internal/block/ExtendedPreformattedBlock.java +++ b/wikitext/core/org.eclipse.mylyn.wikitext.confluence/src/main/java/org/eclipse/mylyn/wikitext/confluence/internal/block/ExtendedPreformattedBlock.java @@ -18,7 +18,7 @@ import org.eclipse.mylyn.wikitext.parser.DocumentBuilder.BlockType; /** * quoted text block, matches blocks that start with <code>{noformat}</code>. Creates an extended block type of * {@link ParagraphBlock paragraph}. - * + * * @author David Green */ public class ExtendedPreformattedBlock extends AbstractConfluenceDelimitedBlock { @@ -39,13 +39,14 @@ public class ExtendedPreformattedBlock extends AbstractConfluenceDelimitedBlock } @Override - protected void handleBlockContent(String content) { + protected int handleBlockContent(String content) { if (content.length() > 0) { builder.characters(content); } else if (blockLineCount == 1) { - return; + return -1; } builder.characters("\n"); //$NON-NLS-1$ + return -1; } @Override diff --git a/wikitext/core/org.eclipse.mylyn.wikitext.confluence/src/main/java/org/eclipse/mylyn/wikitext/confluence/internal/block/ExtendedQuoteBlock.java b/wikitext/core/org.eclipse.mylyn.wikitext.confluence/src/main/java/org/eclipse/mylyn/wikitext/confluence/internal/block/ExtendedQuoteBlock.java index 041af8154..9f7cfcce3 100644 --- a/wikitext/core/org.eclipse.mylyn.wikitext.confluence/src/main/java/org/eclipse/mylyn/wikitext/confluence/internal/block/ExtendedQuoteBlock.java +++ b/wikitext/core/org.eclipse.mylyn.wikitext.confluence/src/main/java/org/eclipse/mylyn/wikitext/confluence/internal/block/ExtendedQuoteBlock.java @@ -20,7 +20,7 @@ import org.eclipse.mylyn.wikitext.parser.markup.Block; /** * quoted text block, matches blocks that start with <code>{quote}</code>. Creates an extended block type of * {@link ParagraphBlock paragraph}. - * + * * @author David Green */ public class ExtendedQuoteBlock extends AbstractConfluenceDelimitedBlock { @@ -64,7 +64,7 @@ public class ExtendedQuoteBlock extends AbstractConfluenceDelimitedBlock { } @Override - protected void handleBlockContent(String content) { + protected int handleBlockContent(String content) { if (nestedBlock == null) { ConfluenceLanguage markupLanguage = (ConfluenceLanguage) getMarkupLanguage(); for (Block block : markupLanguage.getNestedBlocks()) { @@ -87,22 +87,19 @@ public class ExtendedQuoteBlock extends AbstractConfluenceDelimitedBlock { nestedBlock = null; } if (lineOffset < content.length() && lineOffset >= 0) { - if (nestedBlock != null) { - throw new IllegalStateException("if a block does not fully process a line then it must be closed"); //$NON-NLS-1$ - } - content = content.substring(lineOffset); + return lineOffset; } else { - return; + return -1; } } if (blockLineCount == 1 && content.length() == 0) { - return; + return -1; } if (blockLineCount > 1 && paraOpen && getMarkupLanguage().isEmptyLine(content)) { builder.endBlock(); // para paraOpen = false; paraLine = 0; - return; + return -1; } if (!paraOpen) { builder.beginBlock(BlockType.PARAGRAPH, new Attributes()); @@ -113,7 +110,31 @@ public class ExtendedQuoteBlock extends AbstractConfluenceDelimitedBlock { } ++paraLine; getMarkupLanguage().emitMarkupLine(getParser(), state, content, 0); + return -1; + } + + @Override + public int findCloseOffset(String line, int lineOffset) { + if (nestedBlock == null) { + return super.findCloseOffset(line, lineOffset); + } + return nestedBlock.findCloseOffset(line, lineOffset); + } + @Override + public boolean beginNesting() { + if (nestedBlock == null) { + return super.beginNesting(); + } + return nestedBlock.beginNesting(); + } + + @Override + public boolean canResume(String line, int lineOffset) { + if (nestedBlock == null) { + return super.canResume(line, lineOffset); + } + return nestedBlock.canResume(line, lineOffset); } @Override diff --git a/wikitext/core/org.eclipse.mylyn.wikitext.confluence/src/test/java/org/eclipse/mylyn/wikitext/confluence/ConfluenceLanguageTest.java b/wikitext/core/org.eclipse.mylyn.wikitext.confluence/src/test/java/org/eclipse/mylyn/wikitext/confluence/ConfluenceLanguageTest.java index a89b23437..ab2897eca 100644 --- a/wikitext/core/org.eclipse.mylyn.wikitext.confluence/src/test/java/org/eclipse/mylyn/wikitext/confluence/ConfluenceLanguageTest.java +++ b/wikitext/core/org.eclipse.mylyn.wikitext.confluence/src/test/java/org/eclipse/mylyn/wikitext/confluence/ConfluenceLanguageTest.java @@ -150,6 +150,20 @@ public class ConfluenceLanguageTest extends AbstractMarkupGenerationTest<Conflue } @Test + public void testBlockQuoteExtendedWithNestedTable() { + assertMarkup( + "<blockquote><table><tr><td>Names</td><td>Occupation</td></tr><tr><td><ul><li>John</li><li>Jane</li></ul></td><td>Programmer</td></tr></table></blockquote>", + "{quote}|Names|Occupation|\n|* John\n* Jane|Programmer|{quote}\n"); + } + + @Test + public void testBlockQuoteExtendedWithMultipleNestedBlocks() { + assertMarkup( + "<blockquote><table><tr><td>Names</td><td>Occupation</td></tr><tr><td><ul><li>John</li><li>Jane</li></ul></td><td>Programmer</td></tr></table><ul><li>another</li><li>list</li></ul><p>and a para</p></blockquote>", + "{quote}\n|Names|Occupation|\n|* John\n* Jane|Programmer|\n\n* another\n* list\n\nand a para{quote}\n"); + } + + @Test public void testSimplePhraseModifiers() throws IOException { Object[][] pairs = new Object[][] { { "*", "strong" }, { "_", "em" }, { "??", "cite" }, { "-", "del" }, { "+", "u" }, { "^", "sup" }, { "~", "sub" }, }; diff --git a/wikitext/core/org.eclipse.mylyn.wikitext.confluence/src/test/java/org/eclipse/mylyn/wikitext/confluence/internal/ConfluenceDocumentBuilderTest.java b/wikitext/core/org.eclipse.mylyn.wikitext.confluence/src/test/java/org/eclipse/mylyn/wikitext/confluence/internal/ConfluenceDocumentBuilderTest.java index ed3a6e108..8b4f61209 100644 --- a/wikitext/core/org.eclipse.mylyn.wikitext.confluence/src/test/java/org/eclipse/mylyn/wikitext/confluence/internal/ConfluenceDocumentBuilderTest.java +++ b/wikitext/core/org.eclipse.mylyn.wikitext.confluence/src/test/java/org/eclipse/mylyn/wikitext/confluence/internal/ConfluenceDocumentBuilderTest.java @@ -660,6 +660,28 @@ public class ConfluenceDocumentBuilderTest { } @Test + public void nestTablesAfterBlockQuote() { + builder.beginDocument(); + builder.beginBlock(BlockType.QUOTE, new Attributes()); + builder.beginBlock(BlockType.TABLE, new Attributes()); + builder.beginBlock(BlockType.TABLE_ROW, new Attributes()); + builder.beginBlock(BlockType.TABLE_CELL_NORMAL, new Attributes()); + builder.beginBlock(BlockType.BULLETED_LIST, new Attributes()); + emitListItemHavingParagraphAndContent("first"); + emitListItemHavingParagraphAndContent("second"); + builder.endBlock(); + builder.endBlock(); + builder.endBlock(); + builder.endBlock(); + builder.endBlock(); + builder.endDocument(); + + String markup = out.toString(); + + assertEquals("{quote}|* first\n* second|\n\n{quote}\n\n", markup); + } + + @Test public void tableWithNestedList() { assertTableRow("| |* first\n" + // "* second| |\n\n", // diff --git a/wikitext/core/org.eclipse.mylyn.wikitext.confluence/src/test/java/org/eclipse/mylyn/wikitext/confluence/internal/block/ExtendedQuoteBlockTest.java b/wikitext/core/org.eclipse.mylyn.wikitext.confluence/src/test/java/org/eclipse/mylyn/wikitext/confluence/internal/block/ExtendedQuoteBlockTest.java new file mode 100644 index 000000000..e392fa3c1 --- /dev/null +++ b/wikitext/core/org.eclipse.mylyn.wikitext.confluence/src/test/java/org/eclipse/mylyn/wikitext/confluence/internal/block/ExtendedQuoteBlockTest.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 David Green and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * David Green - initial API and implementation + *******************************************************************************/ + +package org.eclipse.mylyn.wikitext.confluence.internal.block; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class ExtendedQuoteBlockTest { + + @Test + public void beginNestingWithoutANestedBlock() { + ExtendedQuoteBlock block = new ExtendedQuoteBlock(); + assertEquals(false, block.beginNesting()); + } + + @Test + public void canResumeWithoutANestedBlock() { + ExtendedQuoteBlock block = new ExtendedQuoteBlock(); + assertEquals(false, block.canResume("some line", 1)); + } + + @Test + public void finadCloseOffsetWithoutANestBlock() { + ExtendedQuoteBlock block = new ExtendedQuoteBlock(); + assertEquals(-1, block.findCloseOffset("some line", 1)); + } +} |