Add select prompt

pull/1/head
trivernis 1 year ago
parent 215c235f4b
commit 9cf4d225d7
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

20
Cargo.lock generated

@ -307,6 +307,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87"
dependencies = [
"console",
"fuzzy-matcher",
"shell-words",
"tempfile",
"zeroize",
@ -394,6 +395,15 @@ dependencies = [
"instant",
]
[[package]]
name = "fuzzy-matcher"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94"
dependencies = [
"thread_local",
]
[[package]]
name = "getrandom"
version = "0.2.9"
@ -1266,6 +1276,16 @@ dependencies = [
"syn 2.0.13",
]
[[package]]
name = "thread_local"
version = "1.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152"
dependencies = [
"cfg-if",
"once_cell",
]
[[package]]
name = "time"
version = "0.1.45"

@ -11,6 +11,6 @@ name = "nu_plugin_dialog"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
dialoguer = "0.10.4"
dialoguer = { version = "0.10.4", features = ["fuzzy-select", "completion"] }
nu-plugin = "0.78.0"
nu-protocol = "0.78.0"

@ -1,7 +1,7 @@
use nu_plugin::{EvaluatedCall, LabeledError};
use nu_protocol::Value;
use crate::DialogPlugin;
use crate::{prompt::UserPrompt, DialogPlugin};
impl DialogPlugin {
pub(crate) fn confirm(
@ -18,11 +18,7 @@ impl DialogPlugin {
if let Some(val) = default_val {
confirm.default(val);
}
let result = confirm.interact().map_err(|e| LabeledError {
label: "Failed to prompt user".into(),
msg: e.to_string(),
span: Some(call.head),
})?;
let result = confirm.prompt()?;
Ok(Value::Bool {
val: result,

@ -3,6 +3,8 @@ use nu_plugin::{LabeledError, Plugin};
use nu_protocol::{PluginSignature, SyntaxShape};
mod confirm;
mod prompt;
mod select;
pub struct DialogPlugin {
pub(crate) theme: Box<dyn Theme>,
@ -38,6 +40,26 @@ impl Plugin for DialogPlugin {
None,
)
.category(nu_protocol::Category::Misc),
PluginSignature::build("ask select")
.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.",
)
.named(
"prompt",
SyntaxShape::String,
"An optional prompt that can be shown to the user for the selection.",
None,
)
.named(
"default",
SyntaxShape::Number,
"The default selection.",
None,
)
.category(nu_protocol::Category::Misc),
]
}
@ -49,6 +71,7 @@ impl Plugin for DialogPlugin {
) -> Result<nu_protocol::Value, nu_plugin::LabeledError> {
match name {
"ask confirm" => self.confirm(call, input),
"ask select" => self.select(call, input),
"ask" =>
Err(LabeledError {
label: "Missing subcommand".into(),

@ -0,0 +1,69 @@
use dialoguer::{theme::Theme, FuzzySelect, Select};
use super::{create_labeled_error, UserPrompt};
pub enum GenericSelect<'a> {
Fuzzy(FuzzySelect<'a>),
Normal(Select<'a>),
}
impl<'a> GenericSelect<'a> {
pub fn fuzzy(theme: &'a dyn Theme) -> Self {
Self::Fuzzy(FuzzySelect::with_theme(theme))
}
pub fn normal(theme: &'a dyn Theme) -> Self {
Self::Normal(Select::with_theme(theme))
}
pub fn items<T: ToString>(&mut self, items: &[T]) -> &mut Self {
match self {
GenericSelect::Fuzzy(f) => f.items(items).nop(),
GenericSelect::Normal(n) => n.items(items).nop(),
}
self
}
pub fn default(&mut self, val: usize) -> &mut Self {
match self {
GenericSelect::Fuzzy(f) => f.default(val).nop(),
GenericSelect::Normal(n) => n.default(val).nop(),
}
self
}
pub fn with_prompt<S: Into<String>>(&mut self, prompt: S) -> &mut Self {
match self {
GenericSelect::Fuzzy(f) => f.with_prompt(prompt).nop(),
GenericSelect::Normal(n) => n.with_prompt(prompt).nop(),
}
self
}
}
impl<'a> UserPrompt for GenericSelect<'a> {
type Output = usize;
fn prompt(&self) -> Result<Self::Output, nu_plugin::LabeledError> {
match self {
GenericSelect::Fuzzy(f) => f.interact(),
GenericSelect::Normal(n) => n.interact(),
}
.map_err(create_labeled_error)
}
fn prompt_opt(&self) -> Result<Option<Self::Output>, nu_plugin::LabeledError> {
match self {
GenericSelect::Fuzzy(f) => f.interact_opt(),
GenericSelect::Normal(n) => n.interact_opt(),
}
.map_err(create_labeled_error)
}
}
trait Nop {
fn nop(&mut self) {}
}
impl<'a> Nop for Select<'a> {}
impl<'a> Nop for FuzzySelect<'a> {}

@ -0,0 +1,33 @@
use std::io;
use nu_plugin::LabeledError;
mod generic_select;
pub use generic_select::GenericSelect;
pub trait UserPrompt {
type Output;
fn prompt(&self) -> Result<Self::Output, LabeledError>;
fn prompt_opt(&self) -> Result<Option<Self::Output>, LabeledError>;
}
impl<'a> UserPrompt for dialoguer::Confirm<'a> {
type Output = bool;
fn prompt(&self) -> Result<Self::Output, LabeledError> {
self.interact().map_err(create_labeled_error)
}
fn prompt_opt(&self) -> Result<Option<Self::Output>, LabeledError> {
self.interact_opt().map_err(create_labeled_error)
}
}
fn create_labeled_error(e: io::Error) -> LabeledError {
LabeledError {
label: "Failed to prompt user".into(),
msg: e.to_string(),
span: None,
}
}

@ -0,0 +1,39 @@
use nu_plugin::{EvaluatedCall, LabeledError};
use nu_protocol::Value;
use crate::{
prompt::{GenericSelect, UserPrompt},
DialogPlugin,
};
impl DialogPlugin {
pub(crate) fn select(
&self,
call: &EvaluatedCall,
_input: &Value,
) -> Result<Value, LabeledError> {
let mut options: Vec<String> = call.req(0)?;
let mut select = if call.has_flag("fuzzy") {
GenericSelect::fuzzy(&*self.theme)
} else {
GenericSelect::normal(&*self.theme)
};
select.items(&options);
if let Some(prompt) = call.get_flag::<String>("prompt")? {
select.with_prompt(prompt);
}
if let Some(def) = call.get_flag::<usize>("default")? {
select.default(def);
}
let selection = select.prompt()?;
let selected_item = options.remove(selection);
Ok(Value::String {
val: selected_item,
span: call.head,
})
}
}
Loading…
Cancel
Save