@hraness/dawg 0.6.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +118 -0
- package/DAWG.md +454 -140
- package/README.md +30 -26
- package/core/autotune.ts +1119 -0
- package/core/chords.ts +271 -23
- package/core/clips.ts +499 -0
- package/core/diff.ts +184 -104
- package/core/expression.ts +15 -0
- package/core/fx.ts +99 -29
- package/core/ids.ts +52 -0
- package/core/instruments.ts +19 -0
- package/core/keys.ts +3 -3
- package/core/loop.ts +8 -0
- package/core/lyrics.ts +297 -0
- package/core/master.ts +3 -3
- package/core/range.ts +581 -0
- package/core/resonators.ts +16 -2
- package/core/routing.ts +165 -0
- package/core/score.ts +955 -14
- package/core/sdk/eval-child.ts +7 -2
- package/core/sdk/eval.ts +35 -6
- package/core/sdk/print.ts +287 -5
- package/core/sdk/sync-lyrics.ts +49 -0
- package/core/sdk/v1.ts +2132 -46
- package/core/sections.ts +480 -35
- package/core/sing.ts +815 -0
- package/core/style-provenance.ts +80 -0
- package/core/styles/africa-mena-southasia.ts +2893 -0
- package/core/styles/americas.ts +3810 -0
- package/core/styles/art.ts +4993 -0
- package/core/styles/base.ts +123 -0
- package/core/styles/cycles.ts +106 -0
- package/core/styles/electronic.ts +2723 -0
- package/core/styles/europe-asia-pacific.ts +2838 -0
- package/core/styles/excerpt.ts +29 -0
- package/core/styles/gamelan.ts +283 -0
- package/core/styles/generate.ts +2199 -0
- package/core/styles/index.ts +515 -0
- package/core/styles/parts.ts +106 -0
- package/core/styles/pop.ts +3189 -0
- package/core/styles/rock.ts +2993 -0
- package/core/styles/roots.ts +4175 -0
- package/core/styles/schema.ts +429 -0
- package/core/styles/taxonomy.ts +940 -0
- package/core/styles/validate.ts +528 -0
- package/core/tempo.ts +32 -2
- package/core/tuning.ts +19 -3
- package/core/vocoder.ts +524 -0
- package/guides/agent.md +29 -0
- package/guides/arrange.md +31 -0
- package/guides/audio.md +31 -0
- package/guides/audition.md +20 -14
- package/guides/automation.md +12 -7
- package/guides/chords.md +15 -15
- package/guides/effects.md +17 -16
- package/guides/faders.md +20 -16
- package/guides/files.md +13 -9
- package/guides/getting-started.md +15 -11
- package/guides/keys.md +19 -15
- package/guides/media.md +17 -12
- package/guides/mix.md +15 -7
- package/guides/music.md +23 -8
- package/guides/notes.md +15 -9
- package/guides/panes.md +32 -0
- package/guides/performance.md +15 -13
- package/guides/play.md +21 -13
- package/guides/project.md +26 -8
- package/guides/providers.md +20 -14
- package/guides/resample.md +15 -9
- package/guides/rhythm.md +18 -13
- package/guides/sessions.md +17 -7
- package/guides/show-me.md +31 -0
- package/guides/sound.md +25 -9
- package/guides/sounds.md +15 -13
- package/guides/styles.md +31 -0
- package/guides/tape.md +32 -0
- package/guides/tempo.md +15 -10
- package/guides/tracks.md +15 -10
- package/guides/tuning.md +32 -0
- package/guides/voice.md +31 -0
- package/guides/web-search.md +18 -8
- package/native/prebuilt/darwin-arm64/libdawg_sink.dylib +0 -0
- package/native/prebuilt/darwin-x64/libdawg_sink.dylib +0 -0
- package/native/prebuilt/linux-arm64/libdawg_sink.so +0 -0
- package/native/prebuilt/linux-x64/libdawg_sink.so +0 -0
- package/native/prebuilt/manifest.json +21 -0
- package/package.json +6 -2
- package/src/agent/agent.ts +130 -18
- package/src/agent/calibration-tools.ts +53 -0
- package/src/agent/clip-tools.ts +453 -0
- package/src/agent/command-agent.ts +378 -0
- package/src/agent/drum-tools.ts +2 -2
- package/src/agent/expression-tools.ts +1 -1
- package/src/agent/gateway.ts +246 -60
- package/src/agent/models.ts +53 -12
- package/src/agent/ops.ts +27 -1
- package/src/agent/pack-tools.ts +1 -1
- package/src/agent/planner.ts +25 -0
- package/src/agent/portable-schema.ts +80 -0
- package/src/agent/preview-tool.ts +4 -1
- package/src/agent/provider.ts +22 -8
- package/src/agent/range-tools.ts +216 -0
- package/src/agent/rhythm-tools.ts +1 -1
- package/src/agent/section-tools.ts +1 -1
- package/src/agent/show-me.ts +497 -0
- package/src/agent/steer.ts +15 -0
- package/src/agent/style-tools.ts +217 -0
- package/src/agent/tool-error.ts +12 -0
- package/src/agent/tools.ts +110 -23
- package/src/agent/usage.ts +2 -2
- package/src/agent/voice-tools.ts +925 -0
- package/src/agent/xcb-agent.ts +13 -10
- package/src/argv.ts +38 -0
- package/src/audio/analysis.ts +253 -0
- package/src/audio/arrange.ts +49 -5
- package/src/audio/audio-command.ts +218 -0
- package/src/audio/autotune-engine.ts +101 -0
- package/src/audio/autotune.ts +640 -0
- package/src/audio/clips.ts +240 -0
- package/src/audio/devices.ts +264 -0
- package/src/audio/doctor.ts +157 -0
- package/src/audio/dsp/bandbank.ts +138 -0
- package/src/audio/dsp/envelope.ts +10 -0
- package/src/audio/dsp/follow.ts +120 -0
- package/src/audio/dsp/formant.ts +427 -0
- package/src/audio/dsp/glottal.ts +243 -0
- package/src/audio/dsp/interp.ts +7 -2
- package/src/audio/dsp/lpc.ts +50 -0
- package/src/audio/dsp/periodicity.ts +59 -0
- package/src/audio/dsp/pitch.ts +995 -0
- package/src/audio/dsp/psola.ts +199 -0
- package/src/audio/effects/chain.ts +3 -1
- package/src/audio/effects/common.ts +43 -0
- package/src/audio/effects/convolution.ts +7 -4
- package/src/audio/effects/filter.ts +48 -69
- package/src/audio/effects/formant.ts +263 -0
- package/src/audio/engine.ts +360 -40
- package/src/audio/fit.ts +35 -3
- package/src/audio/instrument-check.ts +59 -43
- package/src/audio/instruments.ts +4 -0
- package/src/audio/keys/calibration.ts +56 -0
- package/src/audio/keys/electric.ts +8 -1
- package/src/audio/keys/engine.ts +13 -1
- package/src/audio/keys/piano.ts +22 -2
- package/src/audio/kits.ts +135 -6
- package/src/audio/live.ts +114 -20
- package/src/audio/native.ts +615 -0
- package/src/audio/preview.ts +30 -2
- package/src/audio/render-worker.ts +2 -0
- package/src/audio/renderer.ts +2 -0
- package/src/audio/resample.ts +2 -1
- package/src/audio/sampler.ts +85 -4
- package/src/audio/samples.ts +20 -2
- package/src/audio/sing/analysis.ts +193 -0
- package/src/audio/sing/engine.ts +949 -0
- package/src/audio/strings/bow.ts +48 -5
- package/src/audio/strings/engine.ts +8 -2
- package/src/audio/synth/oscillators.ts +31 -21
- package/src/audio/synth/voice.ts +34 -1
- package/src/audio/vocoder/bank.ts +314 -0
- package/src/audio/vocoder/carrier.ts +165 -0
- package/src/audio/vocoder/control.ts +68 -0
- package/src/audio/vocoder/detect.ts +50 -0
- package/src/audio/vocoder/index.ts +304 -0
- package/src/audio/vocoder/talkbox.ts +143 -0
- package/src/audio/wav.ts +500 -77
- package/src/audio/winds/engine.ts +5 -1
- package/src/audio/winds/trim.ts +28 -4
- package/src/audio/winds/trims1.ts +297 -0
- package/src/audio/winds/voice.ts +15 -2
- package/src/auth/cli.ts +38 -36
- package/src/auth/credentials.ts +30 -1
- package/src/auth/login.ts +15 -9
- package/src/auth/tui.ts +19 -10
- package/src/commands/arrange.ts +82 -32
- package/src/commands/autotune.ts +421 -0
- package/src/commands/calibration.ts +74 -0
- package/src/commands/clips.ts +887 -0
- package/src/commands/drums.ts +3 -2
- package/src/commands/edit.ts +11 -4
- package/src/commands/expression.ts +1 -1
- package/src/commands/formant.ts +221 -0
- package/src/commands/fx.ts +101 -32
- package/src/commands/grammar.ts +560 -0
- package/src/commands/help.ts +774 -366
- package/src/commands/history.ts +139 -10
- package/src/commands/keys.ts +25 -8
- package/src/commands/modal.ts +1 -1
- package/src/commands/music.ts +1 -1
- package/src/commands/nearest.ts +53 -0
- package/src/commands/pack.ts +9 -2
- package/src/commands/param-range.ts +56 -0
- package/src/commands/parses.ts +135 -0
- package/src/commands/progression.ts +170 -0
- package/src/commands/range.ts +763 -0
- package/src/commands/resample.ts +13 -10
- package/src/commands/rhythm.ts +3 -0
- package/src/commands/rig.ts +3 -24
- package/src/commands/sample.ts +11 -1
- package/src/commands/sing.ts +474 -0
- package/src/commands/strum.ts +13 -1
- package/src/commands/style.ts +415 -0
- package/src/commands/time.ts +6 -3
- package/src/commands/tuning.ts +3 -3
- package/src/commands/vocal-pitch.ts +617 -0
- package/src/commands/vocal.ts +147 -0
- package/src/commands/vocoder.ts +627 -0
- package/src/commands/wind.ts +2 -2
- package/src/fs/durable.ts +50 -0
- package/src/identity/actor.ts +127 -0
- package/src/lang/glossary.ts +511 -0
- package/src/launch-args.ts +267 -0
- package/src/main.ts +2508 -308
- package/src/media/cli.ts +20 -3
- package/src/media/import.ts +3 -1
- package/src/project/check.ts +21 -2
- package/src/project/clip-pins.ts +72 -0
- package/src/project/init.ts +23 -8
- package/src/project/sync.ts +418 -86
- package/src/render.ts +20 -1
- package/src/session/client.ts +107 -3
- package/src/session/clipboard.ts +79 -0
- package/src/session/daemon.ts +199 -5
- package/src/session/live-host.ts +232 -0
- package/src/session/meta.ts +14 -0
- package/src/session/origin.ts +174 -0
- package/src/session/port.ts +109 -14
- package/src/session/presence.ts +34 -4
- package/src/session/protocol.ts +365 -7
- package/src/session/rebase.ts +63 -12
- package/src/session/receipt.ts +265 -0
- package/src/session/shared-live.ts +131 -0
- package/src/session/store.ts +126 -45
- package/src/tui/arrange-menu.ts +225 -23
- package/src/tui/audition.ts +1 -1
- package/src/tui/euclid.ts +113 -27
- package/src/tui/fader.ts +282 -42
- package/src/tui/granular-menu.ts +2 -4
- package/src/tui/knob-fields.ts +107 -0
- package/src/tui/knob-map.ts +198 -0
- package/src/tui/menu-clips.ts +297 -0
- package/src/tui/menu-time.ts +20 -13
- package/src/tui/menu-voice.ts +405 -0
- package/src/tui/menu.ts +987 -179
- package/src/tui/modal-menu.ts +6 -6
- package/src/tui/performance-menu.ts +5 -2
- package/src/tui/play-chords.ts +4 -2
- package/src/tui/play-mode.ts +15 -1
- package/src/tui/play-session.ts +243 -28
- package/src/tui/sing-menu.ts +278 -0
- package/src/tui/style-menu.ts +104 -0
- package/src/tui/tape-mode.ts +580 -0
- package/src/tui/tape-view.ts +263 -0
- package/src/tui/vocoder-menu.ts +244 -0
- package/src/tui/wind-menu.ts +3 -3
- package/src/version.ts +8 -0
- package/src/web/fetch.ts +115 -29
- package/tui/activity.ts +180 -9
- package/tui/app.ts +491 -84
- package/tui/clip-row.ts +132 -0
- package/tui/delight.ts +193 -0
- package/tui/drawer.ts +233 -27
- package/tui/frame-gate.ts +76 -0
- package/tui/grammar.ts +143 -65
- package/tui/guide.ts +50 -5
- package/tui/highway.ts +309 -30
- package/tui/hints.ts +197 -0
- package/tui/hits.ts +7 -1
- package/tui/input.ts +60 -9
- package/tui/keys.ts +1 -1
- package/tui/knobs.ts +268 -0
- package/tui/play-strip.ts +80 -14
- package/tui/prompt.ts +1 -1
- package/tui/screen.ts +151 -18
- package/tui/tape.ts +439 -0
- package/tui/text.ts +35 -2
- package/tui/theme.ts +46 -1
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `dawg [options]` launch grammar and the small argv contract the plain
|
|
3
|
+
* subcommands share. Pure: no I/O, so every mistake is rejected before
|
|
4
|
+
* `.dawg/` (or any project file) could be written.
|
|
5
|
+
*/
|
|
6
|
+
export { parseSimpleArgv, type SimpleArgv } from "./argv.ts";
|
|
7
|
+
import { parseThemeName, THEME_NAMES, type ThemeName } from "../tui/theme.ts";
|
|
8
|
+
|
|
9
|
+
/** Subcommands that parse their own argv; the launch grammar skips them. */
|
|
10
|
+
export const SUBCOMMANDS: readonly string[] = [
|
|
11
|
+
"login",
|
|
12
|
+
"logout",
|
|
13
|
+
"auth",
|
|
14
|
+
"model",
|
|
15
|
+
"sessions",
|
|
16
|
+
"render",
|
|
17
|
+
"init",
|
|
18
|
+
"check",
|
|
19
|
+
"media",
|
|
20
|
+
];
|
|
21
|
+
export const VALUE_FLAGS = [
|
|
22
|
+
"--session",
|
|
23
|
+
"--track",
|
|
24
|
+
"--import",
|
|
25
|
+
"--export",
|
|
26
|
+
"--theme",
|
|
27
|
+
] as const;
|
|
28
|
+
export type ValueFlag = (typeof VALUE_FLAGS)[number];
|
|
29
|
+
export const BOOLEAN_FLAGS: readonly string[] = [
|
|
30
|
+
"--new",
|
|
31
|
+
"--demo",
|
|
32
|
+
"--help",
|
|
33
|
+
"-h",
|
|
34
|
+
"--version",
|
|
35
|
+
"-v",
|
|
36
|
+
"--reduce-motion",
|
|
37
|
+
"--no-mouse",
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
/** A `--track` value resolved to the id `/track` would use. */
|
|
41
|
+
export type TrackArg = { id: string; name: string };
|
|
42
|
+
|
|
43
|
+
/** Screens a pane can open on (§12.5). */
|
|
44
|
+
export const PANE_SCREENS = ["home", "play", "tape", "sound", "menu"] as const;
|
|
45
|
+
export type PaneScreen = (typeof PANE_SCREENS)[number];
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* `dawg pane <screen> [track] [param] [pin | follow [letter]]`: what this
|
|
49
|
+
* terminal shows of the session in the current directory. `sound` opens
|
|
50
|
+
* the drawer on `param` (default volume); `menu` opens `param` as a menu
|
|
51
|
+
* section. `follow` tracks another pane's focus (`*` = the latest).
|
|
52
|
+
*/
|
|
53
|
+
export type PaneArgs = {
|
|
54
|
+
screen: PaneScreen;
|
|
55
|
+
param: string | undefined;
|
|
56
|
+
pin: boolean;
|
|
57
|
+
follow: string | undefined;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export type LaunchArgs = {
|
|
61
|
+
subcommand: string | undefined;
|
|
62
|
+
/** `dawg pane …` (its track is `track`). */
|
|
63
|
+
pane?: PaneArgs;
|
|
64
|
+
flags: ReadonlySet<string>;
|
|
65
|
+
session: string | undefined;
|
|
66
|
+
track: TrackArg | undefined;
|
|
67
|
+
importPath: string | undefined;
|
|
68
|
+
exportPath: string | undefined;
|
|
69
|
+
theme: ThemeName | undefined;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export type LaunchParse =
|
|
73
|
+
{ ok: true; args: LaunchArgs } | { ok: false; problem: string };
|
|
74
|
+
|
|
75
|
+
const TRACK_NAME = /^[a-z0-9._ -]{1,64}$/i;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* `--track Bass Guitar` → id `bass-guitar`, name `bass guitar`: the rule
|
|
79
|
+
* `/track` applies (letters, digits, `.`, `_`, `-` and spaces, at most 64),
|
|
80
|
+
* lowercased with runs of spaces collapsed. Undefined when invalid.
|
|
81
|
+
*/
|
|
82
|
+
export function normalizeTrackArg(value: string): TrackArg | undefined {
|
|
83
|
+
const name = value.trim().replace(/\s+/g, " ").toLowerCase();
|
|
84
|
+
if (!TRACK_NAME.test(name)) return undefined;
|
|
85
|
+
// `.` and `..` are path segments, never track ids.
|
|
86
|
+
if (/^\.+$/.test(name)) return undefined;
|
|
87
|
+
return { id: name.replace(/ /g, "-"), name };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** The existing track `arg` names (by id or name), else `arg.id`. */
|
|
91
|
+
export function resolveTrackArg(
|
|
92
|
+
tracks: readonly { id: string; name?: string | undefined }[],
|
|
93
|
+
arg: TrackArg,
|
|
94
|
+
): string {
|
|
95
|
+
const found =
|
|
96
|
+
tracks.find((track) => track.id === arg.id) ??
|
|
97
|
+
tracks.find((track) => track.id.toLowerCase() === arg.id) ??
|
|
98
|
+
tracks.find((track) => (track.name ?? track.id).toLowerCase() === arg.name);
|
|
99
|
+
return found?.id ?? arg.id;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Parses `dawg [options]`. A subcommand as the first word ends parsing (the
|
|
104
|
+
* subcommand owns the rest). Value flags need a value that does not start
|
|
105
|
+
* with `-`; each may be given once; `--track` and `--theme` are validated
|
|
106
|
+
* here so a bad value is one line and exit 2, never a stack trace.
|
|
107
|
+
*/
|
|
108
|
+
export function parseLaunchArgs(argv: readonly string[]): LaunchParse {
|
|
109
|
+
const flags = new Set<string>();
|
|
110
|
+
const values = new Map<ValueFlag, string>();
|
|
111
|
+
const first = argv[0];
|
|
112
|
+
if (first === "pane") return parsePaneArgs(argv.slice(1));
|
|
113
|
+
if (first !== undefined && !first.startsWith("-")) {
|
|
114
|
+
if (SUBCOMMANDS.includes(first))
|
|
115
|
+
return { ok: true, args: emptyArgs(first, flags) };
|
|
116
|
+
return { ok: false, problem: `unknown command · ${clip(first)}` };
|
|
117
|
+
}
|
|
118
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
119
|
+
const arg = argv[index]!;
|
|
120
|
+
if ((VALUE_FLAGS as readonly string[]).includes(arg)) {
|
|
121
|
+
const flag = arg as ValueFlag;
|
|
122
|
+
const value = argv[index + 1];
|
|
123
|
+
if (value === undefined || value.length === 0 || value.startsWith("-"))
|
|
124
|
+
return { ok: false, problem: `${flag} needs a value` };
|
|
125
|
+
if (values.has(flag))
|
|
126
|
+
return { ok: false, problem: `${flag} given twice` };
|
|
127
|
+
values.set(flag, value);
|
|
128
|
+
index += 1;
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (BOOLEAN_FLAGS.includes(arg)) {
|
|
132
|
+
flags.add(arg);
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (arg.startsWith("-"))
|
|
136
|
+
return { ok: false, problem: `unknown option · ${clip(arg)}` };
|
|
137
|
+
return { ok: false, problem: `unknown command · ${clip(arg)}` };
|
|
138
|
+
}
|
|
139
|
+
let track: TrackArg | undefined;
|
|
140
|
+
const trackValue = values.get("--track");
|
|
141
|
+
if (trackValue !== undefined) {
|
|
142
|
+
track = normalizeTrackArg(trackValue);
|
|
143
|
+
if (!track) return { ok: false, problem: "invalid track name" };
|
|
144
|
+
}
|
|
145
|
+
let theme: ThemeName | undefined;
|
|
146
|
+
const themeValue = values.get("--theme");
|
|
147
|
+
if (themeValue !== undefined) {
|
|
148
|
+
theme = parseThemeName(themeValue);
|
|
149
|
+
if (!theme)
|
|
150
|
+
return {
|
|
151
|
+
ok: false,
|
|
152
|
+
problem: `unknown theme ${clip(themeValue)} · ${THEME_NAMES.join(" | ")}`,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
return {
|
|
156
|
+
ok: true,
|
|
157
|
+
args: {
|
|
158
|
+
subcommand: undefined,
|
|
159
|
+
flags,
|
|
160
|
+
session: values.get("--session"),
|
|
161
|
+
track,
|
|
162
|
+
importPath: values.get("--import"),
|
|
163
|
+
exportPath: values.get("--export"),
|
|
164
|
+
theme,
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Drawer parameters `dawg pane sound <word>` opens (else the word is a track). */
|
|
170
|
+
const SOUND_PARAMS: readonly string[] = [
|
|
171
|
+
"volume",
|
|
172
|
+
"pan",
|
|
173
|
+
"tempo",
|
|
174
|
+
"bpm",
|
|
175
|
+
"bars",
|
|
176
|
+
"meter",
|
|
177
|
+
];
|
|
178
|
+
|
|
179
|
+
const PANE_USAGE =
|
|
180
|
+
"usage: dawg pane home|play|tape|sound|menu [track] [volume|pan|section] [pin|follow [A-Z]]";
|
|
181
|
+
|
|
182
|
+
export function parsePaneArgs(argv: readonly string[]): LaunchParse {
|
|
183
|
+
const [screenWord, ...rest] = argv;
|
|
184
|
+
const screen = PANE_SCREENS.find(
|
|
185
|
+
(name) => name === screenWord?.toLowerCase(),
|
|
186
|
+
);
|
|
187
|
+
if (!screen)
|
|
188
|
+
return {
|
|
189
|
+
ok: false,
|
|
190
|
+
problem: screenWord
|
|
191
|
+
? `unknown pane screen ${clip(screenWord)} · ${PANE_USAGE}`
|
|
192
|
+
: PANE_USAGE,
|
|
193
|
+
};
|
|
194
|
+
let pin = false;
|
|
195
|
+
let follow: string | undefined;
|
|
196
|
+
const words: string[] = [];
|
|
197
|
+
for (let index = 0; index < rest.length; index += 1) {
|
|
198
|
+
const word = rest[index]!;
|
|
199
|
+
if (word === "pin") pin = true;
|
|
200
|
+
else if (word === "follow") {
|
|
201
|
+
const letter = rest[index + 1];
|
|
202
|
+
if (letter !== undefined && /^[A-Z]$/i.test(letter)) {
|
|
203
|
+
follow = letter.toUpperCase();
|
|
204
|
+
index += 1;
|
|
205
|
+
} else follow = "*";
|
|
206
|
+
} else if (word.startsWith("-"))
|
|
207
|
+
return {
|
|
208
|
+
ok: false,
|
|
209
|
+
problem: `unknown option · ${clip(word)} · ${PANE_USAGE}`,
|
|
210
|
+
};
|
|
211
|
+
else words.push(word);
|
|
212
|
+
}
|
|
213
|
+
if (pin && follow)
|
|
214
|
+
return { ok: false, problem: `pin or follow, not both · ${PANE_USAGE}` };
|
|
215
|
+
if (words.length > 2)
|
|
216
|
+
return { ok: false, problem: `too many words · ${PANE_USAGE}` };
|
|
217
|
+
let track: TrackArg | undefined;
|
|
218
|
+
// `menu mix`, `sound filter`: one word after these is the section or the
|
|
219
|
+
// parameter; a track then comes first (`sound bass filter`).
|
|
220
|
+
const [first, second] = words;
|
|
221
|
+
let param: string | undefined;
|
|
222
|
+
const trackFirst =
|
|
223
|
+
words.length === 2 ||
|
|
224
|
+
(first !== undefined &&
|
|
225
|
+
(screen === "home" ||
|
|
226
|
+
screen === "play" ||
|
|
227
|
+
(screen === "sound" && !SOUND_PARAMS.includes(first.toLowerCase()))));
|
|
228
|
+
if (trackFirst) {
|
|
229
|
+
track = normalizeTrackArg(first!);
|
|
230
|
+
if (!track) return { ok: false, problem: "invalid track name" };
|
|
231
|
+
param = second;
|
|
232
|
+
} else param = first;
|
|
233
|
+
if (param !== undefined && !/^[a-z][a-z0-9 ._-]{0,63}$/i.test(param))
|
|
234
|
+
return { ok: false, problem: `invalid pane parameter · ${PANE_USAGE}` };
|
|
235
|
+
if (param !== undefined && (screen === "home" || screen === "play"))
|
|
236
|
+
return {
|
|
237
|
+
ok: false,
|
|
238
|
+
problem: `${screen} takes a track only · ${PANE_USAGE}`,
|
|
239
|
+
};
|
|
240
|
+
return {
|
|
241
|
+
ok: true,
|
|
242
|
+
args: {
|
|
243
|
+
...emptyArgs(undefined, new Set()),
|
|
244
|
+
track,
|
|
245
|
+
pane: { screen, param: param?.toLowerCase(), pin, follow },
|
|
246
|
+
},
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function emptyArgs(
|
|
251
|
+
subcommand: string | undefined,
|
|
252
|
+
flags: Set<string>,
|
|
253
|
+
): LaunchArgs {
|
|
254
|
+
return {
|
|
255
|
+
subcommand,
|
|
256
|
+
flags,
|
|
257
|
+
session: undefined,
|
|
258
|
+
track: undefined,
|
|
259
|
+
importPath: undefined,
|
|
260
|
+
exportPath: undefined,
|
|
261
|
+
theme: undefined,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function clip(value: string): string {
|
|
266
|
+
return value.length > 40 ? `${value.slice(0, 40)}…` : value;
|
|
267
|
+
}
|