Add multiselect prompt

pull/1/head
trivernis 2 years ago
parent 6e1b3a0647
commit 912020072f
WARNING! Although there is a key with this ID in the database it does not verify this commit! This commit is SUSPICIOUS.
GPG Key ID: DFFFCC2C7A02DB45

@ -3,6 +3,7 @@ use nu_plugin::{LabeledError, Plugin};
use nu_protocol::{PluginSignature, SyntaxShape};
mod confirm;
mod multiselect;
mod password;
mod prompt;
mod select;
@ -64,6 +65,27 @@ impl Plugin for DialogPlugin {
None,
)
.category(nu_protocol::Category::Misc),
PluginSignature::build("ask multiselect")
.usage("Prompt the user with a selection prompt.")
.required(
"items",
SyntaxShape::List(Box::new(SyntaxShape::String)),
"The items out of which one can be selected.",
)
.switch("abortable", "If set users can abort the prompt.", None)
.named(
"prompt",
SyntaxShape::String,
"An optional prompt that can be shown to the user for the selection.",
None,
)
.named(
"default",
SyntaxShape::String,
"The default selections as a comma separated string of indices",
None,
)
.category(nu_protocol::Category::Misc),
PluginSignature::build("ask password")
.usage("Prompt the user with a password input.")
.named(
@ -95,6 +117,7 @@ impl Plugin for DialogPlugin {
match name {
"ask confirm" => self.confirm(call, input),
"ask select" => self.select(call, input),
"ask multiselect" => self.multiselect(call, input),
"ask password" => self.password(call, input),
"ask" =>
Err(LabeledError {

@ -0,0 +1,58 @@
use dialoguer::MultiSelect;
use nu_plugin::{EvaluatedCall, LabeledError};
use nu_protocol::{Span, Value};
use crate::{prompt::UserPrompt, DialogPlugin};
impl DialogPlugin {
pub(crate) fn multiselect(
&self,
call: &EvaluatedCall,
_input: &Value,
) -> Result<Value, LabeledError> {
let options: Vec<String> = call.req(0)?;
let mut select = MultiSelect::new();
select.items(&options);
if let Some(prompt) = call.get_flag::<String>("prompt")? {
select.with_prompt(prompt);
}
if let Some(def) = call.get_flag::<String>("default")? {
let defaults = def
.split(',')
.map(|v| v.trim())
.filter_map(|v| v.parse::<usize>().ok())
.collect::<Vec<_>>();
let check_states = (0..options.len())
.map(|i| defaults.contains(&i))
.collect::<Vec<_>>();
select.defaults(&check_states);
}
if call.has_flag("abortable") {
if let Some(selection) = select.ask_opt(call.head)? {
Ok(map_selection(selection, options, call.head))
} else {
Ok(Value::Nothing { span: call.head })
}
} else {
let selection = select.ask(call.head)?;
Ok(map_selection(selection, options, call.head))
}
}
}
fn map_selection(selection: Vec<usize>, options: Vec<String>, span: Span) -> Value {
let selected_items = options
.into_iter()
.enumerate()
.filter(|(i, _)| selection.contains(i))
.map(|(_, val)| Value::String { val, span })
.collect::<Vec<_>>();
Value::List {
vals: selected_items,
span,
}
}

@ -1,6 +1,6 @@
use std::io;
use dialoguer::Password;
use dialoguer::{MultiSelect, Password};
use nu_plugin::LabeledError;
mod generic_select;
pub use generic_select::GenericSelect;
@ -39,6 +39,19 @@ impl<'a> UserPrompt for Password<'a> {
}
}
impl<'a> UserPrompt for MultiSelect<'a> {
type Output = Vec<usize>;
fn ask(&self, span: Span) -> Result<Self::Output, LabeledError> {
self.interact().map_err(|e| create_labeled_error(e, span))
}
fn ask_opt(&self, span: Span) -> Result<Option<Self::Output>, LabeledError> {
self.interact_opt()
.map_err(|e| create_labeled_error(e, span))
}
}
fn create_labeled_error(e: io::Error, span: Span) -> LabeledError {
LabeledError {
label: "Failed to prompt user".into(),

Loading…
Cancel
Save