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

tempestphp / tempest-framework / 14024978163

23 Mar 2025 05:55PM UTC coverage: 79.391% (-0.05%) from 79.441%
14024978163

push

github

web-flow
feat(view): cache Blade and Twig templates in internal storage (#1061)

2 of 2 new or added lines in 2 files covered. (100.0%)

912 existing lines in 110 files now uncovered.

10478 of 13198 relevant lines covered (79.39%)

91.09 hits per line

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

46.03
/src/Tempest/Console/src/Components/Interactive/SingleChoiceComponent.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Tempest\Console\Components\Interactive;
6

7
use Stringable;
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\StaticSingleChoiceComponent;
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 UnitEnum;
25

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

33
    private ChoiceRenderer $renderer;
34

35
    private OptionCollection $options;
36

37
    public function __construct(
34✔
38
        public string $label,
39
        iterable $options,
40
        public null|int|UnitEnum|string $default = null,
41
    ) {
42
        $this->bufferEnabled = false;
34✔
43
        $this->options = new OptionCollection($options);
34✔
44
        $this->buffer = new TextBuffer();
34✔
45
        $this->renderer = new ChoiceRenderer(multiple: false, default: $default);
34✔
46
        $this->updateQuery();
34✔
47
    }
48

49
    public StaticConsoleComponent $staticComponent {
50
        get => new StaticSingleChoiceComponent(
51
            label: $this->label,
52
            options: $this->options->getRawOptions(),
53
            default: $this->default,
54
        );
55
    }
56

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

UNCOV
61
        return $this->renderer->render(
×
UNCOV
62
            terminal: $terminal,
×
UNCOV
63
            state: $this->state,
×
UNCOV
64
            label: $this->label,
×
UNCOV
65
            query: $this->buffer,
×
UNCOV
66
            options: $this->options,
×
UNCOV
67
            placeholder: 'Filter...',
×
UNCOV
68
            filtering: $this->bufferEnabled,
×
UNCOV
69
        );
×
70
    }
71

UNCOV
72
    private function getControls(): array
×
73
    {
UNCOV
74
        $controls = [];
×
75

UNCOV
76
        if ($this->bufferEnabled) {
×
UNCOV
77
            $controls['esc'] = 'select';
×
78
        } else {
UNCOV
79
            $controls['/'] = 'filter';
×
UNCOV
80
            $controls['space'] = 'select';
×
81
        }
82

UNCOV
83
        if ($this->default !== null) {
×
UNCOV
84
            $controls['alt+enter'] = 'default';
×
85
        }
86

UNCOV
87
        return [
×
UNCOV
88
            ...$controls,
×
UNCOV
89
            '↑' => 'up',
×
UNCOV
90
            '↓' => 'down',
×
UNCOV
91
            'enter' => 'confirm',
×
UNCOV
92
            'ctrl+c' => 'cancel',
×
UNCOV
93
        ];
×
94
    }
95

96
    private function updateQuery(): void
34✔
97
    {
98
        $this->options->filter($this->buffer->text);
34✔
99
    }
100

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

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

111
    #[HandlesKey]
2✔
112
    public function input(string $key): void
113
    {
114
        if (! $this->bufferEnabled && $key === '/') {
2✔
115
            $this->bufferEnabled = true;
2✔
116

117
            return;
2✔
118
        }
119

120
        if (! $this->bufferEnabled) {
2✔
121
            match (mb_strtolower($key)) {
1✔
UNCOV
122
                'h', 'k' => $this->options->previous(),
×
UNCOV
123
                'j', 'l' => $this->options->next(),
×
124
                default => null,
1✔
125
            };
1✔
126
            $this->updateQuery();
1✔
127

128
            return;
1✔
129
        }
130

131
        $this->buffer->input($key);
2✔
132
        $this->updateQuery();
2✔
133
    }
134

135
    #[HandlesKey(Key::ENTER)]
4✔
136
    public function enter(): null|int|string|Stringable|UnitEnum
137
    {
138
        return $this->options->getRawActiveOption($this->default);
4✔
139
    }
140

141
    #[HandlesKey(Key::ALT_ENTER)]
1✔
142
    public function altEnter(): null|int|string|Stringable|UnitEnum
143
    {
144
        $this->options->setActive($this->default);
1✔
145

146
        return $this->default;
1✔
147
    }
148

149
    #[HandlesKey(Key::ESCAPE)]
1✔
150
    public function stopFiltering(): void
151
    {
152
        $this->bufferEnabled = false;
1✔
153
    }
154

UNCOV
155
    #[HandlesKey(Key::UP)]
×
156
    #[HandlesKey(Key::HOME)]
157
    #[HandlesKey(Key::START_OF_LINE)]
158
    public function up(): void
159
    {
UNCOV
160
        $this->options->previous();
×
161
    }
162

163
    #[HandlesKey(Key::DOWN)]
3✔
164
    #[HandlesKey(Key::END)]
165
    #[HandlesKey(Key::END_OF_LINE)]
166
    public function down(): void
167
    {
168
        $this->options->next();
3✔
169
    }
170
}
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

© 2026 Coveralls, Inc