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