46 public const ESCAPE =
"\xc2\xa7";
47 public const EOL =
"\n";
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";
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,
109 public const OBFUSCATED = TextFormat::ESCAPE .
"k";
110 public const BOLD = TextFormat::ESCAPE .
"l";
111 public const ITALIC = TextFormat::ESCAPE .
"o";
113 public const FORMATS = [
114 self::OBFUSCATED => self::OBFUSCATED,
115 self::BOLD => self::BOLD,
116 self::ITALIC => self::ITALIC,
119 public const RESET = TextFormat::ESCAPE .
"r";
121 private static function makePcreError() : \InvalidArgumentException{
122 $errorCode = preg_last_error();
124 PREG_INTERNAL_ERROR =>
"Internal error",
125 PREG_BACKTRACK_LIMIT_ERROR =>
"Backtrack limit reached",
126 PREG_RECURSION_LIMIT_ERROR =>
"Recursion limit reached",
127 PREG_BAD_UTF8_ERROR =>
"Malformed UTF-8",
128 PREG_BAD_UTF8_OFFSET_ERROR =>
"Bad UTF-8 offset",
129 PREG_JIT_STACKLIMIT_ERROR =>
"PCRE JIT stack limit reached"
130 ][$errorCode] ??
"Unknown (code $errorCode)";
131 throw new \InvalidArgumentException(
"PCRE error: $message");
137 private static function preg_replace(
string $pattern,
string $replacement,
string $string) :
string{
138 $result = preg_replace($pattern, $replacement, $string);
139 if($result ===
null){
140 throw self::makePcreError();
150 public static function tokenize(
string $string) : array{
151 $result = preg_split(
"/(" .
TextFormat::ESCAPE .
"[0-9a-v])/u", $string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
152 if($result ===
false)
throw self::makePcreError();
161 public static function clean(
string $string,
bool $removeFormat =
true) : string{
162 $string = mb_scrub($string,
'UTF-8');
163 $string = self::preg_replace(
"/[\x{E000}-\x{F8FF}]/u",
"", $string);
165 $string = str_replace(TextFormat::ESCAPE,
"", self::preg_replace(
"/" . TextFormat::ESCAPE .
"[0-9a-v]/u",
"", $string));
167 return str_replace(
"\x1b",
"", self::preg_replace(
"/\x1b[\\(\\][[0-9;\\[\\(]+[Bm]/u",
"", $string));
175 public static function colorize(
string $string,
string $placeholder =
"&") : string{
176 return self::preg_replace(
'/' . preg_quote($placeholder,
"/") .
'([0-9a-v])/u',
TextFormat::ESCAPE .
'$1', $string);
192 public static function addBase(
string $baseFormat,
string $string) : string{
193 $baseFormatParts = self::tokenize($baseFormat);
194 foreach($baseFormatParts as $part){
195 if(!isset(self::FORMATS[$part]) && !isset(self::COLORS[$part])){
196 throw new \InvalidArgumentException(
"Unexpected base format token \"$part\", expected only color and format tokens");
199 $baseFormat = self::RESET . $baseFormat;
201 return $baseFormat . str_replace(TextFormat::RESET, $baseFormat, $string);
221 public static function toHTML(
string $string) : string{
224 foreach(self::tokenize($string) as $token){
225 $formatString = match($token){
226 TextFormat::BLACK =>
"color:#000",
227 TextFormat::DARK_BLUE =>
"color:#00A",
228 TextFormat::DARK_GREEN =>
"color:#0A0",
229 TextFormat::DARK_AQUA =>
"color:#0AA",
230 TextFormat::DARK_RED =>
"color:#A00",
231 TextFormat::DARK_PURPLE =>
"color:#A0A",
232 TextFormat::GOLD =>
"color:#FA0",
233 TextFormat::GRAY =>
"color:#AAA",
234 TextFormat::DARK_GRAY =>
"color:#555",
235 TextFormat::BLUE =>
"color:#55F",
236 TextFormat::GREEN =>
"color:#5F5",
237 TextFormat::AQUA =>
"color:#5FF",
238 TextFormat::RED =>
"color:#F55",
239 TextFormat::LIGHT_PURPLE =>
"color:#F5F",
240 TextFormat::YELLOW =>
"color:#FF5",
241 TextFormat::WHITE =>
"color:#FFF",
242 TextFormat::MINECOIN_GOLD =>
"color:#dd0",
243 TextFormat::MATERIAL_QUARTZ =>
"color:#e2d3d1",
244 TextFormat::MATERIAL_IRON =>
"color:#cec9c9",
245 TextFormat::MATERIAL_NETHERITE =>
"color:#44393a",
246 TextFormat::MATERIAL_REDSTONE =>
"color:#961506",
247 TextFormat::MATERIAL_COPPER =>
"color:#b4684d",
248 TextFormat::MATERIAL_GOLD =>
"color:#deb02c",
249 TextFormat::MATERIAL_EMERALD =>
"color:#119f36",
250 TextFormat::MATERIAL_DIAMOND =>
"color:#2cb9a8",
251 TextFormat::MATERIAL_LAPIS =>
"color:#20487a",
252 TextFormat::MATERIAL_AMETHYST =>
"color:#9a5cc5",
253 TextFormat::MATERIAL_RESIN =>
"color:#fc7812",
254 TextFormat::BOLD =>
"font-weight:bold",
255 TextFormat::ITALIC =>
"font-style:italic",
258 if($formatString !==
null){
259 $newString .=
"<span style=\"$formatString\">";
261 }elseif($token === TextFormat::RESET){
262 $newString .= str_repeat(
"</span>", $tokens);
265 $newString .= $token;
269 $newString .= str_repeat(
"</span>", $tokens);