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

dg / texy / 22262589061

21 Feb 2026 07:04PM UTC coverage: 92.991% (+1.8%) from 91.178%
22262589061

push

github

dg
LinkModule: deprecated label and modifiers in link definitions

3 of 3 new or added lines in 1 file covered. (100.0%)

126 existing lines in 22 files now uncovered.

2083 of 2240 relevant lines covered (92.99%)

0.93 hits per line

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

94.12
/src/Texy/InlineParser.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;
9

10
use function array_keys, strlen, substr_replace;
11

12

13
/**
14
 * Parses inline structures (links, images, formatting, etc.).
15
 */
16
class InlineParser extends Parser
17
{
18
        public bool $again;
19

20

21
        public function __construct(
1✔
22
                protected Texy $texy,
23
                /** @var array<string, array{handler: \Closure(InlineParser, array<string>, string): (HtmlElement|string|null), pattern: string, again: ?string}> */
24
                public array $patterns,
25
        ) {
26
        }
1✔
27

28

29
        public function parse(string $text): string
1✔
30
        {
31
                if (!$this->patterns) { // nothing to do
1✔
UNCOV
32
                        return $text;
×
33
                }
34

35
                $offset = 0;
1✔
36
                $names = array_keys($this->patterns);
1✔
37
                /** @var array<string, array<string>> $matches */
38
                $matches = $offsets = [];
1✔
39
                foreach ($names as $name) {
1✔
40
                        $offsets[$name] = -1;
1✔
41
                }
42

43
                do {
44
                        $first = $this->match($text, $offset, $names, $offsets, $matches);
1✔
45
                        if ($first === null) {
1✔
46
                                break;
1✔
47
                        }
48

49
                        $px = $this->patterns[$first];
1✔
50
                        $offset = $start = $offsets[$first];
1✔
51

52
                        $this->again = false;
1✔
53
                        $res = $px['handler']($this, $matches[$first], $first);
1✔
54

55
                        if ($res instanceof HtmlElement) {
1✔
56
                                $res = $res->toString($this->texy);
1✔
57
                        } elseif ($res === null) {
1✔
58
                                $offsets[$first] = -2;
1✔
59
                                continue;
1✔
60
                        }
61

62
                        $len = strlen($matches[$first][0]);
1✔
63
                        $text = substr_replace($text, $res, $start, $len);
1✔
64

65
                        $delta = strlen($res) - $len;
1✔
66
                        foreach ($names as $name) {
1✔
67
                                if ($offsets[$name] < $start + $len) {
1✔
68
                                        $offsets[$name] = -1;
1✔
69
                                } else {
70
                                        $offsets[$name] += $delta;
1✔
71
                                }
72
                        }
73

74
                        if ($this->again) {
1✔
75
                                $offsets[$first] = -2;
1✔
76
                        } else {
77
                                $offsets[$first] = -1;
1✔
78
                                $offset += strlen($res);
1✔
79
                        }
80
                } while (1);
1✔
81

82
                return $text;
1✔
83
        }
84

85

86
        /**
87
         * @param  array<int, string>  $names
88
         * @param  array<string, int>  $offsets
89
         * @param  array<string, array<string>>  $matches
90
         */
91
        private function match(string $text, int $offset, array &$names, array &$offsets, array &$matches): ?string
1✔
92
        {
93
                $first = null;
1✔
94
                $minOffset = strlen($text);
1✔
95

96
                foreach ($names as $index => $name) {
1✔
97
                        if ($offsets[$name] < $offset) {
1✔
98
                                $delta = 0;
1✔
99
                                if ($offsets[$name] === -2) {
1✔
100
                                        do {
101
                                                $delta++;
1✔
102
                                        } while (
103
                                                isset($text[$offset + $delta])
1✔
104
                                                && $text[$offset + $delta] >= "\x80"
1✔
105
                                                && $text[$offset + $delta] < "\xC0"
1✔
106
                                        );
107
                                }
108

109
                                if ($offset + $delta > strlen($text)) {
1✔
UNCOV
110
                                        unset($names[$index]);
×
UNCOV
111
                                        continue;
×
112

113
                                } elseif ($m = Regexp::match(
1✔
114
                                        $text,
1✔
115
                                        $this->patterns[$name]['pattern'],
1✔
116
                                        captureOffset: true,
1✔
117
                                        offset: $offset + $delta,
1✔
118
                                )) {
119
                                        /** @var array<int|string, array{string, int}> $m */
120
                                        if (!strlen($m[0][0])) {
1✔
UNCOV
121
                                                continue;
×
122
                                        }
123

124
                                        $offsets[$name] = $m[0][1];
1✔
125
                                        $matches[$name] = [];
1✔
126
                                        foreach ($m as $keyx => $value) {
1✔
127
                                                $matches[$name][$keyx] = $value[0];
1✔
128
                                        }
129
                                } else {
130
                                        // try next time?
131
                                        if (
132
                                                !$this->patterns[$name]['again']
1✔
133
                                                || !Regexp::match($text, $this->patterns[$name]['again'], offset: $offset + $delta)
1✔
134
                                        ) {
135
                                                unset($names[$index]);
1✔
136
                                        }
137

138
                                        continue;
1✔
139
                                }
140
                        }
141

142
                        if ($offsets[$name] < $minOffset) {
1✔
143
                                $minOffset = $offsets[$name];
1✔
144
                                $first = $name;
1✔
145
                        }
146
                }
147

148
                return $first;
1✔
149
        }
150
}
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