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

veeso / tui-realm-stdlib / 22143900361

18 Feb 2026 02:31PM UTC coverage: 76.863% (+4.4%) from 72.486%
22143900361

Pull #58

github

web-flow
Merge 82269e219 into 237158c92
Pull Request #58: Remove unnecessary features

588 of 1352 new or added lines in 21 files covered. (43.49%)

40 existing lines in 15 files now uncovered.

3940 of 5126 relevant lines covered (76.86%)

4.91 hits per line

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

76.57
/src/components/select.rs
1
//! `Select` represents a select field, like in HTML. The size for the component must be 3 (border + selected) + the quantity of rows
2
//! you want to display other options when opened (at least 3).
3

4
use tuirealm::command::{Cmd, CmdResult, Direction};
5
use tuirealm::props::{
6
    AttrValue, Attribute, Borders, Color, LineStatic, PropPayload, PropValue, Props, Style,
7
    TextModifiers, Title,
8
};
9
use tuirealm::ratatui::text::Line as Spans;
10
use tuirealm::ratatui::{
11
    layout::{Constraint, Direction as LayoutDirection, Layout, Rect},
12
    widgets::{List, ListItem, ListState, Paragraph},
13
};
14
use tuirealm::{Frame, MockComponent, State, StateValue};
15

16
use crate::prop_ext::CommonProps;
17
use crate::utils::borrow_clone_line;
18

19
// -- states
20

21
/// The states that need to be kept for the [`Select`] component.
22
#[derive(Default)]
23
pub struct SelectStates {
24
    /// Available choices
25
    pub choices: Vec<String>,
26
    /// Currently selected choice
27
    pub selected: usize,
28
    /// Choice selected before opening the tab
29
    pub previously_selected: usize,
30
    pub tab_open: bool,
31
}
32

33
impl SelectStates {
34
    /// Move choice index to next choice.
35
    pub fn next_choice(&mut self, rewind: bool) {
22✔
36
        if self.tab_open {
22✔
37
            if rewind && self.selected + 1 >= self.choices.len() {
18✔
38
                self.selected = 0;
2✔
39
            } else if self.selected + 1 < self.choices.len() {
16✔
40
                self.selected += 1;
12✔
41
            }
12✔
42
        }
4✔
43
    }
22✔
44

45
    /// Move choice index to previous choice.
46
    pub fn prev_choice(&mut self, rewind: bool) {
22✔
47
        if self.tab_open {
22✔
48
            if rewind && self.selected == 0 && !self.choices.is_empty() {
16✔
49
                self.selected = self.choices.len() - 1;
2✔
50
            } else if self.selected > 0 {
14✔
51
                self.selected -= 1;
12✔
52
            }
12✔
53
        }
6✔
54
    }
22✔
55

56
    /// Overwrite the choices available with new ones.
57
    ///
58
    /// In addition resets current selection and keep index if possible or set it to the first value
59
    /// available.
60
    pub fn set_choices(&mut self, choices: impl Into<Vec<String>>) {
28✔
61
        self.choices = choices.into();
28✔
62
        // Keep index if possible
14✔
63
        if self.selected >= self.choices.len() {
28✔
64
            self.selected = match self.choices.len() {
4✔
65
                0 => 0,
2✔
66
                l => l - 1,
2✔
67
            };
68
        }
24✔
69
    }
28✔
70

71
    pub fn select(&mut self, i: usize) {
6✔
72
        if i < self.choices.len() {
6✔
73
            self.selected = i;
6✔
74
        }
6✔
75
    }
6✔
76

77
    /// Close tab.
78
    pub fn close_tab(&mut self) {
12✔
79
        self.tab_open = false;
12✔
80
    }
12✔
81

82
    /// Open tab.
83
    pub fn open_tab(&mut self) {
12✔
84
        self.previously_selected = self.selected;
12✔
85
        self.tab_open = true;
12✔
86
    }
12✔
87

88
    /// Cancel tab open.
89
    pub fn cancel_tab(&mut self) {
2✔
90
        self.close_tab();
2✔
91
        self.selected = self.previously_selected;
2✔
92
    }
2✔
93

94
    /// Returns whether the tab is open.
95
    #[must_use]
96
    pub fn is_tab_open(&self) -> bool {
46✔
97
        self.tab_open
46✔
98
    }
46✔
99
}
100

