diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4752065..690edf9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -364,8 +364,6 @@ jobs: audit } - # Single stable job name for branch protection: require this one check and - # matrix/job changes never break the required-checks configuration. # The skill for coding agents (skills/termlens/SKILL.md) is what an agent # copies from, so a recipe that no longer compiles teaches the wrong API to # everyone who installed it. Every Rust block in it is compiled against the @@ -382,6 +380,8 @@ jobs: toolchain: stable - run: .github/scripts/check-skill-snippets.sh + # Single stable job name for branch protection: require this one check and + # matrix/job changes never break the required-checks configuration. required-green: name: required-green if: always() diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6fd71e1..c775154 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -120,6 +120,10 @@ cargo insta review # inspect and accept/reject each diff block in `SKILL.md` is compiled against the crate by `.github/scripts/check-skill-snippets.sh`; run it after editing the file. `.claude/skills/termlens` links to it so Claude Code finds it here. +- `tools/` — contributor tooling. `preflight.sh` runs §1's gate list in + order, one line per gate (`--fast` for fmt, clippy and the tests), and + each `*-selftest/run.sh` proves that a gate — or the runner itself — goes + red when it should, before a green run of it is trusted. - `.github/` — CI, commit policy enforcement, release automation. ## 3. Testing policy diff --git a/docs/DESIGN.md b/docs/DESIGN.md index b859510..e021994 100644 --- a/docs/DESIGN.md +++ b/docs/DESIGN.md @@ -852,10 +852,11 @@ But it is an implementation detail: reader (an open hyperlink label) still sees the same set. Rewriting before either parser is what keeps the primary and the attribute shadow the same shape, exactly as the SGR rewrite does. Scope is deliberately - narrow and stated in the README: G0–G3 designation, locking shifts on - G0/G1, SS2/SS3 for one character, one set translated, everything else - read as ASCII. `LS2`/`LS3` and `DECSC`/`DECRC` of charset state are not - modelled. + narrow and listed in `docs/LIMITATIONS.md`: G0–G3 designation, locking + shifts on G0/G1, SS2/SS3 for one character, two sets translated — DEC + Special Graphics and the UK set — and everything else read as ASCII. + `DECSC`/`DECRC` save and restore the charset state with the cursor; + `LS2`/`LS3` are not modelled. - vt100's tab stops are a hardcoded eight with no way to be told otherwise, so **the stop set is termlens's too**, and for the same reason: `HTS`, `TBC`, `CHT` and `CBT` reached `unhandled_escape`/`unhandled_csi` and were @@ -875,9 +876,10 @@ But it is an implementation detail: wins, which is sound because `HT` draws nothing and only moves the cursor. Both parsers are fed the rewrite, so the attribute shadow keeps the same shape as the primary grid and the invariant `snapshot` debug-asserts still - holds. Scope is in the README: `TBC 0` and `TBC 3` only, back-tab to the - nearest stop strictly left of the cursor, and a resize that extends into - new columns with the default pattern while leaving existing stops alone. + holds. Scope is in `docs/LIMITATIONS.md`: `TBC 0` and `TBC 3` only, + back-tab to the nearest stop strictly left of the cursor, and a resize + that extends into new columns with the default pattern while leaving + existing stops alone. ### The attribute shadow @@ -940,7 +942,10 @@ test overrides it) so escape output matches what the emulator speaks regardless of host. `env_clear()` blocks inheritance while keeping `env()`-set variables — order-independent, unlike `std::process::Command`, because a builder that silently drops your explicit `TERM` depending on -call order is a trap. +call order is a trap. `env_clear()` also pins `SHELL=/bin/sh` unless the +test sets `SHELL` itself: the PTY layer fills `SHELL` from the host's login +shell when it is absent, which put one machine-shaped value inside an +environment `env_clear` promises is hermetic (#221). ## 6. Input encoding diff --git a/docs/LIMITATIONS.md b/docs/LIMITATIONS.md index 46cc3c1..e48bcea 100644 --- a/docs/LIMITATIONS.md +++ b/docs/LIMITATIONS.md @@ -112,8 +112,8 @@ CHANGELOG entry. reporting, the cursor's visibility and shape, the character sets — and leaves the alternate screen alone; attributes, margins, origin and insert modes and the keypad are not modelled. -- **Two SGR style attributes are not modeled.** Overline (`SGR 53`) and double - underline (`SGR 21`) do not reach [`Style`](https://docs.rs/termlens/latest/termlens/struct.Style.html), +- **Two SGR style attributes are not modelled.** Overline (`SGR 53`) and + double underline (`SGR 21`) do not reach [`Style`](https://docs.rs/termlens/latest/termlens/struct.Style.html), so `with_styles()` cannot distinguish those attributes from a plain cell. Blink reaches the ANSI, HTML and SVG renderings. The HTML one stops animating under `prefers-reduced-motion`; the SVG one cannot, since SMIL @@ -180,4 +180,4 @@ CHANGELOG entry. release it after asserting — see the "instant-exit caveat" in [DESIGN.md](DESIGN.md). - Exotic grapheme clusters render as the vt100 crate renders them; the - unicode-torture fixture pins the current behavior. + unicode-torture fixture pins the current behaviour. diff --git a/docs/RELEASING.md b/docs/RELEASING.md index 3591866..a003f4d 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -78,8 +78,13 @@ gh run watch # ubuntu, macos, windows × 5 shar # action pin lives in three hand-maintained files, and releases bumped two # of the three twice before the gate that catches it existed (#386); # `check-report-pin.sh` fails whenever one disagrees with this number. +# Two more copies of the version have no gate: SKILL.md's "Written +# against **termlens X.Y.Z**" line, and the bug report form's version +# placeholder, which still said 0.5.0 through eleven later releases, +# 0.6.0 to 0.11.1, until #432 caught it. $EDITOR Cargo.toml crates/termlens-cli/Cargo.toml $EDITOR README.md .github/actions/report/README.md skills/termlens/SKILL.md +$EDITOR .github/ISSUE_TEMPLATE/bug_report.yml # placeholder: "X.Y.Z (or git SHA)" cargo check --workspace # refreshes Cargo.lock # 2. Move the CHANGELOG section. A `- **Breaking:**` bullet moves with it, diff --git a/fixtures/emit/src/main.rs b/fixtures/emit/src/main.rs index 3d75494..8284ada 100644 --- a/fixtures/emit/src/main.rs +++ b/fixtures/emit/src/main.rs @@ -16,9 +16,10 @@ //! two writes says so with two steps. `--wait` at EOF exits 0: a harness that //! closed the terminal has finished with it. //! -//! Fixture rules: **no timing but the explicit `--sleep` and the 2s of -//! `--read-quiet`; std, plus `libc` on Unix for the terminal-mode, ioctl and -//! signal steps and nothing else.** A dependency with behaviour of its own +//! Fixture rules: **no timing but the explicit `--sleep`, the 2s of +//! `--read-quiet`, and the 10 ms poll `--idle` waits for SIGTERM with; std, +//! plus `libc` on Unix for the terminal-mode, ioctl and signal steps and +//! nothing else.** A dependency with behaviour of its own //! would make this a second thing the suite tests; a clock would make it a //! second source of flakiness. Off Unix the terminal-mode steps are accepted //! and do nothing — the tests that need them are Unix-only for other reasons.