chkc_help/
doc_registry.rs

1//! stash extra text for commands and guides keyed by their full path.
2//!
3//! keys use dot separators for subcommands (e.g. `"git.commit.amend"`). an empty key means "the
4//! program itself".
5
6use std::collections::HashMap;
7
8/// extra help metadata layered on top of clap output.
9#[derive(Debug, Clone)]
10pub struct CommandDoc {
11    /// short blurb shown under the header.
12    pub description: Option<String>,
13
14    /// sample invocations printed as a numbered list.
15    pub examples: Vec<String>,
16
17    /// quick tips / caveats shown as bullets.
18    pub notes: Vec<String>,
19}
20
21impl CommandDoc {
22    /// convenience constructor; empty descriptions are treated as `None`.
23    pub fn new<D, E, N>(description: D, examples: E, notes: N) -> Self
24    where
25        D: Into<String>,
26        E: IntoIterator,
27        E::Item: Into<String>,
28        N: IntoIterator,
29        N::Item: Into<String>,
30    {
31        Self {
32            description: Some(description.into()).filter(|s| !s.is_empty()),
33            examples: examples.into_iter().map(Into::into).collect(),
34            notes: notes.into_iter().map(Into::into).collect(),
35        }
36    }
37}
38
39/// holds every command doc and guide for the current program session.
40#[derive(Default)]
41pub struct DocRegistry {
42    commands: HashMap<String, CommandDoc>,
43    guides: HashMap<String, String>,
44}
45
46impl DocRegistry {
47    /// start fresh.
48    pub fn new() -> Self {
49        Self::default()
50    }
51
52    /// attach metadata to a command path (dot-separated, `""` for the main program).
53    pub fn register_command<K: Into<String>>(&mut self, key: K, doc: CommandDoc) {
54        self.commands.insert(key.into(), doc);
55    }
56
57    /// add a free-form markdown guide that can be opened via `guide <path>`.
58    pub fn register_guide<K, C>(&mut self, key: K, content: C)
59    where
60        K: Into<String>,
61        C: Into<String>,
62    {
63        self.guides.insert(key.into(), content.into());
64    }
65
66    /// fetch docs for a command, if any.
67    pub fn command(&self, key: &str) -> Option<&CommandDoc> {
68        self.commands.get(key)
69    }
70
71    /// fetch markdown for a guide, if any.
72    pub fn guide(&self, key: &str) -> Option<&str> {
73        self.guides.get(key).map(|s| s.as_str())
74    }
75}