101
// -- component
102

103
/// `Select` represents a select field, like in HTML. The size for the component must be 3 (border + selected) + the quantity of rows
104
/// you want to display other options when opened (at least 3).
105
///
106
/// Similar to [`Radio`](crate::Radio), [`Select`] is a single-choice selector, but the difference is that it does not show the selector
107
/// unless the "Tab" is open, and only shows the currently selected choice.
108
#[derive(Default)]
109
#[must_use]
110
pub struct Select {
111
    common: CommonProps,
112
    props: Props,
113
    pub states: SelectStates,
114
}
115

116
impl Select {
117
    /// Set the main foreground color. This may get overwritten by individual text styles.
118
    pub fn foreground(mut self, fg: Color) -> Self {
2✔
119
        self.attr(Attribute::Foreground, AttrValue::Color(fg));
2✔
120
        self
2✔
121
    }
2✔
122

123
    /// Set the main background color. This may get overwritten by individual text styles.
124
    pub fn background(mut self, bg: Color) -> Self {
2✔
125
        self.attr(Attribute::Background, AttrValue::Color(bg));
2✔
126
        self
2✔
127
    }
2✔
128

129
    /// Set the main text modifiers. This may get overwritten by individual text styles.
NEW
130
    pub fn modifiers(mut self, m: TextModifiers) -> Self {
×
NEW
131
        self.attr(Attribute::TextProps, AttrValue::TextModifiers(m));
×
UNCOV
132
        self
×
UNCOV
133
    }
×
134

135
    /// Set the main style. This may get overwritten by individual text styles.
136
    ///
137
    /// This option will overwrite any previous [`foreground`](Self::foreground), [`background`](Self::background) and [`modifiers`](Self::modifiers)!
NEW
138
    pub fn style(mut self, style: Style) -> Self {
×
NEW
139
        self.attr(Attribute::Style, AttrValue::Style(style));
×
UNCOV
140
        self
×
UNCOV
141
    }
×
142

143
    /// Set a custom style for the border when the component is unfocused.
NEW
144
    pub fn inactive(mut self, s: Style) -> Self {
×
NEW
145
        self.attr(Attribute::FocusStyle, AttrValue::Style(s));
×
UNCOV
146
        self
×
UNCOV
147
    }
×
148

149
    /// Add a border to the component.
150
    pub fn borders(mut self, b: Borders) -> Self {
2✔
151
        self.attr(Attribute::Borders, AttrValue::Borders(b));
2✔
152
        self
2✔
153
    }
2✔
154

155
    /// Add a title to the component.
156
    pub fn title<T: Into<Title>>(mut self, title: T) -> Self {
2✔
157
        self.attr(Attribute::Title, AttrValue::Title(title.into()));
2✔
158
        self
2✔
159
    }
2✔
160

161
    /// Set whether wraparound should be possible (down on the last choice wraps around to 0, and the other way around).
162
    pub fn rewind(mut self, r: bool) -> Self {
2✔
163
        self.attr(Attribute::Rewind, AttrValue::Flag(r));
2✔
164
        self
2✔
165
    }
2✔
166

167
    /// Set the Symbol and Style for the indicator of the current line.
168
    pub fn highlighted_str<S: Into<LineStatic>>(mut self, s: S) -> Self {
2✔
169
        self.attr(Attribute::HighlightedStr, AttrValue::TextLine(s.into()));
2✔
170
        self
2✔
171
    }
2✔
172

173
    /// Set a custom foreground color for the currently highlighted item.
174
    pub fn highlighted_color(mut self, c: Color) -> Self {
2✔
175
        // TODO: shouldnt this be a highlight style instead?
1✔
176
        self.attr(Attribute::HighlightedColor, AttrValue::Color(c));
2✔
177
        self
2✔
178
    }
2✔
179

180
    /// Set the choices that should be possible.
181
    pub fn choices<S: Into<String>>(mut self, choices: impl IntoIterator<Item = S>) -> Self {
14✔
182
        self.attr(
14✔
183
            Attribute::Content,
14✔
184
            AttrValue::Payload(PropPayload::Vec(
7✔
185
                choices
14✔
186
                    .into_iter()
14✔
187
                    .map(|v| PropValue::Str(v.into()))
18✔
188
                    .collect(),
14✔
189
            )),
7✔
190
        );
7✔
191
        self
14✔
192
    }
14✔
193

194
    /// Set the initially selected choice.
195
    pub fn value(mut self, i: usize) -> Self {
2✔
196
        // Set state
1✔
197
        self.attr(
2✔
198
            Attribute::Value,
2✔
199
            AttrValue::Payload(PropPayload::Single(PropValue::Usize(i))),
2✔
200
        );
1✔
201
        self
2✔
202
    }
2✔
203

204
    /// ### render_open_tab
205
    ///
206
    /// Render component when tab is open
NEW
207
    fn render_open_tab(&mut self, render: &mut Frame, mut area: Rect) {
×
208
        // Make choices
209
        let choices: Vec<ListItem> = self
×
210
            .states
×
211
            .choices
×
212
            .iter()
×
213
            .map(|x| ListItem::new(Spans::from(x.as_str())))
×
214
            .collect();
×
215

NEW
216
        let hg = self
×
217
            .props
×
NEW
218
            .get_ref(Attribute::HighlightedColor)
×
NEW
219
            .and_then(AttrValue::as_color);
×
220

NEW
221
        if let Some(block) = self.common.get_block() {
×
NEW
222
            let inner = block.inner(area);
×
NEW
223
            render.render_widget(block, area);
×
NEW
224
            area = inner;
×
NEW
225
        }
×
226

227
        // Prepare layout
NEW
228
        let [para_area, list_area] = Layout::default()
×
229
            .direction(LayoutDirection::Vertical)
×
230
            .margin(0)
×
231
            .constraints([Constraint::Length(2), Constraint::Min(1)])
×
NEW
232
            .areas(area);
×
233
        // Render like "closed" tab in chunk 0
234
        let selected_text: String = match self.states.choices.get(self.states.selected) {
×
235
            None => String::default(),
×
236
            Some(s) => s.clone(),
×
237
        };
238

NEW
239
        let para = Paragraph::new(selected_text).style(self.common.style);
×
NEW
240
        render.render_widget(para, para_area);
×
241

NEW
242
        let hg_style = if let Some(color) = hg {
×
NEW
243
            Style::new().fg(color)
×
244
        } else {
NEW
245
            Style::new()
×
246
        }
NEW
247
        .add_modifier(TextModifiers::REVERSED);
×
248

249
        // Render the list of elements in chunks [1]
250
        // Make list
251
        let mut list = List::new(choices)
×
252
            .direction(tuirealm::ratatui::widgets::ListDirection::TopToBottom)
×
NEW
253
            .style(self.common.style)
×
NEW
254
            .highlight_style(hg_style);
×
255
        // Highlighted symbol
256
        let hg_str = self
×
257
            .props
×
258
            .get_ref(Attribute::HighlightedStr)
×
259
            .and_then(|x| x.as_textline());
×
260
        if let Some(hg_str) = hg_str {
×
261
            list = list.highlight_symbol(borrow_clone_line(hg_str));
×
262
        }
×
263
        let mut state: ListState = ListState::default();
×
264
        state.select(Some(self.states.selected));
×
265

NEW
266
        render.render_stateful_widget(list, list_area, &mut state);
×
UNCOV
267
    }
×
268

269
    /// ### render_closed_tab
270
    ///
271
    /// Render component when tab is closed
272
    fn render_closed_tab(&self, render: &mut Frame, area: Rect) {
×
273
        let selected_text: String = match self.states.choices.get(self.states.selected) {
×
274
            None => String::default(),
×
275
            Some(s) => s.clone(),
×
276
        };
NEW
277
        let mut widget = Paragraph::new(selected_text).style(self.common.style);
×
278

NEW
279
        if let Some(block) = self.common.get_block() {
×
NEW
280
            widget = widget.block(block);
×
NEW
281
        }
×
282

NEW
283
        render.render_widget(widget, area);
×
UNCOV
284
    }
×
285

286
    fn rewindable(&self) -> bool {
16✔
287
        self.props
16✔
288
            .get_or(Attribute::Rewind, AttrValue::Flag(false))
16✔
289
            .unwrap_flag()
16✔
290
    }
16✔
291
}
292

