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}