1use std::fmt::Display;
4
5use dialoguer::{Confirm, Input, MultiSelect, Password, Select, theme::ColorfulTheme};
6use wowlab_fs::path::PathBuf;
7
8fn theme() -> ColorfulTheme {
9 ColorfulTheme::default()
10}
11
12#[must_use]
18pub fn text(label: &str, default: Option<&str>) -> String {
19 let t = theme();
20 let mut input = Input::<String>::with_theme(&t).with_prompt(label);
21
22 if let Some(d) = default {
23 input = input.default(d.to_string());
24 }
25
26 input.interact_text().expect("failed to read input")
27}
28
29#[must_use]
31pub fn path(label: &str, default: Option<&str>) -> PathBuf {
32 PathBuf::from(text(label, default))
33}
34
35#[must_use]
41pub fn confirm(label: &str, default: bool) -> bool {
42 Confirm::with_theme(&theme())
43 .with_prompt(label)
44 .default(default)
45 .interact()
46 .expect("failed to read confirmation")
47}
48
49pub fn select<T>(label: &str, items: &[T]) -> usize
55where
56 T: Display,
57{
58 Select::with_theme(&theme())
59 .with_prompt(label)
60 .items(items)
61 .default(0)
62 .interact()
63 .expect("failed to read selection")
64}
65
66pub fn multi_select<T>(label: &str, items: &[T]) -> Vec<usize>
72where
73 T: Display,
74{
75 MultiSelect::with_theme(&theme())
76 .with_prompt(label)
77 .items(items)
78 .interact()
79 .expect("failed to read multi-selection")
80}
81
82pub fn multi_select_items<T>(label: &str, items: &[T]) -> Vec<T>
84where
85 T: Display + Copy,
86{
87 let indices = multi_select(label, items);
88 indices.into_iter().map(|i| items[i]).collect()
91}
92
93#[must_use]
99pub fn password(label: &str) -> String {
100 Password::with_theme(&theme())
101 .with_prompt(label)
102 .interact()
103 .expect("failed to read password")
104}
105
106pub fn resolved(label: &str, value: &str) {
108 crate::output::kv(label, value);
109}