Completed
Pull Request — master (#78)
by Aydin
02:26
created

UnixTerminal::getHeight()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 2
eloc 2
nc 2
nop 0
1
<?php
2
3
namespace PhpSchool\CliMenu\Terminal;
4
5
/**
6
 * Class UnixTerminal
7
 *
8
 * @package PhpSchool\CliMenu\Terminal
9
 * @author Michael Woodward <[email protected]>
10
 */
11
class UnixTerminal implements TerminalInterface
12
{
13
    /**
14
     * @var bool
15
     */
16
    private $isTTY;
17
18
    /**
19
     * @var bool
20
     */
21
    private $isCanonical = false;
22
23
    /**
24
     * @var int
25
     */
26
    private $width;
27
28
    /**
29
     * @var int
30
     */
31
    private $height;
32
33
    /**
34
     * @var string
35
     */
36
    private $details;
37
38
    /**
39
     * @var string
40
     */
41
    private $originalConfiguration;
42
43
    /**
44
     * Initialise the terminal from resource
45
     *
46
     */
47
    public function __construct()
48
    {
49
        $this->getOriginalConfiguration();
50
    }
51
52
    /**
53
     * Get the available width of the terminal
54
     *
55
     * @return int
56
     */
57
    public function getWidth()
58
    {
59
        return $this->width ?: $this->width = (int) exec('tput cols');
60
    }
61
62
    /**
63
     * Get the available height of the terminal
64
     *
65
     * @return int
66
     */
67
    public function getHeight()
68
    {
69
        return $this->height ?: $this->height = (int) exec('tput lines');
70
    }
71
72
    /**
73
     * Get terminal details
74
     *
75
     * @return string
76
     */
77
    public function getDetails()
78
    {
79
        if (!$this->details) {
80
            $this->details = function_exists('posix_ttyname')
81
                ? @posix_ttyname(STDOUT)
82
                : "Can't retrieve terminal details";
83
        }
84
85
        return $this->details;
86
    }
87
88
    /**
89
     * Get the original terminal configuration / mode
90
     *
91
     * @return string
92
     */
93
    private function getOriginalConfiguration()
94
    {
95
        return $this->originalConfiguration ?: $this->originalConfiguration = exec('stty -g');
96
    }
97
98
    /**
99
     * Toggle canonical mode on TTY
100
     *
101
     * @param bool $useCanonicalMode
102
     */
103
    public function setCanonicalMode($useCanonicalMode = true)
104
    {
105
        if ($useCanonicalMode) {
106
            exec('stty -icanon');
107
            $this->isCanonical = true;
108
        } else {
109
            exec('stty ' . $this->getOriginalConfiguration());
110
            $this->isCanonical = false;
111
        }
112
    }
113
114
    /**
115
     * Check if TTY is in canonical mode
116
     * Assumes the terminal was never in canonical mode
117
     *
118
     * @return bool
119
     */
120
    public function isCanonical()
121
    {
122
        return $this->isCanonical;
123
    }
124
125
    /**
126
     * Test whether terminal is valid TTY
127
     *
128
     * @return bool
129
     */
130
    public function isTTY()
131
    {
132
        return $this->isTTY ?: $this->isTTY = function_exists('posix_isatty') && @posix_isatty(STDOUT);
133
    }
134
135
    /**
136
     * Test whether terminal supports colour output
137
     *
138
     * @return bool
139
     *
140
     * @link https://github.com/symfony/Console/blob/master/Output/StreamOutput.php#L95-L102
141
     */
142
    public function supportsColour()
143
    {
144
        if (DIRECTORY_SEPARATOR === '\\') {
145
            return false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI') || 'xterm' === getenv('TERM');
146
        }
147
148
        return $this->isTTY();
149
    }
150
151
    /**
152
     * @param array $map
153
     * @return string
154
     */
155
    public function getKeyedInput(array $map = [])
156
    {
157
        // TODO: Move to class var?
158
        // TODO: up, down, enter etc in Abstract CONSTs
159
160
        if (empty($map)) {
161
            $map = [
162
                "\033[A" => 'up',
163
                "k"      => 'up',
164
                ""      => 'up', // emacs ^P
165
                "\033[B" => 'down',
166
                "j"      => 'down',
167
                ""      => 'down', //emacs ^N
168
                "\n"     => 'enter',
169
                "\r"     => 'enter',
170
                " "      => 'enter',
171
                "\177"   => 'backspace'
172
            ];
173
        }
174
175
        $input = fread(STDIN, 4);
176
        $this->clearLine();
177
178
        return array_key_exists($input, $map)
179
            ? $map[$input]
180
            : $input;
181
    }
182
183
    /**
184
     * Clear the terminal window
185
     */
186
    public function clear()
187
    {
188
        echo "\033[2J";
189
    }
190
191
    /**
192
     * Enable cursor
193
     */
194
    public function enableCursor()
195
    {
196
        echo "\033[?25h";
197
    }
198
199
    /**
200
     * Disable cursor
201
     */
202
    public function disableCursor()
203
    {
204
        echo "\033[?25l";
205
    }
206
207
    /**
208
     * Move the cursor to the top left of the window
209
     *
210
     * @return void
211
     */
212
    public function moveCursorToTop()
213
    {
214
        echo "\033[H";
215
    }
216
217
    /**
218
     * Move the cursor to the start of a specific row
219
     *
220
     * @param int $rowNumber
221
     */
222
    public function moveCursorToRow($rowNumber)
223
    {
224
        echo sprintf("\033[%d;0H", $rowNumber);
225
    }
226
227
    /**
228
     * Move the cursor to the start of a specific column
229
     *
230
     * @param int $column
231
     */
232
    public function moveCursorToColumn($column)
233
    {
234
        echo sprintf("\033[%dC", $column);
235
    }
236
237
    /**
238
     * Clear the current cursors line
239
     *
240
     * @return void
241
     */
242
    public function clearLine()
243
    {
244
        echo sprintf("\033[%dD\033[K", $this->getWidth());
245
    }
246
247
    /**
248
     * Clean the whole console without jumping the window
249
     */
250
    public function clean()
251
    {
252
        foreach (range(0, $this->getHeight()) as $rowNum) {
253
            $this->moveCursorToRow($rowNum);
254
            $this->clearLine();
255
        }
256
    }
257
}
258