use std::marker::PhantomData;
use super::{BaseCommand, Command};
use crate::command_set::CommandSet;
use crate::error::ShiError;
use crate::shell::Shell;
use crate::Result;
#[derive(Debug)]
pub struct HelpTreeCommand<'a, S> {
phantom: &'a PhantomData<S>,
}
#[derive(Clone)]
struct IndentContext {
last: bool,
parent_lastness_chain: Vec<bool>,
}
impl IndentContext {
fn indent(&self, last: bool) -> Self {
let mut parent_chain_copy = self.parent_lastness_chain.to_vec();
parent_chain_copy.push(last);
IndentContext {
last,
parent_lastness_chain: parent_chain_copy,
}
}
fn with_last(&self, new_last: bool) -> Self {
IndentContext {
last: new_last,
parent_lastness_chain: self.parent_lastness_chain.to_vec(),
}
}
}
impl<'a, S> Default for HelpTreeCommand<'a, S> {
fn default() -> Self {
Self::new()
}
}
impl<'a, S> HelpTreeCommand<'a, S> {
pub fn new() -> HelpTreeCommand<'a, S> {
HelpTreeCommand {
phantom: &PhantomData,
}
}
fn add_name_to_lines(&self, ctx: &IndentContext, lines: &mut Vec<String>, name: &str) {
let mut line_elems: Vec<&str> = Vec::new();
for parent_was_last in &ctx.parent_lastness_chain {
if *parent_was_last {
line_elems.push(" ");
} else {
line_elems.push("│ ");
}
}
if ctx.last {
line_elems.push("└");
} else {
line_elems.push("├");
}
let dash_name = format!("── {}", name);
line_elems.push(&dash_name);
lines.push(line_elems.join(""))
}
fn add_tree_lines_for_children<T>(
&self,
ctx: &IndentContext,
lines: &mut Vec<String>,
cmds: &CommandSet<T>,
) {
for (i, cmd) in cmds.iter().enumerate() {
let last = i == cmds.len() - 1;
self.add_name_to_lines(&ctx.with_last(last), lines, cmd.name());
match &**cmd {
Command::Leaf(_) => continue, Command::Parent(parent_cmd) => {
self.add_tree_lines_for_children(
&ctx.indent(last),
lines,
parent_cmd.sub_commands(),
);
}
}
}
}
fn to_lines(&self, shell: &Shell<'a, S>) -> Vec<String> {
let ctx = IndentContext {
last: false,
parent_lastness_chain: Vec::new(),
};
let mut lines: Vec<String> = vec![String::from("Normal commands")];
self.add_tree_lines_for_children(&ctx.with_last(false), &mut lines, &shell.cmds.borrow());
lines.push(String::from("\n"));
lines.push(String::from("Builtins"));
self.add_tree_lines_for_children(&ctx.with_last(false), &mut lines, &shell.builtins);
lines
}
}
impl<'a, S> BaseCommand for HelpTreeCommand<'a, S> {
type State = Shell<'a, S>;
fn name(&self) -> &str {
"helptree"
}
fn validate_args(&self, args: &[String]) -> Result<()> {
if !args.is_empty() {
return Err(ShiError::ExtraArgs { got: args.to_vec() });
}
Ok(())
}
fn execute(&self, shell: &mut Shell<'a, S>, _: &[String]) -> Result<String> {
let help_lines = self.to_lines(shell);
Ok(help_lines.join("\n"))
}
fn help(&self) -> String {
String::from("Prints a tree depiction of all commands in this shell")
}
}