use clap::ArgMatches;
use clap::Command;
use ratatui::text::Line;
pub trait CommanderCommand
{
fn is<S>(
&self,
prefix: S,
) -> bool
where
S: AsRef<str>;
fn is_filtered_by<S>(
&self,
prefix: S,
) -> bool
where
S: AsRef<str>;
fn wrapped_description(
&self,
width: usize,
) -> Vec<Line>;
}
impl CommanderCommand for Command
{
fn is<S>(
&self,
prefix: S,
) -> bool
where
S: AsRef<str>,
{
let inner = move |prefix: &str| {
let cond1 = self
.get_name()
.eq(prefix);
let mut cond2 = false;
for alias in self.get_all_aliases()
{
if alias.eq(prefix)
{
cond2 = true;
}
}
cond1 || cond2
};
inner(prefix.as_ref())
}
fn is_filtered_by<S>(
&self,
prefix: S,
) -> bool
where
S: AsRef<str>,
{
let inner = move |prefix: &str| {
let cond1 = self
.get_name()
.starts_with(prefix);
let mut cond2 = false;
for alias in self.get_all_aliases()
{
if alias.starts_with(prefix)
{
cond2 = true;
}
}
cond1 || cond2
};
inner(prefix.as_ref())
}
fn wrapped_description(
&self,
width: usize,
) -> Vec<Line>
{
let about = self
.get_long_about()
.or(self.get_about())
.unwrap_or_default();
let description = if self
.get_all_aliases()
.count()
== 0
{
about.to_string()
}
else
{
format!(
"{about}\n\nAliases: {}",
self.get_all_aliases()
.collect::<Vec<_>>()
.join(", ")
)
};
let wrapped = textwrap::wrap(
&description,
width,
)
.iter()
.map(|s| Line::raw(s.to_string()))
.collect::<Vec<_>>();
wrapped
}
}
pub(crate) fn get_current_subcommands(
filter: String,
filtered: bool,
command: &Command,
matches: ArgMatches,
) -> Vec<&Command>
{
let Some((name, submatches)) = matches.subcommand()
else
{
let options = command
.get_subcommands()
.filter(
|c| {
if filtered
{
c.is_filtered_by(&filter)
}
else
{
true
}
},
)
.collect::<Vec<_>>();
return options;
};
let Some(subcommand) = command
.get_subcommands()
.find(|c| c.is(name))
else
{
return command
.get_subcommands()
.collect::<Vec<_>>();
};
get_current_subcommands(
filter,
filtered,
subcommand,
submatches.to_owned(),
)
}
pub(crate) fn get_current_command(
filter: String,
filtered: bool,
command: &Command,
matches: ArgMatches,
) -> Option<&Command>
{
let Some((name, submatches)) = matches.subcommand()
else
{
if filtered
{
let mut available = command
.get_subcommands()
.filter(|c| c.is_filtered_by(&filter))
.collect::<Vec<_>>();
if available.is_empty()
{
return None;
}
else if available.len() == 1
{
return available.pop();
}
else
{
return Some(command);
}
}
else
{
return Some(command);
}
};
let Some(subcommand) = command
.get_subcommands()
.find(|c| c.is(name))
else
{
return None;
};
get_current_command(
filter,
filtered,
subcommand,
submatches.to_owned(),
)
}
pub(crate) fn get_arg_matches(
command: &Command,
items: &mut Vec<String>,
filtered: bool,
) -> Option<(
ArgMatches,
bool,
)>
{
let matches = match command
.clone()
.try_get_matches_from(items.iter())
{
Ok(value) => value,
Err(_) =>
{
if items.len() == 1
{
return None;
}
else
{
items.pop();
return get_arg_matches(
command, items, true,
);
}
}
};
Some((
matches, filtered,
))
}