Skip to main content

fslite_command/
help.rs

1//! Per-verb documentation metadata for the `fslite help` command.
2//!
3//! Each [`VerbHelp`] entry carries the verb's canonical name, a one-line
4//! summary, and the list of `--flag` names the parser accepts for that
5//! verb (mirroring [`parse`](crate::parser::parse) at
6//! `crates/fslite-command/src/parser.rs:177`, where every verb dispatches
7//! with `args.check_known_flags(verb, &[flags])`). The renderer uses this
8//! to avoid listing flags the verb does not accept.
9//!
10//! This list is the single source of truth for the `fslite help` output
11//! and for the `reference/cli-verbs.md` page in the docs site. When a
12//! verb gains or loses a flag in the parser, update the matching entry
13//! here in the same commit.
14
15/// Documentation metadata for one CLI verb.
16pub struct VerbHelp {
17    /// The canonical verb name as spelled on the command line
18    /// (e.g. `"write-at"`, `"trash-ls"`).
19    pub name: &'static str,
20    /// A single-line summary shown in `fslite help` and as the lead line
21    /// of `fslite help <verb>`.
22    pub summary: &'static str,
23    /// The list of `--flag` names this verb accepts. Empty for verbs that
24    /// take only positional arguments.
25    pub flags: &'static [&'static str],
26}
27
28/// The full per-verb metadata table. Order is canonical: alphabetical by
29/// `name`. The total count matches the number of variant arms in
30/// [`parse`](crate::parser::parse) — 28 verbs.
31pub const VERB_HELP: &[VerbHelp] = &[
32    VerbHelp {
33        name: "append",
34        summary: "Append bytes to a regular file (creates if missing).",
35        flags: &["text", "expected-revision"],
36    },
37    VerbHelp {
38        name: "batch",
39        summary: "Atomically execute a list of metadata operations from a file or stdin.",
40        flags: &["file"],
41    },
42    VerbHelp {
43        name: "cat",
44        summary: "Stream a regular file's contents to stdout.",
45        flags: &["range", "no-follow"],
46    },
47    VerbHelp {
48        name: "changes",
49        summary: "Stream the workspace change feed (cursor-paginated).",
50        flags: &["after", "cursor", "limit"],
51    },
52    VerbHelp {
53        name: "cp",
54        summary: "Copy a node within the workspace.",
55        flags: &["recursive", "overwrite", "expected-revision"],
56    },
57    VerbHelp {
58        name: "exists",
59        summary: "Test whether a path resolves to a visible node (exit 0 if yes).",
60        flags: &["no-follow"],
61    },
62    VerbHelp {
63        name: "find",
64        summary: "Match nodes by bounded metadata predicates (kind, size, mtime, name).",
65        flags: &[
66            "name-contains",
67            "kind",
68            "min-size",
69            "max-size",
70            "modified-after",
71            "modified-before",
72            "cursor",
73            "limit",
74        ],
75    },
76    VerbHelp {
77        name: "glob",
78        summary: "Match absolute paths by shape (e.g. `/logs/*.txt`).",
79        flags: &["cursor", "limit"],
80    },
81    VerbHelp {
82        name: "grep",
83        summary: "Literal byte matches inside regular files (returns matched ranges).",
84        flags: &["cursor", "limit"],
85    },
86    VerbHelp {
87        name: "ln",
88        summary: "Create a symbolic link.",
89        flags: &["parents", "exist-ok", "expected-revision"],
90    },
91    VerbHelp {
92        name: "ls",
93        summary: "List one directory's direct children (cursor-paginated).",
94        flags: &["cursor", "limit"],
95    },
96    VerbHelp {
97        name: "mkdir",
98        summary: "Create a directory.",
99        flags: &["parents", "exist-ok", "expected-revision"],
100    },
101    VerbHelp {
102        name: "mv",
103        summary: "Move a node within the workspace.",
104        flags: &["overwrite", "expected-revision"],
105    },
106    VerbHelp {
107        name: "purge",
108        summary: "Permanently delete a trashed node.",
109        flags: &[],
110    },
111    VerbHelp {
112        name: "readlink",
113        summary: "Print a symbolic link's stored target.",
114        flags: &[],
115    },
116    VerbHelp {
117        name: "restore",
118        summary: "Restore a trashed node (optionally to a different path).",
119        flags: &["to", "expected-revision"],
120    },
121    VerbHelp {
122        name: "rm",
123        summary: "Permanently remove a node and (recursively) its subtree.",
124        flags: &["recursive", "expected-revision"],
125    },
126    VerbHelp {
127        name: "rmattr",
128        summary: "Remove a custom attribute from a node.",
129        flags: &["expected-revision"],
130    },
131    VerbHelp {
132        name: "setattr",
133        summary: "Set an opaque custom attribute on a node.",
134        flags: &["value", "expected-revision"],
135    },
136    VerbHelp {
137        name: "stat",
138        summary: "Print metadata for one path.",
139        flags: &["no-follow"],
140    },
141    VerbHelp {
142        name: "touch",
143        summary: "Update timestamps or create an empty regular file.",
144        flags: &["no-create", "expected-revision"],
145    },
146    VerbHelp {
147        name: "trash",
148        summary: "Move a node into recoverable trash.",
149        flags: &["expected-revision"],
150    },
151    VerbHelp {
152        name: "trash-ls",
153        summary: "List recoverable trash records (cursor-paginated).",
154        flags: &["cursor", "limit"],
155    },
156    VerbHelp {
157        name: "tree",
158        summary: "Recursively enumerate a subtree (cursor-paginated).",
159        flags: &["max-depth", "follow-symlinks", "cursor", "limit"],
160    },
161    VerbHelp {
162        name: "truncate",
163        summary: "Set a regular file's logical length.",
164        flags: &["length", "expected-revision"],
165    },
166    VerbHelp {
167        name: "usage",
168        summary: "Print workspace byte/node usage and quota limits.",
169        flags: &[],
170    },
171    VerbHelp {
172        name: "write",
173        summary: "Replace a regular file's contents (creates by default).",
174        flags: &["text", "no-create", "expected-revision"],
175    },
176    VerbHelp {
177        name: "write-at",
178        summary: "Write bytes beginning at a logical offset.",
179        flags: &["offset", "text", "no-create", "expected-revision"],
180    },
181];
182
183/// Print the full verb table to stdout, sorted alphabetically by name.
184/// Each line is two-space-indented `<name>  <summary>` with names left-
185/// padded to the widest name.
186pub fn print_verb_table() {
187    let mut entries: Vec<&VerbHelp> = VERB_HELP.iter().collect();
188    entries.sort_by_key(|e| e.name);
189    let name_width = entries.iter().map(|e| e.name.len()).max().unwrap_or(0);
190    for entry in entries {
191        println!(
192            "  {:<width$}  {}",
193            entry.name,
194            entry.summary,
195            width = name_width,
196        );
197    }
198}
199
200/// Print one verb's help to stdout: summary line, blank line, then either
201/// `(none)` for verbs without flags or one `--flag` per line under a
202/// `Flags:` header.
203///
204/// Returns the verb's [`VerbHelp`] if found, or `None` if no entry exists
205/// (so the caller can print a distinct "unknown verb" message and choose
206/// its exit code).
207pub fn print_verb_help(verb: &str) -> Option<&'static VerbHelp> {
208    let entry = VERB_HELP.iter().find(|e| e.name == verb)?;
209    println!("{}", entry.summary);
210    println!();
211    println!("Flags:");
212    if entry.flags.is_empty() {
213        println!("  (none)");
214    } else {
215        for flag in entry.flags {
216            println!("  --{flag}");
217        }
218    }
219    Some(entry)
220}