Skip to main content

sva_cli/
help.rs

1// Concern: the `--help` page, each flag's default printed from its own constant | Non-concern: parsing those flags (args/), the JSON a subcommand answers (output.rs) | IO: () -> the page
2
3use sva_core::{DEFAULT_LEDGER_DEPTH, DEFAULT_MAX_PEAKS, DEFAULT_OVERSAMPLE};
4use sva_engine::{DEFAULT_FRAME_SECS, DEFAULT_SAMPLE_RATE, PSYCHOACOUSTIC_V1};
5
6/// Read off the constants the parser itself defaults to, so a printed default cannot drift
7/// from the one a render actually uses.
8pub fn help_text() -> String {
9    let budget = PSYCHOACOUSTIC_V1.flop_budget;
10    format!(
11        r#"USAGE:
12  sva-cli (render | analyze | lint | trace | builtins | new) [arguments]
13
14DESCRIPTION:
15  A composition is a directory of node files, each one closed-form expression in
16  `t` or `f`. sva-cli reads that composition and prints what it is and what it
17  sounds like, as JSON on stdout.
18
19  `--in <dir>` picks the composition for render, lint and trace, wherever in the
20  arguments it is written; without it they read the current directory. `new`
21  writes beside the current directory and `analyze` reads a file, so neither
22  takes `--in`.
23
24RENDER:
25  sva-cli render [<node|expression>] [query options]
26
27  Renders a node, `master` by default, and prints one reading per `--as`. The
28  argument may be an expression instead, in the grammar a node file's body uses.
29  Every reading states its `source` (exact or measured), the conformance profile
30  it ran under, and its rate.
31
32  `--as lines` and `--as atoms` read the closed form and allocate no buffer.
33  `--as samples=<path>.wav` writes 32-bit float audio, or 16-bit PCM under
34  `--pcm16`. Any other destination path takes the same JSON, uncapped. A path
35  that already holds a file refuses unless `--confirm` is written.
36
37  `--from`/`--to` bound the window a collapse runs over. `--sample-rate <hz>` is
38  the observation rate and is legal with every `--as`: no expression can read it.
39  `--no-cache` skips the disk store.
40
41  `--as ledger` prints one row per node under the target. A row's `share` is the
42  part of its reader's own energy that row accounts for, so one reader's refs sum
43  to 1; a ref no addend isolates, such as one factor of a product, prints `null`.
44  Each ref carrying a share is collapsed once on its own, so a ledger costs one
45  collapse per attributed ref beyond the render, and `--depth` bounds how many.
46  `--brief` keeps only the rows that clipped, `--skim` drops the wider fields.
47
48ANALYZE:
49  sva-cli analyze <file.wav> [--as <representation>[=<destination>]]...
50
51  Runs the same readings over an external `.wav` at its own rate, never
52  resampled. Only the readings a buffer answers alone apply; the rest need the
53  graph behind it.
54
55LINT:
56  sva-cli lint [<node|expression>] [--in <dir>] [--format <json|text>]
57
58  Checks binding, ref and tempo resolution without rendering a sample. With no
59  target it checks the whole directory against `master`. With a target it checks
60  only the nodes that target reaches, and `entry-point` does not run, since the
61  target's own reach references every node in it.
62
63  Every check prints one `data.diagnostics` item. `advice` and `warning` exit 0,
64  `error` exits non-zero, so branch on the verdict and never on whether the array
65  is empty. No flag downgrades an error.
66
67  error    missing-comment       no `;` comment line
68           multiline-comment     more than one
69           malformed-comment     not four ` | ` fields, `Models:` `Neglects:`
70                                 `IO: <in> -> <out>` `Tags: <tag>[, <tag>...]`
71           long-comment-block    a `;` block over 1000 characters, the line-1
72                                 doc comment's own run exempted
73           long-expression-body  a body over 10000 characters, a backstop rather
74                                 than a complexity budget
75  warning  grid-rows-per-bar     a TSV grid's row count does not divide evenly
76                                 into its filename's bar span
77           key-is-not-a-pitch    `variables/key` holds neither a note name nor
78                                 a number of hertz
79           entry-point-refused   a node a whole-directory render reaches does
80                                 not type
81  advice   entry-point           nothing references this node
82           no-default-root       the directory has no `master`
83           tag-shape             a tag over 3 lowercase words or 24 characters
84           window-inside-ramp    a window sits wholly inside a crop's shoulder
85           literal-sample-rate   a written rate where `sp` belongs
86           not-a-file            a socket, FIFO or device in the directory
87           not-a-node            a filename no `@ref` can spell
88
89TRACE:
90  sva-cli trace <node|expression> [--in <dir>]
91
92  Prints one node's position without rendering audio: what it reads (`down`, one
93  hop), everything that reads it (`up`, transitively to an entry point), each
94  beside the expression doing the reading, the node that made it discrete, and
95  the feedback loop it sits in, if any.
96
97BUILTINS:
98  sva-cli builtins
99
100  Prints the whole callable and syntactic vocabulary: every builtin with its
101  arity and named arguments, unit suffixes, the note-name grammar, reserved
102  identifiers, special call shapes, and what has no operator at all.
103
104NEW:
105  sva-cli new <name> [--idempotency-key <key>]
106
107  Writes a starter composition at ./<name>, and refuses if that directory
108  exists. `--idempotency-key <key>` records the key beside the composition, so a
109  retry under the same key succeeds identically while the tree still holds what
110  was written. Any other key, or an edited tree, refuses.
111
112EXAMPLES:
113  sva-cli new song1 && cd song1
114  cd ./song1 && sva-cli render --as samples=/tmp/song1.wav
115  sva-cli render master --in ./song1 --as ledger --as loudness
116  cd ./song1 && sva-cli render chord/home --as lines
117  sva-cli lint --in ./song1
118  cd ./song1 && sva-cli lint voice/note
119  cd ./song1 && sva-cli trace grid/phrase-2b
120  sva-cli builtins
121
122OUTPUT:
123  {{"status": "success", "data": {{"node": "master", "down": {{"items": [...]}},
124  "diagnostics": {{"items": []}}}},
125   "meta": {{"request_id": "req_...", "timestamp": 1700000000}}}}
126
127  An error adds "error": {{"code", "message", "details": {{"count", "codes"}}}}.
128  Success or error, every response carries every finding in full at
129  "data": {{"diagnostics": {{"items": [{{"code", "severity", "message",
130  "location", "help"}}], "pagination": {{"count", "has_more", "next_cursor"}}}}}},
131  empty where it found none.
132
133  Every collection carries that same {{items, pagination}} pair. `count` is the
134  whole reading's, `has_more` says `items` holds less than that, and
135  `next_cursor` is a `--from` value to pass back verbatim for the rest. A framed
136  measurement restarts its state at that instant, so a second page is a second
137  reading rather than a continuation. `--as <name>=<path>` writes the whole
138  reading to a file instead, uncapped. This page is an envelope of its own, at
139  "data": {{"help"}}.
140
141DEFAULTS:
142  --depth <n>          how deep below its target a `ledger` walks.
143                       Default {DEFAULT_LEDGER_DEPTH}.
144  --peaks <n>          peaks a `spectrum` keeps, notes a `pitch`, formants a
145                       `formants`. Default {DEFAULT_MAX_PEAKS}.
146  --oversample <n>     the multiple `alias` re-renders at to hear what folded.
147                       Default {DEFAULT_OVERSAMPLE}.
148  --frame <secs>       the step a framed reading advances by, in seconds.
149                       Default {DEFAULT_FRAME_SECS}, except `spectrum`, which
150                       sizes its own transform to the window unless this flag is
151                       given.
152  --sample-rate <hz>   the observation rate a render lays its seconds on.
153                       Default {DEFAULT_SAMPLE_RATE}.
154  --flop-budget <n>    the operation count paid before a render refuses.
155                       Default {budget}, the `psychoacoustic-v1` profile's own.
156  --format <json|text> how `lint` prints its findings: the envelope, or one
157                       terminal line each, colored where stdout is a terminal.
158                       The same objects either way. Default json.
159  --in <dir>           the composition `render`, `lint` and `trace` read.
160                       Default: the directory the process runs in.
161  --node <path>        the instance a reading is taken of. Defaults to the
162                       target itself; `--as bindings` requires it.
163  --against <file.wav> the second signal `--as masking` reads against. No
164                       default: that one analysis requires it.
165  --from <time>        default 0s; `--to <time>` defaults to the node's extent.
166  --confirm            replaces a destination that already holds a file. Without
167                       it a path already taken refuses as `conflict` and nothing
168                       is written.
169  --no-cache, --brief, --skim and --pcm16 are all off unless written.
170
171EXIT CODES:
172  0  success (error.code absent)
173  1  internal_error (a destination could not be written)
174  3  validation_error (bad arguments, or a composition that failed to parse)
175  4  conflict (a name `new` would overwrite, or a destination already holding a
176     file, without `--confirm`)
177  24 not_found (a `.wav` file, or a node this composition does not define)
178
179VERB ALIASES:
180  validate = lint, list = builtins, create = new, show = trace, from the `cli`
181  standard's own verb list. `render` and `analyze` take a reading, which that
182  list has no word for, so they keep their own names.
183
184SEE ALSO:
185  sva-cli --version    Show version information"#
186    )
187}