293
impl MockComponent for Select {
294
    fn view(&mut self, render: &mut Frame, area: Rect) {
×
NEW
295
        if !self.common.display {
×
NEW
296
            return;
×
NEW
297
        }
×
298

NEW
299
        if self.states.is_tab_open() {
×
NEW
300
            self.render_open_tab(render, area);
×
NEW
301
        } else {
×
NEW
302
            self.render_closed_tab(render, area);
×
303
        }
×
304
    }
×
305

306
    fn query(&self, attr: Attribute) -> Option<AttrValue> {
×
NEW
307
        if let Some(value) = self.common.get(attr) {
×
NEW
308
            return Some(value);
×
NEW
309
        }
×
310

311
        self.props.get(attr)
×
312
    }
×
313

314
    fn attr(&mut self, attr: Attribute, value: AttrValue) {
32✔
315
        if let Some(value) = self.common.set(attr, value) {
32✔
NEW
316
            match attr {
×
317
                Attribute::Content => {
7✔
318
                    // Reset choices
7✔
319
                    let choices: Vec<String> = value
14✔
320
                        .unwrap_payload()
14✔
321
                        .unwrap_vec()
14✔
322
                        .iter()
14✔
323
                        .map(|x| x.clone().unwrap_str())
18✔
324
                        .collect();
14✔
325
                    self.states.set_choices(choices);
14✔
326
                }
7✔
327
                Attribute::Value => {
4✔
328
                    self.states
4✔
329
                        .select(value.unwrap_payload().unwrap_single().unwrap_usize());
4✔
330
                }
4✔
NEW
331
                Attribute::Focus if self.states.is_tab_open() => {
×
NEW
332
                    if let AttrValue::Flag(false) = value {
×
NEW
333
                        self.states.cancel_tab();
×
NEW
334
                    }
×
NEW
335
                    self.props.set(attr, value);
×
336
                }
337
                attr => {
6✔
338
                    self.props.set(attr, value);
6✔
339
                }
6✔
340
            }
341
        }
8✔
342
    }
32✔
343

344
    fn state(&self) -> State {
6✔
345
        if self.states.is_tab_open() {
6✔
346
            State::None
×
347
        } else {
348
            State::Single(StateValue::Usize(self.states.selected))
6✔
349
        }
350
    }
6✔
351

352
    fn perform(&mut self, cmd: Cmd) -> CmdResult {
22✔
353
        match cmd {
16✔
354
            Cmd::Move(Direction::Down) => {
355
                // Increment choice
356
                self.states.next_choice(self.rewindable());
8✔
357
                // Return CmdResult On Change or None if tab is closed
4✔
358
                if self.states.is_tab_open() {
8✔
359
                    CmdResult::Changed(State::Single(StateValue::Usize(self.states.selected)))
6✔
360
                } else {
361
                    CmdResult::None
2✔
362
                }
363
            }
364
            Cmd::Move(Direction::Up) => {
365
                // Increment choice
366
                self.states.prev_choice(self.rewindable());
8✔
367
                // Return CmdResult On Change or None if tab is closed
4✔
368
                if self.states.is_tab_open() {
8✔
369
                    CmdResult::Changed(State::Single(StateValue::Usize(self.states.selected)))
6✔
370
                } else {
371
                    CmdResult::None
2✔
372
                }
373
            }
374
            Cmd::Cancel => {
375
                self.states.cancel_tab();
×
376
                CmdResult::Changed(self.state())
×
377
            }
378
            Cmd::Submit => {
379
                // Open or close tab
380
                if self.states.is_tab_open() {
6✔
381
                    self.states.close_tab();
4✔
382
                    CmdResult::Submit(self.state())
4✔
383
                } else {
384
                    self.states.open_tab();
2✔
385
                    CmdResult::None
2✔
386
                }
387
            }
388
            _ => CmdResult::None,
×
389
        }
390
    }
22✔
391
}
392

