Search in sources :

Example 1 with NodeIterator

use of com.vladsch.flexmark.ast.NodeIterator in project flexmark-java by vsch.

the class TableParagraphPreProcessor method preProcessBlock.

@Override
public int preProcessBlock(Paragraph block, ParserState state) {
    InlineParser inlineParser = state.getInlineParser();
    ArrayList<BasedSequence> tableLines = new ArrayList<BasedSequence>();
    int separatorLineNumber = -1;
    BasedSequence separatorLine = null;
    int blockIndent = block.getLineIndent(0);
    BasedSequence captionLine = null;
    int i = 0;
    for (BasedSequence rowLine : block.getContentLines()) {
        int rowNumber = tableLines.size();
        // too many header rows
        if (separatorLineNumber == -1 && rowNumber > options.maxHeaderRows)
            return 0;
        if (rowLine.indexOf('|') < 0) {
            if (separatorLineNumber == -1)
                return 0;
            if (options.withCaption) {
                BasedSequence trimmed = rowLine.trim();
                if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
                    captionLine = trimmed;
                }
            }
            break;
        }
        BasedSequence fullRowLine = block.getLineIndent(rowNumber) <= blockIndent ? rowLine.trimEOL() : rowLine.baseSubSequence(rowLine.getStartOffset() - (block.getLineIndent(rowNumber) - blockIndent), rowLine.getEndOffset() - rowLine.eolLength());
        if (separatorLineNumber == -1) {
            if (rowNumber >= options.minHeaderRows && TABLE_HEADER_SEPARATOR.matcher(rowLine).matches()) {
                // must start with | or cell, whitespace means its not a separator line
                if (fullRowLine.charAt(0) != ' ' && fullRowLine.charAt(0) != '\t' || rowLine.charAt(0) != '|') {
                    separatorLineNumber = rowNumber;
                    separatorLine = rowLine;
                } else if (fullRowLine.charAt(0) == ' ' || fullRowLine.charAt(0) == '\t') {
                    block.setHasTableSeparator(true);
                }
            }
        } else if (options.multiLineRows) {
        // TODO: need to do inline parsing here to determine whether we have open element constructs which need to include the next line
        }
        tableLines.add(rowLine);
        i++;
    }
    if (separatorLineNumber == -1)
        return 0;
    ArrayList<TableRow> tableRows = new ArrayList<TableRow>();
    for (BasedSequence rowLine : tableLines) {
        int rowNumber = tableRows.size();
        BasedSequence fullRowLine = block.getLineIndent(rowNumber) <= blockIndent ? rowLine.trimEOL() : rowLine.baseSubSequence(rowLine.getStartOffset() - (block.getLineIndent(rowNumber) - blockIndent), rowLine.getEndOffset() - rowLine.eolLength());
        TableRow tableRow = new TableRow(fullRowLine);
        int tableRowNumber;
        List<Node> sepList;
        if (rowNumber == separatorLineNumber) {
            sepList = inlineParser.parseCustom(fullRowLine, tableRow, separatorCharacters, pipeNodeMap);
            tableRowNumber = 0;
        } else {
            sepList = inlineParser.parseCustom(fullRowLine, tableRow, pipeCharacters, pipeNodeMap);
            if (rowNumber < separatorLineNumber)
                tableRowNumber = rowNumber + 1;
            else
                tableRowNumber = rowNumber - separatorLineNumber;
        }
        if (sepList == null) {
            if (rowNumber <= separatorLineNumber)
                return 0;
            break;
        }
        tableRow.setRowNumber(tableRowNumber);
        tableRows.add(tableRow);
    }
    // table is done, could be earlier than the lines tested earlier, may need to truncate lines
    Block tableBlock = new TableBlock(tableLines.subList(0, tableRows.size()));
    Node section = new TableHead(tableLines.get(0).subSequence(0, 0));
    tableBlock.appendChild(section);
    List<TableCell.Alignment> alignments = parseAlignment(separatorLine);
    int rowNumber = 0;
    int separatorColumns = alignments.size();
    for (TableRow tableRow : tableRows) {
        if (rowNumber == separatorLineNumber) {
            section.setCharsFromContent();
            section = new TableSeparator();
            tableBlock.appendChild(section);
        } else if (rowNumber == separatorLineNumber + 1) {
            section.setCharsFromContent();
            section = new TableBody();
            tableBlock.appendChild(section);
        }
        boolean firstCell = true;
        int cellCount = 0;
        NodeIterator nodes = new NodeIterator(tableRow.getFirstChild());
        TableRow newTableRow = new TableRow(tableRow.getChars());
        newTableRow.setRowNumber(tableRow.getRowNumber());
        int accumulatedSpanOffset = 0;
        while (nodes.hasNext()) {
            if (cellCount >= separatorColumns && options.discardExtraColumns) {
                if (options.headerSeparatorColumnMatch && rowNumber < separatorLineNumber) {
                    // header/separator mismatch
                    return 0;
                }
                break;
            }
            TableCell tableCell = new TableCell();
            if (firstCell && nodes.peek() instanceof TableColumnSeparator) {
                Node columnSep = nodes.next();
                tableCell.setOpeningMarker(columnSep.getChars());
                columnSep.unlink();
                firstCell = false;
            }
            TableCell.Alignment alignment = cellCount + accumulatedSpanOffset < separatorColumns ? alignments.get(cellCount + accumulatedSpanOffset) : null;
            tableCell.setHeader(rowNumber < separatorLineNumber);
            tableCell.setAlignment(alignment);
            // take all until separator or end of iterator
            while (nodes.hasNext()) {
                if (nodes.peek() instanceof TableColumnSeparator)
                    break;
                tableCell.appendChild(nodes.next());
            }
            // accumulate closers, and optional spans
            BasedSequence closingMarker = null;
            int span = 1;
            while (nodes.hasNext()) {
                if (!(nodes.peek() instanceof TableColumnSeparator))
                    break;
                if (closingMarker == null) {
                    closingMarker = nodes.next().getChars();
                    if (!options.columnSpans)
                        break;
                } else {
                    BasedSequence nextSep = nodes.peek().getChars();
                    if (!closingMarker.isContinuedBy(nextSep))
                        break;
                    closingMarker = closingMarker.spliceAtEnd(nextSep);
                    nodes.next().unlink();
                    span++;
                }
            }
            accumulatedSpanOffset += span - 1;
            if (closingMarker != null)
                tableCell.setClosingMarker(closingMarker);
            tableCell.setChars(tableCell.getChildChars());
            // TODO: Add option to keep cell whitespace, if yes, then convert it to text and merge adjacent text nodes
            if (options.trimCellWhitespace)
                tableCell.trimWhiteSpace();
            else
                tableCell.mergeWhiteSpace();
            tableCell.setText(tableCell.getChildChars());
            tableCell.setCharsFromContent();
            tableCell.setSpan(span);
            newTableRow.appendChild(tableCell);
            cellCount++;
        }
        if (options.headerSeparatorColumnMatch && rowNumber < separatorLineNumber && cellCount < separatorColumns) {
            // no match
            return 0;
        }
        while (options.appendMissingColumns && cellCount < separatorColumns) {
            TableCell tableCell = new TableCell();
            tableCell.setHeader(rowNumber < separatorLineNumber);
            tableCell.setAlignment(alignments.get(cellCount));
            newTableRow.appendChild(tableCell);
            cellCount++;
        }
        newTableRow.setCharsFromContent();
        section.appendChild(newTableRow);
        rowNumber++;
    }
    section.setCharsFromContent();
    if (section instanceof TableSeparator) {
        TableBody tableBody = new TableBody(section.getChars().subSequence(section.getChars().length()));
        tableBlock.appendChild(tableBody);
    }
    // Add caption if the option is enabled
    if (captionLine != null) {
        TableCaption caption = new TableCaption(captionLine.subSequence(0, 1), captionLine.subSequence(1, captionLine.length() - 1), captionLine.subSequence(captionLine.length() - 1));
        inlineParser.parse(caption.getText(), caption);
        caption.setCharsFromContent();
        tableBlock.appendChild(caption);
    }
    tableBlock.setCharsFromContent();
    block.insertBefore(tableBlock);
    state.blockAdded(tableBlock);
    return tableBlock.getChars().length();
}
Also used : NodeIterator(com.vladsch.flexmark.ast.NodeIterator) BasedSequence(com.vladsch.flexmark.util.sequence.BasedSequence) Node(com.vladsch.flexmark.ast.Node) InlineParser(com.vladsch.flexmark.parser.InlineParser) Block(com.vladsch.flexmark.ast.Block)

Aggregations

Block (com.vladsch.flexmark.ast.Block)1 Node (com.vladsch.flexmark.ast.Node)1 NodeIterator (com.vladsch.flexmark.ast.NodeIterator)1 InlineParser (com.vladsch.flexmark.parser.InlineParser)1 BasedSequence (com.vladsch.flexmark.util.sequence.BasedSequence)1