Checkboxes::handleCharacter()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 19
ccs 12
cts 12
cp 1
rs 9.6333
c 0
b 0
f 0
cc 4
nc 4
nop 1
crap 4
1
<?php
2
3
namespace League\CLImate\TerminalObject\Dynamic;
4
5
use League\CLImate\Util\Reader\ReaderInterface;
6
use League\CLImate\Util\Reader\Stdin;
7
8
class Checkboxes extends InputAbstract
9
{
10
    /**
11
     * The options to choose from
12
     *
13
     * @var Checkbox\CheckboxGroup $checkboxes
14
     */
15
    protected $checkboxes;
16
17 16
    public function __construct($prompt, array $options, ReaderInterface $reader = null)
18
    {
19 16
        $this->prompt  = $prompt;
20 16
        $this->reader  = $reader ?: new Stdin();
21
22 16
        $this->checkboxes = $this->buildCheckboxes($options);
23 16
    }
24
25
    /**
26
     * Do it! Prompt the user for information!
27
     *
28
     * @return string
29
     */
30 16
    public function prompt()
31
    {
32 16
        $this->output->write($this->parser->apply($this->promptFormatted()));
33
34 16
        $this->writeCheckboxes();
35
36 16
        $this->util->system->exec('stty sane');
37
38 16
        return $this->checkboxes->getCheckedValues();
39
    }
40
41
    /**
42
     * Build out the checkboxes
43
     *
44
     * @param array $options
45
     *
46
     * @return Checkbox\CheckboxGroup
47
     */
48 12
    protected function buildCheckboxes(array $options)
49
    {
50 12
        return new Checkbox\CheckboxGroup($options);
51
    }
52
53
    /**
54
     * Format the prompt string
55
     *
56
     * @return string
57
     */
58 16
    protected function promptFormatted()
59
    {
60 16
        return $this->prompt . ' (use <space> to select)';
61
    }
62
63
    /**
64
     * Output the checkboxes and listen for any keystrokes
65
     */
66 16
    protected function writeCheckboxes()
67
    {
68 16
        $this->updateCheckboxView();
69
70 16
        $this->util->system->exec('stty -icanon');
71 16
        $this->output->sameLine()->write($this->util->cursor->hide());
72
73 16
        $this->listenForInput();
74 16
    }
75
76
    /**
77
     * Listen for input and act on it
78
     */
79 16
    protected function listenForInput()
80
    {
81 16
        while ($char = $this->reader->char(1)) {
82 16
            if ($this->handleCharacter($char)) {
83 16
                break;
84
            }
85
86 16
            $this->moveCursorToTop();
87 16
            $this->updateCheckboxView();
88 16
        }
89 16
    }
90
91
    /**
92
     * Take the appropriate action based on the input character,
93
     * returns whether to stop listening or not
94
     *
95
     * @param string $char
96
     *
97
     * @return bool
98
     */
99 16
    protected function handleCharacter($char)
100
    {
101
        switch ($char) {
102 16
            case "\n":
103 16
                $this->output->sameLine()->write($this->util->cursor->defaultStyle());
104 16
                $this->output->sameLine()->write("\e[0m");
105 16
            return true; // Break the while loop as well
106
107 16
            case "\e":
108 8
                $this->handleAnsi();
109 8
            break;
110
111 16
            case ' ':
112 16
                $this->checkboxes->toggleCurrent();
113 16
            break;
114
        }
115
116 16
        return false;
117
    }
118
119
    /**
120
     * Move the cursor to the top of the option list
121
     */
122 16
    protected function moveCursorToTop()
123
    {
124 16
        $output = $this->util->cursor->up($this->checkboxes->count() - 1);
125 16
        $output .= $this->util->cursor->startOfCurrentLine();
126
127 16
        $this->output->sameLine()->write($output);
128 16
    }
129
130
    /**
131
     * Handle any ANSI characters
132
     */
133 8
    protected function handleAnsi()
134
    {
135 8
        switch ($this->reader->char(2)) {
136
            // Up arrow
137 8
            case '[A':
138
                $this->checkboxes->setCurrent('previous');
139
            break;
140
141
            // Down arrow
142 8
            case '[B':
143 8
                $this->checkboxes->setCurrent('next');
144 8
            break;
145 8
        }
146 8
    }
147
148
    /**
149
     * Re-write the checkboxes based on the current objects
150
     */
151 16
    protected function updateCheckboxView()
152
    {
153 16
        $this->checkboxes->util($this->util);
154 16
        $this->checkboxes->output($this->output);
155 16
        $this->checkboxes->parser($this->parser);
156
157 16
        $this->checkboxes->write();
158 16
    }
159
}
160