The command line
Partly written. §1 was written with milestone M2 of the Lyric 5 plan, §2 with M7, §3 with M8a; the rest comes with M8a–M13, spec-first: each rule lands here with its conformance case before or with its implementation. Source of the decisions: 11 Tooling and interop W1.
Scope
The one binary and its verbs, option grammar, the precedence ladder, exit codes, the NDJSON output schema. Versioned as a contract (C10).
1. build and run
What the command line does for a single file (M2) and for a package (M7). The precedence ladder, the NDJSON stream and the other verbs follow with their milestones; the rules below stay.
Conformance. The suite runs programs, not the command line: the toolchain's own tests
are the conformance of this section (tests/Lyric5.Tests, BuildTests, DriverTests and
BuildStatusTests).
1.1 Verbs and options
lyric build <file.lyr>compiles the program that starts at the file to a binary: a single file's own, or — for a module of a package — the package's, entered there (04 §2).lyric buildwithout a file builds the programs of the package of the current directory — the nearestlyric.tomlat or above it —: itssrc/main.lyrand its[[bin]]programs (15 §1);--bin <name>names one, and a file is a program by itself.lyric run [<file.lyr>] [-- args…]builds the same way and then runs the binary with the arguments after--, on the caller's own console.--belongs torun:buildrefuses it.lyric update [<package>…]reads the packages from git anew, raises a tag that is a version to the newest of its line in the manifest, and writes the lock (15 §3); it takes-Cand--offline.- Options take a value as
--name valueor--name=value(11 C3):--profile <name>— a profile built in or the manifest's (15 §4); without the option the environment'sLYRIC_PROFILE, thendebug; an unknown name is refused, from either;asanandtsanneed clang —,--target <triple>(a Tier 1 triple; default: this machine),--emit ir|c(prints instead of building;runrefuses it),-C <dir>(the package is searched from<dir>instead of the current directory, and a relative file is relative to it).--offlinetakes no value: nothing is fetched, and a package read from git comes from the user's cache (15 §2).--lockedtakes none either:build,runandtesttake the lock as it is (15 §3 rule 4). A profile's fields change for one build with--opt <0-3>,--gc <immix|boehm>and--lto,--debug-info,--deny-warnings,--overflow-checks,--fast-math, each with its--no-form; a field flag is over the profile (11 C4), and a flag with its--no-form is refused. - The command line is strict: an unknown verb, option or value is refused.
- A binary for a target that is not this machine is built and not run:
runrefuses it and names the binary. - Without a file and without a manifest at or above the directory there is nothing to build
(
LYR-CLI0004). A package withoutsrc/main.lyris a library:buildchecks it (15 §2) —build --libbuilds it for C (rule 9) —, andrunhas no program there (LYR-CLI0005). lyric expand [<file.lyr>]prints the program's entry module after its macros' expansion (11 §5) to standard output: the results in the sites' places, the rest as written, in the formatter's form — comments fall, as do the module's header line and attributes. It chooses the program asrundoes (--bin,-C, the profile and the target, whichcomptimereads), builds nothing, and refuses--emit. The program is resolved and expanded, not checked: what the expansion needs is reported with exit 1 — a site of no macro, a macro's own error —, and a type error after it isbuild's to find. Without a site, the module prints as it is.lyric fix [<file.lyr>]makes the safe changes the findings suggest in the package's own files, and--dry-runprints them as a diff instead (16 §6).lyric check [<file.lyr>]takes the programsbuildwould take — or checks the library, asbuilddoes — through everything a build does before the C: the build scripts, for what they write intogen/(15 §8), the front end and the lints,comptime, and the lowering. It says whatbuildsays, exits asbuilddoes (§1.3), and makes neither C nor a binary. It takesbuild's options but--emit,--liband--shared.lyric build --libbuilds the package's library for C — itssrc/lib.lyrand what that imports — instead of its programs (13 §4): the archivelib<name>.aand the header<name>.h, or with--shareda shared library in the archive's place; for the archive it says what a C program links beside it (13 §4 rule 9). Withoutsrc/lib.lyrthere is nothing to build (LYR-CLI0001);--sharedwithout--lib, and--libwith a file,--binor--emit, are refused (exit 2).-v(--verbose) onbuild,run,check,expand,testandbenchsays each command of the C compiler, the archiver and the linker on the standard error as it starts —running:and the command —, the build scripts' and the bindings' among them; what is up to date runs nothing and says nothing. It writes text: with--jsonit is refused (exit 2).- Status lines.
build,run,check,expand,testandbenchsay each step that does work on the standard error as it starts, one line each — a word right-aligned in twelve columns, then what it works on —, whether or not the standard error is a terminal:FetchingandUpdatinga package or a source tree read from git,Runninga build script,Bindinga module made from a header,Compilinga program's front end (app v0.1.0 (src/main.lyr)), the runtime, and the C units —3 of 14 C units of app, the ones whose object is not cached —,Checkinga program (check), the front end's phasesParsing,Expanding,Analyzing,EvaluatingandLowering,Emittingits C,Linkinga binary or a shared library,Archivinga static one. What is up to date says nothing. Abuild,runorcheckthat succeeds saysFinished, the profile, its level and debug information, and the time the command took (Finished debug [opt 0, debug info] in 0.42s), abuildorrunProduced, the file it made with its size, andSummarywhere there are warnings or C units from the cache; one that fails ends with its findings.runthen says the binary it runs (Running out/debug/<target>/app). Where the standard error is a terminal, a phase, the C units, a link and an archive each stay one line, drawn over itself: the C units compiled so far are counted on it (Compiling [3/14] app), and its end adds its time (Linking app 0.05s); elsewhere, or under-v, each says a whole line as it starts, and a last lineTimingsgives their times.-valso says each package (Package std v5.0.0), each C unit with its time (Compiled …) and each command. The word is coloured as the diagnostics are (16 §1).-q(--quiet) says no status line, and--jsonnone (11 C6): the findings stay. The lines are text for a reader, not a format: their words and their order may change.
1.2 Where the files go
- A single file is an implicit package named after the file (11 C8); a package is named in its manifest (15 §1).
out/lies by the manifest — the nearestlyric.tomlat or above the file, also for a single file beside a package'ssrc/; without one, at the nearest directory upward holding.git; without that, by the file (P5). Under it, the binary isout/<profile>/<target>/<name>, with the executable suffix of the target — named after the package for itssrc/main.lyr, after the module's last segment for another module of the package, after the file for a single file —, a library for C beside it (13 §4 rule 7), andout/cache/holds what the build keeps between runs (P4; 01 L7).- An unchanged program compiles nothing twice: the same sources — every module of the program,
the standard library's included —, toolchain and options reuse the cache, and the binary is
linked only when an input to it changed (11 C9). A build that reuses the cache says again
what the build that filled it said: the same findings, in the form and the colour the command
line asks for now, counted in its
summary(16 §4). - A build holds
out/.lockwhile it writes intoout/(11 P5): a second build of the package waits for the first, and says so once. The lock is the operating system's on an open file; it ends with its process.
1.3 Exit codes
As 11 C5:
| Code | Meaning |
|---|---|
| 0 | done |
| 1 | the program or its manifest was refused: a compile error, or a construct the compiler does not translate yet |
| 2 | the command line or the environment: unknown verb, option or value, a missing file, no package to build, a program to run among several unnamed, no C compiler, a C compiler that fails or does not finish within its limit (LYR-BLD0001), a link that fails (LYR-LNK…, 15 §5.2), a git repository that cannot be reached, a toolchain below what a package asks for |
| 101 | the toolchain itself failed (LYR-ICE0001): said with its trace, and written with the version, the command and the machine to a report under out/ — of the package the command ran in, else of the working directory — which the message names |
| the program's | run passes the program's own exit through: its main value masked to 0..255 (13 §1.5), 101 for a panic |
2. clean, metadata, add, remove and bindgen
The verbs about a package besides building it — the package of the nearest lyric.toml at or
above the current directory, or above -C <dir>; without one there is nothing to do
(LYR-CLI0004).
Conformance. The toolchain's own tests (tests/Lyric5.Tests, OutTests,
ManifestEditTests, BindingsTests).
lyric cleanremoves the package'sout/, once a build that writes into it is done (§1.2).lyric metadatawrites the package as one JSON object, on one line, to standard output (11 P10):"version", the schema's: 1;"toolchain", the toolchain's version;"root", the package's name;"packages", the graph's, each with its"name","version","edition","manifest", its"toolchain"pin where it has one, where it is read from —"path", its directory, or"git"with the"url", the revision ("tag","branch"or"rev", none for the default branch) and the"commit"— and the"dependencies"it declares;"programs", each with its binary's"name", its"entry"file and its"module";"profiles", each with its"name", its"base"— the built-in profile it comes from — and its fields;"targets", the Tier 1 triples,"host", this machine's, and"out".
Within a schema version a field may be added, none is changed or removed (11 C10). Its options are
-C,--offline, and--json, the one form there is.lyric add <name> --path <dir>or--git <url>, with at most one of--tag,--branchand--rev, writes the dependency into[dependencies]as one line —geo = { path = "../geo" }, the path relative to the manifest — in place of the line that names it, or after the table's last, or in a table it begins at the end. Every other line of the manifest stays as it was. The graph is then read with the dependency (15 §2); a graph that refuses it leaves the manifest as it was, and the refusal is the graph's. With--vendorthe line names a source tree and goes into[native.vendor]instead (15 §5.3):--git <url>and a revision as above, read once to show the revision is there — the lock gets it when a build needs it —, or--url <url>, the file loaded and its SHA-256 written as the line'shash.--pathnames no tree, and--urlgoes with--vendoralone (LYR-CLI0003).lyric remove <name>takes the dependency's line out of[dependencies], and the graph — the lock with it (15 §3) — is read again; with--vendor, the tree's line out of[native.vendor]. A name the table does not hold is refused (LYR-CLI0003).A dependency written otherwise than as one line — a table of its own, dotted keys — is the person's to edit:
addandremoverefuse it (LYR-CLI0008). Both take-Cand--offline.lyric bindgen <header>writes to standard output the module abindingsentry makes of the header (15 §5.4) — for the host, or the target--targetnames —, to be kept undersrc/instead of made by every build. Within a package the header is compiled with the package'sincludeanddefinesfor that target, and a path@name/…names a file of its source tree; outside a package, with none. A header that does not compile is refused as the build refuses it (LYR-BLD0005).
3. test
The package's tests (10 B12, 07 V4) — the package of the nearest lyric.toml,
as in §2.
Conformance. The toolchain's own tests (tests/Lyric5.Tests, TestCommandTests, DocTestTests;
the standard library's own tests through it, StdTests).
lyric testbuilds every function the package marks@Test(11 §1) — in its modules undersrc/and undertests/(15 §7) — into one program for this machine, under the profile asked for asbuildtakes it (§1.1), and runs it in the package's directory, the one itslyric.tomlstands in, whereverlyricis called: a test reads its package's files by their paths in it (the sweep after M10, X1). A library has tests as well. It takes no file. Built for another machine — or for the target--targetnames, asruntakes it — the program is named and not run, exit 2.- The tests run one after another — module by module in the order of their paths, each
module's in the order it writes them —, each in a task of its own: a panic or an error that
leaves a test fails it, and the run goes on. A test with a
skipis named and not run. A test markedparallel—@Test { parallel = true }— runs beside the others marked so, after the rest, each in a task of its own on a pool of a thread for each processor (X3: an opt-in, since what tests share — the working directory, the environment, a globalvar— they share as threads do). Their lines come in their order; theirtimeouts are one deadline, the longest of them, from their start; and a parallel test has no subtest —subtestfails it, as a subtest is reported under the test that runs alone. - After each test has ended, a line:
ok,FAILwith the panic or the error below it, orskipwith the reason — a test's own output comes before its line —; then the count. A subtest —std.test.subtest("name") { … }— runs in a task of its own and has a line of its own,app.tests.math.table/name; one that fails fails its test, and the test goes on. A test that outlives itstimeoutends the run, with itsFAILline, exit 1: a task gives way only where it waits, so nothing stops it short of the end. A failure's further lines — the first difference of two values too long to compare by eye — stand under its first.-f <text>(--filter <text>) runs the tests whose name — the module's path and the function's,app.tests.math.adds— holds the text. - The exit is 0 when every test held — or when there is none to run —, and 1 when one failed or the program was refused (§1.3).
- Doc-tests: each
```lyricblock in a documentation comment —///or//!— of the package's modules undersrc/is a test of its own, after the marked ones, module by module in the order of their paths. It is nameddoc: <module>.<element> (<file>:<line>)— the element the comment documents, a member asType.member, the module alone for//!— and-fand the count take it as the others. Its fence says what it must do, as the Book's snippets (Book) do:lyricbuilds and runs, and prints what an```outputblock right below it says;lyric,no_runbuilds;lyric,compile_fail=CODEfails to build with that code and no other, and says what a```diagnosticblock right below it says. A block withoutfn mainis made a program as the Book's are — its statements the body ofmain, or its declarations beside an empty one —, and imports the element it documents, its type for a member, where that ispuband the block imports nothing of the module itself. A comment whose block the form refuses fails a test named after its module. Built for another machine, no doc-test is built. --no-runbuilds the program and runs none of it: its path is the last line printed, and no doc-test is built — each is a program of its own. It is what a debugger launches (§12).
4. bench
The package's benchmarks (12 §Benchmarks, 10 X4) — the package of the nearest
lyric.toml, as in §2.
Conformance. The toolchain's own tests (tests/Lyric5.Tests, BenchCommandTests).
lyric benchbuilds every function the package marks@Bench— in its modules undersrc/and undertests/— into one program for this machine, in the release profile unless--profilenames another, and runs them one after another on one thread, in the package's directory astestruns its program;--targetastesttakes it (§3). The files of--saveand--compareare where the command line names them.- A line for each:
bench app.tests.speed.reads: 412.3 ns/op, 0 allocs/op, 0 B/op, 2483.2 MB/s (290000 runs)— the nanoseconds a run, the allocations a run and their bytes, the megabytes a second where the benchmark said its bytes, and the runs measured.-f <text>(--filter <text>) runs those whose name holds the text; where none does, or there is none, a line says so. --save <file>writes the run's times to the file, a line a benchmark — its name, then the nanoseconds, the allocations and the bytes a run, apart by tabs —;--compare <file>reads such a file, and the line of a benchmark it has a row for ends with how its time changed:, was 400.1 ns/op: +3.0%.- The exit is 0, and 1 where the file to compare with or to save to could not be read or written, or the program was refused (§1.3).
5. The verbs and their options
Conformance. The toolchain's own tests (tests/Lyric5.Tests, VerbTableTests).
- The verbs and their options are one table: the command line is read by it,
lyric helpprints it, and the table below is printed from it (lyric help --markdown). An option the table does not give a verb is refused with exit 2 (§1.1 rule 3), as is a value missing or a value given to a flag (--lto=yes). lyric helplists the verbs and the options every verb takes;lyric help <verb>andlyric <verb> --help(-h) list the verb's own. A--helpafterrun's--is the program's.- The options every verb takes, before or after the verb:
--color <auto|always|never>,--absolute-paths,--max-errors <n>(16 §1); where the table marks the verb,--json(16 §4) and the lint options-A,-W,-D <lint>and--warn-deps(16 §5). A field of the profile is--xand--no-x.
| verb | words | options | lints | --json |
|---|---|---|---|---|
build |
[<file.lyr>] |
--profile <name>, --opt <0-3>, --gc <immix|boehm>, --[no-]lto, --[no-]debug-info, --[no-]deny-warnings, --[no-]overflow-checks, --[no-]fast-math, --target <triple>, -C <dir>, --bin <name>, --offline, --locked, --verbose, -v, --quiet, -q, --emit <ir|c>, --lib, --shared |
yes | yes |
run |
[<file.lyr>] [-- <args>…] |
--profile <name>, --opt <0-3>, --gc <immix|boehm>, --[no-]lto, --[no-]debug-info, --[no-]deny-warnings, --[no-]overflow-checks, --[no-]fast-math, --target <triple>, -C <dir>, --bin <name>, --offline, --locked, --verbose, -v, --quiet, -q |
yes | yes |
check |
[<file.lyr>] |
--profile <name>, --opt <0-3>, --gc <immix|boehm>, --[no-]lto, --[no-]debug-info, --[no-]deny-warnings, --[no-]overflow-checks, --[no-]fast-math, --target <triple>, -C <dir>, --bin <name>, --offline, --locked, --verbose, -v, --quiet, -q |
yes | yes |
expand |
[<file.lyr>] |
--profile <name>, --opt <0-3>, --gc <immix|boehm>, --[no-]lto, --[no-]debug-info, --[no-]deny-warnings, --[no-]overflow-checks, --[no-]fast-math, --target <triple>, -C <dir>, --bin <name>, --offline, --locked, --verbose, -v, --quiet, -q |
yes | — |
test |
— | --profile <name>, --opt <0-3>, --gc <immix|boehm>, --[no-]lto, --[no-]debug-info, --[no-]deny-warnings, --[no-]overflow-checks, --[no-]fast-math, --target <triple>, -C <dir>, --offline, --locked, --verbose, -v, --quiet, -q, --filter, -f <text>, --no-run |
yes | yes |
bench |
— | --profile <name>, --opt <0-3>, --gc <immix|boehm>, --[no-]lto, --[no-]debug-info, --[no-]deny-warnings, --[no-]overflow-checks, --[no-]fast-math, --target <triple>, -C <dir>, --offline, --locked, --verbose, -v, --quiet, -q, --filter, -f <text>, --save <file>, --compare <file> |
yes | — |
fix |
[<file.lyr>] |
-C <dir>, --offline, --dry-run, --from-4 |
yes | yes |
fmt |
[<file.lyr>…] |
-C <dir>, --check, --diff |
— | — |
doc |
— | -C <dir>, --offline, --out <dir>, --std |
— | — |
api |
— | -C <dir>, --json, --diff <rev>, --std |
— | — |
lsp |
— | --stdio |
— | — |
dap |
— | — | — | — |
env |
— | -C <dir>, --profile <name>, --target <triple>, --opt <0-3>, --gc <immix|boehm>, --[no-]lto, --[no-]debug-info, --[no-]deny-warnings, --[no-]overflow-checks, --[no-]fast-math, --offline, --json |
yes | — |
new |
<name> |
--lib, --[no-]git, -C <dir> |
— | — |
init |
— | --lib, --name <name>, --[no-]git, -C <dir> |
— | — |
update |
[<package>…] |
-C <dir>, --offline |
— | — |
add |
<name> |
--path <dir>, --git <url>, --tag <tag>, --branch <branch>, --rev <commit>, --vendor, --url <url>, -C <dir>, --offline |
— | — |
remove |
<name> |
--vendor, -C <dir>, --offline |
— | — |
bindgen |
<header> |
--target <triple>, -C <dir>, --offline |
— | — |
clean |
— | -C <dir> |
— | — |
metadata |
— | -C <dir>, --offline, --json |
— | — |
toolchain |
<install|list|default|remove|update> [<version>|zig] |
--available |
— | — |
explain |
<code> |
— | — | — |
completions |
<bash|zsh|fish|pwsh> |
— | — | — |
version |
— | — | — | — |
help |
[<verb>] |
--markdown |
— | — |
6. env
(11 C4)
Conformance. The toolchain's own tests (tests/Lyric5.Tests, VerbTableTests).
lyric envsays every setting a build of the package here reads — the toolchain, the standard library, the manifest, the C compiler and zig apart from it, the cache, the profile and each of its fields, the target, each lint's level (lint.<name>, andlint.warnDeps), and eachLYRIC_*variable that is set — with its value and where it comes from:command line, the variable's name (LYRIC_PROFILE),lyric.toml, ordefault; the C compiler and zig alsoinstalled(the zig of §13 rule 12) orPATH. The command line is over the environment, the environment over the manifest, the manifest over the default.- It takes the options that change a setting —
-C,--profile, the profile's fields,--target, the lint options-A,-W,-Dand--warn-deps— so that it says what the build with them would read.--jsonwrites one document instead:{"version": 1, "settings": [{"name", "value", "origin"}, …]}.
7. new, init and completions
(11 C2)
Conformance. The toolchain's own tests (tests/Lyric5.Tests, NewCommandTests).
lyric new <name>makes the directory<name>and a package in it;lyric initmakes the package in the directory it runs in —-Cnames another —, named after the directory unless--name <name>names it. The files:lyric.toml([package]withnameandversion = "0.1.0"),src/main.lyrprintingHello, world!— or, with--lib, a library'ssrc/lib.lyr—, and.gitignoreholdingout/; no build script. A fileinitfinds there is kept.- A name that is no package name (15 §1 rule 2) is refused with exit 2, and with
the name it would be where there is one (
My-App→my_app).newinto a directory that is there, andinitwhere alyric.tomlis, are refused (LYR-CLI0021, exit 2). - git:
--gitmakes a repository in the package's directory,--no-gitnone; without either, the environment'sLYRIC_GIT_ON_NEWdecides —1ortruemakes one where no repository holds the directory already and git is found. The command line is over the environment (§6). A--gitthat git refuses, or that finds no git, fails the command (LYR-CLI0021) after the files are written. lyric completions <bash|zsh|fish|pwsh>prints the shell's completion script — the verbs, and for each its options and the options every verb takes, as §5's table has them — and runs nothing. Another shell is refused (exit 2).
8. fmt
(11 E5)
Conformance. The toolchain's own tests (tests/Lyric5.Tests, FmtCommandTests; the form itself
in tests/Lyric.Tests.Formatting).
lyric fmtputs Lyric files in the one form: there are no options that change it. Without words it takes the package found from here (-Cnames another directory) — every.lyrfile undersrc/andtests/, andbuild.lyr—; with words, the files named and no others.- The form keeps what the program means, its comments and the parentheses it writes; formatting a formatted file changes nothing. A file in the form is not written. A file is written with LF line ends and one final newline.
- A file that does not parse is left as it is: its findings are said, and the command ends with exit 1 after the other files are formatted.
--checkwrites nothing: it names each file that would change, one to a line, and ends with exit 1 where one would, 0 where none would.--diff, with--checkonly, shows each change as a unified diff instead of the name.
9. doc
(11 E7)
Conformance. The toolchain's own tests (tests/Lyric5.Tests, DocCommandTests).
lyric docwrites the reference of the package found from here (-Cnames another directory) as static pages, intoout/doc/or the directory--outnames: a page for the package, one for each module and one for each type, from thepubdeclarations the checker sees and their documentation comments. A package that does not check is not documented: its findings are said and the command ends with exit 1, writing nothing.- A module's documentation is the
//!lines that open its file (01); an item's is the///lines above it. A page shows each item's signature as written, its documentation as Markdown, and for a type its conformances — those its declaration lists and those blocks of the package add. - Each member stands under an anchor that names its kind:
#field.x,#method.push,#variant.Up,#assoc.Item,#const.xon a type's page,#fn.name,#const.name,#type.Aliason a module's. A second member of one name and kind takes-2, and so on. --stdwrites the standard library's reference instead of a package's.
10. api
Conformance. The toolchain's own tests (tests/Lyric5.Tests, ApiCommandTests).
lyric apiprints the public surface of the package found from here (-Cnames another directory): whatlyric docdocuments (§9) — eachpubitem of its modules, each member of a type, each conformance a type's declaration lists or a block of the package adds — one line per element. A package that does not check prints nothing: its findings are said and the command ends with exit 1.--stdprints the standard library's surface instead.- A line is the element's signature with its qualified path for its name
(
pub fn geo.distance(a: Point, b: Point): float,pub geo.Point.y: float = 0.0,variant geo.Dir.Up); a conformance is a line of its own (geo.Point :: Equatable), and a type's line carries no::list. An interface's method that has a body ends with{ … }. - The lines are written in one spelling: comments, line breaks, spaces and a trailing comma do not change a line; a parameter's name does, since a call may name its argument. The lines are sorted by path, a type's own line before its conformances: the same declarations print the same text, byte for byte.
--jsonprints the same elements as one document:{"package", "version", "elements": [{"module", "path", "kind", "signature", "line", "owner"?, "default"?}]}, in the text's order;kindis one offn,struct,class,enum,interface,type,const,field,method,variant,assoc,conformance;owneris the kind of a member's type,defaultis present and true where a field or an associated type has a value or an interface's method has a body.--diff <rev>compares the surface with the package's as the git revision<rev>of its repository holds it — read from the repository, not from the working tree. Each element is removed, added or changed (the same kind and path with another line). Removed and changed are breaking; added is breaking only where the language makes code written before write it out: a field without a value in a struct or class (an initializer names it), a variant of an enum (amatchover every case misses it), an interface's method without a body or associated type without a value (each conformer must give it). An interface's method that only gains a body is compatible; one that loses it is breaking.- The diff lists the breaking changes first, each with the old line (
-) and the new (+), then the compatible ones, and ends with the count. The command ends with exit 1 where a change is breaking and 0 where none is;--jsonprints{"breaking": n, "changes": [{"change", "breaking", "path", "kind", "old"?, "new"?, "why"}]}. - A directory in no git repository, a revision git cannot read, or one without the package's
lyric.tomlis LYR-CLI0022, exit 2.--diffwith--stdis refused with exit 2.
11. lsp
Conformance. The toolchain's own tests (tests/Lyric.Tests.Lsp; the verb in tests/Lyric5.Tests,
LspCommandTests).
lyric lspis the language server: it speaks the Language Server Protocol with an editor over its standard input and output until the editor saysexit, and ends with exit 0 after ashutdown, 1 without one.--stdionames the one way there is; editors pass it.- A file is analysed as a module of its package where it lies under the
src/ortests/of the nearestlyric.tomlabove it: with every other module of the package, in the one compilationlyric testmakes of them (§3), and the packages of its graph. Any other file is analysed alone, with the standard library, aslyric check <file>checks it. - The findings the editor shows are those
lyric checksays of the same text, except those only the lowering finds — a monomorphization that does not end (LYR-SEM0197) is said by the build; the text of every file the editor holds open counts instead of what is saved. - The server reads the manifest and the graph as a build reads them, except that it fetches
nothing — a package from git comes from the cache — and writes nothing:
lyric.lockis left as it is. A manifest it cannot read leaves the file analysed alone, and the server says why in the editor's log. - An edit arrives as the ranges it replaces. A client that asks for a document's findings
(
textDocument/diagnostic) gets them for the documents it has open; the findings of every other file of the package are sent to it (textDocument/publishDiagnostics), as to a client that does not ask. - A
comptimesite of the program is evaluated under at most a tenth of the toolchain's budget (11 §2 rule 5); a site that runs out of it is shown without a value and without a finding — the build evaluates it under the program's budget. The standard library's sites keep theirs. - What a declaration is under the cursor — its signature, its uses, its new name — is answered for every package the editor has analysed: the uses of a library's function include those of an open program that depends on it. A rename edits each of them, and nothing in a package read from git or in the standard library; a rename that would is refused, and says why.
- A finding links the page of its code in the catalog, of the toolchain's version, the one
lyric explainnames. The quick fixes at a place are the changes the findings' notes suggest, word for word — the onelyric fixapplies preferred, the others offered —, and for a lint the@Allowof its code above the declaration it stands in; the editor composes no change of its own. - The document's form is
lyric fmt's (§8), sent as the lines it changes. The commandlyric.expandanswers the open module with its macros expanded, aslyric expandprints it. - Each
@Testfunction of a package's file and each runnable block of its documentation carries two commands for the editor to run, run and debug, with the package's directory and the namelyric testgives it —app.tests.check.adds,doc: app.add (src/lib.lyr:3); the requestlyric/testslists them for a document. The server runs no test: the editor runslyric test -f <name>(§3).
12. dap
Conformance. The toolchain's own tests (tests/Lyric5.Tests, DapCommandTests).
lyric dapis the debug adapter: it speaks the Debug Adapter Protocol with an editor over its standard input and output, and lldb-dap behind it does the debugging — breakpoints with their conditions, logpoints, stepping, threads, attaching are lldb's. Where no lldb-dap is found (LYRIC_LLDB_DAPnames one, else the path and Xcode's), each request is refused with the reason.- A
launchnames inprograma package's directory or a.lyrfile: the adapter builds it in the debug profile first, what the build says reaches the editor's console, and a program that does not build is refused; the binary built is what runs, with theargsandcwdthe launch gives. - A panic is the exception filter
lyric-panic, on unless the editor turns it off: the program stops where it panics, before the panic leaves its task. It is the only filter offered. - A frame is shown by its Lyric name (
app.main.deep) at its Lyric line. A build writes the names beside the binary —<binary>.lyric-names, a line per function: its C name, a tab, its Lyric name —; a frame of the runtime keeps its name and is marked as set back (subtle). - A value is shown as Lyric writes it: a local by its Lyric name, a string as its text, an
array as its length with its elements, an optional as its value or
none, an enum as its variant with its payload, a struct's and a class's fields by their names; what the compiler made — its temporaries, its locals of its own — is not shown, nor what the runtime keeps beside the program. The names file says which C type is which Lyric type (type,variant,globallines beside the functions'); the toolchain'slldb/lyric_lldb.pyreads it, and lldb loads it withcommand script import. - A line breakpoint stops at the line's code: the function's own setting up stands at the function's line, never at a line after it. The sources are found where they lie, by the names the binary writes for them (§1.2).
- On Windows the adapter is measured, not promised: the binary carries PDB, and whether lldb-dap reads it is reported, not gated.
- A
launchwith atestdebugs the package's tests whose names hold it: the programlyric test --no-run -f <test>builds (§3), run in the package's directory astestruns it.
13. toolchain
Conformance. The toolchain's own tests (tests/Lyric5.Tests, ToolchainCommandTests, against
a mirror served on the machine): a conformance case fetches nothing.
The home. Toolchains are installed side by side under
~/.lyric— or the directoryLYRIC_HOMEnames:toolchains/<version>/holds each as its archive unpacked it,config.tomlnames the default (default = "<version>", the one key it takes), andbinis a link to the default's directory — a symbolic link, on Windows a junction —, so thatbinon thePATHruns the default, andseen/remembers the newest index of each channel. A directory an install has not finished is no toolchain.lyric toolchain install <version|dev|stable>installs a toolchain for this machine's target.devandstablename the newest version of their channel; a version is one its channel lists, written with its build part (+…) or without. A development build's version (-dev.…) is thedevchannel's, every other thestablechannel's. The first toolchain installed becomes the default. A version installed already is said and fetched no further.What an install trusts. The channel's index is fetched with its signature and checked with the keys the toolchain carries for that channel, its own and a reserve; its number is no lower than the highest this machine has seen from the same signer. The archive is fetched no further than the size the index gives and checked against its SHA-256; it is unpacked beside the toolchains and checked against its own
toolchain.json— its version, its target and every file; only then is it moved into place. A difference anywhere installs nothing (LYR-CLI0024), and a run cut short leaves nothing a later one counts as installed.Where from. The index and the archives come from the mirror, then from GitHub's releases. A source that cannot be reached is followed by the next; one that serves what rule 3 refuses is followed by the next with a warning, because only a signature and a hash make anything acceptable, whichever source it came from. An index whose signature does not hold is fetched once more, with its signature, before it is refused: the two are two requests, and a publish can fall between them. Where no source serves what holds, nothing is installed:
LYR-CLI0024where one served something refused, elseLYR-CLI0023.LYRIC_MIRRORnames another mirror in place of both, andLYRIC_MIRROR_KEYthe key its signatures are checked with — set without a mirror, it is refused.lyric toolchain listnames the installed toolchains, the newest first, the default marked; with--available, the versions both channels offer, with their dates, those installed marked. A channel that cannot be fetched is said, and is an error only where neither can.lyric toolchain default [<version>]says the default, or makes the installed version the default:config.tomlwritten,binpointed at it. Abinthat is no link is refused, and left as it is.lyric toolchain remove <version>removes an installed toolchain; not the default, nor the toolchain the command runs from (LYR-CLI0025).lyric toolchain updateinstalls the newest version of the default's channel beside the default and makes it the default; the old one stays until it is removed. Where the default is the newest, it is said.While an archive is fetched, its progress is drawn on the standard error where that is a terminal, and nowhere else.
Every refusal is the environment's, exit 2: an action or a version missing, an unknown action,
--availablebeside another action (§1.3); a toolchain that cannot be fetched (LYR-CLI0023); one that is not what its index says (LYR-CLI0024); a change the installed toolchains refuse (LYR-CLI0025).Which toolchain runs a command. Before a verb runs, the toolchain it should run with is decided:
LYRIC_TOOLCHAIN—localfor the toolchain that was started, or an installed version, written with its build part or without (one not installed is refused,LYR-CLI0025) — over thetoolchainthe package the command runs in asks for (15 §1 rule 6), a least version. The toolchain that was started runs the command where it is what is asked for; else the default, where it is; else the newest installed that is. Another toolchain is handed the command as it was given — on Unix in place of the process, on Windows as a child whose exit is the command's — withLYRIC_TOOLCHAIN_FROMset, and a command that carries it is never handed on again. Where no installed toolchain is what the package asks for, a terminal is offered the least stable version that is, installed on a yes; elsewhere the verb runs and refuses the package (LYR-PKG0009).toolchain,help,explain,completions,newandinitare never handed on, and only the package the command runs in is read — a dependency's pin is the build's to check.lyric toolchain install ziginstalls the zig the toolchain is built and tested with — its version is the toolchain's — under the home aszig/<version>/, where the search for a C compiler finds it afterLYRIC_CCand before thePATH. The archive's name, size and SHA-256 come from zig's index on its download page; the archive comes from zig's community mirrors in a shuffled order, each asked with?source=lyric, and from the download page last. It is checked with zig's minisign key and against the file its signature's trusted comment names; a source whose archive does not hold is passed over for the next, and where none holds, nothing is installed (LYR-CLI0024). An index that cannot be had, or that has no archive of the version for this machine, isLYR-CLI0023.LYRIC_ZIG_MIRRORnames a server in place of the download page — its index, its list of mirrors and the archives —, andLYRIC_ZIG_MIRROR_KEYthe key it signs with; set without the server, it is refused.lyric toolchain listnames the zig installed.
13.1 The archive, the index and the signature (informative)
- The archive of a toolchain is one per Tier 1 target:
.zipfor Windows,.tar.gzfor the others, holding the binary,stdlib5/, the runtime as C source and prebuilt for the archive's target,lldb/,LICENSEand the notices, andtoolchain.json—{"version", "triple", "files": [{"path", "size", "sha256"}, …]}, every other file with its size and SHA-256. - The index of a channel is
dev.jsonorstable.json:{"channel", "sequence", "versions": [{"version", "date", "archives": {"<triple>": {"file", "size", "sha256"}}}]},sequencea positive integer that grows from one index of the channel to the next, the newest version first where two compare equal. On a mirror it lies at<base>/<channel>.json, its archives under<base>/<channel>/; on GitHub the releasedevcarries the development build withdev.json, the releasechannelscarriesstable.json, and each stable version has its releasev<version>. - The signature is minisign's, beside the file as
<file>.minisig: Ed25519 over the file's BLAKE2b-512 hash, and over that signature with its trusted comment; minisign's legacy form, which signs the file itself, is refused. - zig's archives are a
.tar.xz— a.zipfor Windows — holding one directory withzigand itslib; zig's index isindex.jsonon its download page ({"<version>": {"<arch>-<os>": {"tarball", "shasum", "size"}}}), the archives lie under<page>/<version>/, its community mirrors are listed incommunity-mirrors.txtbeside the index, one address a line, and serve an archive as<mirror>/<file>.
14. fix --from-4 (informative)
lyric fix --from-4 [<file.lyr>] migrates a Lyric 4 program: the lyric.json of the working
directory (-C <dir>), or the file named. Nothing here is a promise about the result, which may
not compile; lyric check says what is left. The rules it applies are no part of this
specification, and the notes it gives stand in Appendix A under
LYR-MIG.
- What it reads: the program, with the front end of Lyric 4.6. A program 4.6 refuses is not
changed (
LYR-MIG0001, exit 1). - What it writes, in place: each changed source file, as replacements of what a rule changes, so
comments and layout stay;
lyric.tomlforlyric.json, which goes. It moves no file: where the sources lie outsidesrc/, a note says so. --dry-runprints the changes as a unified diff and writes nothing.--jsondoes not go with--from-4.- The report,
fix-from-4.txtbeside the manifest or the file, lists each note with its rule, place, reason and proposal:proposal[…]for a change made for a person to confirm,by hand[…]for one left to a person. - Exit codes: 0 when it has migrated, whatever the notes say; 1 as above; 2 for a wrong use.