• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

dg / texy / 22262497275

21 Feb 2026 07:01PM UTC coverage: 93.057% (+0.7%) from 92.367%
22262497275

push

github

dg
added CLAUDE.md

2426 of 2607 relevant lines covered (93.06%)

0.93 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.04
/src/Texy/Modules/ParagraphModule.php
1
<?php declare(strict_types=1);
2

3
/**
4
 * This file is part of the Texy! (https://texy.nette.org)
5
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6
 */
7

8
namespace Texy\Modules;
9

10
use Texy;
11
use Texy\Regexp;
12
use function preg_match, preg_split, str_contains, str_replace, strlen, strtr, substr_replace, trim;
13
use const PREG_SPLIT_NO_EMPTY;
14

15

16
/**
17
 * Processes paragraphs and handles line breaks.
18
 */
19
final class ParagraphModule extends Texy\Module
20
{
21
        public function __construct(Texy\Texy $texy)
1✔
22
        {
23
                $this->texy = $texy;
1✔
24
                $texy->addHandler('paragraph', $this->solve(...));
1✔
25
        }
1✔
26

27

28
        public function process(Texy\BlockParser $parser, string $content, Texy\HtmlElement $el): void
1✔
29
        {
30
                $parts = $parser->isIndented()
1✔
31
                        ? preg_split('#(\n(?!\ )|\n{2,})#', $content, -1, PREG_SPLIT_NO_EMPTY)
1✔
32
                        : preg_split('#(\n{2,})#', $content, -1, PREG_SPLIT_NO_EMPTY);
1✔
33

34
                foreach ($parts ?: [] as $s) {
1✔
35
                        $s = trim($s);
1✔
36
                        if ($s === '') {
1✔
37
                                continue;
×
38
                        }
39

40
                        // try to find modifier
41
                        $mod = null;
1✔
42
                        if ($mx = Regexp::match($s, '#' . Texy\Patterns::MODIFIER_H . '(?=\n|\z)#sUm', Regexp::OFFSET_CAPTURE)) {
1✔
43
                                [$mMod] = $mx[1];
1✔
44
                                $s = trim(substr_replace($s, '', $mx[0][1], strlen($mx[0][0])));
1✔
45
                                if ($s === '') {
1✔
46
                                        continue;
1✔
47
                                }
48

49
                                $mod = new Texy\Modifier;
1✔
50
                                $mod->setProperties($mMod);
1✔
51
                        }
52

53
                        $res = $this->texy->invokeAroundHandlers('paragraph', $parser, [$s, $mod]);
1✔
54
                        if ($res) {
1✔
55
                                $el->insert(null, $res);
1✔
56
                        }
57
                }
58
        }
1✔
59

60

61
        /**
62
         * Finish invocation.
63
         */
64
        private function solve(
1✔
65
                Texy\HandlerInvocation $invocation,
66
                string $content,
67
                ?Texy\Modifier $mod = null,
68
        ): Texy\HtmlElement
69
        {
70
                $texy = $this->texy;
1✔
71

72
                // find hard linebreaks
73
                $content = $texy->mergeLines
1✔
74
                        // ....
75
                        // ... => \r means break line
76
                        ? Regexp::replace($content, '#\n\ +(?=\S)#', "\r")
1✔
77
                        : Regexp::replace($content, '#\n#', "\r");
1✔
78

79
                $el = new Texy\HtmlElement('p');
1✔
80
                $el->parseLine($texy, $content);
1✔
81
                $content = $el->getText();
1✔
82
                assert($content !== null);
83

84
                // check content type
85
                // block contains block tag
86
                if (str_contains($content, $texy::CONTENT_BLOCK)) {
1✔
87
                        $el->setName(null); // ignores modifier!
1✔
88

89
                // block contains text (protected)
90
                } elseif (str_contains($content, $texy::CONTENT_TEXTUAL)) {
1✔
91
                        // leave element p
92

93
                // block contains text
94
                } elseif (preg_match('#[^\s' . Texy\Patterns::MARK . ']#u', $content)) {
1✔
95
                        // leave element p
96

97
                // block contains only replaced element
98
                } elseif (str_contains($content, $texy::CONTENT_REPLACED)) {
1✔
99
                        if ($texy->nontextParagraph instanceof Texy\HtmlElement) {
1✔
100
                                $el = (clone $texy->nontextParagraph)->setText($content);
1✔
101
                        } else {
102
                                $el->setName($texy->nontextParagraph);
1✔
103
                        }
104

105
                // block contains only markup tags or spaces or nothing
106
                } else {
107
                        // if {ignoreEmptyStuff} return null;
108
                        if (!$mod) {
1✔
109
                                $el->setName(null);
1✔
110
                        }
111
                }
112

113
                if ($el->getName()) {
1✔
114
                        // apply modifier
115
                        if ($mod) {
1✔
116
                                $mod->decorate($texy, $el);
1✔
117
                        }
118

119
                        // add <br>
120
                        if (str_contains($content, "\r")) {
1✔
121
                                $key = $texy->protect('<br>', $texy::CONTENT_REPLACED);
1✔
122
                                $content = str_replace("\r", $key, $content);
1✔
123
                        }
124
                }
125

126
                $content = strtr($content, "\r\n", '  ');
1✔
127
                $el->setText($content);
1✔
128

129
                return $el;
1✔
130
        }
131
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc