• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tempestphp / tempest-framework / 12021213285

26 Nov 2024 12:18AM UTC coverage: 77.441% (-2.0%) from 79.441%
12021213285

Pull #754

github

web-flow
Merge 46eda39bc into cc0c7eea3
Pull Request #754: feat(framework): overhaul console interactions

734 of 1174 new or added lines in 55 files covered. (62.52%)

54 existing lines in 12 files now uncovered.

8239 of 10639 relevant lines covered (77.44%)

60.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

70.67
/src/Tempest/Console/src/Components/Interactive/SearchComponent.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Tempest\Console\Components\Interactive;
6

7
use Closure;
8
use Tempest\Console\Components\Concerns\HasErrors;
9
use Tempest\Console\Components\Concerns\HasState;
10
use Tempest\Console\Components\Concerns\HasTextBuffer;
11
use Tempest\Console\Components\Concerns\RendersControls;
12
use Tempest\Console\Components\OptionCollection;
13
use Tempest\Console\Components\Renderers\ChoiceRenderer;
14
use Tempest\Console\Components\Static\StaticSearchComponent;
15
use Tempest\Console\Components\TextBuffer;
16
use Tempest\Console\HandlesKey;
17
use Tempest\Console\HasCursor;
18
use Tempest\Console\HasStaticComponent;
19
use Tempest\Console\InteractiveConsoleComponent;
20
use Tempest\Console\Key;
21
use Tempest\Console\Point;
22
use Tempest\Console\StaticConsoleComponent;
23
use Tempest\Console\Terminal\Terminal;
24
use Tempest\Support\ArrayHelper;
25

26
final class SearchComponent implements InteractiveConsoleComponent, HasCursor, HasStaticComponent
27
{
28
    use HasErrors;
29
    use HasState;
30
    use RendersControls;
31
    use HasTextBuffer;
32

33
    private ChoiceRenderer $renderer;
34

35
    public OptionCollection $options;
36

37
    private ?string $previousQuery = null;
38

39
    public function __construct(
9✔
40
        public string $label,
41
        public Closure $search,
42
        public bool $multiple = false,
43
        public null|array|string $default = null,
44
    ) {
45
        $this->bufferEnabled = ! $this->multiple;
9✔
46
        $this->buffer = new TextBuffer();
9✔
47
        $this->renderer = new ChoiceRenderer(default: $default, multiple: $multiple);
9✔
48
        $this->options = new OptionCollection([]);
9✔
49

50
        if ($this->multiple) {
9✔
51
            $this->default = ArrayHelper::wrap($this->default);
3✔
52
        }
53

54
        $this->updateQuery();
9✔
55
    }
56

57
    public function render(Terminal $terminal): string
2✔
58
    {
59
        $this->updateQuery();
2✔
60

61
        return $this->renderer->render(
2✔
62
            terminal: $terminal,
2✔
63
            state: $this->state,
2✔
64
            label: $this->label,
2✔
65
            query: $this->buffer,
2✔
66
            filtering: $this->bufferEnabled,
2✔
67
            options: $this->options,
2✔
68
        );
2✔
69
    }
70

71
    private function updateQuery(): void
9✔
72
    {
73
        if ($this->previousQuery === $this->buffer->text) {
9✔
74
            return;
4✔
75
        }
76

77
        $this->options->setCollection(array_values(($this->search)($this->buffer->text)));
9✔
78
        $this->previousQuery = $this->buffer->text;
9✔
79
    }
80

NEW
UNCOV
81
    private function getControls(): array
×
82
    {
NEW
UNCOV
83
        return [
×
NEW
84
            ...($this->multiple ? [
×
NEW
UNCOV
85
                ...($this->bufferEnabled ? [
×
NEW
86
                    'esc' => 'select',
×
87
                ] : [
88
                    '/' => 'filter',
89
                    'space' => 'select',
90
                ]),
91
            ] : []),
NEW
UNCOV
92
            '↑' => 'up',
×
NEW
93
            '↓' => 'down',
×
NEW
94
            'enter' => $this->multiple && $this->default && $this->options->getSelectedOptions() === []
×
NEW
95
                ? 'skip'
×
NEW
96
                : 'confirm',
×
NEW
97
            'ctrl+c' => 'cancel',
×
NEW
98
        ];
×
99
    }
100

NEW
101
    public function getCursorPosition(Terminal $terminal): Point
×
102
    {
NEW
UNCOV
103
        return $this->renderer->getCursorPosition($terminal, $this->buffer);
×
104
    }
105

NEW
106
    public function cursorVisible(): bool
×
107
    {
NEW
UNCOV
108
        return $this->bufferEnabled;
×
109
    }
110

111
    public function getStaticComponent(): StaticConsoleComponent
5✔
112
    {
113
        return new StaticSearchComponent(
5✔
114
            label: $this->label,
5✔
115
            search: $this->search,
5✔
116
            multiple: $this->multiple,
5✔
117
            default: $this->default,
5✔
118
        );
5✔
119
    }
120

121
    #[HandlesKey]
3✔
122
    public function input(string $key): void
123
    {
124
        if ($this->multiple) {
3✔
125
            if (! $this->bufferEnabled && $key === '/') {
2✔
126
                $this->bufferEnabled = true;
1✔
127
                $this->updateQuery();
1✔
128

129
                return;
1✔
130
            }
131

132
            if (! $this->bufferEnabled) {
2✔
133
                match (mb_strtolower($key)) {
2✔
134
                    ' ' => $this->options->toggleCurrent(),
2✔
NEW
135
                    'h', 'k' => $this->options->previous(),
×
NEW
136
                    'j', 'l' => $this->options->next(),
×
NEW
137
                    default => null,
×
138
                };
2✔
139

140
                $this->updateQuery();
2✔
141

142
                return;
2✔
143
            }
144
        }
145

146
        $this->buffer->input($key);
2✔
147
        $this->updateQuery();
2✔
148
    }
149

150
    #[HandlesKey(Key::ENTER)]
4✔
151
    public function enter(): mixed
152
    {
153
        if ($this->multiple) {
4✔
154
            return $this->options->getRawSelectedOptions() ?: $this->default;
3✔
155
        }
156

157
        return $this->options->getActive()->value;
1✔
158
    }
159

160
    #[HandlesKey(Key::ESCAPE)]
1✔
161
    public function stopFiltering(): void
162
    {
163
        if (! $this->multiple) {
1✔
NEW
164
            return;
×
165
        }
166

167
        $this->bufferEnabled = false;
1✔
168
    }
169

NEW
170
    #[HandlesKey(Key::UP)]
×
171
    #[HandlesKey(Key::HOME)]
172
    #[HandlesKey(Key::START_OF_LINE)]
173
    public function up(): void
174
    {
NEW
175
        $this->options->previous();
×
176
    }
177

178
    #[HandlesKey(Key::DOWN)]
2✔
179
    #[HandlesKey(Key::END)]
180
    #[HandlesKey(Key::END_OF_LINE)]
181
    public function down(): void
182
    {
183
        $this->options->next();
2✔
184
    }
185
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc