Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
0.00% |
0 / 4 |
CRAP | |
0.00% |
0 / 29 |
Termios | |
0.00% |
0 / 1 |
|
0.00% |
0 / 4 |
56 | |
0.00% |
0 / 29 |
__construct | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 6 |
|||
enableRawMode | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 14 |
|||
disableRawMode | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 6 |
|||
getInstance | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 3 |
1 | <?php declare(strict_types=1); |
2 | |
3 | namespace Aviat\Kilo; |
4 | |
5 | use FFI; |
6 | use FFI\CData; |
7 | |
8 | use Aviat\Kilo\Enum\C; |
9 | |
10 | /** |
11 | * An implicit singleton wrapper around terminal settings to simplify enabling/disabling raw mode |
12 | */ |
13 | class Termios { |
14 | private CData $originalTermios; |
15 | |
16 | private function __construct() |
17 | { |
18 | $ffi = get_ffi(); |
19 | $termios = $ffi->new('struct termios'); |
20 | $res = $ffi->tcgetattr(C::STDIN_FILENO, FFI::addr($termios)); |
21 | |
22 | if ($res === -1) |
23 | { |
24 | throw new TermiosException('Failed to get existing terminal settings'); |
25 | } |
26 | |
27 | $this->originalTermios = $termios; |
28 | } |
29 | |
30 | /** |
31 | * Put the current terminal into raw input mode |
32 | * |
33 | * Returns TRUE if successful. Will return NULL if run more than once, as |
34 | * raw mode is pretty binary...there's no point in reapplying raw mode! |
35 | * |
36 | * @return bool|null |
37 | */ |
38 | public static function enableRawMode(): ?bool |
39 | { |
40 | static $run = FALSE; |
41 | |
42 | // Don't run this more than once! |
43 | if ($run === TRUE) |
44 | { |
45 | return NULL; |
46 | } |
47 | |
48 | $run = TRUE; |
49 | |
50 | $instance = self::getInstance(); |
51 | |
52 | // Make sure to restore normal mode on exit/die/crash |
53 | register_shutdown_function([static::class, 'disableRawMode']); |
54 | |
55 | $termios = clone $instance->originalTermios; |
56 | // $termios->c_iflag &= ~(C::BRKINT | C::ICRNL | C::INPCK | C::ISTRIP | C::IXON); |
57 | // $termios->c_oflag &= ~(C::OPOST); |
58 | $termios->c_iflag = 0; |
59 | $termios->c_oflag = 0; |
60 | $termios->c_cflag |= (C::CS8); |
61 | $termios->c_lflag &= ~( C::ECHO | C::ICANON | C::IEXTEN | C::ISIG ); |
62 | $termios->c_cc[C::VMIN] = 0; |
63 | $termios->c_cc[C::VTIME] = 1; |
64 | |
65 | // Turn on raw mode |
66 | $res = get_ffi()->tcsetattr(C::STDIN_FILENO, C::TCSAFLUSH, FFI::addr($termios)); |
67 | |
68 | return $res !== -1; |
69 | } |
70 | |
71 | /** |
72 | * Restores terminal settings that were changed when going into raw mode. |
73 | * |
74 | * Returns TRUE if settings are applied successfully. If raw mode was not |
75 | * enabled, this will output a line of escape codes and a new line. |
76 | * |
77 | * @return bool |
78 | */ |
79 | public static function disableRawMode(): bool |
80 | { |
81 | $instance = self::getInstance(); |
82 | |
83 | // Cleanup |
84 | write_stdout(ANSI::CLEAR_SCREEN); |
85 | write_stdout(ANSI::RESET_CURSOR); |
86 | write_stdout("\n"); // New line, please |
87 | |
88 | $res = get_ffi()->tcsetattr(C::STDIN_FILENO, C::TCSAFLUSH, FFI::addr($instance->originalTermios)); |
89 | |
90 | return $res !== -1; |
91 | } |
92 | |
93 | private static function getInstance(): self |
94 | { |
95 | static $instance; |
96 | |
97 | if ($instance === NULL) |
98 | { |
99 | $instance = new self(); |
100 | } |
101 | |
102 | return $instance; |
103 | } |
104 | } |