393
#[cfg(test)]
394
mod test {
395

396
    use super::*;
397

398
    use pretty_assertions::assert_eq;
399

400
    use tuirealm::props::{HorizontalAlignment, PropPayload, PropValue};
401

402
    #[test]
403
    fn test_components_select_states() {
2✔
404
        let mut states: SelectStates = SelectStates::default();
2✔
405
        assert_eq!(states.selected, 0);
2✔
406
        assert_eq!(states.choices.len(), 0);
2✔
407
        assert_eq!(states.tab_open, false);
2✔
408
        let choices: &[String] = &[
2✔
409
            "lemon".to_string(),
2✔
410
            "strawberry".to_string(),
2✔
411
            "vanilla".to_string(),
2✔
412
            "chocolate".to_string(),
2✔
413
        ];
2✔
414
        states.set_choices(choices);
2✔
415
        assert_eq!(states.selected, 0);
2✔
416
        assert_eq!(states.choices.len(), 4);
2✔
417
        // Move
418
        states.prev_choice(false);
2✔
419
        assert_eq!(states.selected, 0);
2✔
420
        states.next_choice(false);
2✔
421
        // Tab is closed!!!
1✔
422
        assert_eq!(states.selected, 0);
2✔
423
        states.open_tab();
2✔
424
        assert_eq!(states.is_tab_open(), true);
2✔
425
        // Now we can move
426
        states.next_choice(false);
2✔
427
        assert_eq!(states.selected, 1);
2✔
428
        states.next_choice(false);
2✔
429
        assert_eq!(states.selected, 2);
2✔
430
        // Forward overflow
431
        states.next_choice(false);
2✔
432
        states.next_choice(false);
2✔
433
        assert_eq!(states.selected, 3);
2✔
434
        states.prev_choice(false);
2✔
435
        assert_eq!(states.selected, 2);
2✔
436
        // Close tab
437
        states.close_tab();
2✔
438
        assert_eq!(states.is_tab_open(), false);
2✔
439
        states.prev_choice(false);
2✔
440
        assert_eq!(states.selected, 2);
2✔
441
        // Update
442
        let choices: &[String] = &["lemon".to_string(), "strawberry".to_string()];
2✔
443
        states.set_choices(choices);
2✔
444
        assert_eq!(states.selected, 1); // Move to first index available
2✔
445
        assert_eq!(states.choices.len(), 2);
2✔
446
        let choices = vec![];
2✔
447
        states.set_choices(choices);
2✔
448
        assert_eq!(states.selected, 0); // Move to first index available
2✔
449
        assert_eq!(states.choices.len(), 0);
2✔
450
        // Rewind
451
        let choices: &[String] = &[
2✔
452
            "lemon".to_string(),
2✔
453
            "strawberry".to_string(),
2✔
454
            "vanilla".to_string(),
2✔
455
            "chocolate".to_string(),
2✔
456
        ];
2✔
457
        states.set_choices(choices);
2✔
458
        states.open_tab();
2✔
459
        assert_eq!(states.selected, 0);
2✔
460
        states.prev_choice(true);
2✔
461
        assert_eq!(states.selected, 3);
2✔
462
        states.next_choice(true);
2✔
463
        assert_eq!(states.selected, 0);
2✔
464
        states.next_choice(true);
2✔
465
        assert_eq!(states.selected, 1);
2✔
466
        states.prev_choice(true);
2✔
467
        assert_eq!(states.selected, 0);
2✔
468
        // Cancel tab
469
        states.close_tab();
2✔
470
        states.select(2);
2✔
471
        states.open_tab();
2✔
472
        states.prev_choice(true);
2✔
473
        states.prev_choice(true);
2✔
474
        assert_eq!(states.selected, 0);
2✔
475
        states.cancel_tab();
2✔
476
        assert_eq!(states.selected, 2);
2✔
477
        assert_eq!(states.is_tab_open(), false);
2✔
478
    }
2✔
479

480
    #[test]
481
    fn test_components_select() {
2✔
482
        // Make component
1✔
483
        let mut component = Select::default()
2✔
484
            .foreground(Color::Red)
2✔
485
            .background(Color::Black)
2✔
486
            .borders(Borders::default())
2✔
487
            .highlighted_color(Color::Red)
2✔
488
            .highlighted_str(">>")
2✔
489
            .title(
2✔
490
                Title::from("C'est oui ou bien c'est non?").alignment(HorizontalAlignment::Center),
2✔
491
            )
1✔
492
            .choices(["Oui!", "Non", "Peut-ĂȘtre"])
2✔
493
            .value(1)
2✔
494
            .rewind(false);
2✔
495
        assert_eq!(component.states.is_tab_open(), false);
2✔
496
        component.states.open_tab();
2✔
497
        assert_eq!(component.states.is_tab_open(), true);
2✔
498
        component.states.close_tab();
2✔
499
        assert_eq!(component.states.is_tab_open(), false);
2✔
500
        // Update
501
        component.attr(
2✔
502
            Attribute::Value,
2✔
503
            AttrValue::Payload(PropPayload::Single(PropValue::Usize(2))),
2✔
504
        );
1✔
505
        // Get value
1✔
506
        assert_eq!(component.state(), State::Single(StateValue::Usize(2)));
2✔
507
        // Open tab
508
        component.states.open_tab();
2✔
509
        // Events
1✔
510
        // Move cursor
1✔
511
        assert_eq!(
2✔
512
            component.perform(Cmd::Move(Direction::Up)),
2✔
513
            CmdResult::Changed(State::Single(StateValue::Usize(1))),
1✔
514
        );
1✔
515
        assert_eq!(
2✔
516
            component.perform(Cmd::Move(Direction::Up)),
2✔
517
            CmdResult::Changed(State::Single(StateValue::Usize(0))),
1✔
518
        );
1✔
519
        // Upper boundary
520
        assert_eq!(
2✔
521
            component.perform(Cmd::Move(Direction::Up)),
2✔
522
            CmdResult::Changed(State::Single(StateValue::Usize(0))),
1✔
523
        );
1✔
524
        // Move down
525
        assert_eq!(
2✔
526
            component.perform(Cmd::Move(Direction::Down)),
2✔
527
            CmdResult::Changed(State::Single(StateValue::Usize(1))),
1✔
528
        );
1✔
529
        assert_eq!(
2✔
530
            component.perform(Cmd::Move(Direction::Down)),
2✔
531
            CmdResult::Changed(State::Single(StateValue::Usize(2))),
1✔
532
        );
1✔
533
        // Lower boundary
534
        assert_eq!(
2✔
535
            component.perform(Cmd::Move(Direction::Down)),
2✔
536
            CmdResult::Changed(State::Single(StateValue::Usize(2))),
1✔
537
        );
1✔
538
        // Press enter
539
        assert_eq!(
2✔
540
            component.perform(Cmd::Submit),
2✔
541
            CmdResult::Submit(State::Single(StateValue::Usize(2))),
1✔
542
        );
1✔
543
        // Tab should be closed
544
        assert_eq!(component.states.is_tab_open(), false);
2✔
545
        // Re open
546
        assert_eq!(component.perform(Cmd::Submit), CmdResult::None);
2✔
547
        assert_eq!(component.states.is_tab_open(), true);
2✔
548
        // Move arrows
549
        assert_eq!(
2✔
550
            component.perform(Cmd::Submit),
2✔
551
            CmdResult::Submit(State::Single(StateValue::Usize(2))),
1✔
552
        );
1✔
553
        assert_eq!(component.states.is_tab_open(), false);
2✔
554
        assert_eq!(
2✔
555
            component.perform(Cmd::Move(Direction::Down)),
2✔
556
            CmdResult::None
1✔
557
        );
1✔
558
        assert_eq!(component.perform(Cmd::Move(Direction::Up)), CmdResult::None);
2✔
559
    }
2✔
560

561
    #[test]
562
    fn various_set_choice_types() {
2✔
563
        // static array of strings
1✔
564
        SelectStates::default().set_choices(&["hello".to_string()]);
2✔
565
        // vector of strings
1✔
566
        SelectStates::default().set_choices(vec!["hello".to_string()]);
2✔
567
        // boxed array of strings
1✔
568
        SelectStates::default().set_choices(vec!["hello".to_string()].into_boxed_slice());
2✔
569
    }
2✔
570

571
    #[test]
572
    fn various_choice_types() {
2✔
573
        // static array of static strings
1✔
574
        let _ = Select::default().choices(["hello"]);
2✔
575
        // static array of strings
1✔
576
        let _ = Select::default().choices(["hello".to_string()]);
2✔
577
        // vec of static strings
1✔
578
        let _ = Select::default().choices(vec!["hello"]);
2✔
579
        // vec of strings
1✔
580
        let _ = Select::default().choices(vec!["hello".to_string()]);
2✔
581
        // boxed array of static strings
1✔
582
        let _ = Select::default().choices(vec!["hello"].into_boxed_slice());
2✔
583
        // boxed array of strings
1✔
584
        let _ = Select::default().choices(vec!["hello".to_string()].into_boxed_slice());
2✔
585
    }
2✔
586
}
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