1+ <?php
2+
3+ declare (strict_types=1 );
4+
5+ namespace Mathematicator \Engine \Helper ;
6+
7+
8+ use Mathematicator \Engine \MathematicatorException ;
9+ use Nette \StaticClass ;
10+
11+ class Terminal
12+ {
13+
14+ use StaticClass;
15+
16+ /**
17+ * @var int
18+ */
19+ private static $ staticTtl = 0 ;
20+
21+ /**
22+ * Render code snippet to Terminal.
23+ *
24+ * @param string $path
25+ * @param int|null $line -> if not null mark selected line by red color
26+ */
27+ public static function code (string $ path , int $ line = null ): void
28+ {
29+ echo "\n" . $ path . ($ line === null ? '' : ' [on line ' . $ line . '] ' ) . "\n\n" ;
30+ if (\is_file ($ path )) {
31+ echo '----- file ----- ' . "\n" ;
32+ $ file = str_replace (["\r\n" , "\r" ], "\n" , (string ) file_get_contents ($ path ));
33+ $ fileParser = explode ("\n" , $ file );
34+ $ start = $ line > 8 ? $ line - 8 : 0 ;
35+
36+ for ($ i = $ start ; $ i <= $ start + 15 ; $ i ++) {
37+ if (!isset ($ fileParser [$ i ])) {
38+ break ;
39+ }
40+
41+ $ currentLine = $ i + 1 ;
42+ $ highlight = $ line === $ currentLine ;
43+
44+ echo ($ highlight ? "\e[1;37m \e[41m " : "\e[100m " )
45+ . str_pad (' ' . $ currentLine . ': ' , 6 , ' ' ) . ($ highlight ? '' : "\e[0m " )
46+ . str_replace ("\t" , ' ' , $ fileParser [$ i ])
47+ . ($ highlight ? "\e[0m " : '' )
48+ . "\n" ;
49+ }
50+
51+ echo '----- file ----- ' . "\n\n" ;
52+ }
53+ }
54+
55+ /**
56+ * Ask question in Terminal and return user answer (string or null if empty).
57+ *
58+ * Function will be asked since user give valid answer.
59+ *
60+ * @param string $question -> only display to user
61+ * @param string[]|null $possibilities -> if empty, answer can be every valid string or null.
62+ * @return string|null -> null if empty answer
63+ * @throws MathematicatorException
64+ */
65+ public static function ask (string $ question , ?array $ possibilities = null ): ?string
66+ {
67+ self ::$ staticTtl = 0 ;
68+
69+ echo "\n" . str_repeat ('- ' , 100 ) . "\n" ;
70+
71+ if ($ possibilities !== [] && $ possibilities !== null ) {
72+ $ renderPossibilities = static function (array $ possibilities ): string {
73+ $ return = '' ;
74+ $ containsNull = false ;
75+
76+ foreach ($ possibilities as $ possibility ) {
77+ if ($ possibility !== null ) {
78+ $ return .= ($ return === '' ? '' : '", " ' ) . $ possibility ;
79+ } elseif ($ containsNull === false ) {
80+ $ containsNull = true ;
81+ }
82+ }
83+
84+ return 'Possible values: " ' . $ return . '" ' . ($ containsNull ? ' or press ENTER ' : '' ) . '. ' ;
85+ };
86+
87+ echo $ renderPossibilities ($ possibilities ) . "\n" ;
88+ }
89+
90+ echo 'Q: ' . trim ($ question ) . "\n" . 'A: ' ;
91+
92+ $ fOpen = fopen ('php://stdin ' , 'rb ' );
93+
94+ if (\is_resource ($ fOpen ) === false ) {
95+ throw new MathematicatorException ('Problem with opening "php://stdin". ' );
96+ }
97+
98+ $ input = trim ((string ) fgets ($ fOpen ));
99+ echo "\n" ;
100+
101+ $ input = $ input === '' ? null : $ input ;
102+
103+ if ($ possibilities !== [] && $ possibilities !== null ) {
104+ if (\in_array ($ input , $ possibilities , true )) {
105+ return $ input ;
106+ }
107+
108+ self ::renderError ('!!! Invalid answer !!! ' );
109+ self ::$ staticTtl ++;
110+
111+ if (self ::$ staticTtl > 16 ) {
112+ throw new MathematicatorException (
113+ 'The maximum invalid response limit was exceeded. Current limit: ' . self ::$ staticTtl
114+ );
115+ }
116+
117+ return self ::ask ($ question , $ possibilities );
118+ }
119+
120+ return $ input ;
121+ }
122+
123+ /**
124+ * Render red block with error message.
125+ *
126+ * @param string $message
127+ */
128+ public static function renderError (string $ message ): void
129+ {
130+ echo "\033[1;37m \033[41m " ;
131+
132+ for ($ i = 0 ; $ i < 100 ; $ i ++) {
133+ echo ' ' ;
134+ }
135+
136+ echo "\n" . str_pad (' ' . $ message . ' ' , 100 ) . "\n" ;
137+
138+ for ($ i = 0 ; $ i < 100 ; $ i ++) {
139+ echo ' ' ;
140+ }
141+
142+ echo "\033[0m " ;
143+ }
144+
145+ }
0 commit comments