Skip to main content

terminal_magic/
prompts.rs

1use async_std::task;
2use indexmap::IndexMap;
3use mustache::MapBuilder;
4use prompts::{confirm::ConfirmPrompt, Prompt, text::TextPrompt};
5
6use crate::models::EntryType;
7
8// Copyright (c) 2022 Patrick Amrein <amrein@ubique.ch>
9// 
10// This software is released under the MIT License.
11// https://opensource.org/licenses/MIT
12
13
14pub fn boolean_prompt(prompt_string: &str) -> bool {
15    let mut prompt = ConfirmPrompt::new(prompt_string);
16    match task::block_on(async { prompt.run().await }) {
17        Ok(Some(val)) => val,
18        _ => std::process::exit(1),
19    }
20}
21pub fn text_prompt(prompt_string: &str) -> Option<String> {
22    let mut prompt = TextPrompt::new(prompt_string);
23    match task::block_on(async { prompt.run().await }) {
24        Ok(val) => val,
25        _ => None,
26    }
27}
28pub fn password_prompt(prompt_string: &str) -> Option<String> {
29    let mut prompt = TextPrompt::new(prompt_string).with_style(prompts::text::Style::Password);
30    match task::block_on(async { prompt.run().await }) {
31        Ok(val) => val,
32        _ => None,
33    }
34}
35
36
37pub fn read(key: &str, entry_type: &EntryType, map_builder: MapBuilder) -> (MapBuilder, EntryType) {
38    match entry_type {
39        EntryType::Value(str) => (map_builder, read_value(key, str)),
40        EntryType::Array(array) => read_array(key, &array[0], map_builder),
41        EntryType::Object(obj) => read_object(obj, map_builder),
42    }
43}
44
45pub fn read_value(key: &str, str: &str) -> EntryType {
46    let mut prompt = TextPrompt::new(format!("{} [{}]? ", key, str));
47    match task::block_on(async { prompt.run().await }) {
48        Ok(Some(s)) => {
49            if !s.is_empty() {
50                EntryType::Value(shellexpand::tilde(&s).to_string())
51            } else {
52                EntryType::Value(shellexpand::tilde(&str).to_string())
53            }
54        }
55        _ => std::process::exit(1),
56    }
57}
58
59pub fn get_short_names(array: &[EntryType]) -> String {
60    let mut short_names: Vec<String> = vec![];
61    for entry in array {
62        if let EntryType::Object(obj) = entry {
63            if obj.contains_key("shortName") {
64                if let Some(EntryType::Value(short_name)) = obj.get("shortName") {
65                    short_names.push(short_name.clone());
66                }
67            }
68        }
69    }
70    short_names.join(" ")
71}
72
73pub fn read_array(
74    key: &str,
75    proto_type: &EntryType,
76    mut map_builder: MapBuilder,
77) -> (MapBuilder, EntryType) {
78    let mut new_array = vec![];
79    loop {
80        let object = proto_type.clone();
81        let (new_map_builder, object_to_insert) = read(key, &object, map_builder);
82        map_builder = new_map_builder;
83        new_array.push(object_to_insert);
84        let mut prompt = ConfirmPrompt::new("Another one? ");
85        match task::block_on(async { prompt.run().await }) {
86            Ok(Some(true)) => continue,
87            _ => break,
88        }
89    }
90    let name = get_short_names(&new_array);
91    map_builder = map_builder.insert_str(format!("{}_shortNames", key), name);
92    (map_builder, EntryType::Array(new_array))
93}
94
95pub fn read_object(
96    obj: &IndexMap<String, EntryType>,
97    mut map_builder: MapBuilder,
98) -> (MapBuilder, EntryType) {
99    let mut new_obj = IndexMap::new();
100    for keys in obj.iter() {
101        let (new_map_builder, object) = read(keys.0, keys.1, map_builder);
102        map_builder = new_map_builder;
103        new_obj.insert(keys.0.to_string(), object);
104    }
105    (map_builder, EntryType::Object(new_obj))
106}