CommonMark

Block Parsing

Block parsers should implement BlockParserInterface and implement the following method:

parse()

When parsing a new line, the DocParser iterates through all registered block parsers and calls their parse() method. Each parser must determine whether it can handle the given line; if so, it should parse the given block and return true.

Parameters

Return value

parse() should return false if it’s unable to handle the current line for any reason. (The Cursor state should be restored before returning false if modified). Other parsers will then have a chance to try parsing the line. If all registered parsers return false, the line will be parsed as text.

Returning true tells the engine that you’ve successfully parsed the block at the given position. It is your responsibility to:

  1. Advance the cursor to the end of syntax indicating the block start
  2. Add the parsed block via $context->addBlock()

Tips

Block Elements

In addition to creating a block parser, you may also want to have it return a custom “block element” - this is a class that extends from AbstractBlock and represents that particular block within the AST.

Block elements also play a role during the parsing process as they tell the underlying engine how to handle subsequent blocks that are found.

AbstractBlockElement Methods

Method Purpose
canContain(...) Tell the engine whether a subsequent block can be added as a child of yours
isCode() Returns whether this block represents <code>
matchesNextLine(...) Returns whether this block continues onto the next line (some blocks are multi-line)
shouldLastLineBeBlank() Returns whether the last line should be blank (primarily used by ListItem elements)
finalize(...) Finalizes the block after all child items have been added, thus marking it as closed for modification

For examples on how these methods are used, see the core block element classes included with this library.

AbstractStringContainerBlock

If your element can contain strings of text, you should extend AbstractStringContainerBlock instead of AbstractBlock. This provides some additional methods needed to manage that inner text:

Method Purpose
handleRemainingContents(...) This is called when a block has been created but some other text still exists on that line
addLine(...) Adds the given line of text to the block element
getStringContent() Returns the strings contained with that block element

InlineContainerInterface

If the text contained by your block should be parsed for inline elements, you should also implement the InlineContainerInterface. This doesn’t add any new methods but does signal to the engine that inline parsing is required.

Multi-line Code Blocks

If you have a block which spans multiple lines and doesn’t contain any child blocks, consider having isCode() return true. Code blocks have a special feature which enables “greedy parsing” - once it first parses your block, the engine will assume that most of the subsequent lines of Markdown belong to your block - it won’t try using any other parsers until your parser’s matchesNextLine() method returns false, indicating that we’ve reached the end of that code block.