cliclack_yaml/steps/
multi_select.rs1use std::collections::HashMap;
2use anyhow::Result;
3use serde::{Deserialize, Serialize};
4use crate::{PromptStepType, replace_variables};
5
6#[derive(Debug, Deserialize, Serialize, Clone)]
7pub struct MultiSelectItem {
8 pub value: String,
9 pub label: String,
10 pub hint: Option<String>,
11}
12
13#[derive(Debug, Deserialize, Serialize, Clone)]
14#[serde(untagged)]
15pub enum MultiSelectItems {
16 Static(Vec<MultiSelectItem>),
17 Variable(String),
18}
19
20pub fn handle_multi_select(
22 step_type: &PromptStepType,
23 context: &mut HashMap<String, String>,
24 last_input: &mut Option<String>
25) -> Result<()> {
26 if let PromptStepType::MultiSelect { prompt, items, output, required } = step_type {
27 let mut multiselect_builder = cliclack::multiselect(prompt);
28
29 let resolved_items = match items {
31 MultiSelectItems::Static(static_items) => static_items.clone(),
32 MultiSelectItems::Variable(variable_ref) => {
33 let resolved_var = replace_variables(variable_ref, context, last_input);
35
36 if let Ok(items) = serde_json::from_str::<Vec<MultiSelectItem>>(&resolved_var) {
39 items
40 } else if let Ok(config_map) = serde_json::from_str::<HashMap<String, String>>(&resolved_var) {
41 config_map.into_iter().map(|(key, value)| {
43 let hint = if value.len() > 50 {
44 format!("{}...", &value[..47])
45 } else {
46 value
47 };
48 MultiSelectItem {
49 value: key.clone(),
50 label: key,
51 hint: Some(hint),
52 }
53 }).collect()
54 } else {
55 Vec::new()
56 }
57 }
58 };
59
60 if resolved_items.is_empty() {
62 return Err(anyhow::anyhow!("No items available for multiselect"));
63 }
64
65 for item in &resolved_items {
66 let hint = item.hint.as_deref().unwrap_or("");
67 multiselect_builder = multiselect_builder.item(&item.value, &item.label, hint);
68 }
69
70 if let Some(is_required) = required {
72 if *is_required {
73 multiselect_builder = multiselect_builder.required(true);
74 }
75 }
76
77 let selected_values: Vec<String> = multiselect_builder.interact()?.iter().map(|s| s.to_string()).collect();
78
79 if let Some(output_key) = output {
81 let combined_values = selected_values.join(",");
83 context.insert(output_key.clone(), combined_values);
84
85 for (index, value) in selected_values.iter().enumerate() {
87 context.insert(format!("{}_{}", output_key, index), value.clone());
88 }
89
90 context.insert(format!("{}_count", output_key), selected_values.len().to_string());
92 }
93 }
94 Ok(())
95}