diff options
author | Jeremie Bresson | 2012-09-05 20:46:24 +0000 |
---|---|---|
committer | David Green | 2012-09-05 20:46:24 +0000 |
commit | 7cac0792730a2a6985ea873589bf527e16e164c4 (patch) | |
tree | d6016750b1cde6097407932c6e8cd0becfeb7210 | |
parent | b4943d28d911e14b25a3582f740bc90a04ad6e98 (diff) | |
download | org.eclipse.mylyn.docs-7cac0792730a2a6985ea873589bf527e16e164c4.tar.gz org.eclipse.mylyn.docs-7cac0792730a2a6985ea873589bf527e16e164c4.tar.xz org.eclipse.mylyn.docs-7cac0792730a2a6985ea873589bf527e16e164c4.zip |
bug 381912: [MediaWiki] support for nested blocks in table cells.
Add the possibility to have more complex cell content in tables.
- Add the nesting protocol to TableBlock
- Add the cases described in the bug to the test suite
- Correction of the JavaDoc of Block.canResume(String, int)
Bugzilla:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=381912
Change-Id: Iecd139af2cfd6d358b86aa4fc2b380c00a168567
3 files changed, 179 insertions, 27 deletions
diff --git a/org.eclipse.mylyn.wikitext.core/src/org/eclipse/mylyn/wikitext/core/parser/markup/Block.java b/org.eclipse.mylyn.wikitext.core/src/org/eclipse/mylyn/wikitext/core/parser/markup/Block.java index cec28ec03..f47810191 100644 --- a/org.eclipse.mylyn.wikitext.core/src/org/eclipse/mylyn/wikitext/core/parser/markup/Block.java +++ b/org.eclipse.mylyn.wikitext.core/src/org/eclipse/mylyn/wikitext/core/parser/markup/Block.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2009 David Green and others. + * Copyright (c) 2007, 2012 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 @@ -7,6 +7,7 @@ * * Contributors: * David Green - initial API and implementation + * Jeremie Bresson - Bug 381912 *******************************************************************************/ package org.eclipse.mylyn.wikitext.core.parser.markup; @@ -95,16 +96,17 @@ public abstract class Block extends Processor implements Cloneable { } /** - * Indicate if the block can continue on the given line at the given offset. blocks that implement a nesting - * protocol should implement this method. + * Indicates if the block can resume with the given markup line at the provided offset. Resuming a block, means that + * the nested children blocks are closed. Blocks that implement a nesting protocol should implement this method. * * @param line * the line of content * @param lineOffset * the 0-based offset into the line - * @return the 0-based offset where the close will occur, or -1 if the block should not close on this line. + * @return <code>true</code> if the block can resume <code>false</code> if nested block needs to handle the content + * further. * @see #beginNesting() - * @see #canResume(String, int) + * @see #findCloseOffset(String, int) * @since 1.6 */ public boolean canResume(String line, int lineOffset) { diff --git a/org.eclipse.mylyn.wikitext.mediawiki.core/src/org/eclipse/mylyn/internal/wikitext/mediawiki/core/block/TableBlock.java b/org.eclipse.mylyn.wikitext.mediawiki.core/src/org/eclipse/mylyn/internal/wikitext/mediawiki/core/block/TableBlock.java index d2dd5c25f..7f1105d24 100644 --- a/org.eclipse.mylyn.wikitext.mediawiki.core/src/org/eclipse/mylyn/internal/wikitext/mediawiki/core/block/TableBlock.java +++ b/org.eclipse.mylyn.wikitext.mediawiki.core/src/org/eclipse/mylyn/internal/wikitext/mediawiki/core/block/TableBlock.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2011 David Green and others. + * Copyright (c) 2007, 2012 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 @@ -7,13 +7,13 @@ * * Contributors: * David Green - initial API and implementation + * Jeremie Bresson - Bug 381912 *******************************************************************************/ package org.eclipse.mylyn.internal.wikitext.mediawiki.core.block; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.eclipse.mylyn.wikitext.core.parser.Attributes; import org.eclipse.mylyn.wikitext.core.parser.DocumentBuilder.BlockType; import org.eclipse.mylyn.wikitext.core.parser.TableAttributes; import org.eclipse.mylyn.wikitext.core.parser.TableCellAttributes; @@ -49,6 +49,8 @@ public class TableBlock extends Block { private boolean openRow; + private boolean openCell; + @Override public int processLineContent(String line, int offset) { if (blockLineCount++ == 0) { @@ -130,22 +132,22 @@ public class TableBlock extends Block { Matcher cellMatcher = cellPattern.matcher(line); if (cellMatcher.matches()) { String kind = cellMatcher.group(1); + BlockType type = ("!".equals(kind)) ? BlockType.TABLE_CELL_HEADER : BlockType.TABLE_CELL_NORMAL; //$NON-NLS-1$ + String contents = cellMatcher.group(2); if (contents == null) { - // likely an incomplete line + //cell was just opened, no cell options. + openCell(cellMatcher.start(), type, new TableCellAttributes()); return -1; } - int contentsStart = cellMatcher.start(2); - BlockType type = ("!".equals(kind)) ? BlockType.TABLE_CELL_HEADER : BlockType.TABLE_CELL_NORMAL; //$NON-NLS-1$ - if (!openRow) { - openRow(cellMatcher.start(), new Attributes()); - } + int contentsStart = cellMatcher.start(2); emitCells(contentsStart, type, contents); return -1; } else { // ignore, bad formatting or unsupported syntax (caption) + // in case of cells this will be handled with NestedBlocks return -1; } } @@ -188,13 +190,6 @@ public class TableBlock extends Block { throw new IllegalStateException(); } String cellOptions = cellSplitterMatcher.group(1); - String cellContents = cellSplitterMatcher.group(2); - if (cellContents == null) { - // probably invalid syntax - return; - } - - int contentsStart = cellSplitterMatcher.start(2); TableCellAttributes attributes = new TableCellAttributes(); @@ -224,15 +219,19 @@ public class TableBlock extends Block { } } } - state.setLineCharacterOffset(lineCharacterOffset); - builder.beginBlock(type, attributes); - - markupLanguage.emitMarkupLine(parser, state, lineCharacterOffset + contentsStart, cellContents, 0); - builder.endBlock(); + String cellContents = cellSplitterMatcher.group(2); + if (cellContents == null) { + //cell was opened, no content on this line + openCell(lineCharacterOffset + cellSplitterMatcher.end(), type, attributes); + } else { + int contentsStart = cellSplitterMatcher.start(2); + openCell(lineCharacterOffset, type, attributes); + markupLanguage.emitMarkupLine(parser, state, lineCharacterOffset + contentsStart, cellContents, 0); + } } - private void openRow(int lineOffset, Attributes attributes) { + private void openRow(int lineOffset, TableRowAttributes attributes) { closeRow(); state.setLineCharacterOffset(lineOffset); builder.beginBlock(BlockType.TABLE_ROW, attributes); @@ -240,12 +239,43 @@ public class TableBlock extends Block { } private void closeRow() { + closeCell(); if (openRow) { builder.endBlock(); openRow = false; } } + /** + * Open a cell block. + * + * @param lineOffset + * line offset + * @param type + * type of cell (expecting {@link BlockType#TABLE_CELL_HEADER} or {@link BlockType#TABLE_CELL_NORMAL}). + * @param attributes + * attributes of the cell + */ + private void openCell(int lineOffset, BlockType type, TableCellAttributes attributes) { + closeCell(); + if (!openRow) { + openRow(lineOffset, new TableRowAttributes()); + } + state.setLineCharacterOffset(lineOffset); + builder.beginBlock(type, attributes); + openCell = true; + } + + /** + * Close a cell block if it was opened. + */ + private void closeCell() { + if (openCell) { + builder.endBlock(); + openCell = false; + } + } + @Override public boolean canStart(String line, int lineOffset) { blockLineCount = 0; @@ -262,10 +292,41 @@ public class TableBlock extends Block { @Override public void setClosed(boolean closed) { if (closed && !isClosed()) { + closeCell(); closeRow(); builder.endBlock(); } super.setClosed(closed); } + @Override + public boolean beginNesting() { + return openCell; + } + + @Override + public int findCloseOffset(String line, int lineOffset) { + if (openCell) { + if (!checkAtNewTableRow(line, lineOffset)) { + return -1; + } + } + return lineOffset; //Close here. + } + + private boolean checkAtNewTableRow(String line, int lineOffset) { + if (lineOffset < line.length()) { + char startChar = line.charAt(lineOffset); + if (startChar == '|' || startChar == '!') { + //new line, a new cell or a new header cell + return true; + } + } + return false; + } + + @Override + public boolean canResume(String line, int lineOffset) { + return checkAtNewTableRow(line, lineOffset); + } } diff --git a/org.eclipse.mylyn.wikitext.tests/src/org/eclipse/mylyn/wikitext/mediawiki/core/MediaWikiLanguageTest.java b/org.eclipse.mylyn.wikitext.tests/src/org/eclipse/mylyn/wikitext/mediawiki/core/MediaWikiLanguageTest.java index 6a4ed94ce..e52f2f639 100644 --- a/org.eclipse.mylyn.wikitext.tests/src/org/eclipse/mylyn/wikitext/mediawiki/core/MediaWikiLanguageTest.java +++ b/org.eclipse.mylyn.wikitext.tests/src/org/eclipse/mylyn/wikitext/mediawiki/core/MediaWikiLanguageTest.java @@ -7,7 +7,7 @@ * * Contributors: * David Green - initial API and implementation - * Jeremie Bresson - Bug 381506 + * Jeremie Bresson - Bug 381506, 381912 *******************************************************************************/ package org.eclipse.mylyn.wikitext.mediawiki.core; @@ -718,6 +718,95 @@ public class MediaWikiLanguageTest extends TestCase { assertTrue(html.contains("<table class=\"foo\"><tr><td>Some text</td></tr></table>")); } + public void testTableWithParagraphs() { + //BUG 381912: + StringBuilder sb = new StringBuilder(); + sb.append("{|border=\"1\"\n"); + sb.append("|\n"); + sb.append("A paragraph with '''Bold text''' in a cell.\n"); + sb.append("|\n"); + sb.append("A cell ''containing'' more...\n"); + sb.append("\n"); + sb.append("Than one paragraph.\n"); + sb.append("|}\n"); + + String html = parser.parseToHtml(sb.toString()); + TestUtil.println("HTML: \n" + html); + Pattern pattern = Pattern.compile("<table border=\"1\">\\s*<tr>\\s*<td>\\s*<p>\\s*A paragraph with \\s*<b>\\s*Bold text\\s*</b>\\s* in a cell.\\s*</p>\\s*</td>\\s*<td>\\s*<p>\\s*A cell \\s*<i>\\s*containing\\s*</i>\\s* more...\\s*</p>\\s*<p>\\s*Than one paragraph.\\s*</p>\\s*</td>\\s*</tr>\\s*</table>"); + assertContainsPattern(html, pattern); + } + + public void testTableWithLongerText() { + //BUG 381912: + //See: http://www.mediawiki.org/wiki/Help:Tables "longer text and more complex wiki syntax inside table cells". + StringBuilder sb = new StringBuilder(); + sb.append("{|border=\"1\"\n"); + sb.append("|Sxto mesto kusoks ti sam, \n"); + sb.append("Da skandalis studentis bezopasostif tut, \n"); + sb.append("dost takai vcxera na mne\n"); + sb.append("Mai na zxen problem zembulbas, \n"); + sb.append("dost vozduh dusxijm kai te. \n"); + sb.append("\n"); + sb.append("Oliv slozxju informacias bi bez\n"); + sb.append("om gde detes komnat,\n"); + sb.append("To divaj neskolk pridijt ili\n"); + sb.append("Ktor zapalka bezopasostif es tot. \n"); + sb.append("|\n"); + sb.append("* Sxto mesto kusoks ti sam\n"); + sb.append("* Vi edat zaspatit zapomnitlubovijm sol\n"); + sb.append("* dost takai vcxera na mne\n"); + sb.append("|}\n"); + + String html = parser.parseToHtml(sb.toString()); + TestUtil.println("HTML: \n" + html); + Pattern pattern = Pattern.compile("<table border=\"1\">\\s*<tr>\\s*<td>\\s*Sxto mesto kusoks ti sam,\\s*<p>\\s*Da skandalis studentis bezopasostif tut,\\s+dost takai vcxera na mne\\s+Mai na zxen problem zembulbas,\\s+dost vozduh dusxijm kai te.\\s*</p>\\s*<p>\\s*Oliv slozxju informacias bi bez\\s*om gde detes komnat,\\s*To divaj neskolk pridijt ili\\s*Ktor zapalka bezopasostif es tot.\\s*</p>\\s*</td>\\s*<td>\\s*<ul>\\s*<li>\\s*Sxto mesto kusoks ti sam\\s*</li>\\s*<li>\\s*Vi edat zaspatit zapomnitlubovijm sol\\s*</li>\\s*<li>\\s*dost takai vcxera na mne\\s*</li>\\s*</ul>\\s*</td>\\s*</tr>\\s*</table>"); + assertContainsPattern(html, pattern); + } + + public void testTableWithCodeInCellAndOptions() { + //BUG 381912: + StringBuilder sb = new StringBuilder(); + sb.append("{|border=\"1\"\n"); + sb.append("|\n"); + sb.append(" some\n"); + sb.append("|\n"); + sb.append(" code\n"); + sb.append(" multiline\n"); + sb.append("|style=\"background-color:#FFFF00;\"|\n"); + sb.append(" this is code in an highlighted cell\n"); + sb.append("|}\n"); + + String html = parser.parseToHtml(sb.toString()); + TestUtil.println("HTML: \n" + html); + Pattern pattern = Pattern.compile("<table border=\"1\">\\s*<tr>\\s*<td>\\s*<pre>\\s*some\n</pre>\\s*</td>\\s*<td>\\s*<pre>\\s*code\n multiline\n</pre>\\s*</td>\\s*<td style=\"background-color:#FFFF00;\">\\s*<pre>\\s*this is code in an highlighted cell\n</pre>\\s*</td>\\s*</tr>\\s*</table>"); + assertContainsPattern(html, pattern); + } + + public void testTableWithExplicitFirstRowAndRowSpan() { + //BUG 381912: + StringBuilder sb = new StringBuilder(); + sb.append("{|border=\"1\"\n"); + sb.append("|-\n"); + sb.append("!colspan=\"6\"|XYZ uv\n"); + sb.append("|-\n"); + sb.append("|rowspan=\"2\"|X1 & X2\n"); + sb.append("|y1\n"); + sb.append("|y2\n"); + sb.append("|y3\n"); + sb.append("|colspan=\"2\"|Z9\n"); + sb.append("|-\n"); + sb.append("|z8\n"); + sb.append("|colspan=\"2\"|T6\n"); + sb.append("|u4\n"); + sb.append("|U6\n"); + sb.append("|}\n"); + + String html = parser.parseToHtml(sb.toString()); + TestUtil.println("HTML: \n" + html); + Pattern pattern = Pattern.compile("<table border=\"1\">\\s*<tr>\\s*<th colspan=\"6\">\\s*XYZ uv\\s*</th>\\s*</tr>\\s*<tr>\\s*<td rowspan=\"2\">\\s*X1 & X2\\s*</td>\\s*<td>\\s*y1\\s*</td>\\s*<td>\\s*y2\\s*</td>\\s*<td>\\s*y3\\s*</td>\\s*<td colspan=\"2\">\\s*Z9\\s*</td>\\s*</tr>\\s*<tr>\\s*<td>\\s*z8\\s*</td>\\s*<td colspan=\"2\">\\s*T6\\s*</td>\\s*<td>\\s*u4\\s*</td>\\s*<td>\\s*U6\\s*</td>\\s*</tr>\\s*</table>"); + assertContainsPattern(html, pattern); + } + public void testEntityReference() { String tests = "À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ñ Ò Ó Ô Õ Ö Ø Ù Ú Û Ü ß à á â ã ä å æ ç è é ê ë ì í î ï ñ ò ó ô œ õ ö ø ù ú û ü ÿ ¿ ¡ § ¶ † ‡ • – — ‹ › « » ‘ ’ “ ” ™ © ® ¢ € ¥ £ ¤ ⁰ ¹ ² ³ ⁴ ∫ ∑ ∏ √ − ± ∞ ≈ ∝ ≡ ≠ ≤ ≥ × · ÷ ∂ ′ ″ ∇ ‰ ° ∴ ℵ ø ∈ ∉ ∩ ∪ ⊂ ⊃ ⊆ ⊇ ¬ ∧ ∨ ∃ ∀ ⇒ ⇐ ⇓ ⇑ ⇔ → ↓ ↑ ← ↔ — –"; final String[] allEntities = tests.split("\\s+"); |