Index: src/main/java/org/apache/maven/doxia/module/confluence/ConfluenceParser.java =================================================================== --- src/main/java/org/apache/maven/doxia/module/confluence/ConfluenceParser.java (revision 591745) +++ src/main/java/org/apache/maven/doxia/module/confluence/ConfluenceParser.java (working copy) @@ -40,10 +40,10 @@ import org.apache.maven.doxia.util.ByLineSource; /** - * Parse the Confluence. - * See - * Confluence Notation Guide Overview - * + * Parse the Confluence. See Confluence Notation Guide + * Overview + * * @version $Id$ * @since 1.0 * @plexus.component role="org.apache.maven.doxia.parser.Parser" role-hint="confluence" @@ -59,11 +59,14 @@ BlockParser figureParser = new FigureBlockParser(); BlockParser verbatimParser = new VerbatimBlockParser(); BlockParser horizontalRuleParser = new HorizontalRuleBlockParser(); - BlockParser paragraphParser = new ParagraphBlockParser(); BlockParser listParser = new ListBlockParser(); BlockParser tableParser = new TableBlockParser(); - parsers = new BlockParser[] { headingParser, figureParser, verbatimParser, horizontalRuleParser, listParser, + BlockParser[] subparsers = new BlockParser[] { headingParser, figureParser, listParser, tableParser }; + BlockParser paragraphParser = new ParagraphBlockParser( subparsers ); + + parsers = + new BlockParser[] { headingParser, figureParser, verbatimParser, horizontalRuleParser, listParser, tableParser, paragraphParser }; } @@ -90,11 +93,10 @@ if ( parser.accept( line, source ) ) { /* - System.out.println( "------------------------------------------------------------" ); - System.out.println( "line = " + line ); - System.out.println( "line accepted by: " + parser ); - System.out.println( "------------------------------------------------------------" ); - */ + * System.out.println( "------------------------------------------------------------" ); + * System.out.println( "line = " + line ); System.out.println( "line accepted by: " + parser ); + * System.out.println( "------------------------------------------------------------" ); + */ accepted = true; @@ -105,19 +107,16 @@ } /* - if ( !accepted ) - { - throw new ParseException( "don't know how to handle line: " + source.getLineNumber() + ": " + line ); - } - */ + * if ( !accepted ) { throw new ParseException( "don't know how to handle line: " + source.getLineNumber() + ": " + + * line ); } + */ } return blocks; } /** {@inheritDoc} */ - public synchronized void parse( Reader reader, - Sink sink ) + public synchronized void parse( Reader reader, Sink sink ) throws ParseException { List blocks; Index: src/main/java/org/apache/maven/doxia/module/confluence/parser/ChildBlocksBuilder.java =================================================================== --- src/main/java/org/apache/maven/doxia/module/confluence/parser/ChildBlocksBuilder.java (revision 591745) +++ src/main/java/org/apache/maven/doxia/module/confluence/parser/ChildBlocksBuilder.java (working copy) @@ -23,8 +23,6 @@ import java.util.Arrays; import java.util.List; -import org.apache.maven.doxia.parser.ParseException; -import org.apache.maven.doxia.util.ByLineSource; import org.codehaus.plexus.util.StringUtils; /** @@ -199,54 +197,4 @@ return new StringBuffer(); } - /** - * Slurp lines from the source starting with the given line appending them together into a StringBuffer until an - * empty line is reached, and while the source contains more lines. The result can be passed to the - * {@link #getBlocks(String)} method. - * - * @param line the first line - * @param source the source to read new lines from - * @return a StringBuffer appended with lines - * @throws ParseException - */ - public String appendUntilEmptyLine( ByLineSource source ) - throws ParseException - { - StringBuffer text = new StringBuffer(); - - String line; - - while ( ( line = source.getNextLine() ) != null ) - { - - if ( line.trim().length() == 0 ) - { - break; - } - - if ( text.length() == 0 ) - { - text.append( line.trim() ); - } - else - { - text.append( " " + line.trim() ); - } - - } - // TODO: instead of just flying along we should probably test new lines - // in the other parsers - // to make sure there aren't things that should be handled by other - // parsers. For example, right - // now: - // Blah blah blah blah - // # one - // # two - // - // Will not get processed correctly. This parser will try to deal with - // it when it should be handled - // by the list parser. - - return text.toString(); - } } Index: src/main/java/org/apache/maven/doxia/module/confluence/parser/FigureBlockParser.java =================================================================== --- src/main/java/org/apache/maven/doxia/module/confluence/parser/FigureBlockParser.java (revision 591745) +++ src/main/java/org/apache/maven/doxia/module/confluence/parser/FigureBlockParser.java (working copy) @@ -42,10 +42,8 @@ line = line.substring( 2 ); } - ChildBlocksBuilder builder = new ChildBlocksBuilder(); + String caption = line + appendUntilEmptyLine( source ); - String caption = line + builder.appendUntilEmptyLine( source ); - if ( caption.trim().length() > 0 ) { return new FigureBlock( image, caption ); @@ -53,4 +51,42 @@ return new FigureBlock( image ); } + + /** + * Slurp lines from the source starting with the given line appending them together into a StringBuffer until an + * empty line is reached, and while the source contains more lines. + * + * @param source the source to read new lines from + * @return a StringBuffer appended with lines + * @throws ParseException + */ + private String appendUntilEmptyLine(ByLineSource source ) + throws ParseException + { + StringBuffer text = new StringBuffer(); + + String line; + + while ( ( line = source.getNextLine() ) != null ) + { + + if ( line.trim().length() == 0 ) + { + break; + } + + if ( text.length() == 0 ) + { + text.append( line.trim() ); + } + else + { + text.append( " " + line.trim() ); + } + + } + + return text.toString(); + } + } Index: src/main/java/org/apache/maven/doxia/module/confluence/parser/list/ListBlockParser.java =================================================================== --- src/main/java/org/apache/maven/doxia/module/confluence/parser/list/ListBlockParser.java (revision 591745) +++ src/main/java/org/apache/maven/doxia/module/confluence/parser/list/ListBlockParser.java (working copy) @@ -37,64 +37,77 @@ public boolean accept( String line, ByLineSource source ) { - String nextLine = null; - - try + if ( isList( line ) ) { - nextLine = source.getNextLine(); - - source.ungetLine(); - } - catch ( ParseException e ) - { - // do nothing - } - - if ( isList( line ) && isList( nextLine ) ) - { return true; } return false; } - public Block visit( String line, ByLineSource source ) + public Block visit( String line, ByLineSource source ) throws ParseException { - TreeListBuilder treeListBuilder = new TreeListBuilder(); + TreeListBuilder treeListBuilder = new TreeListBuilder(); - String l = line; + StringBuffer text = new StringBuffer(); do { - if ( !isList( l ) ) + if ( line.trim().length() == 0 ) { break; } + + if (text.length()>0 && isList( line ) ) + { + // We reached a new line with list prefix + addItem( treeListBuilder, text ); + } - if ( isBulletedList( l ) ) + if ( text.length() == 0 ) { - int level = getLevel( l, '*' ); - - treeListBuilder.feedEntry( BULLETED_LIST, level, l.substring( level ) ); + text.append( line.trim() ); } else { - int level = getLevel( l, '#' ); + text.append( " " + line.trim() ); + } - treeListBuilder.feedEntry( NUMBERED_LIST, level, l.substring( level ) ); - } } - while ( ( l = source.getNextLine() ) != null ); + while ( ( line = source.getNextLine() ) != null ); + if ( text.length() > 0 ) + { + addItem( treeListBuilder, text ); + } + return treeListBuilder.getBlock(); } - private int getLevel( String line, char c ) + private void addItem( TreeListBuilder treeListBuilder, StringBuffer text ) { + String item = text.toString(); + if ( isBulletedList( item ) ) + { + int level = getLevel( item, '*' ); + + treeListBuilder.feedEntry( BULLETED_LIST, level, item.substring( level ) ); + } + else + { + int level = getLevel( item, '#' ); + + treeListBuilder.feedEntry( NUMBERED_LIST, level, item.substring( level ) ); + } + text.setLength( 0 ); + } + + private int getLevel( String line, char c ) + { int level = 0; - while ( line.charAt( level ) == c ) + while ( line.charAt( level ) == c ) { level++; } Index: src/main/java/org/apache/maven/doxia/module/confluence/parser/list/TreeListBuilder.java =================================================================== --- src/main/java/org/apache/maven/doxia/module/confluence/parser/list/TreeListBuilder.java (revision 591745) +++ src/main/java/org/apache/maven/doxia/module/confluence/parser/list/TreeListBuilder.java (working copy) @@ -82,7 +82,7 @@ } } } - current.addChildren( text, type ); + current.addChildren( text.trim(), type ); } public ListBlock getBlock() Index: src/main/java/org/apache/maven/doxia/module/confluence/parser/ParagraphBlockParser.java =================================================================== --- src/main/java/org/apache/maven/doxia/module/confluence/parser/ParagraphBlockParser.java (revision 591745) +++ src/main/java/org/apache/maven/doxia/module/confluence/parser/ParagraphBlockParser.java (working copy) @@ -26,6 +26,14 @@ implements BlockParser { + private BlockParser[] parsers; + + public ParagraphBlockParser( BlockParser[] parsers ) + { + super(); + this.parsers = parsers; + } + public boolean accept( String line, ByLineSource source ) { return true; @@ -36,9 +44,63 @@ { ChildBlocksBuilder builder = new ChildBlocksBuilder(); - StringBuffer text = new StringBuffer( line ); - text.append( builder.appendUntilEmptyLine( source ) ); + return new ParagraphBlock( builder.getBlocks( appendUntilEmptyLine( line, source ) ) ); + } - return new ParagraphBlock( builder.getBlocks( text.toString() ) ); + /** + * Slurp lines from the source starting with the given line appending them together into a StringBuffer until an + * empty line is reached, and while the source contains more lines. The result can be passed to the + * {@link #getBlocks(String)} method. + * + * @param line the first line + * @param source the source to read new lines from + * @return a StringBuffer appended with lines + * @throws ParseException + */ + private String appendUntilEmptyLine( String line, ByLineSource source ) + throws ParseException + { + StringBuffer text = new StringBuffer(); + + do + { + + if ( line.trim().length() == 0 ) + { + break; + } + + boolean accepted = false; + for ( int i = 0; i < parsers.length; i++ ) + { + BlockParser parser = parsers[i]; + if ( parser.accept( line, source ) ) + { + accepted = true; + break; + } + } + if ( accepted ) + { + // Slightly fragile - if any of the parsers need to do this in order to decide whether to accept a line, + // then it will barf because of the contract of ByLineSource + source.ungetLine(); + break; + } + + if ( text.length() == 0 ) + { + text.append( line.trim() ); + } + else + { + text.append( " " + line.trim() ); + } + + } + while ( ( line = source.getNextLine() ) != null ); + + return text.toString(); } + } Index: src/test/java/org/apache/maven/doxia/module/confluence/ConfluenceParserTest.java =================================================================== --- src/test/java/org/apache/maven/doxia/module/confluence/ConfluenceParserTest.java (revision 591745) +++ src/test/java/org/apache/maven/doxia/module/confluence/ConfluenceParserTest.java (working copy) @@ -146,8 +146,7 @@ { String result = locateAndParseTestSourceFile( "nested-list" ); - assertContainsLines( "Nested list not found", result, - "begin:listItem\ntext: A top level list item\nbegin:list" ); + assertContainsLines( "Nested list not found", result, "begin:listItem\ntext: A top level list item\nbegin:list" ); // two lists in the input... assertEquals( 3, result.split( "end:list\n" ).length ); // ...and 4 list items @@ -165,11 +164,13 @@ assertContainsLines( result, "begin:monospaced\ntext: monospaced\n" ); assertContainsLines( result, "begin:link, name: http://jira.codehaus.org\ntext: http://jira.codehaus.org\n" ); assertContainsLines( result, "begin:link, name: http://jira.codehaus.org\ntext: JIRA\n" ); - assertContainsLines( result, "begin:listItem\ntext: Item with no formatting\nend:listItem\n" ); - // one list in the input... - assertEquals( 2, result.split( "end:list\n" ).length ); - // ...and 5 list items - assertEquals( 6, result.split( "end:listItem\n" ).length ); + assertContainsLines( result, "begin:listItem\ntext: Item with no formatting\nend:listItem\n" ); + assertContainsLines( result, "begin:listItem\ntext: One bullet\nend:listItem\n" ); + assertContainsLines( result, "begin:listItem\ntext: A list item with more than one line\nend:listItem\n" ); + // 3 lists in the input... + assertEquals( 4, result.split( "end:list\n" ).length ); + // ...and 7 list items + assertEquals( 8, result.split( "end:listItem\n" ).length ); } /** @throws Exception */ @@ -219,13 +220,13 @@ assertContainsLines( result, "figureGraphics, name: images/photo.jpg\n" + "begin:figureCaption\ntext: With caption on same line\n" + "end:figureCaption" ); assertContainsLines( result, "figureGraphics, name: images/nolinebreak.jpg\n" - + "begin:figureCaption\ntext: With caption underneath and no linebreak\nend:figureCaption" ); + + "begin:figureCaption\ntext: With caption underneath and no linebreak\nend:figureCaption" ); // ignore linebreak after figure insert... assertContainsLines( result, "figureGraphics, name: images/linebreak.jpg\n" - + "begin:figureCaption\ntext: With caption underneath and linebreak\nend:figureCaption" ); + + "begin:figureCaption\ntext: With caption underneath and linebreak\nend:figureCaption" ); // ignore formtting in caption... assertContainsLines( result, "figureGraphics, name: images/bold.jpg\n" - + "begin:figureCaption\ntext: With *bold* caption underneath\nend:figureCaption" ); + + "begin:figureCaption\ntext: With *bold* caption underneath\nend:figureCaption" ); // 2 paragraphs in the input... (the figures do not go in a paragraph by analogy with AptParser) assertEquals( 3, result.split( "end:paragraph\n" ).length ); } @@ -247,6 +248,49 @@ assertEquals( 6, result.split( "end:link\n" ).length ); } + /** @throws Exception */ + public void testParagraphWithList() + throws Exception + { + String result = locateAndParseTestSourceFile( "paragraph-list" ); + + assertContainsLines( result, "begin:paragraph\ntext: A paragraph\nend:paragraph\n" ); + assertContainsLines( result, "begin:listItem\ntext: A nested list item\nend:listItem\n" ); + assertContainsLines( result, "begin:listItem\ntext: Another nested list item with two lines\nend:listItem\n" ); + // 2 paragraphs in the input... + assertEquals( 3, result.split( "end:paragraph\n" ).length ); + // 1 list in the input... + assertEquals( 2, result.split( "end:list\n" ).length ); + } + + /** @throws Exception */ + public void testParagraphWithFigure() + throws Exception + { + String result = locateAndParseTestSourceFile( "paragraph-figure" ); + + assertContainsLines( result, "begin:paragraph\ntext: A paragraph\nend:paragraph\n" ); + assertContainsLines( result, "begin:figure\nfigureGraphics, name: images/logo.png\nbegin:figureCaption\ntext: with a figure\nend:figureCaption" ); + // 2 paragraphs in the input... + assertEquals( 3, result.split( "end:paragraph\n" ).length ); + // 1 figure in the input... + assertEquals( 2, result.split( "end:figure\n" ).length ); + } + + /** @throws Exception */ + public void testParagraphWithHeader() + throws Exception + { + String result = locateAndParseTestSourceFile( "paragraph-header" ); + + assertContainsLines( result, "begin:paragraph\ntext: A paragraph\nend:paragraph\n" ); + assertContainsLines( result, "begin:section2\nbegin:sectionTitle2\ntext: A header\nend:sectionTitle2" ); + // 3 paragraphs in the input... + assertEquals( 4, result.split( "end:paragraph\n" ).length ); + // 1 header in the input... + assertEquals( 2, result.split( "end:sectionTitle2\n" ).length ); + } + private void assertContainsLines( String message, String result, String lines ) { lines = StringUtils.replace( lines, "\n", EOL ); Index: src/test/resources/paragraph-figure.confluence =================================================================== --- src/test/resources/paragraph-figure.confluence (revision 0) +++ src/test/resources/paragraph-figure.confluence (revision 0) @@ -0,0 +1,6 @@ + +A paragraph +!images/logo.png! +with a figure + +Another paragraph Index: src/test/resources/paragraph-header.confluence =================================================================== --- src/test/resources/paragraph-header.confluence (revision 0) +++ src/test/resources/paragraph-header.confluence (revision 0) @@ -0,0 +1,6 @@ + +A paragraph +h2. A header +with a header + +Another paragraph Index: src/test/resources/paragraph-list.confluence =================================================================== --- src/test/resources/paragraph-list.confluence (revision 0) +++ src/test/resources/paragraph-list.confluence (revision 0) @@ -0,0 +1,8 @@ + +A paragraph +* A nested list item +* Another nested list item +with two lines + +Back at the top level + Index: src/test/resources/simple-list.confluence =================================================================== --- src/test/resources/simple-list.confluence (revision 591745) +++ src/test/resources/simple-list.confluence (working copy) @@ -4,3 +4,10 @@ * This is some {{monospaced}} text. * Item with no formatting +Paragraph + +* One bullet + +* A list item with +more than one line +