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

dg / texy / 22262381750

25 Jan 2026 11:44PM UTC coverage: 92.367% (-0.7%) from 93.057%
22262381750

push

github

dg
cs

9 of 11 new or added lines in 8 files covered. (81.82%)

161 existing lines in 23 files now uncovered.

2384 of 2581 relevant lines covered (92.37%)

0.92 hits per line

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

91.1
/src/Texy/Modules/BlockModule.php
1
<?php
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
declare(strict_types=1);
9

10
namespace Texy\Modules;
11

12
use Texy;
13
use Texy\Helpers;
14
use Texy\HtmlElement;
15
use function assert, htmlspecialchars, preg_split, str_replace, trim;
16
use const ENT_NOQUOTES;
17

18

19
/**
20
 * Special blocks module.
21
 */
22
final class BlockModule extends Texy\Module
23
{
24
        public function __construct(Texy\Texy $texy)
1✔
25
        {
26
                $this->texy = $texy;
1✔
27

28
                //$texy->allowed['blocks'] = true;
29
                $texy->allowed['block/default'] = true;
1✔
30
                $texy->allowed['block/pre'] = true;
1✔
31
                $texy->allowed['block/code'] = true;
1✔
32
                $texy->allowed['block/html'] = true;
1✔
33
                $texy->allowed['block/text'] = true;
1✔
34
                $texy->allowed['block/texysource'] = true;
1✔
35
                $texy->allowed['block/comment'] = true;
1✔
36
                $texy->allowed['block/div'] = true;
1✔
37

38
                $texy->addHandler('block', $this->solve(...));
1✔
39
                $texy->addHandler('beforeBlockParse', $this->beforeBlockParse(...));
1✔
40

41
                $texy->registerBlockPattern(
1✔
42
                        $this->pattern(...),
1✔
43
                        '#^/--++\ *+(.*)' . Texy\Patterns::MODIFIER_H . '?$((?:\n(?0)|\n.*+)*)(?:\n\\\--.*$|\z)#mUi',
1✔
44
                        'blocks',
1✔
45
                );
46
        }
1✔
47

48

49
        /**
50
         * Single block pre-processing.
51
         */
52
        private function beforeBlockParse(Texy\BlockParser $parser, string &$text): void
1✔
53
        {
54
                // autoclose exclusive blocks
55
                $text = Texy\Regexp::replace(
1✔
56
                        $text,
1✔
57
                        '#^(/--++\ *+(?!div|texysource).*)$((?:\n.*+)*?)(?:\n\\\--.*$|(?=(\n/--.*$)))#mi',
1✔
58
                        "\$1\$2\n\\--",
1✔
59
                );
60
        }
1✔
61

62

63
        /**
64
         * Callback for:.
65
         * /-----code html .(title)[class]{style}
66
         * ....
67
         * ....
68
         * \----
69
         */
70
        public function pattern(Texy\BlockParser $parser, array $matches): HtmlElement|string|null
1✔
71
        {
72
                [, $mParam, $mMod, $mContent] = $matches;
1✔
73
                // [1] => code | text | ...
74
                // [2] => ... additional parameters
75
                // [3] => .(title)[class]{style}<>
76
                // [4] => ... content
77

78
                $mod = new Texy\Modifier($mMod);
1✔
79
                $parts = preg_split('#\s+#u', $mParam, 2);
1✔
80
                $blocktype = empty($parts[0]) ? 'block/default' : 'block/' . $parts[0];
1✔
81
                $param = empty($parts[1]) ? null : $parts[1];
1✔
82

83
                return $this->texy->invokeAroundHandlers('block', $parser, [$blocktype, $mContent, $param, $mod]);
1✔
84
        }
85

86

87
        /**
88
         * Finish invocation.
89
         */
90
        private function solve(
1✔
91
                Texy\HandlerInvocation $invocation,
92
                string $blocktype,
93
                string $s,
94
                $param,
95
                Texy\Modifier $mod,
96
        ): HtmlElement|string|null
97
        {
98
                $texy = $this->texy;
1✔
99
                $parser = $invocation->getParser();
1✔
100
                assert($parser instanceof Texy\BlockParser);
101

102
                if ($blocktype === 'block/texy') {
1✔
UNCOV
103
                        return $this->blockTexy($s, $texy, $parser);
×
104
                } elseif (empty($texy->allowed[$blocktype])) {
1✔
105
                        return null;
1✔
106
                } elseif ($blocktype === 'block/texysource') {
1✔
107
                        return $this->blockTexySource($s, $texy, $mod, $param);
1✔
108
                } elseif ($blocktype === 'block/code') {
1✔
109
                        return $this->blockCode($s, $texy, $mod, $param);
1✔
110
                } elseif ($blocktype === 'block/default') {
1✔
111
                        return $this->blockDefault($s, $texy, $mod, $param);
1✔
112
                } elseif ($blocktype === 'block/pre') {
1✔
113
                        return $this->blockPre($s, $texy, $mod);
1✔
114
                } elseif ($blocktype === 'block/html') {
1✔
115
                        return $this->blockHtml($s, $texy);
1✔
116
                } elseif ($blocktype === 'block/text') {
1✔
117
                        return $this->blockText($s, $texy);
1✔
118
                } elseif ($blocktype === 'block/comment') {
1✔
119
                        return $this->blockComment();
1✔
120
                } elseif ($blocktype === 'block/div') {
1✔
121
                        return $this->blockDiv($s, $texy, $mod, $parser);
1✔
122
                }
123

UNCOV
124
                return null;
×
125
        }
126

127

128
        private function blockTexy(string $s, Texy\Texy $texy, Texy\BlockParser $parser): HtmlElement
129
        {
UNCOV
130
                $el = new HtmlElement;
×
131
                $el->parseBlock($texy, $s, $parser->isIndented());
×
132
                return $el;
×
133
        }
134

135

136
        private function blockTexySource(string $s, Texy\Texy $texy, Texy\Modifier $mod, $param): string|HtmlElement
1✔
137
        {
138
                $s = Helpers::outdent($s);
1✔
139
                if ($s === '') {
1✔
UNCOV
140
                        return "\n";
×
141
                }
142

143
                $el = new HtmlElement;
1✔
144
                if ($param === 'line') {
1✔
UNCOV
145
                        $el->parseLine($texy, $s);
×
146
                } else {
147
                        $el->parseBlock($texy, $s);
1✔
148
                }
149

150
                $s = $el->toHtml($texy);
1✔
151
                return $this->blockCode($s, $texy, $mod, 'html');
1✔
152
        }
153

154

155
        private function blockCode(string $s, Texy\Texy $texy, Texy\Modifier $mod, $param): string|HtmlElement
1✔
156
        {
157
                $s = Helpers::outdent($s);
1✔
158
                if ($s === '') {
1✔
UNCOV
159
                        return "\n";
×
160
                }
161

162
                $s = htmlspecialchars($s, ENT_NOQUOTES, 'UTF-8');
1✔
163
                $s = $texy->protect($s, $texy::CONTENT_BLOCK);
1✔
164
                $el = new HtmlElement('pre');
1✔
165
                $mod->decorate($texy, $el);
1✔
166
                $el->attrs['class'][] = $param; // lang
1✔
167
                $el->create('code', $s);
1✔
168
                return $el;
1✔
169
        }
170

171

172
        private function blockDefault(string $s, Texy\Texy $texy, Texy\Modifier $mod, $param): string|HtmlElement
1✔
173
        {
174
                $s = Helpers::outdent($s);
1✔
175
                if ($s === '') {
1✔
UNCOV
176
                        return "\n";
×
177
                }
178

179
                $el = new HtmlElement('pre');
1✔
180
                $mod->decorate($texy, $el);
1✔
181
                $el->attrs['class'][] = $param; // lang
1✔
182
                $s = htmlspecialchars($s, ENT_NOQUOTES, 'UTF-8');
1✔
183
                $s = $texy->protect($s, $texy::CONTENT_BLOCK);
1✔
184
                $el->setText($s);
1✔
185
                return $el;
1✔
186
        }
187

188

189
        private function blockPre(string $s, Texy\Texy $texy, Texy\Modifier $mod): string|HtmlElement
1✔
190
        {
191
                $s = Helpers::outdent($s);
1✔
192
                if ($s === '') {
1✔
UNCOV
193
                        return "\n";
×
194
                }
195

196
                $el = new HtmlElement('pre');
1✔
197
                $mod->decorate($texy, $el);
1✔
198
                $lineParser = new Texy\LineParser($texy, $el);
1✔
199
                // special mode - parse only html tags
200
                $tmp = $lineParser->patterns;
1✔
201
                $lineParser->patterns = [];
1✔
202
                if (isset($tmp['html/tag'])) {
1✔
203
                        $lineParser->patterns['html/tag'] = $tmp['html/tag'];
1✔
204
                }
205

206
                if (isset($tmp['html/comment'])) {
1✔
207
                        $lineParser->patterns['html/comment'] = $tmp['html/comment'];
1✔
208
                }
209

210
                unset($tmp);
1✔
211

212
                $lineParser->parse($s);
1✔
213
                $s = $el->getText();
1✔
214
                $s = Helpers::unescapeHtml($s);
1✔
215
                $s = htmlspecialchars($s, ENT_NOQUOTES, 'UTF-8');
1✔
216
                $s = $texy->unprotect($s);
1✔
217
                $s = $texy->protect($s, $texy::CONTENT_BLOCK);
1✔
218
                $el->setText($s);
1✔
219
                return $el;
1✔
220
        }
221

222

223
        private function blockHtml(string $s, Texy\Texy $texy): string
1✔
224
        {
225
                $s = trim($s, "\n");
1✔
226
                if ($s === '') {
1✔
UNCOV
227
                        return "\n";
×
228
                }
229

230
                $el = new HtmlElement;
1✔
231
                $lineParser = new Texy\LineParser($texy, $el);
1✔
232
                // special mode - parse only html tags
233
                $tmp = $lineParser->patterns;
1✔
234
                $lineParser->patterns = [];
1✔
235
                if (isset($tmp['html/tag'])) {
1✔
236
                        $lineParser->patterns['html/tag'] = $tmp['html/tag'];
1✔
237
                }
238

239
                if (isset($tmp['html/comment'])) {
1✔
240
                        $lineParser->patterns['html/comment'] = $tmp['html/comment'];
1✔
241
                }
242

243
                unset($tmp);
1✔
244

245
                $lineParser->parse($s);
1✔
246
                $s = $el->getText();
1✔
247
                $s = Helpers::unescapeHtml($s);
1✔
248
                $s = htmlspecialchars($s, ENT_NOQUOTES, 'UTF-8');
1✔
249
                $s = $texy->unprotect($s);
1✔
250
                return $texy->protect($s, $texy::CONTENT_BLOCK) . "\n";
1✔
251
        }
252

253

254
        private function blockText(string $s, Texy\Texy $texy): string
1✔
255
        {
256
                $s = trim($s, "\n");
1✔
257
                if ($s === '') {
1✔
UNCOV
258
                        return "\n";
×
259
                }
260

261
                $s = htmlspecialchars($s, ENT_NOQUOTES, 'UTF-8');
1✔
262
                $s = str_replace("\n", (new HtmlElement('br'))->startTag(), $s); // nl2br
1✔
263
                return $texy->protect($s, $texy::CONTENT_BLOCK) . "\n";
1✔
264
        }
265

266

267
        private function blockComment(): string
268
        {
269
                return "\n";
1✔
270
        }
271

272

273
        private function blockDiv(string $s, Texy\Texy $texy, Texy\Modifier $mod, Texy\BlockParser $parser)
1✔
274
        {
275
                $s = Helpers::outdent($s, firstLine: true);
1✔
276
                if ($s === '') {
1✔
UNCOV
277
                        return "\n";
×
278
                }
279

280
                $el = new HtmlElement('div');
1✔
281
                $mod->decorate($texy, $el);
1✔
282
                $el->parseBlock($texy, $s, $parser->isIndented()); // TODO: INDENT or NORMAL ?
1✔
283
                return $el;
1✔
284
        }
285
}
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