PocketMine-MP 5.33.2 git-09cc76ae2b49f1fe3ab0253e6e987fb82bd0a08f
Loading...
Searching...
No Matches
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 public const MATERIAL_QUARTZ = TextFormat::ESCAPE . "h";
67 public const MATERIAL_IRON = TextFormat::ESCAPE . "i";
68 public const MATERIAL_NETHERITE = TextFormat::ESCAPE . "j";
69 public const MATERIAL_REDSTONE = TextFormat::ESCAPE . "m";
70 public const MATERIAL_COPPER = TextFormat::ESCAPE . "n";
71 public const MATERIAL_GOLD = TextFormat::ESCAPE . "p";
72 public const MATERIAL_EMERALD = TextFormat::ESCAPE . "q";
73 public const MATERIAL_DIAMOND = TextFormat::ESCAPE . "s";
74 public const MATERIAL_LAPIS = TextFormat::ESCAPE . "t";
75 public const MATERIAL_AMETHYST = TextFormat::ESCAPE . "u";
76 public const MATERIAL_RESIN = TextFormat::ESCAPE . "v";
77
78 public const COLORS = [
79 self::BLACK => self::BLACK,
80 self::DARK_BLUE => self::DARK_BLUE,
81 self::DARK_GREEN => self::DARK_GREEN,
82 self::DARK_AQUA => self::DARK_AQUA,
83 self::DARK_RED => self::DARK_RED,
84 self::DARK_PURPLE => self::DARK_PURPLE,
85 self::GOLD => self::GOLD,
86 self::GRAY => self::GRAY,
87 self::DARK_GRAY => self::DARK_GRAY,
88 self::BLUE => self::BLUE,
89 self::GREEN => self::GREEN,
90 self::AQUA => self::AQUA,
91 self::RED => self::RED,
92 self::LIGHT_PURPLE => self::LIGHT_PURPLE,
93 self::YELLOW => self::YELLOW,
94 self::WHITE => self::WHITE,
95 self::MINECOIN_GOLD => self::MINECOIN_GOLD,
96 self::MATERIAL_QUARTZ => self::MATERIAL_QUARTZ,
97 self::MATERIAL_IRON => self::MATERIAL_IRON,
98 self::MATERIAL_NETHERITE => self::MATERIAL_NETHERITE,
99 self::MATERIAL_REDSTONE => self::MATERIAL_REDSTONE,
100 self::MATERIAL_COPPER => self::MATERIAL_COPPER,
101 self::MATERIAL_GOLD => self::MATERIAL_GOLD,
102 self::MATERIAL_EMERALD => self::MATERIAL_EMERALD,
103 self::MATERIAL_DIAMOND => self::MATERIAL_DIAMOND,
104 self::MATERIAL_LAPIS => self::MATERIAL_LAPIS,
105 self::MATERIAL_AMETHYST => self::MATERIAL_AMETHYST,
106 self::MATERIAL_RESIN => self::MATERIAL_RESIN,
107 ];
108
109 public const OBFUSCATED = TextFormat::ESCAPE . "k";
110 public const BOLD = TextFormat::ESCAPE . "l";
112 public const STRIKETHROUGH = "";
114 public const UNDERLINE = "";
115 public const ITALIC = TextFormat::ESCAPE . "o";
116
117 public const FORMATS = [
118 self::OBFUSCATED => self::OBFUSCATED,
119 self::BOLD => self::BOLD,
120 self::ITALIC => self::ITALIC,
121 ];
122
123 public const RESET = TextFormat::ESCAPE . "r";
124
125 private static function makePcreError() : \InvalidArgumentException{
126 $errorCode = preg_last_error();
127 $message = [
128 PREG_INTERNAL_ERROR => "Internal error",
129 PREG_BACKTRACK_LIMIT_ERROR => "Backtrack limit reached",
130 PREG_RECURSION_LIMIT_ERROR => "Recursion limit reached",
131 PREG_BAD_UTF8_ERROR => "Malformed UTF-8",
132 PREG_BAD_UTF8_OFFSET_ERROR => "Bad UTF-8 offset",
133 PREG_JIT_STACKLIMIT_ERROR => "PCRE JIT stack limit reached"
134 ][$errorCode] ?? "Unknown (code $errorCode)";
135 throw new \InvalidArgumentException("PCRE error: $message");
136 }
137
141 private static function preg_replace(string $pattern, string $replacement, string $string) : string{
142 $result = preg_replace($pattern, $replacement, $string);
143 if($result === null){
144 throw self::makePcreError();
145 }
146 return $result;
147 }
148
154 public static function tokenize(string $string) : array{
155 $result = preg_split("/(" . TextFormat::ESCAPE . "[0-9a-v])/u", $string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
156 if($result === false) throw self::makePcreError();
157 return $result;
158 }
159
165 public static function clean(string $string, bool $removeFormat = true) : string{
166 $string = mb_scrub($string, 'UTF-8');
167 $string = self::preg_replace("/[\x{E000}-\x{F8FF}]/u", "", $string); //remove unicode private-use-area characters (they might break the console)
168 if($removeFormat){
169 $string = str_replace(TextFormat::ESCAPE, "", self::preg_replace("/" . TextFormat::ESCAPE . "[0-9a-v]/u", "", $string));
170 }
171 return str_replace("\x1b", "", self::preg_replace("/\x1b[\\(\\][[0-9;\\[\\(]+[Bm]/u", "", $string));
172 }
173
179 public static function colorize(string $string, string $placeholder = "&") : string{
180 return self::preg_replace('/' . preg_quote($placeholder, "/") . '([0-9a-v])/u', TextFormat::ESCAPE . '$1', $string);
181 }
182
196 public static function addBase(string $baseFormat, string $string) : string{
197 $baseFormatParts = self::tokenize($baseFormat);
198 foreach($baseFormatParts as $part){
199 if(!isset(self::FORMATS[$part]) && !isset(self::COLORS[$part])){
200 throw new \InvalidArgumentException("Unexpected base format token \"$part\", expected only color and format tokens");
201 }
202 }
203 $baseFormat = self::RESET . $baseFormat;
204
205 return $baseFormat . str_replace(TextFormat::RESET, $baseFormat, $string);
206 }
207
218 public static function javaToBedrock(string $string) : string{
219 return str_replace([TextFormat::ESCAPE . "m", TextFormat::ESCAPE . "n"], "", $string);
220 }
221
225 public static function toHTML(string $string) : string{
226 $newString = "";
227 $tokens = 0;
228 foreach(self::tokenize($string) as $token){
229 $formatString = match($token){
230 TextFormat::BLACK => "color:#000",
231 TextFormat::DARK_BLUE => "color:#00A",
232 TextFormat::DARK_GREEN => "color:#0A0",
233 TextFormat::DARK_AQUA => "color:#0AA",
234 TextFormat::DARK_RED => "color:#A00",
235 TextFormat::DARK_PURPLE => "color:#A0A",
236 TextFormat::GOLD => "color:#FA0",
237 TextFormat::GRAY => "color:#AAA",
238 TextFormat::DARK_GRAY => "color:#555",
239 TextFormat::BLUE => "color:#55F",
240 TextFormat::GREEN => "color:#5F5",
241 TextFormat::AQUA => "color:#5FF",
242 TextFormat::RED => "color:#F55",
243 TextFormat::LIGHT_PURPLE => "color:#F5F",
244 TextFormat::YELLOW => "color:#FF5",
245 TextFormat::WHITE => "color:#FFF",
246 TextFormat::MINECOIN_GOLD => "color:#dd0",
247 TextFormat::MATERIAL_QUARTZ => "color:#e2d3d1",
248 TextFormat::MATERIAL_IRON => "color:#cec9c9",
249 TextFormat::MATERIAL_NETHERITE => "color:#44393a",
250 TextFormat::MATERIAL_REDSTONE => "color:#961506",
251 TextFormat::MATERIAL_COPPER => "color:#b4684d",
252 TextFormat::MATERIAL_GOLD => "color:#deb02c",
253 TextFormat::MATERIAL_EMERALD => "color:#119f36",
254 TextFormat::MATERIAL_DIAMOND => "color:#2cb9a8",
255 TextFormat::MATERIAL_LAPIS => "color:#20487a",
256 TextFormat::MATERIAL_AMETHYST => "color:#9a5cc5",
257 TextFormat::MATERIAL_RESIN => "color:#fc7812",
258 TextFormat::BOLD => "font-weight:bold",
259 TextFormat::ITALIC => "font-style:italic",
260 default => null
261 };
262 if($formatString !== null){
263 $newString .= "<span style=\"$formatString\">";
264 ++$tokens;
265 }elseif($token === TextFormat::RESET){
266 $newString .= str_repeat("</span>", $tokens);
267 $tokens = 0;
268 }else{
269 $newString .= $token;
270 }
271 }
272
273 $newString .= str_repeat("</span>", $tokens);
274
275 return $newString;
276 }
277}
static addBase(string $baseFormat, string $string)
static colorize(string $string, string $placeholder="&")
static tokenize(string $string)
static clean(string $string, bool $removeFormat=true)
static javaToBedrock(string $string)
static toHTML(string $string)