Skip to content

api-ergonomics-pass-2: Line shorthands, AppendRule, Collapsible.AppendLine, paste routing, multi-select Back (0.2.0-rc.3)#8

Merged
ThatRendle merged 12 commits into
mainfrom
change/api-ergonomics-pass-2
May 29, 2026
Merged

api-ergonomics-pass-2: Line shorthands, AppendRule, Collapsible.AppendLine, paste routing, multi-select Back (0.2.0-rc.3)#8
ThatRendle merged 12 commits into
mainfrom
change/api-ergonomics-pass-2

Conversation

@ThatRendle
Copy link
Copy Markdown
Contributor

Second dcli public-API ergonomics pass (follows api-ergonomics-pass-1 rc.1 and multi-line-dialog-prompts rc.2). Closes the remaining §14.4 dmon-wizard-port friction plus three contracts the specs already named but the code never satisfied. Released as dcli + dcli.testing 0.2.0-rc.3. No breaking changes — every addition is a new factory, overload, method, or opt-in flag.

Sections (one commit each, worker→reviewer→gates per the OpenSpec apply workflow)

§ Change Capability
1 Line.Bold/Dim/Fg/Bg(string) single-style factories styled-text (ADDED)
2 IScrollback.AppendRule() — width-aware rule resolved at paint time inline-scrollback (closes spec/impl gap)
3 ICollapsible.AppendLine(Line)/(string) — incremental hidden-line append inline-scrollback (MODIFIED)
4 PasteEvent routing into the owned input editor (+ secret first-edit flip) fixed-region (MODIFIED)
5 MultiSelectRequest.AllowBack via [ (the contended edit) fixed-region (MODIFIED)
6 Sample migration onto the new Line factories samples
7 Validation & packaging (0.2.0-rc.3)

Notable

  • §5 reverses the previously-shipped fixed-region sentence "MultiSelectRequest SHALL continue to omit AllowBack" — settled by binding a distinct key ([, not the ambiguous Backspace-at-toggle). Multi-select [ fires at any time; Select/Choice additionally accept [ (movement-suppressed like their pass-1 Backspace).
  • §2/§3 close gaps the specs already named (AppendRule was mandated-but-unimplemented; Collapsible.AppendLine was a documented gap).
  • §4 terminal-safety verified: pasted escape bytes are neutralized on the render path (Segment.Raw is not on the paste path); paste flips the secret-default _userEdited flag.

Quality

  • 827 → 856 tests (+29), all green. Build 0 warnings (analyzers as warnings-as-errors), dotnet format clean, openspec validate --strict clean.
  • Reviewer caught and the worker fixed 3 real issues pre-commit (a test reinventing HeadlessTerminal; an orphaned never-instantiated command file; a missing multi-select regression guard).
  • No HITL required — §4 and §5 are fully covered headlessly.
  • All four NuGet artifacts produced (dcli/dcli.testing .nupkg+.snupkg).
  • Change archived to openspec/changes/archive/2026-05-29-api-ergonomics-pass-2/ (with DEVLOG); delta specs synced into openspec/specs/{styled-text,inline-scrollback,fixed-region}/.

🤖 Generated with Claude Code

ThatRendle and others added 12 commits May 29, 2026 21:54
OpenSpec change scaffold for the second public-API ergonomics pass:
Line single-style factories, Scrollback.AppendRule, incremental
Collapsible.AppendLine, PasteEvent editor routing, and multi-select
DialogOutcome.Back via '['. Validates --strict.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ection 1)

- 1.1 Line.Bold(string) — single bold segment via FromText
- 1.2 Line.Dim(string) — single dim segment via FromText
- 1.3 Line.Fg(string, Color) — single fg-colored segment, Format.None
- 1.4 Line.Bg(string, Color) — single bg-colored segment, Format.None
- 1.5 XML docs: sanitizing wrappers; no Italic/Underline/Reverse/Strikethrough/Raw
- 1.6/1.7 9 LineTests: single-segment, FromText equivalence, control-byte sanitize parity

Thin sanitizing wrappers over Line.FromText; Segment.Raw/LineBuilder.Raw remain
the only verbatim seams. No implicit string->Line conversion. Reviewer clean.
Gates: build 0 warnings, 836 tests green (+9), format clean, validate --strict clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 2.1 RuleBlock : ILineObject — width-aware horizontal rule resolved at paint time
- 2.2 IScrollback.AppendRule() with XML doc
- 2.3 ScrollbackSurface.AppendRule() posts private nested AppendRuleToScrollbackCommand
- 2.4 removed the "// AppendRule ... deferred" documented-gap comment
- 2.5/2.6 2 HeadlessTerminal/FrameSnapshot tests: render-at-width + resize re-expansion
- FakeScrollback gains an AppendRule() stub for the new interface member

Closes the spec/impl gap: inline-scrollback "Scrollback command surface" already
mandated a rule command. Rule width resolves to model.Columns at render time, so it
re-expands across resize. Loop-thread-only mutation. Reviewer: clean after rewriting
the test onto the real harness. Gates: build 0 warnings, 838 tests green (+2),
format clean, validate --strict clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ion 3)

- 3.1 ICollapsible.AppendLine(Line)/(string) with one-way no-op-after-expand/horizon docs
- 3.2 ScrollbackModel.AppendToCollapsible guards mirror ExpandCollapsible
- 3.3 CollapsibleHandle posts AppendLineToCollapsibleFacadeCommand; "documented gap" remarks closed
- 3.4-3.7 6 model-level tests: grow-on-expand, no-op-after-expand, no-op-after-horizon-freeze,
  oversized-reprint ordering regression, AppendHidden unit, ctor-copies-list

Collapsible._hiddenLines becomes an owned List<Line> (.ToList() copy — also closes a
latent off-thread-mutation leak). Append touches only the pre-expansion snapshot and
never initiates a reprint, so it cannot worsen the oversized-reprint ordering edge
(design Decision 4). Loop-thread-only mutation. Reviewer: clean after deleting an
orphaned unused command file. Gates: build 0 warnings, 844 tests green (+6),
format clean, validate --strict clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 4.1 LoopEngine.ApplyInputEvent gains a PasteEvent case (overlay-first intercept chain)
- 4.2 base-editor paste inserts at caret via TextBuffer.Insert(string), emits InputChanged
- 4.3 InputDialog.HandlePaste flips the sticky _userEdited flag (secret first-edit)
- IOverlay.HandlePaste(string): InputDialog inserts+consumes, modal Dialog consumes+ignores,
  Autocomplete passes through (cursor stays in base editor)
- 4.4-4.7 4 tests: caret-advance, multiline wrap, secret-default flip + Submit value, modal no-leak

PasteEvent was previously dropped by the loop. Pasted control/escape bytes are
neutralized on the render path (TextBuffer.Render / MaskLine build via the sanitizing
Segment ctor; Segment.Raw is not on the paste path). Loop-thread-only mutation; no new
restore-path state. Reviewer clean first pass; no HITL needed. Gates: build 0 warnings,
848 tests green (+4), format clean, validate --strict clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 5.1 MultiSelectRequest gains AllowBack (default false; mirrors SelectRequest ctors)
- 5.2 Dialog.HandleKey: '[' -> OverlayCloseKind.Back for multi-select at any time
- 5.3 Select/Choice additionally accept '[' as a secondary Back key (movement-suppressed)
- Terminal.MultiSelectAsync passes allowBack: req.AllowBack; Back maps to DialogOutcome.Back
- 5.4/5.5 8 tests: multi '['->Back, survives Space-toggle, survives arrow-move, default-false
  no-op; select/choice '['-before-move->Back, '['-after-move no-op; Backspace regression

Reverses the prior "MultiSelectRequest SHALL continue to omit AllowBack" — settled by
binding a distinct key ('[') instead of the ambiguous Backspace-at-toggle. One gated
branch handles all three dialogs (multi: any time; single/choice: before movement).
Removed the obsolete test that pinned the reversed contract. Reviewer clean (6 dims).
Gates: build 0 warnings, 856 tests green (+8), format clean, validate --strict clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…tion 6)

- 6.1 WizardRenderer.cs: 13 single-style LineBuilder sites -> Line.Bold/Dim/Fg (0 left)
- 6.2 Program.cs: 22 single-style sites migrated; 11 multi-segment chains left untouched
- 6.3 skipped (AppendRule/AppendLine demo not a natural fit)

Samples-only; no library/test changes. Validates the §1 ergonomics win at the
~24 concrete call sites that motivated the headline factories. Reviewer clean.
Gates: build 0 warnings, 856 tests green (unchanged), format clean, validate clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…tion 7)

- 7.1-7.2 all four gates green in Release (build 0 warnings, 856 tests, format, validate)
- 7.3 Version 0.2.0-rc.2 -> 0.2.0-rc.3 in Dcli.csproj + Dcli.Testing.csproj
- 7.4 dotnet pack produced dcli.0.2.0-rc.3.{nupkg,snupkg} + dcli.testing.0.2.0-rc.3.{nupkg,snupkg}
- 7.5 per-section commit hashes recorded in DEVLOG

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
All 7 sections landed; released as dcli + dcli.testing 0.2.0-rc.3. DEVLOG flipped
to shipped framing ahead of /opsx:archive.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Move change to openspec/changes/archive/2026-05-29-api-ergonomics-pass-2/ and
sync the delta specs into the live specs:
- styled-text: + Single-style line shorthand factories
- inline-scrollback: ~ One-way collapsible, ~ Scrollback command surface
- fixed-region: ~ Owned input editor, ~ Awaitable modal dialogs

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ThatRendle ThatRendle merged commit e7e7276 into main May 29, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant