The League of Extraordinary Packages

Our Packages:

Presented by The League of Extraordinary Packages

Getting Started

Customization

Inline Parsing

Inline parsers should extend from AbstractInlineParser and implement two methods:

getCharacters()

This method should return an array of single characters which the inline parser engine should stop on. When it does find a match in the current line the parse() method below may be called.

parse()

This method will be called if both conditions are met:

  1. The engine has stopped at a matching character; and,
  2. No other inline parsers have successfully parsed the character

Parameters

Return value

parse() should return false if it’s unable to handle the current line/character 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 character will be added as plain text.

Returning true tells the engine that you’ve successfully parsed the character (and related ones after it). It is your responsibility to:

  1. Advance the cursor to the end of the parsed text
  2. Add the parsed inline to the container ($inlineContext->getContainer()->appendChild(...))

Examples

Example 1 - Twitter Handles

Let’s say you wanted to autolink Twitter handles without using the link syntax. This could be accomplished by registering a new inline parser to handle the @ character:

<?php

class TwitterHandleParser extends AbstractInlineParser
{
    public function getCharacters()
    {
        return ['@'];
    }
    public function parse(InlineParserContext $inlineContext)
    {
        $cursor = $inlineContext->getCursor();
        // The @ symbol must not have any other characters immediately prior
        $previousChar = $cursor->peek(-1);
        if ($previousChar !== null && $previousChar !== ' ') {
            // peek() doesn't modify the cursor, so no need to restore state first
            return false;
        }
        // Save the cursor state in case we need to rewind and bail
        $previousState = $cursor->saveState();
        // Advance past the @ symbol to keep parsing simpler
        $cursor->advance();
        // Parse the handle
        $handle = $cursor->match('/^[A-Za-z0-9_]{1,15}(?!\w)/');
        if (empty($handle)) {
            // Regex failed to match; this isn't a valid Twitter handle
            $cursor->restoreState($previousState);
            return false;
        }
        $profileUrl = 'https://twitter.com/' . $handle;
        $inlineContext->getContainer()->appendChild(new Link($profileUrl, '@' . $handle));
        return true;
    }
}

$environment = Environment::createCommonMarkEnvironment();
$environment->addInlineParser(new TwitterHandleParser());

Example 2 - Emoticons

Let’s say you want to automatically convert smilies (or “frownies”) to emoticon images. This is incredibly easy with an inline parser:

<?php

class SmilieParser extends AbstractInlineParser
{
    public function getCharacters()
    {
        return [':'];
    }

    public function parse(InlineParserContext $inlineContext)
    {
        $cursor = $inlineContext->getCursor();

        // The next character must be a paren; if not, then bail
        // We use peek() to quickly check without affecting the cursor
        $nextChar = $cursor->peek();
        if ($nextChar !== '(' && $nextChar !== ')') {
            return false;
        }

        // Advance the cursor past the 2 matched chars since we're able to parse them successfully
        $cursor->advanceBy(2);
        
        // Add the corresponding image
        if ($nextChar === ')') {
            $inlineContext->getContainer()->appendChild(new Image('/img/happy.png'));
        } elseif ($nextChar === '(') {
            $inlineContext->getContainer()->appendChild(new Image('/img/sad.png'));
        }

        return true;
    }
}

$environment = Environment::createCommonMarkEnvironment();
$environment->addInlineParser(new SmilieParserParser());

Tips