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

nette / tester / 22278741586

22 Feb 2026 02:09PM UTC coverage: 81.835%. First build
22278741586

Pull #467

github

web-flow
Merge b74a1f536 into 29a5403e0
Pull Request #467: Feat/structural metrics v2

79 of 107 new or added lines in 18 files covered. (73.83%)

1757 of 2147 relevant lines covered (81.84%)

0.82 hits per line

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

80.43
/src/Framework/Ansi.php
1
<?php
2

3
/**
4
 * This file is part of the Nette Tester.
5
 * Copyright (c) 2009 David Grudl (https://davidgrudl.com)
6
 */
7

8
declare(strict_types=1);
9

10
namespace Tester;
11

12

13
/**
14
 * ANSI escape sequences for terminal colors, cursor control, and text formatting.
15
 * @internal
16
 */
17
class Ansi
18
{
19
        private const Colors = [
20
                'black' => '0;30', 'gray' => '1;30', 'silver' => '0;37', 'white' => '1;37',
21
                'navy' => '0;34', 'blue' => '1;34', 'green' => '0;32', 'lime' => '1;32',
22
                'teal' => '0;36', 'aqua' => '1;36', 'maroon' => '0;31', 'red' => '1;31',
23
                'purple' => '0;35', 'fuchsia' => '1;35', 'olive' => '0;33', 'yellow' => '1;33',
24
                '' => '0',
25
        ];
26

27

28
        /**
29
         * Returns ANSI escape sequence for given color.
30
         * Color format: 'foreground' or 'foreground/background' (e.g. 'red', 'white/blue').
31
         */
32
        public static function color(string $color): string
1✔
33
        {
34
                $c = explode('/', $color);
1✔
35
                return "\e["
36
                        . str_replace(';', "m\e[", self::Colors[$c[0]] . (empty($c[1]) ? '' : ';4' . substr(self::Colors[$c[1]], -1)))
1✔
37
                        . 'm';
1✔
38
        }
39

40

41
        /**
42
         * Wraps text with ANSI color sequence and color reset.
43
         * Color format: 'foreground' or 'foreground/background' (e.g. 'red', 'white/blue').
44
         */
45
        public static function colorize(string $text, string $color): string
1✔
46
        {
47
                return self::color($color) . $text . self::reset();
1✔
48
        }
49

50

51
        /**
52
         * Returns ANSI sequence to turn on bold text.
53
         */
54
        public static function boldOn(): string
55
        {
56
                return "\e[1m";
1✔
57
        }
58

59

60
        /**
61
         * Returns ANSI sequence to turn off bold text.
62
         */
63
        public static function boldOff(): string
64
        {
65
                return "\e[22m";
1✔
66
        }
67

68

69
        public static function showCursor(): string
70
        {
71
                return "\e[?25h";
×
72
        }
73

74

75
        public static function hideCursor(): string
76
        {
77
                return "\e[?25l";
×
78
        }
79

80

81
        public static function cursorMove(int $x = 0, int $y = 0): string
82
        {
83
                return match (true) {
NEW
84
                        $x < 0 => "\e[" . (-$x) . 'D',
×
NEW
85
                        $x > 0 => "\e[{$x}C",
×
NEW
86
                        default => '',
×
87
                } . match (true) {
NEW
88
                        $y < 0 => "\e[" . (-$y) . 'A',
×
NEW
89
                        $y > 0 => "\e[{$y}B",
×
NEW
90
                        default => '',
×
91
                };
92
        }
93

94

95
        /**
96
         * Returns ANSI sequence to clear from cursor to end of line.
97
         */
98
        public static function clearLine(): string
99
        {
100
                return "\e[K";
×
101
        }
102

103

104
        /**
105
         * Removes all ANSI escape sequences from string (colors, cursor control, etc.).
106
         */
107
        public static function stripAnsi(string $text): string
1✔
108
        {
109
                return preg_replace('/\e\[[0-?]*[ -\/]*[@-~]|\e\][^\x07]*(\x07|\e\\\)/', '', $text);
1✔
110
        }
111

112

113
        /**
114
         * Returns ANSI sequence to reset all attributes.
115
         */
116
        public static function reset(): string
117
        {
118
                return "\e[0m";
1✔
119
        }
120

121

122
        /**
123
         * Returns display width of string (number of terminal columns).
124
         */
125
        public static function textWidth(string $text): int
1✔
126
        {
127
                $text = self::stripAnsi($text);
1✔
128
                return preg_match_all('/./su', $text)
1✔
129
                        + preg_match_all('/[\x{1F300}-\x{1F9FF}]/u', $text); // emoji are 2-wide
1✔
130
        }
131

132

133
        /**
134
         * Pads text to specified display width.
135
         * @param STR_PAD_LEFT|STR_PAD_RIGHT|STR_PAD_BOTH  $type
136
         */
137
        public static function pad(
138
                string $text,
1✔
139
                int $width,
1✔
140
                string $char = ' ',
1✔
141
                int $type = STR_PAD_RIGHT,
142
        ): string
143
        {
144
                $padding = $width - self::textWidth($text);
1✔
145
                if ($padding <= 0) {
1✔
146
                        return $text;
1✔
147
                }
148

149
                return match ($type) {
150
                        STR_PAD_LEFT => str_repeat($char, $padding) . $text,
1✔
151
                        STR_PAD_RIGHT => $text . str_repeat($char, $padding),
1✔
152
                        STR_PAD_BOTH => str_repeat($char, intdiv($padding, 2)) . $text . str_repeat($char, $padding - intdiv($padding, 2)),
1✔
153
                };
154
        }
155

156

157
        /**
158
         * Truncates text to max display width, adding ellipsis if needed.
159
         */
160
        public static function truncate(string $text, int $maxWidth, string $ellipsis = '…'): string
1✔
161
        {
162
                if (self::textWidth($text) <= $maxWidth) {
1✔
163
                        return $text;
1✔
164
                }
165

166
                $maxWidth -= self::textWidth($ellipsis);
1✔
167
                $res = '';
1✔
168
                $width = 0;
1✔
169
                foreach (preg_split('//u', $text, -1, PREG_SPLIT_NO_EMPTY) as $char) {
1✔
170
                        $charWidth = preg_match('/[\x{1F300}-\x{1F9FF}]/u', $char) ? 2 : 1;
1✔
171
                        if ($width + $charWidth > $maxWidth) {
1✔
172
                                break;
1✔
173
                        }
174
                        $res .= $char;
1✔
175
                        $width += $charWidth;
1✔
176
                }
177

178
                return $res . $ellipsis;
1✔
179
        }
180
}
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