xref: /dokuwiki/inc/Parsing/ParserMode/Preformatted.php (revision 96d096f148d7def1456456590bd2910ff9115c0f)
1<?php
2
3namespace dokuwiki\Parsing\ParserMode;
4
5use dokuwiki\Parsing\Handler;
6use dokuwiki\Parsing\Handler\Preformatted as PreformattedHandler;
7
8class Preformatted extends AbstractMode
9{
10    /** @inheritdoc */
11    public function getSort()
12    {
13        return 20;
14    }
15
16    /**
17     * Number of leading spaces that trigger a preformatted block.
18     *
19     * DokuWiki's historical value is 2 spaces; Markdown uses 4. When
20     * `$conf['syntax']` is `markdown` or `md+dw` (Markdown preferred),
21     * we flip to 4 so indented code blocks match GFM. A single tab is
22     * always a trigger regardless of the space threshold.
23     */
24    protected function getIndentWidth(): int
25    {
26        global $conf;
27        $syntax = $conf['syntax'] ?? 'dokuwiki';
28        return in_array($syntax, ['markdown', 'md+dw'], true) ? 4 : 2;
29    }
30
31    /** @inheritdoc */
32    public function connectTo($mode)
33    {
34        $indent = str_repeat(' ', $this->getIndentWidth());
35
36        $this->Lexer->addEntryPattern('\n' . $indent, $mode, 'preformatted');
37        $this->Lexer->addEntryPattern('\n\t', $mode, 'preformatted');
38
39        // match continuation lines inside the preformatted block
40        $this->Lexer->addPattern('\n' . $indent, 'preformatted');
41        $this->Lexer->addPattern('\n\t', 'preformatted');
42    }
43
44    /** @inheritdoc */
45    public function postConnect()
46    {
47        $this->Lexer->addExitPattern('\n', 'preformatted');
48    }
49
50    /** @inheritdoc */
51    public function handle($match, $state, $pos, Handler $handler)
52    {
53        switch ($state) {
54            case DOKU_LEXER_ENTER:
55                $handler->setCallWriter(new PreformattedHandler($handler->getCallWriter()));
56                $handler->addCall('preformatted_start', [], $pos);
57                break;
58            case DOKU_LEXER_EXIT:
59                $handler->addCall('preformatted_end', [], $pos);
60                /** @var PreformattedHandler $reWriter */
61                $reWriter = $handler->getCallWriter();
62                $handler->setCallWriter($reWriter->process());
63                break;
64            case DOKU_LEXER_MATCHED:
65                $handler->addCall('preformatted_newline', [], $pos);
66                break;
67            case DOKU_LEXER_UNMATCHED:
68                $handler->addCall('preformatted_content', [$match], $pos);
69                break;
70        }
71
72        return true;
73    }
74}
75