PocketMine-MP 5.25.1 git-694aa17cc916a954b10fe12721c81b1dc73eecd5
Loading...
Searching...
No Matches
Terminal.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 fclose;
27use function fopen;
28use function function_exists;
29use function getenv;
30use function is_string;
31use function sapi_windows_vt100_support;
32use function shell_exec;
33use function stream_isatty;
34use const PHP_EOL;
35
36abstract class Terminal{
37 public static string $FORMAT_BOLD = "";
38 public static string $FORMAT_OBFUSCATED = "";
39 public static string $FORMAT_ITALIC = "";
40 public static string $FORMAT_UNDERLINE = "";
41 public static string $FORMAT_STRIKETHROUGH = "";
42
43 public static string $FORMAT_RESET = "";
44
45 public static string $COLOR_BLACK = "";
46 public static string $COLOR_DARK_BLUE = "";
47 public static string $COLOR_DARK_GREEN = "";
48 public static string $COLOR_DARK_AQUA = "";
49 public static string $COLOR_DARK_RED = "";
50 public static string $COLOR_PURPLE = "";
51 public static string $COLOR_GOLD = "";
52 public static string $COLOR_GRAY = "";
53 public static string $COLOR_DARK_GRAY = "";
54 public static string $COLOR_BLUE = "";
55 public static string $COLOR_GREEN = "";
56 public static string $COLOR_AQUA = "";
57 public static string $COLOR_RED = "";
58 public static string $COLOR_LIGHT_PURPLE = "";
59 public static string $COLOR_YELLOW = "";
60 public static string $COLOR_WHITE = "";
61 public static string $COLOR_MINECOIN_GOLD = "";
62 public static string $COLOR_MATERIAL_QUARTZ = "";
63 public static string $COLOR_MATERIAL_IRON = "";
64 public static string $COLOR_MATERIAL_NETHERITE = "";
65 public static string $COLOR_MATERIAL_REDSTONE = "";
66 public static string $COLOR_MATERIAL_COPPER = "";
67 public static string $COLOR_MATERIAL_GOLD = "";
68 public static string $COLOR_MATERIAL_EMERALD = "";
69 public static string $COLOR_MATERIAL_DIAMOND = "";
70 public static string $COLOR_MATERIAL_LAPIS = "";
71 public static string $COLOR_MATERIAL_AMETHYST = "";
72 public static string $COLOR_MATERIAL_RESIN = "";
73
74 private static ?bool $formattingCodes = null;
75
76 public static function hasFormattingCodes() : bool{
77 if(self::$formattingCodes === null){
78 throw new \LogicException("Formatting codes have not been initialized");
79 }
80 return self::$formattingCodes;
81 }
82
83 private static function detectFormattingCodesSupport() : bool{
84 $stdout = fopen("php://stdout", "w");
85 if($stdout === false) throw new AssumptionFailedError("Opening php://stdout should never fail");
86 $result = (
87 stream_isatty($stdout) && //STDOUT isn't being piped
88 (
89 getenv('TERM') !== false || //Console says it supports colours
90 (function_exists('sapi_windows_vt100_support') && sapi_windows_vt100_support($stdout)) //we're on windows and have vt100 support
91 )
92 );
93 fclose($stdout);
94 return $result;
95 }
96
97 protected static function getFallbackEscapeCodes() : void{
98 self::$FORMAT_BOLD = "\x1b[1m";
99 self::$FORMAT_OBFUSCATED = "";
100 self::$FORMAT_ITALIC = "\x1b[3m";
101 self::$FORMAT_UNDERLINE = "\x1b[4m";
102 self::$FORMAT_STRIKETHROUGH = "\x1b[9m";
103
104 self::$FORMAT_RESET = "\x1b[m";
105
106 $color = fn(int $code) => "\x1b[38;5;{$code}m";
107
108 self::$COLOR_BLACK = $color(16);
109 self::$COLOR_DARK_BLUE = $color(19);
110 self::$COLOR_DARK_GREEN = $color(34);
111 self::$COLOR_DARK_AQUA = $color(37);
112 self::$COLOR_DARK_RED = $color(124);
113 self::$COLOR_PURPLE = $color(127);
114 self::$COLOR_GOLD = $color(214);
115 self::$COLOR_GRAY = $color(145);
116 self::$COLOR_DARK_GRAY = $color(59);
117 self::$COLOR_BLUE = $color(63);
118 self::$COLOR_GREEN = $color(83);
119 self::$COLOR_AQUA = $color(87);
120 self::$COLOR_RED = $color(203);
121 self::$COLOR_LIGHT_PURPLE = $color(207);
122 self::$COLOR_YELLOW = $color(227);
123 self::$COLOR_WHITE = $color(231);
124 self::$COLOR_MINECOIN_GOLD = $color(184);
125 self::$COLOR_MATERIAL_QUARTZ = $color(188);
126 self::$COLOR_MATERIAL_IRON = $color(251);
127 self::$COLOR_MATERIAL_NETHERITE = $color(237);
128 self::$COLOR_MATERIAL_REDSTONE = $color(88);
129 self::$COLOR_MATERIAL_COPPER = $color(131);
130 self::$COLOR_MATERIAL_GOLD = $color(178);
131 self::$COLOR_MATERIAL_EMERALD = $color(35);
132 self::$COLOR_MATERIAL_DIAMOND = $color(37);
133 self::$COLOR_MATERIAL_LAPIS = $color(24);
134 self::$COLOR_MATERIAL_AMETHYST = $color(98);
135 self::$COLOR_MATERIAL_RESIN = $color(208);
136 }
137
138 protected static function getEscapeCodes() : void{
139 $tput = fn(string $args) => is_string($result = shell_exec("tput $args")) ? $result : "";
140 $setaf = fn(int $code) => $tput("setaf $code");
141
142 self::$FORMAT_BOLD = $tput("bold");
143 self::$FORMAT_OBFUSCATED = $tput("smacs");
144 self::$FORMAT_ITALIC = $tput("sitm");
145 self::$FORMAT_UNDERLINE = $tput("smul");
146 self::$FORMAT_STRIKETHROUGH = "\x1b[9m"; //`tput `;
147
148 self::$FORMAT_RESET = $tput("sgr0");
149
150 $colors = (int) $tput("colors");
151 if($colors > 8){
152 self::$COLOR_BLACK = $colors >= 256 ? $setaf(16) : $setaf(0);
153 self::$COLOR_DARK_BLUE = $colors >= 256 ? $setaf(19) : $setaf(4);
154 self::$COLOR_DARK_GREEN = $colors >= 256 ? $setaf(34) : $setaf(2);
155 self::$COLOR_DARK_AQUA = $colors >= 256 ? $setaf(37) : $setaf(6);
156 self::$COLOR_DARK_RED = $colors >= 256 ? $setaf(124) : $setaf(1);
157 self::$COLOR_PURPLE = $colors >= 256 ? $setaf(127) : $setaf(5);
158 self::$COLOR_GOLD = $colors >= 256 ? $setaf(214) : $setaf(3);
159 self::$COLOR_GRAY = $colors >= 256 ? $setaf(145) : $setaf(7);
160 self::$COLOR_DARK_GRAY = $colors >= 256 ? $setaf(59) : $setaf(8);
161 self::$COLOR_BLUE = $colors >= 256 ? $setaf(63) : $setaf(12);
162 self::$COLOR_GREEN = $colors >= 256 ? $setaf(83) : $setaf(10);
163 self::$COLOR_AQUA = $colors >= 256 ? $setaf(87) : $setaf(14);
164 self::$COLOR_RED = $colors >= 256 ? $setaf(203) : $setaf(9);
165 self::$COLOR_LIGHT_PURPLE = $colors >= 256 ? $setaf(207) : $setaf(13);
166 self::$COLOR_YELLOW = $colors >= 256 ? $setaf(227) : $setaf(11);
167 self::$COLOR_WHITE = $colors >= 256 ? $setaf(231) : $setaf(15);
168 self::$COLOR_MINECOIN_GOLD = $colors >= 256 ? $setaf(184) : $setaf(11);
169 self::$COLOR_MATERIAL_QUARTZ = $colors >= 256 ? $setaf(188) : $setaf(7);
170 self::$COLOR_MATERIAL_IRON = $colors >= 256 ? $setaf(251) : $setaf(7);
171 self::$COLOR_MATERIAL_NETHERITE = $colors >= 256 ? $setaf(237) : $setaf(1);
172 self::$COLOR_MATERIAL_REDSTONE = $colors >= 256 ? $setaf(88) : $setaf(9);
173 self::$COLOR_MATERIAL_COPPER = $colors >= 256 ? $setaf(131) : $setaf(3);
174 self::$COLOR_MATERIAL_GOLD = $colors >= 256 ? $setaf(178) : $setaf(11);
175 self::$COLOR_MATERIAL_EMERALD = $colors >= 256 ? $setaf(35) : $setaf(2);
176 self::$COLOR_MATERIAL_DIAMOND = $colors >= 256 ? $setaf(37) : $setaf(14);
177 self::$COLOR_MATERIAL_LAPIS = $colors >= 256 ? $setaf(24) : $setaf(12);
178 self::$COLOR_MATERIAL_AMETHYST = $colors >= 256 ? $setaf(98) : $setaf(13);
179 self::$COLOR_MATERIAL_RESIN = $colors >= 256 ? $setaf(208) : $setaf(11);
180 }else{
181 self::$COLOR_BLACK = self::$COLOR_DARK_GRAY = self::$COLOR_MATERIAL_NETHERITE = $setaf(0);
182 self::$COLOR_RED = self::$COLOR_DARK_RED = self::$COLOR_MATERIAL_REDSTONE = self::$COLOR_MATERIAL_COPPER = $setaf(1);
183 self::$COLOR_GREEN = self::$COLOR_DARK_GREEN = self::$COLOR_MATERIAL_EMERALD = $setaf(2);
184 self::$COLOR_YELLOW = self::$COLOR_GOLD = self::$COLOR_MINECOIN_GOLD = self::$COLOR_MATERIAL_GOLD = self::$COLOR_MATERIAL_RESIN = $setaf(3);
185 self::$COLOR_BLUE = self::$COLOR_DARK_BLUE = self::$COLOR_MATERIAL_LAPIS = $setaf(4);
186 self::$COLOR_LIGHT_PURPLE = self::$COLOR_PURPLE = self::$COLOR_MATERIAL_AMETHYST = $setaf(5);
187 self::$COLOR_AQUA = self::$COLOR_DARK_AQUA = self::$COLOR_MATERIAL_DIAMOND = $setaf(6);
188 self::$COLOR_GRAY = self::$COLOR_WHITE = self::$COLOR_MATERIAL_QUARTZ = self::$COLOR_MATERIAL_IRON = $setaf(7);
189 }
190 }
191
192 public static function init(?bool $enableFormatting = null) : void{
193 self::$formattingCodes = $enableFormatting ?? self::detectFormattingCodesSupport();
194 if(!self::$formattingCodes){
195 return;
196 }
197
198 switch(Utils::getOS()){
199 case Utils::OS_LINUX:
200 case Utils::OS_MACOS:
201 case Utils::OS_BSD:
202 if(getenv('TERM') !== false){
203 self::getEscapeCodes();
204 return;
205 }
206
207 case Utils::OS_WINDOWS:
208 case Utils::OS_ANDROID:
209 self::getFallbackEscapeCodes();
210 return;
211 }
212
213 //TODO: iOS
214 }
215
216 public static function isInit() : bool{
217 return self::$formattingCodes !== null;
218 }
219
224 public static function toANSI(string $string) : string{
225 $newString = "";
226 foreach(TextFormat::tokenize($string) as $token){
227 $newString .= match ($token) {
228 TextFormat::BOLD => Terminal::$FORMAT_BOLD,
229 TextFormat::OBFUSCATED => Terminal::$FORMAT_OBFUSCATED,
230 TextFormat::ITALIC => Terminal::$FORMAT_ITALIC,
231 TextFormat::RESET => Terminal::$FORMAT_RESET,
232 TextFormat::BLACK => Terminal::$COLOR_BLACK,
233 TextFormat::DARK_BLUE => Terminal::$COLOR_DARK_BLUE,
234 TextFormat::DARK_GREEN => Terminal::$COLOR_DARK_GREEN,
235 TextFormat::DARK_AQUA => Terminal::$COLOR_DARK_AQUA,
236 TextFormat::DARK_RED => Terminal::$COLOR_DARK_RED,
237 TextFormat::DARK_PURPLE => Terminal::$COLOR_PURPLE,
238 TextFormat::GOLD => Terminal::$COLOR_GOLD,
239 TextFormat::GRAY => Terminal::$COLOR_GRAY,
240 TextFormat::DARK_GRAY => Terminal::$COLOR_DARK_GRAY,
241 TextFormat::BLUE => Terminal::$COLOR_BLUE,
242 TextFormat::GREEN => Terminal::$COLOR_GREEN,
243 TextFormat::AQUA => Terminal::$COLOR_AQUA,
244 TextFormat::RED => Terminal::$COLOR_RED,
245 TextFormat::LIGHT_PURPLE => Terminal::$COLOR_LIGHT_PURPLE,
246 TextFormat::YELLOW => Terminal::$COLOR_YELLOW,
247 TextFormat::WHITE => Terminal::$COLOR_WHITE,
248 TextFormat::MINECOIN_GOLD => Terminal::$COLOR_MINECOIN_GOLD,
249 TextFormat::MATERIAL_QUARTZ => Terminal::$COLOR_MATERIAL_QUARTZ,
250 TextFormat::MATERIAL_IRON => Terminal::$COLOR_MATERIAL_IRON,
251 TextFormat::MATERIAL_NETHERITE => Terminal::$COLOR_MATERIAL_NETHERITE,
252 TextFormat::MATERIAL_REDSTONE => Terminal::$COLOR_MATERIAL_REDSTONE,
253 TextFormat::MATERIAL_COPPER => Terminal::$COLOR_MATERIAL_COPPER,
254 TextFormat::MATERIAL_GOLD => Terminal::$COLOR_MATERIAL_GOLD,
255 TextFormat::MATERIAL_EMERALD => Terminal::$COLOR_MATERIAL_EMERALD,
256 TextFormat::MATERIAL_DIAMOND => Terminal::$COLOR_MATERIAL_DIAMOND,
257 TextFormat::MATERIAL_LAPIS => Terminal::$COLOR_MATERIAL_LAPIS,
258 TextFormat::MATERIAL_AMETHYST => Terminal::$COLOR_MATERIAL_AMETHYST,
259 TextFormat::MATERIAL_RESIN => Terminal::$COLOR_MATERIAL_RESIN,
260 default => $token,
261 };
262 }
263
264 return $newString;
265 }
266
270 public static function write(string $line) : void{
271 echo self::toANSI($line);
272 }
273
278 public static function writeLine(string $line) : void{
279 echo self::toANSI($line) . self::$FORMAT_RESET . PHP_EOL;
280 }
281}
static toANSI(string $string)
Definition Terminal.php:224
static write(string $line)
Definition Terminal.php:270
static writeLine(string $line)
Definition Terminal.php:278
static tokenize(string $string)
static getOS(bool $recalculate=false)
Definition Utils.php:269