xref: /dokuwiki/inc/Parsing/ParserMode/GfmEmphasisStrong.php (revision 057ab5a057a76df652cfe4176512a550ca9937f6)
1<?php
2
3namespace dokuwiki\Parsing\ParserMode;
4
5use dokuwiki\Parsing\Handler;
6
7/**
8 * GFM / CommonMark em-wrapping-strong via triple asterisks: `***text***`.
9 *
10 * Renders as <em><strong>text</strong></em>. Only the exact 3+3 symmetric
11 * variant is supported. Longer symmetric runs (`****foo****`,
12 * `******foo******`) or asymmetric runs (`***foo**`) require CommonMark's
13 * full delimiter-pairing algorithm and are out of scope.
14 *
15 * Sort 65 is below Strong (70) so this mode wins the lexer race for
16 * `***...***` patterns.
17 */
18class GfmEmphasisStrong extends AbstractFormatting
19{
20    /** @inheritdoc */
21    public function getSort()
22    {
23        return 65;
24    }
25
26    /** @inheritdoc */
27    protected function getModeName(): string
28    {
29        return 'gfm_emphasis_strong';
30    }
31
32    /** @inheritdoc */
33    protected function getEntryPattern(): string
34    {
35        // Broken down:
36        //   (?<!\*)                  — opener not preceded by `*` (so we
37        //                              don't match inside `****...` runs)
38        //   \*\*\*                   — exactly three opening `*`
39        //   (?=[^\s*])               — next body char: not whitespace, not `*`
40        //                              (flanking-opener rule)
41        return '(?<!\*)\*\*\*(?=[^\s*])';
42    }
43
44    /** @inheritdoc */
45    protected function getExitPattern(): string
46    {
47        return '(?<=[^\s])\*\*\*(?!\*)';
48    }
49
50    /**
51     * Emit em wrapping strong (and their closers in reverse order).
52     * Overridden because AbstractFormatting's default emits a single
53     * open/close pair — we need two each.
54     *
55     * @inheritdoc
56     */
57    public function handle($match, $state, $pos, Handler $handler)
58    {
59        switch ($state) {
60            case DOKU_LEXER_ENTER:
61                $handler->addCall('emphasis_open', [], $pos);
62                $handler->addCall('strong_open', [], $pos);
63                break;
64            case DOKU_LEXER_EXIT:
65                $handler->addCall('strong_close', [], $pos);
66                $handler->addCall('emphasis_close', [], $pos);
67                break;
68            case DOKU_LEXER_UNMATCHED:
69                $handler->addCall('cdata', [$match], $pos);
70                break;
71        }
72        return true;
73    }
74}
75