Block parsers should implement
BlockParserInterface and implement the following method:
public function parse(ContextInterface $context, Cursor $cursor): bool;
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
ContextInterface $context- Provides information about the current context of the DocParser. Includes access to things like the document, current block container, and more.
Cursor $cursor- The
Cursorencapsulates the current state of the line being parsed and provides helpers for looking around the current position.
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.
true tells the engine that you’ve successfully parsed the block at the given position. It is your responsibility to:
- Advance the cursor to the end of syntax indicating the block start
- Add the parsed block via
- For best performance,
return falseas soon as possible
parse()method may be called thousands of times so be sure your code is optimized
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.
||Tell the engine whether a subsequent block can be added as a child of yours|
||Returns whether this block represents an extra-greedy
||Returns whether this block continues onto the next line (some blocks are multi-line)|
||Returns whether the last line should be blank (primarily used by
||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.
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:
||This is called when a block has been created but some other text still exists on that line|
||Adds the given line of text to the block element|
||Returns the strings contained with that block element|
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
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.