1use crate::handlers;
2
3pub struct CommandDoc {
4 pub name: &'static str,
5 pub kind: DocKind,
6 pub description: &'static str,
7}
8
9pub enum DocKind {
10 AlwaysSafe,
11 Handler,
12}
13
14pub fn all_command_docs() -> Vec<CommandDoc> {
15 let mut docs = safe_cmd_docs();
16 docs.extend(handlers::handler_docs());
17 docs.sort_by_key(|d| d.name);
18 docs
19}
20
21pub fn render_markdown(docs: &[CommandDoc]) -> String {
22 let mut out = String::from(
23 "# Supported Commands\n\
24 \n\
25 Auto-generated by `safe-chains --list-commands`.\n\
26 \n\
27 Any command with only `--version` or `--help` as its sole argument is always allowed.\n\
28 \n\
29 ## Unconditionally Safe\n\
30 \n\
31 These commands are allowed with any arguments.\n\
32 \n\
33 | Command | Description |\n\
34 |---------|-------------|\n",
35 );
36
37 for doc in docs.iter().filter(|d| matches!(d.kind, DocKind::AlwaysSafe)) {
38 out.push_str(&format!("| `{}` | {} |\n", doc.name, doc.description));
39 }
40
41 out.push_str("\n## Handled Commands\n\nThese commands are allowed with specific subcommands or flags.\n\n");
42
43 for doc in docs.iter().filter(|d| matches!(d.kind, DocKind::Handler)) {
44 out.push_str(&format!("### `{}`\n\n{}\n\n", doc.name, doc.description));
45 }
46
47 out
48}
49
50fn safe_cmd_docs() -> Vec<CommandDoc> {
51 handlers::SAFE_CMD_ENTRIES
52 .iter()
53 .map(|&(name, description)| CommandDoc {
54 name,
55 kind: DocKind::AlwaysSafe,
56 description,
57 })
58 .collect()
59}