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