Skip to main content

tome/commands/
help.rs

1use super::super::directory::scan_directory;
2use super::super::finder::{self, FindResult};
3use super::super::script::Script;
4use super::builtins::BUILTIN_COMMANDS;
5use std::path::PathBuf;
6
7macro_rules! help_template {
8    () => {
9        r#"echo -e
10'This is an instance of tome, running against the directory {}.
11\nThe commands are namespaced by the directory structure.
12\n
13\n{}commands available are:
14\n    {}
15\n
16\nBuiltin commands available to all instance of tome are:
17\n    {}
18';"#
19    };
20}
21
22pub fn help(root: &str, args: &[String]) -> Result<String, String> {
23    if args.is_empty() {
24        return help_all(root, "Full list of ");
25    }
26    match finder::find_script(root, args) {
27        Ok(FindResult::File(invocation)) => {
28            let script = Script::load(invocation.target.to_str().unwrap_or_default())
29                .map_err(|e| echo_error(&format!("IOError loading file: {:?}", e)))?;
30            Ok(help_for_script(&invocation.target, &script))
31        }
32        Ok(FindResult::Directory(path)) => {
33            let dir_str = path.to_str().unwrap_or_default();
34            let scope_label = args.join(" ");
35            help_all_in_dir(root, dir_str, &format!("The list of {} ", scope_label))
36        }
37        Err(err) => Ok(echo_error(&err)),
38    }
39}
40
41fn echo_error(msg: &str) -> String {
42    format!("echo '{}' >&2", escape_slashes(msg))
43}
44
45fn help_for_script(path: &PathBuf, script: &Script) -> String {
46    let name = path
47        .file_name()
48        .and_then(|n| n.to_str())
49        .unwrap_or_default();
50    let summary = escape_slashes(&script.summary_string);
51    let help = escape_slashes(&script.help_string);
52    format!(
53        "echo -e\n'{}: {}\n{}';",
54        escape_slashes(name),
55        summary,
56        help
57    )
58}
59
60fn help_all(root: &str, label: &str) -> Result<String, String> {
61    help_all_in_dir(root, root, label)
62}
63
64fn help_all_in_dir(root: &str, dir: &str, list_label: &str) -> Result<String, String> {
65    let builtins_with_help: Vec<_> = BUILTIN_COMMANDS
66        .iter()
67        .map(|(command, command_struct)| {
68            format!(
69                "    {}: {}",
70                escape_slashes(command),
71                escape_slashes(command_struct.help_text),
72            )
73        })
74        .collect();
75
76    let ignorer = super::super::directory::TomeIgnorer::new(std::path::Path::new(root));
77    let commands_and_scripts =
78        scan_directory(dir, &mut vec![], &ignorer).map_err(|e| echo_error(&format!("{}", e)))?;
79    let commands_with_help: Vec<_> = commands_and_scripts
80        .iter()
81        .map(|(command, script)| {
82            format!(
83                "    {}: {}",
84                escape_slashes(command),
85                escape_slashes(&script.summary_string)
86            )
87        })
88        .collect();
89
90    Ok(format!(
91        help_template!(),
92        root,
93        list_label,
94        commands_with_help.join("\\n"),
95        builtins_with_help.join("\\n"),
96    ))
97}
98
99fn escape_slashes(s: &str) -> String {
100    s.replace('\'', "'\\''")
101}