1<?php
2
3/*
4 * This file is part of the league/commonmark package.
5 *
6 * (c) Colin O'Dell <colinodell@gmail.com>
7 *
8 * Original code based on the CommonMark JS reference parser (http://bitly.com/commonmark-js)
9 *  - (c) John MacFarlane
10 *
11 * For the full copyright and license information, please view the LICENSE
12 * file that was distributed with this source code.
13 */
14
15namespace League\CommonMark\Extension\SmartPunct;
16
17use League\CommonMark\Inline\Element\Text;
18use League\CommonMark\Inline\Parser\InlineParserInterface;
19use League\CommonMark\InlineParserContext;
20
21final class PunctuationParser implements InlineParserInterface
22{
23    /**
24     * @return string[]
25     */
26    public function getCharacters(): array
27    {
28        return ['-', '.'];
29    }
30
31    public function parse(InlineParserContext $inlineContext): bool
32    {
33        $cursor = $inlineContext->getCursor();
34        $ch = $cursor->getCharacter();
35
36        // Ellipses
37        if ($ch === '.' && $matched = $cursor->match('/^\\.( ?\\.)\\1/')) {
38            $inlineContext->getContainer()->appendChild(new Text('…'));
39
40            return true;
41        }
42
43        // Em/En-dashes
44        elseif ($ch === '-' && $matched = $cursor->match('/^(?<!-)(-{2,})/')) {
45            $count = strlen($matched);
46            $en_dash = '–';
47            $en_count = 0;
48            $em_dash = '—';
49            $em_count = 0;
50            if ($count % 3 === 0) { // If divisible by 3, use all em dashes
51                $em_count = $count / 3;
52            } elseif ($count % 2 === 0) { // If divisible by 2, use all en dashes
53                $en_count = $count / 2;
54            } elseif ($count % 3 === 2) { // If 2 extra dashes, use en dash for last 2; em dashes for rest
55                $em_count = ($count - 2) / 3;
56                $en_count = 1;
57            } else { // Use en dashes for last 4 hyphens; em dashes for rest
58                $em_count = ($count - 4) / 3;
59                $en_count = 2;
60            }
61            $inlineContext->getContainer()->appendChild(new Text(
62                str_repeat($em_dash, (int) $em_count) . str_repeat($en_dash, (int) $en_count)
63            ));
64
65            return true;
66        }
67
68        return false;
69    }
70}
71