PocketMine-MP 5.14.2 git-50e2c469a547a16a23b2dc691e70a51d34e29395
TextFormat.php
1<?php
2
3/*
4 *
5 * ____ _ _ __ __ _ __ __ ____
6 * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8 * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9 * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10 *
11 * This program is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * @author PocketMine Team
17 * @link http://www.pocketmine.net/
18 *
19 *
20 */
21
22declare(strict_types=1);
23
24namespace pocketmine\utils;
25
26use function mb_scrub;
27use function preg_last_error;
28use function preg_quote;
29use function preg_replace;
30use function preg_split;
31use function str_repeat;
32use function str_replace;
33use const PREG_BACKTRACK_LIMIT_ERROR;
34use const PREG_BAD_UTF8_ERROR;
35use const PREG_BAD_UTF8_OFFSET_ERROR;
36use const PREG_INTERNAL_ERROR;
37use const PREG_JIT_STACKLIMIT_ERROR;
38use const PREG_RECURSION_LIMIT_ERROR;
39use const PREG_SPLIT_DELIM_CAPTURE;
40use const PREG_SPLIT_NO_EMPTY;
41
45abstract class TextFormat{
46 public const ESCAPE = "\xc2\xa7"; //ยง
47 public const EOL = "\n";
48
49 public const BLACK = TextFormat::ESCAPE . "0";
50 public const DARK_BLUE = TextFormat::ESCAPE . "1";
51 public const DARK_GREEN = TextFormat::ESCAPE . "2";
52 public const DARK_AQUA = TextFormat::ESCAPE . "3";
53 public const DARK_RED = TextFormat::ESCAPE . "4";
54 public const DARK_PURPLE = TextFormat::ESCAPE . "5";
55 public const GOLD = TextFormat::ESCAPE . "6";
56 public const GRAY = TextFormat::ESCAPE . "7";
57 public const DARK_GRAY = TextFormat::ESCAPE . "8";
58 public const BLUE = TextFormat::ESCAPE . "9";
59 public const GREEN = TextFormat::ESCAPE . "a";
60 public const AQUA = TextFormat::ESCAPE . "b";
61 public const RED = TextFormat::ESCAPE . "c";
62 public const LIGHT_PURPLE = TextFormat::ESCAPE . "d";
63 public const YELLOW = TextFormat::ESCAPE . "e";
64 public const WHITE = TextFormat::ESCAPE . "f";
65 public const MINECOIN_GOLD = TextFormat::ESCAPE . "g";
66
67 public const COLORS = [
68 self::BLACK => self::BLACK,
69 self::DARK_BLUE => self::DARK_BLUE,
70 self::DARK_GREEN => self::DARK_GREEN,
71 self::DARK_AQUA => self::DARK_AQUA,
72 self::DARK_RED => self::DARK_RED,
73 self::DARK_PURPLE => self::DARK_PURPLE,
74 self::GOLD => self::GOLD,
75 self::GRAY => self::GRAY,
76 self::DARK_GRAY => self::DARK_GRAY,
77 self::BLUE => self::BLUE,
78 self::GREEN => self::GREEN,
79 self::AQUA => self::AQUA,
80 self::RED => self::RED,
81 self::LIGHT_PURPLE => self::LIGHT_PURPLE,
82 self::YELLOW => self::YELLOW,
83 self::WHITE => self::WHITE,
84 self::MINECOIN_GOLD => self::MINECOIN_GOLD,
85 ];
86
87 public const OBFUSCATED = TextFormat::ESCAPE . "k";
88 public const BOLD = TextFormat::ESCAPE . "l";
89 public const STRIKETHROUGH = TextFormat::ESCAPE . "m";
90 public const UNDERLINE = TextFormat::ESCAPE . "n";
91 public const ITALIC = TextFormat::ESCAPE . "o";
92
93 public const FORMATS = [
94 self::OBFUSCATED => self::OBFUSCATED,
95 self::BOLD => self::BOLD,
96 self::STRIKETHROUGH => self::STRIKETHROUGH,
97 self::UNDERLINE => self::UNDERLINE,
98 self::ITALIC => self::ITALIC,
99 ];
100
101 public const RESET = TextFormat::ESCAPE . "r";
102
103 private static function makePcreError() : \InvalidArgumentException{
104 $errorCode = preg_last_error();
105 $message = [
106 PREG_INTERNAL_ERROR => "Internal error",
107 PREG_BACKTRACK_LIMIT_ERROR => "Backtrack limit reached",
108 PREG_RECURSION_LIMIT_ERROR => "Recursion limit reached",
109 PREG_BAD_UTF8_ERROR => "Malformed UTF-8",
110 PREG_BAD_UTF8_OFFSET_ERROR => "Bad UTF-8 offset",
111 PREG_JIT_STACKLIMIT_ERROR => "PCRE JIT stack limit reached"
112 ][$errorCode] ?? "Unknown (code $errorCode)";
113 throw new \InvalidArgumentException("PCRE error: $message");
114 }
115
119 private static function preg_replace(string $pattern, string $replacement, string $string) : string{
120 $result = preg_replace($pattern, $replacement, $string);
121 if($result === null){
122 throw self::makePcreError();
123 }
124 return $result;
125 }
126
132 public static function tokenize(string $string) : array{
133 $result = preg_split("/(" . TextFormat::ESCAPE . "[0-9a-gk-or])/u", $string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
134 if($result === false) throw self::makePcreError();
135 return $result;
136 }
137
143 public static function clean(string $string, bool $removeFormat = true) : string{
144 $string = mb_scrub($string, 'UTF-8');
145 $string = self::preg_replace("/[\x{E000}-\x{F8FF}]/u", "", $string); //remove unicode private-use-area characters (they might break the console)
146 if($removeFormat){
147 $string = str_replace(TextFormat::ESCAPE, "", self::preg_replace("/" . TextFormat::ESCAPE . "[0-9a-gk-or]/u", "", $string));
148 }
149 return str_replace("\x1b", "", self::preg_replace("/\x1b[\\(\\][[0-9;\\[\\(]+[Bm]/u", "", $string));
150 }
151
157 public static function colorize(string $string, string $placeholder = "&") : string{
158 return self::preg_replace('/' . preg_quote($placeholder, "/") . '([0-9a-gk-or])/u', TextFormat::ESCAPE . '$1', $string);
159 }
160
174 public static function addBase(string $baseFormat, string $string) : string{
175 $baseFormatParts = self::tokenize($baseFormat);
176 foreach($baseFormatParts as $part){
177 if(!isset(self::FORMATS[$part]) && !isset(self::COLORS[$part])){
178 throw new \InvalidArgumentException("Unexpected base format token \"$part\", expected only color and format tokens");
179 }
180 }
181 $baseFormat = self::RESET . $baseFormat;
182
183 return $baseFormat . str_replace(TextFormat::RESET, $baseFormat, $string);
184 }
185
189 public static function toHTML(string $string) : string{
190 $newString = "";
191 $tokens = 0;
192 foreach(self::tokenize($string) as $token){
193 switch($token){
194 case TextFormat::BOLD:
195 $newString .= "<span style=font-weight:bold>";
196 ++$tokens;
197 break;
198 case TextFormat::OBFUSCATED:
199 //$newString .= "<span style=text-decoration:line-through>";
200 //++$tokens;
201 break;
202 case TextFormat::ITALIC:
203 $newString .= "<span style=font-style:italic>";
204 ++$tokens;
205 break;
206 case TextFormat::UNDERLINE:
207 $newString .= "<span style=text-decoration:underline>";
208 ++$tokens;
209 break;
210 case TextFormat::STRIKETHROUGH:
211 $newString .= "<span style=text-decoration:line-through>";
212 ++$tokens;
213 break;
214 case TextFormat::RESET:
215 $newString .= str_repeat("</span>", $tokens);
216 $tokens = 0;
217 break;
218
219 //Colors
220 case TextFormat::BLACK:
221 $newString .= "<span style=color:#000>";
222 ++$tokens;
223 break;
224 case TextFormat::DARK_BLUE:
225 $newString .= "<span style=color:#00A>";
226 ++$tokens;
227 break;
228 case TextFormat::DARK_GREEN:
229 $newString .= "<span style=color:#0A0>";
230 ++$tokens;
231 break;
232 case TextFormat::DARK_AQUA:
233 $newString .= "<span style=color:#0AA>";
234 ++$tokens;
235 break;
236 case TextFormat::DARK_RED:
237 $newString .= "<span style=color:#A00>";
238 ++$tokens;
239 break;
240 case TextFormat::DARK_PURPLE:
241 $newString .= "<span style=color:#A0A>";
242 ++$tokens;
243 break;
244 case TextFormat::GOLD:
245 $newString .= "<span style=color:#FA0>";
246 ++$tokens;
247 break;
248 case TextFormat::GRAY:
249 $newString .= "<span style=color:#AAA>";
250 ++$tokens;
251 break;
252 case TextFormat::DARK_GRAY:
253 $newString .= "<span style=color:#555>";
254 ++$tokens;
255 break;
256 case TextFormat::BLUE:
257 $newString .= "<span style=color:#55F>";
258 ++$tokens;
259 break;
260 case TextFormat::GREEN:
261 $newString .= "<span style=color:#5F5>";
262 ++$tokens;
263 break;
264 case TextFormat::AQUA:
265 $newString .= "<span style=color:#5FF>";
266 ++$tokens;
267 break;
268 case TextFormat::RED:
269 $newString .= "<span style=color:#F55>";
270 ++$tokens;
271 break;
272 case TextFormat::LIGHT_PURPLE:
273 $newString .= "<span style=color:#F5F>";
274 ++$tokens;
275 break;
276 case TextFormat::YELLOW:
277 $newString .= "<span style=color:#FF5>";
278 ++$tokens;
279 break;
280 case TextFormat::WHITE:
281 $newString .= "<span style=color:#FFF>";
282 ++$tokens;
283 break;
284 case TextFormat::MINECOIN_GOLD:
285 $newString .= "<span style=color:#dd0>";
286 ++$tokens;
287 break;
288 default:
289 $newString .= $token;
290 break;
291 }
292 }
293
294 $newString .= str_repeat("</span>", $tokens);
295
296 return $newString;
297 }
298}
static addBase(string $baseFormat, string $string)
Definition: TextFormat.php:174
static colorize(string $string, string $placeholder="&")
Definition: TextFormat.php:157
static tokenize(string $string)
Definition: TextFormat.php:132
static clean(string $string, bool $removeFormat=true)
Definition: TextFormat.php:143
static toHTML(string $string)
Definition: TextFormat.php:189