xref: /dokuwiki/inc/Parsing/ParserMode/GfmLinebreak.php (revision eb15e634e1400f6c4d78f5fb40179ca25f41574d)
1<?php
2
3namespace dokuwiki\Parsing\ParserMode;
4
5use dokuwiki\Parsing\Handler;
6
7/**
8 * GFM hard line break: two-or-more trailing spaces, or a single
9 * backslash, immediately before a non-final newline.
10 *
11 * Both delimiter forms land in one mode because they share semantics
12 * (emit linebreak), share the block-boundary rule (no break at the
13 * end of a paragraph or other block), and share the next-line
14 * leading-whitespace consumption (GFM strips it). Keeping all hard-
15 * break logic in one pattern is cheaper than two and matches GFM
16 * spec section 6.7 directly.
17 *
18 * Bypass inside code spans and fenced blocks falls out for free:
19 * those are whole-span PROTECTED / FORMATTING modes that capture
20 * their body in one regex match, so SUBSTITION patterns never see
21 * the inner text — same mechanism that exempts GfmEscape from
22 * code spans.
23 *
24 * No collision with the existing DokuWiki Linebreak mode (also at
25 * sort 140): DW's pattern is a literal double backslash `\\`,
26 * unrelated to either GFM delimiter form. In mixed syntax settings
27 * both modes can load and the leftmost match wins position-by-
28 * position. GfmEscape (sort 5) does not steal the backslash form
29 * either: its pattern requires the next char to be ASCII
30 * punctuation, and `\n` is not punctuation.
31 */
32class GfmLinebreak extends AbstractMode
33{
34    /** @inheritdoc */
35    public function getSort()
36    {
37        return 140;
38    }
39
40    /** @inheritdoc */
41    public function connectTo($mode)
42    {
43        // (?:[ ]{2,}|\\)            two+ spaces OR one backslash
44        // \n                        the line ending
45        // (?![ \t]*(?:\n|\z))       not at a paragraph break or EOF
46        // [ \t]*                    swallow leading WS of the next line
47        $this->Lexer->addSpecialPattern(
48            '(?:[ ]{2,}|\\\\)\n(?![ \t]*(?:\n|\z))[ \t]*',
49            $mode,
50            'gfm_linebreak'
51        );
52    }
53
54    /** @inheritdoc */
55    public function handle($match, $state, $pos, Handler $handler)
56    {
57        $handler->addCall('linebreak', [], $pos);
58        return true;
59    }
60}
61