Skip to content

Commit dcb78b0

Browse files
committed
Runner: added, which runs the program in the process: help, version, usage errors and the exit code
It adds --help with -h and, given a version, --version with -V, placed with the options of the program, a flag of that name the program has being answered as it is. A usage error is printed with the help of its command and returns 2 by default. On request it prints the help for an empty line (helpWhenEmpty, before the required arguments are demanded), adds --no-color, read before parsing so that a mistake of the line is plain too (colorFlag), and reports an exception of the handler by its message (errorExitCode). A version may be a closure writing it for the console it goes to.
1 parent 429068c commit dcb78b0

6 files changed

Lines changed: 422 additions & 104 deletions

File tree

‎AGENTS.md‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ three phases of `parse()` with the command selection and the sentinel, `get()` o
2020
command line as a tree of the program and its commands, `Parser` reads a command
2121
line against it and returns a `ParseResult`, `HelpRenderer` draws the help of any
2222
command and a usage error, `Console` writes to a stream in color, `Prompt` asks the
23-
user at a terminal and `Ansi` measures text the way a terminal shows it. The parameters live in the
23+
user at a terminal, `Ansi` measures text the way a terminal shows it and `Runner` runs the
24+
program in the process: help, version, usage errors and the exit code. The parameters live in the
2425
`Parameters` namespace: `Flag` extends `Parameter`, while `Option` and `Argument`
2526
extend it through `ValueParameter`. `Section` and `Text` in the `Help` namespace
2627
shape the help. The attributes `Command`, `Flag`, `Option` and `Argument` in the
@@ -51,9 +52,10 @@ composer phpstan
5152

5253
## Working in this repo
5354

54-
- **Definition, parsing, help and output are four classes.** `Command` never
55+
- **Definition, parsing, help, output and running are five classes.** `Command` never
5556
touches `argv`, the environment or a stream; `Parser` and `HelpRenderer` take
56-
the command as an argument and keep no state; `Console` knows no `Command`.
57+
the command as an argument and keep no state; `Console` knows no `Command`;
58+
`Runner` alone holds the process, `argv`, the consoles and the exit code.
5759
Each node keeps one ordered list of items and the help is always drawn from it.
5860
- **Every setting is a named argument of `add*()` and cannot change afterwards**, so
5961
everything is refused at once, the rules over several arguments included, and the

‎docs/internals.md‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
Small classes, mostly clear from their signatures. This is the thin "invariants & traps"
44
layer, the facts that are expensive to rediscover.
55

6-
## Four roles, four classes
6+
## Five roles, five classes
77

88
- **`Command`** is the definition: a tree whose root is the program and whose nodes are its
99
commands. It knows nothing of `argv`, the environment or the output.
@@ -14,6 +14,22 @@ layer, the facts that are expensive to rediscover.
1414
Like `Parser`, it takes the node as an argument and keeps nothing between calls.
1515
- **`Console`** writes to a stream and knows no `Command`. The renderer colors and writes
1616
through it; `renderToString()` without a console is plain text.
17+
- **`Runner`** is the only one that runs the program in the process: it reads `argv`, owns the
18+
two consoles, answers `--help`, `--version` and `--no-color`, reports a usage error and returns
19+
the exit code. The other four stay free of the process because it holds all of that.
20+
21+
**The runner adds its flags to the program it is given**, so the definition is changed, and a
22+
second runner over it finds them there; a node cannot be copied, so this is the price of the flags
23+
being ordinary ones, listed, parsed and inherited as any other. They are placed before the first
24+
command, section or text by the internal `Command::moveBeforeCommands()`, since a finished
25+
definition usually ends with them and the help would draw the flags as a block of their own after
26+
its texts. A flag of that name the program has is answered as it is; an alias it took is left out.
27+
**`--no-color` is read from the tokens before parsing** (up to `--`, after which nothing is an
28+
option, and a value starting with a dash takes `=`, so a bare `--no-color` is never a value), so that
29+
a mistake of the line is reported plain too; the empty line of `helpWhenEmpty` is decided before
30+
parsing as well, which would demand the required arguments. `errorExitCode` catches what the handler
31+
throws as `\Exception` and never an `\Error`, a bug, nor what `parse()` throws besides a usage
32+
error: an `\InvalidArgumentException` from the binding of handlers is a mistake of the definition.
1733

1834
The parameters live in the `Parameters` namespace and split by **whether they take a value**,
1935
the axis most settings follow. `Flag` takes none; `ValueParameter` holds the enum and the

0 commit comments

Comments
 (0)