22declare(strict_types=1);
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;
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";
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,
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";
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,
101 public const RESET = TextFormat::ESCAPE .
"r";
103 private static function makePcreError() : \InvalidArgumentException{
104 $errorCode = preg_last_error();
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");
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();
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();
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);
147 $string = str_replace(TextFormat::ESCAPE,
"", self::preg_replace(
"/" . TextFormat::ESCAPE .
"[0-9a-gk-or]/u",
"", $string));
149 return str_replace(
"\x1b",
"", self::preg_replace(
"/\x1b[\\(\\][[0-9;\\[\\(]+[Bm]/u",
"", $string));
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);
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");
181 $baseFormat = self::RESET . $baseFormat;
183 return $baseFormat . str_replace(TextFormat::RESET, $baseFormat, $string);
189 public static function toHTML(
string $string) : string{
192 foreach(self::tokenize($string) as $token){
194 case TextFormat::BOLD:
195 $newString .=
"<span style=font-weight:bold>";
198 case TextFormat::OBFUSCATED:
202 case TextFormat::ITALIC:
203 $newString .=
"<span style=font-style:italic>";
206 case TextFormat::UNDERLINE:
207 $newString .=
"<span style=text-decoration:underline>";
210 case TextFormat::STRIKETHROUGH:
211 $newString .=
"<span style=text-decoration:line-through>";
214 case TextFormat::RESET:
215 $newString .= str_repeat(
"</span>", $tokens);
220 case TextFormat::BLACK:
221 $newString .=
"<span style=color:#000>";
224 case TextFormat::DARK_BLUE:
225 $newString .=
"<span style=color:#00A>";
228 case TextFormat::DARK_GREEN:
229 $newString .=
"<span style=color:#0A0>";
232 case TextFormat::DARK_AQUA:
233 $newString .=
"<span style=color:#0AA>";
236 case TextFormat::DARK_RED:
237 $newString .=
"<span style=color:#A00>";
240 case TextFormat::DARK_PURPLE:
241 $newString .=
"<span style=color:#A0A>";
244 case TextFormat::GOLD:
245 $newString .=
"<span style=color:#FA0>";
248 case TextFormat::GRAY:
249 $newString .=
"<span style=color:#AAA>";
252 case TextFormat::DARK_GRAY:
253 $newString .=
"<span style=color:#555>";
256 case TextFormat::BLUE:
257 $newString .=
"<span style=color:#55F>";
260 case TextFormat::GREEN:
261 $newString .=
"<span style=color:#5F5>";
264 case TextFormat::AQUA:
265 $newString .=
"<span style=color:#5FF>";
268 case TextFormat::RED:
269 $newString .=
"<span style=color:#F55>";
272 case TextFormat::LIGHT_PURPLE:
273 $newString .=
"<span style=color:#F5F>";
276 case TextFormat::YELLOW:
277 $newString .=
"<span style=color:#FF5>";
280 case TextFormat::WHITE:
281 $newString .=
"<span style=color:#FFF>";
284 case TextFormat::MINECOIN_GOLD:
285 $newString .=
"<span style=color:#dd0>";
289 $newString .= $token;
294 $newString .= str_repeat(
"</span>", $tokens);
static addBase(string $baseFormat, string $string)
static colorize(string $string, string $placeholder="&")
static tokenize(string $string)
static clean(string $string, bool $removeFormat=true)
static toHTML(string $string)