Skip to content

Converged naming, structure, API shape and the comment register across the library. - #154

Merged
AlexSkrypnyk merged 27 commits into
mainfrom
feature/converge-conventions
Aug 12, 2026
Merged

Converged naming, structure, API shape and the comment register across the library.#154
AlexSkrypnyk merged 27 commits into
mainfrom
feature/converge-conventions

Conversation

@AlexSkrypnyk

@AlexSkrypnyk AlexSkrypnyk commented Aug 11, 2026

Copy link
Copy Markdown
Member

Summary

A convergence pass that makes the codebase internally consistent with itself. Twelve inconsistency classes landed as behavior-preserving changes, one commit converged source comments onto the project's technical register, and a further seven classes were resolved after the deferred judgment calls were decided. Every commit was gated on the full test suite (2918 tests) plus PHPCS, PHPStan level 9 and Rector, all green throughout.

The package is tagged 0.1.x, so the public-surface changes below are deliberate and were taken while they are still cheap.

Behavior-preserving convergence

Naming

  • The five Block\Field methods that return why a candidate value is invalid now share the *Violation suffix already anchored in CollectCapableInterface::requiredViolation and ConstrainCapableInterface::boundsViolation. Collector::optionsError(), Template::partError() and the separate refuses()/refusal() rejection channel are deliberately untouched.
  • Four prefix-less boolean accessors take the dominant is* prefix: Option::selectable(), SelectionCapable*::currentSelectable(), CompletionCapableTrait::completionAvailable() and LayoutManager::nameable(). The existing is* / has* / third-person-verb system (binds, matches, acceptsValue) is left intact.
  • The KeyMap property is cased $keyMap and its constructor argument $key_map, per the project rule that properties are camelCase and method arguments snake_case. This includes the string-based ReflectionProperty lookup in TuiTest, which would otherwise have broken silently.
  • Region's head-packed property is renamed $head to pair with the existing $tail; blocks() still returns head and tail merged, so the property and the accessor no longer disagree.
  • The signed cursor-move amount is $delta, matching StepCapableInterface::stepBy() and KeyRouter::moveBy(). OptionsCapableTrait::stepCursor() keeps $dir, which is a unit scan direction rather than an amount.
  • Field::optionLine() names its narrowed theme argument $elements, matching the seven sibling methods in the same class.
  • DefaultTheme::statusSymbol() becomes statusGlyph(), the vocabulary used everywhere else in the theme core.

Structure

  • Twelve files are brought onto the project's vertical-rhythm rule: one blank line around control blocks and between consecutive guards, exactly one blank line between property declarations. Whitespace only - verified that every changed line in that commit is blank.
  • Three declarations are brought onto the 160-character line rule: Suggest's 208-character implements list is wrapped one interface per line, mirroring Search; the single-parameter promoted constructors in KeyRouter and AbstractLayout collapse back onto one line.
  • #[\Override] is applied exactly where a concrete inherited method is overridden: removed from Template::liveValue(), which implements an abstract base method, and added to SelectionBoundedTrait::renderConstraint(), which overrides a concrete AbstractField default.

API shape

  • Legend::advertise(), Legend::clear() and Breadcrumb::trail() return static with @return static, matching the twelve fluent setters already declared that way across Panel, Progress, Markup and Actions.
  • AgentHelp's constructor takes (root, context, envPrefix), matching SchemaGenerator and SchemaValidator.

Comments

  • Source comments across 55 files converge onto the project's technical register: declarative, present tense, one cause and one effect, no metaphors of agency, no epigrams. Wording only - no comment claim was altered in that pass.

Tensions resolved

These were the judgment calls a behavior-preserving pass deliberately would not make on its own. Each was decided explicitly and then applied.

The choice-list row is an option

The widest vocabulary split in the codebase: one selectable item was entry in the Field API and theme elements, option in the value object and builder, and row in several docblocks. It converges on option, because Option, OptionType, FieldBuilder::option() and OptionsCapable* already carried it.

This renames the public FieldElementsInterface methods - fieldEntry(), fieldEntryMarker(), fieldEntrySeparator(), fieldEntrySelector(), fieldEntryNote(), fieldEntryDescription() all become fieldOption*. A consumer with a custom theme must rename those methods. 43 files changed.

Terminal extent is columns and rows

The two dialects were split about evenly, with ScreenController mixing both in one file. columns/rows wins because the renderer, Region, the whole layout family and the public LayoutInterface already spoke it.

Terminal::width() and Terminal::height() become Terminal::columns() and Terminal::rows(), with BufferedTerminal renamed in lockstep so the double still mirrors its subject. Overlay's $area_width and Scroller's $height follow. ScreenRenderer::height() becomes rows() and its pieces() array key changes from height to rows.

String-measurement helpers (Ansi::width(), Markup::width()), theme frame widths and content widths in Box/Table are a different concept and keep their names.

FormException for consumer-declaration mistakes

The original plan reported six raw \InvalidArgumentException throws. Auditing the repo found 38, spanning four distinct families, so a blanket conversion would have swept in errors that are not form declarations at all.

Sixteen throws in the declaration family now throw FormException: Actions::select(), Region::fixed()/flex(), AbstractLayout region declaration, KeyMap binding validation, DefaultTheme option validation, Translator source, InputResolver prompts and PagingCapableTrait page size. Because FormException extends \InvalidArgumentException, this is catch-compatible: existing catch (\InvalidArgumentException) still fires.

Twenty-two throws stay raw and internally consistent as their own families: the eight "theme cannot draw X" errors, the nine registry and class-validation errors, and the five stream and programming errors.

Naming ties settled

  • The element under the cursor is current*. Template::$active/activeName() become $current/currentName(), and AbstractField::highlightedDescription() becomes currentDescription(). Template composes TextEditCapableTrait, which already owns $cursor for the buffer offset, so $current avoids that collision.
  • The enum suffix is -Type. OptionKind becomes OptionType and MarkupKind becomes MarkupType, both files renamed to match PSR-4. Field::valueKind() becomes valueType().
  • The selection move verb is moveCursor(). Reorder::move() and Template::move() follow FilePicker. OptionsCapableTrait::stepCursor() stays - it is a unit scan with different semantics - and Calendar::move(Key) stays, being key interpretation rather than cursor movement.

Public surface aligned

  • Output::box() takes its title first, matching its sibling Output::card().
  • Progress::run() narrows callable to \Closure, the convention everywhere else in the codebase.
  • renderBanner() returns list<string> like renderCard(), renderText(), renderTable() and renderDefinitions(). Rendered output is unchanged - callers join with a newline exactly as the imploded string did.
  • ScreenTester::theme() and TuiTester::theme() both accept ThemeInterface|string, so an instance and a name work on either harness. The three session-abort conventions are out of scope and unchanged.

Grid capacity error

PanelBuilder::descend() reported declares %d slot(s) for %d window(s) while feeding it (count(windows()), count(panels)). The counts were in the right order; the nouns were inverted - the grid's declared cells are windows() in code, and the things needing one are panels. Both copies of the message (in PanelBuilder and GridLayout::assertDeals()) now read declares %d window(s) for %d panel(s)., and assertDeals()'s parameter is renamed $panels to match. This changes observable message text.

One scroll subsystem

The renderer re-derived the overflow-indicator rule inline in moved() and packed(), while Scroller plus Viewport did the same work on the controller path - three implementations of one rule.

Both renderer paths now resolve their window through Scroller::viewport() and slice through Scroller::slice(), so the docblock claim that Scroller is "the one place the scroll-indicator flags are decided" is now true. Verified safe first: the two clamps looked divergent because ScrollCapableTrait::offset() lacks the outer max(0, ...) that Scroller::clamp() has, but scrollTo() already applies max(0, $row), so the difference was unreachable.

Documentation claims corrected

Nine comments asserted something the code does not do. The register pass deliberately left them alone, because correcting a claim inside a wording pass hides a behavior-documentation fix in a diff nobody reviews as one. They are corrected in their own commit instead.

  • src/Block/AbstractBlock.php described the narrowing failure as a type error. elements() throws \InvalidArgumentException.
  • src/Block/Field.php still described the narrowed theme argument as "The theme." after the rename.
  • src/Block/Panel.php claimed ids() returns every row carrying an id. It collects from Field, Markup and Progress only, so nested panel ids are excluded.
  • src/Builder/FieldBuilder.php carried a malformed sentence in the class docblock.
  • src/Field/Capability/OptionsCapableTrait.php claimed the cursor is only ever placed on a selectable row. firstSelectable() falls back to index 0 when no row is selectable.
  • src/Field/Rating.php called typing inert on any scale running past nine. One digit names one point, so 0 to 9 stay reachable on a 1-15 scale; only the points above nine are not.
  • src/Field/Reorder.php named Space, Up and Down in two comments. The actions resolve through ScopedKeyMap, so a vim preset or custom map rebinds them.
  • src/Screen/Capability/ScrollCapableInterface.php did not declare the \LogicException that ScrollCapableTrait::scrollTo() throws for a surface that does not scroll.
  • src/Terminal/Ansi.php claimed link() drops every control byte. stripControl() matches /[\x00-\x1F\x7F]/, which is the C0 bytes and DEL.

Still open

Four comment claims are still flagged and unfixed. Each needs a decision about intended behavior rather than a wording change, so none belongs in this PR.

  • src/Tui.php claims another facade constructed or configured meanwhile may have replaced the shared translator. Translator::setShared() is called only from operations, so only another facade's operation can replace it.
  • src/Answers/Answers.php refers to items(). The snapshots live in the public $items property; per-id access is item($id).
  • src/Translation/Translator.php claims a missing bundled directory would otherwise error on every construction. Catalogs load lazily from catalog() on first translate, so the error would surface at first use.
  • src/Field/Suggest.php describes a fixed option set. adoptQueryRows() replaces the values whenever a query source settles.

Six convergence classes were considered and deliberately left alone.

  • Transform names stay a string const list rather than an enum. They mirror external Str2Name methods resolved by string, cross the consumer boundary in derive() declarations and are serialized into the JSON schema, so an enum would have to round-trip back to strings at both boundaries.
  • The verb settle still carries four distinct operations across Collector, Field, KeyRouter and ScreenController. Renaming ScreenController::settled() to settle() was evaluated and rejected, because resettle() already exists in the same class and calls it.
  • SelectionBoundedTrait still breaks the <Verb>CapableInterface + <Verb>CapableTrait pattern while living in Capability/. All three candidate fixes coin a name or a contract the codebase never used.
  • AgentHelp and SchemaGenerator still emit two key vocabularies (x-asked-when against asked_when) from one per-field pipeline. Both are machine-readable output consumed outside the library.
  • Screen\Source and Answers\Provenance remain two enums for where a value came from, bridged by a match(TRUE) in Collector::provenance().
  • FilePicker and Suggest still hand-roll logic their sibling capability traits provide, with deliberate behavioral deltas (append-only editing, string rows, a -1 idle cursor).

The <noun>Text() getter convergence was approved but found inapplicable: both candidates, Panel::preparation() and Progress::workload(), return ?\Closure rather than a string, so the Text suffix cannot apply.

Coverage note

The comment-register pass completed fully on 2 of 16 source slices and partially on the rest before the run ended; 55 of 217 source files carry comment changes from it. The largest files - ScreenController, ScreenRenderer, DefaultTheme and AbstractTheme - are largely untouched by that pass. It is idempotent, so re-running the convergence finishes the remainder without redoing what has landed.

Before / After

NAMING                    before                          after
                          ├─ templateError()              ├─ templateViolation()
  validity checks         ├─ entryError()          ──▶    ├─ optionViolation()
                          ├─ rankingError()               ├─ rankingViolation()
                          └─ limitRefusal()               └─ limitViolation()

                          ├─ Option::selectable()         ├─ Option::isSelectable()
  boolean accessors       ├─ currentSelectable()   ──▶    ├─ isCurrentSelectable()
                          └─ nameable()                   └─ isNameable()

                          ├─ Field::entries()             ├─ Field::options()
  choice-list row         ├─ fieldEntry()          ──▶    ├─ fieldOption()
                          └─ OptionKind                   └─ OptionType

                          ├─ Terminal::width()            ├─ Terminal::columns()
  terminal extent         ├─ Terminal::height()    ──▶    ├─ Terminal::rows()
                          └─ ScreenRenderer::height()     └─ ScreenRenderer::rows()

API SHAPE
                          ├─ box($body, $title)           ├─ box($title, $body)
  primitives              ├─ run(callable $work)   ──▶    ├─ run(\Closure $work)
                          └─ renderBanner(): string       └─ renderBanner(): list<string>

  errors                  16x \InvalidArgumentException ──▶ 16x FormException
                          (22 left raw, in 3 coherent families)

ARCHITECTURE              before                          after

  scroll indicator        ScreenRenderer::moved()  ─┐
  rule, 3 copies          ScreenRenderer::packed() ─┼──▶  Scroller::viewport()
                          Scroller::viewport()     ─┘     (the one home)

Summary by CodeRabbit

  • New Features

    • Testing utilities now accept theme instances or theme names.
    • Banner rendering provides individual lines for improved output handling.
  • API Updates

    • Renamed field, option, markup, and terminal sizing APIs for clearer terminology.
    • Updated box output to accept the title before its content.
    • Progress callbacks now require closures.
    • Invalid configuration errors now use a form-specific exception type.
  • Documentation

    • Clarified behavior across forms, fields, layouts, rendering, validation, and terminal features.

@AlexSkrypnyk AlexSkrypnyk added the AUTOMERGE Pull request has been approved and set to automerge label Aug 11, 2026
@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown

@AlexSkrypnyk AlexSkrypnyk removed the AUTOMERGE Pull request has been approved and set to automerge label Aug 11, 2026
@github-actions

This comment has been minimized.

@codecov

codecov Bot commented Aug 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.10526% with 21 lines in your changes missing coverage. Please review.
✅ Project coverage is 98.05%. Comparing base (12293a8) to head (6f54886).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/Block/Field.php 69.44% 11 Missing ⚠️
src/Testing/ScreenTester.php 72.72% 3 Missing ⚠️
src/Testing/TuiTester.php 85.71% 2 Missing ⚠️
src/Builder/PanelBuilder.php 0.00% 1 Missing ⚠️
src/Screen/Layout/LayoutManager.php 50.00% 1 Missing ⚠️
src/Screen/Region.php 83.33% 1 Missing ⚠️
src/Screen/ScreenRenderer.php 90.90% 1 Missing ⚠️
src/Theme/Override/FieldOverrides.php 50.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #154      +/-   ##
==========================================
- Coverage   98.14%   98.05%   -0.10%     
==========================================
  Files         150      150              
  Lines        6033     6054      +21     
==========================================
+ Hits         5921     5936      +15     
- Misses        112      118       +6     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 32 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8053365e-e9ce-4fc9-aae8-17b49863cc78

📥 Commits

Reviewing files that changed from the base of the PR and between 373b2dd and 6f54886.

📒 Files selected for processing (44)
  • AGENTS.md
  • docs/content/fields/anatomy.mdx
  • docs/content/specification.mdx
  • docs/content/themes.mdx
  • playground/09-themes-elements.php
  • playground/themes/OceanTheme.php
  • src/Block/Element/FieldElementsInterface.php
  • src/Block/Field.php
  • src/Block/Prose.php
  • src/Builder/FieldBuilder.php
  • src/Builder/Form.php
  • src/Condition/Condition.php
  • src/Field/FieldFactory.php
  • src/Schema/DefaultResolver.php
  • src/Schema/SchemaGenerator.php
  • src/Screen/Collector.php
  • src/Screen/ScreenController.php
  • src/Screen/ScreenRenderer.php
  • src/Theme/Capability/ColorSchemeCapableInterface.php
  • src/Theme/Capability/ColorSchemeCapableTrait.php
  • src/Theme/Capability/MarkdownCapableInterface.php
  • src/Theme/Capability/UnicodeCapableInterface.php
  • src/Theme/Capability/UnicodeCapableTrait.php
  • src/Theme/DefaultTheme.php
  • src/Theme/Override/FieldOverrides.php
  • src/Theme/ThemeBuilder.php
  • src/Tui.php
  • tests/phpunit/Unit/Block/CapabilityTest.php
  • tests/phpunit/Unit/Block/FieldBlockTest.php
  • tests/phpunit/Unit/Block/FieldDeclarationTest.php
  • tests/phpunit/Unit/Block/OptionTest.php
  • tests/phpunit/Unit/Builder/FormTest.php
  • tests/phpunit/Unit/ControlBytesTest.php
  • tests/phpunit/Unit/Field/FieldFactoryTest.php
  • tests/phpunit/Unit/Screen/CollectorTest.php
  • tests/phpunit/Unit/Screen/KeyRouterTest.php
  • tests/phpunit/Unit/Screen/ScreenControllerTest.php
  • tests/phpunit/Unit/Screen/ScreenParityTest.php
  • tests/phpunit/Unit/Theme/BuiltinThemesTest.php
  • tests/phpunit/Unit/Theme/ElementDelegationTest.php
  • tests/phpunit/Unit/Theme/SupportTest.php
  • tests/phpunit/Unit/Theme/ThemeBuilderTest.php
  • tests/phpunit/Unit/Theme/ThemeManagerTest.php
  • tests/phpunit/Unit/Theme/ThemeTest.php
📝 Walkthrough

Walkthrough

This change aligns option, markup, terminal, theme, layout, exception, and rendering APIs. It also updates documentation, tests, examples, and playground themes.

Changes

API and implementation alignment

Layer / File(s) Summary
Option and field terminology
src/Block/*, src/Field/*, src/Builder/*, src/Schema/*, src/Screen/Collector.php, tests/phpunit/Unit/Block/*, tests/phpunit/Unit/Field/*
Renamed OptionKind to OptionType, entry APIs to option APIs, and selectability methods to isSelectable(). Updated validation, selection, completion, rendering, callers, and tests.
Theme and output contracts
src/Block/Element/*, src/Theme/*, src/Primitive/*, playground/themes/*, tests/phpunit/Unit/Theme/*, tests/phpunit/Unit/Primitive/*
Renamed fieldEntry* theme methods to fieldOption*. Changed renderBanner() to return line arrays and reordered Output::box() arguments.
Terminal, layout, and screen handling
src/Terminal/*, src/Screen/*, src/Tui.php, src/Testing/*, tests/phpunit/Unit/Terminal/*, tests/phpunit/Unit/Testing/*
Renamed terminal dimensions to rows() and columns(), integrated Scroller, renamed layout and storage helpers, and added direct theme-instance support to testers.
Contracts, exceptions, and documentation
src/Answers/*, src/Block/*, src/Builder/*, src/Input/*, src/Translation/*, docs/content/output.mdx, playground/18-output-box.php
Updated PHPDoc, constructor and callback contracts, and declaration-related exceptions. Updated examples and named constructor arguments.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • drevops/tui#3: Direct overlap with the theme API and rendering changes.
  • drevops/tui#27: Direct overlap with OptionType, option APIs, and selectable-option handling.
  • drevops/tui#143: Direct overlap with block, field, theme, layout, and screen API refactors.

Suggested labels: A1

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the broad naming, structure, API, and documentation convergence described in the pull request.
Docstring Coverage ✅ Passed Docstring coverage is 97.35% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/converge-conventions

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/Block/AbstractBlock.php`:
- Around line 14-16: Update the AbstractBlock class documentation describing
elements() so it names \InvalidArgumentException instead of \TypeError when the
theme lacks a declared element interface, while preserving the existing behavior
description.

In `@src/Block/Field.php`:
- Around line 2341-2342: Update the PHPDoc for entryLine() so the $elements
parameter description accurately identifies it as the narrowed field elements,
replacing the incorrect “The theme.” text while preserving the declared
FieldElementsInterface type.

In `@src/Block/Panel.php`:
- Around line 392-395: Update the documentation for Panel::ids() to describe
only the IDs it returns: those from Field, Markup, and Progress blocks.
Explicitly state that IDs belonging to nested Panel blocks are excluded.

In `@src/Block/Tree.php`:
- Around line 14-16: Correct the ownership documentation near Tree so it no
longer claims the headless answer snapshot uses Tree’s flattening traversal.
Keep the implementation unchanged unless deliberately updating
Answers::forTree() to delegate to Tree is required; ensure the comment
accurately describes only the consumers that actually use Tree.

In `@src/Builder/FieldBuilder.php`:
- Around line 29-31: Update the documentation sentence near the builder
declaration to replace the malformed phrase “and one the kind has nowhere to
put” with grammatically complete wording that clearly states declarations
without a valid answer kind are rejected at their original location.

In `@src/Field/Capability/OptionsCapableTrait.php`:
- Around line 15-18: Update the cursor invariant documentation in
OptionsCapableTrait to state that the cursor points to a selectable row when one
exists, and explicitly document that firstSelectable() falls back to index 0
when no row is selectable, which may reference a non-selectable row or no row.

In `@src/Field/Rating.php`:
- Around line 97-98: Update the documentation near applyChar() to clarify that
digit input selects values 0–9 that fall within the configured scale; scales
with min <= 9 and max > 9 remain partially selectable, while values above 9
cannot be selected by digit input. Remove wording that implies every scale
extending past nine is inert.

In `@src/Field/Reorder.php`:
- Around line 95-96: Update the comments in Reorder::handle() around the Accept,
Grab, MoveUp, and MoveDown actions to describe action names and movement
directions rather than fixed Space, Up, or Down keys. Keep the comments accurate
for custom ScopedKeyMap bindings, including the note that accepting a drop
commits no change mid-move.

In `@src/Screen/Capability/ScrollCapableTrait.php`:
- Around line 8-15: Add an `@throws \LogicException` declaration to the
`ScrollCapableInterface::scrollTo()` method documentation, matching the
exception behavior implemented by `ScrollCapableTrait::scrollTo()`.

In `@src/Terminal/Ansi.php`:
- Around line 67-69: Update the comment in Ansi::link() to state that
stripControl() removes C0 control bytes and DEL, rather than claiming every
control byte is dropped; do not change the filter unless the implementation is
explicitly required to reject C1 controls as well.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4d172b2b-bd71-4d52-b23b-6562598b5273

📥 Commits

Reviewing files that changed from the base of the PR and between 12293a8 and dafbc42.

📒 Files selected for processing (82)
  • src/Answers/Answers.php
  • src/Answers/Provenance.php
  • src/Answers/SummaryFormatter.php
  • src/Answers/ValueFormatter.php
  • src/Block/AbstractBlock.php
  • src/Block/BlockInterface.php
  • src/Block/Breadcrumb.php
  • src/Block/Capability/ActivateCapableInterface.php
  • src/Block/Field.php
  • src/Block/FieldType.php
  • src/Block/Legend.php
  • src/Block/Markup.php
  • src/Block/Option.php
  • src/Block/Panel.php
  • src/Block/Progress.php
  • src/Block/TableSpec.php
  • src/Block/Tree.php
  • src/Builder/FieldBuilder.php
  • src/Builder/Form.php
  • src/Builder/PanelBuilder.php
  • src/CancelException.php
  • src/CollectException.php
  • src/Discovery/Dotenv.php
  • src/Discovery/Scan.php
  • src/Field/AbstractField.php
  • src/Field/Calendar.php
  • src/Field/Capability/CompletionCapableTrait.php
  • src/Field/Capability/FilterCapableInterface.php
  • src/Field/Capability/FilterCapableTrait.php
  • src/Field/Capability/OptionsCapableInterface.php
  • src/Field/Capability/OptionsCapableTrait.php
  • src/Field/Capability/PagingCapableTrait.php
  • src/Field/Capability/PlaceholderCapableTrait.php
  • src/Field/Capability/QueryOptionsCapableInterface.php
  • src/Field/Capability/QueryOptionsCapableTrait.php
  • src/Field/Capability/SelectionBoundedTrait.php
  • src/Field/Capability/SelectionCapableInterface.php
  • src/Field/Capability/SelectionCapableTrait.php
  • src/Field/Capability/TextEditCapableInterface.php
  • src/Field/Capability/TextEditCapableTrait.php
  • src/Field/FieldFactory.php
  • src/Field/FilePicker.php
  • src/Field/Rating.php
  • src/Field/Reorder.php
  • src/Field/Search.php
  • src/Field/Suggest.php
  • src/Field/Template.php
  • src/FormException.php
  • src/Handler/HandlerRegistry.php
  • src/Input/Action.php
  • src/Input/Binding.php
  • src/Input/KeyMap.php
  • src/Input/KeyParser.php
  • src/Resolver/InputResolver.php
  • src/Schema/AgentHelp.php
  • src/Schema/SchemaGenerator.php
  • src/Schema/SchemaValidator.php
  • src/Screen/Capability/BorderCapableInterface.php
  • src/Screen/Capability/BorderCapableTrait.php
  • src/Screen/Capability/ScrollCapableInterface.php
  • src/Screen/Capability/ScrollCapableTrait.php
  • src/Screen/Collector.php
  • src/Screen/ExternalEditor.php
  • src/Screen/KeyRouter.php
  • src/Screen/Layout/AbstractLayout.php
  • src/Screen/Layout/LayoutManager.php
  • src/Screen/Overlay.php
  • src/Screen/Region.php
  • src/Screen/Scroller.php
  • src/Terminal/Ansi.php
  • src/Terminal/Terminal.php
  • src/Testing/TuiTester.php
  • src/Theme/DefaultTheme.php
  • src/Translation/Translator.php
  • src/Tui.php
  • src/Utils/Strings.php
  • tests/phpunit/Unit/Block/EntryTest.php
  • tests/phpunit/Unit/Block/FieldBlockTest.php
  • tests/phpunit/Unit/Block/FieldDeclarationTest.php
  • tests/phpunit/Unit/Schema/AgentHelpTest.php
  • tests/phpunit/Unit/Translation/TranslationRenderTest.php
  • tests/phpunit/Unit/TuiTest.php

Comment thread src/Block/AbstractBlock.php Outdated
Comment thread src/Block/Field.php Outdated
Comment thread src/Block/Panel.php Outdated
Comment thread src/Block/Tree.php
Comment thread src/Builder/FieldBuilder.php Outdated
Comment thread src/Field/Capability/OptionsCapableTrait.php Outdated
Comment thread src/Field/Rating.php Outdated
Comment thread src/Field/Reorder.php Outdated
Comment on lines +8 to +15
* Holds a surface's offset; scrollTo() throws for one that does not scroll.
*
* @package DrevOps\Tui\Screen\Capability
*/
trait ScrollCapableTrait {

/**
* Whether this surface's contents may outrun it.
* Whether this surface's contents may overflow it.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Document the scrollTo() exception on the interface.

ScrollCapableTrait::scrollTo() throws \LogicException when the surface is not scrollable. ScrollCapableInterface::scrollTo() does not declare this exception. Add @throws \LogicException to the interface method so interface callers see the runtime contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Screen/Capability/ScrollCapableTrait.php` around lines 8 - 15, Add an
`@throws \LogicException` declaration to the
`ScrollCapableInterface::scrollTo()` method documentation, matching the
exception behavior implemented by `ScrollCapableTrait::scrollTo()`.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 98430f9. ScrollCapableInterface::scrollTo() now declares @throws \LogicException, matching what the trait throws when the surface does not scroll.

Comment thread src/Terminal/Ansi.php
@github-actions

This comment has been minimized.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/Terminal/Ansi.php (1)

32-32: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Describe the scope of STYLE_SEQUENCE accurately.

STYLE_SEQUENCE matches CSI sequences whose final byte is any ASCII letter. That set includes terminal controls other than styling commands. The current text therefore overstates the styling guarantee. Describe the sequence as one recognized by Ansi::strip(), or narrow the pattern if only styling commands are intended.

Proposed wording
-   * A CSI sequence; CSI sequences carry the styling.
+   * A CSI sequence recognized by the ANSI escape-sequence stripper.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Terminal/Ansi.php` at line 32, Update the documentation for
STYLE_SEQUENCE in Ansi::strip() to accurately state that it matches recognized
CSI sequences, including non-styling terminal controls; do not describe all
matched sequences as styling-only unless the pattern is narrowed accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/Terminal/Ansi.php`:
- Line 32: Update the documentation for STYLE_SEQUENCE in Ansi::strip() to
accurately state that it matches recognized CSI sequences, including non-styling
terminal controls; do not describe all matched sequences as styling-only unless
the pattern is narrowed accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f63d5ba0-1374-4e71-9d93-3563d8fddc2d

📥 Commits

Reviewing files that changed from the base of the PR and between dafbc42 and 98430f9.

📒 Files selected for processing (9)
  • src/Block/AbstractBlock.php
  • src/Block/Field.php
  • src/Block/Panel.php
  • src/Builder/FieldBuilder.php
  • src/Field/Capability/OptionsCapableTrait.php
  • src/Field/Rating.php
  • src/Field/Reorder.php
  • src/Screen/Capability/ScrollCapableInterface.php
  • src/Terminal/Ansi.php

@AlexSkrypnyk AlexSkrypnyk added the Needs review Pull request needs a review from assigned developers label Aug 11, 2026
@AlexSkrypnyk AlexSkrypnyk changed the title Converged naming, structure, API shape and comment register across the library. Converged naming, structure, API shape and the comment register across the library. Aug 11, 2026
@github-actions

This comment has been minimized.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/Field/FilePicker.php (1)

289-303: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Return the Toggle hint only in multiple mode.

When $this->multiple is FALSE, hints() still returns new Hint('select', Action::Toggle). The hint advertises an action that does not affect the single-selection value. Add it only when $this->multiple is TRUE.

The supplied hints() and liveValue() implementations provide this evidence.

Proposed fix
-    return [
-      new Hint('select', Action::Toggle),
+    $hints = [
       new Hint('move', Action::MoveUp, Action::MoveDown),
       new Hint('open', Action::MoveRight),
       new Hint('go up', Action::MoveLeft),
       new Hint($this->multiple ? 'accept' : 'select', Action::Accept),
       new Hint('show hidden', Action::Reveal),
       new Hint('cancel', Action::Cancel),
     ];
+
+    if ($this->multiple) {
+      array_unshift($hints, new Hint('select', Action::Toggle));
+    }
+
+    return $hints;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Field/FilePicker.php` around lines 289 - 303, Update FilePicker::hints()
so the Action::Toggle “select” hint is included only when $this->multiple is
true; preserve the remaining hints and existing single-versus-multiple Accept
label behavior.
src/Resolver/InputResolver.php (1)

125-138: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Reject JSON lists for --prompts.

is_array($data) accepts decoded JSON lists. For example, ["answer"] becomes a PHP array and creates a numeric field ID. Decode without the associative flag and require \stdClass before converting its properties to the output map.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Resolver/InputResolver.php` around lines 125 - 138, Update
InputResolver::parsePrompts to decode JSON without the associative-array flag,
require the decoded value to be an stdClass, and reject all other values
including JSON lists with the existing FormException. After validation, convert
the object properties into the returned associative map.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/content/output.mdx`:
- Line 19: Preserve or document all changed public contracts: in
docs/content/output.mdx lines 19-19 and 37-41, update examples to reflect the
supported Output::box($body, $title) contract or provide migration guidance; in
playground/themes/OceanTheme.php lines 243-255 and
src/Primitive/Element/PrimitiveElementsInterface.php, keep renderBanner()
return-type compatibility or document the required theme migration; in
src/Block/Element/FieldElementsInterface.php lines 106-199, restore deprecated
forwarding fieldEntry* methods or document migration; in src/Block/Option.php
lines 55-66 and src/Block/OptionType.php line 15, retain an OptionKind alias or
document the OptionType migration; update stale fieldEntry* references in
docs/content/specification.mdx, docs/content/fields/option-groups.mdx, and
docs/content/fields/anatomy.mdx.

In `@src/Field/FieldFactory.php`:
- Around line 64-72: In FieldFactory::open(), rename the local variable assigned
from $block->options() from $entries to $options, and update every reference in
the method, including optionLabels(), optionDescriptions(), Select, Toggle,
Reorder, and Search construction.

In `@src/Primitive/Output.php`:
- Line 26: Restore the existing positional parameter order in the box() method
so its first argument remains $body and calls such as box('Body text') continue
rendering body content. Update any title handling and related
documentation/examples around box() accordingly; do not reinterpret the first
argument as a title or change existing call behavior.

In `@src/Screen/Scroller.php`:
- Line 23: Preserve named-argument compatibility for the public follow(),
viewport(), and slice() methods by retaining the $height parameter name, or
provide an explicit migration path if the rename to $rows is intentional and
permitted. Ensure existing callers using height: continue to work.

In `@src/Testing/ScreenTester.php`:
- Around line 161-168: Update ScreenTester::theme() to store a named theme
identifier instead of constructing it immediately; preserve direct
ThemeInterface assignment. In controller(), after all tester configuration is
finalized, create the named theme using the final themeOptions(), cols, and
existing ThemeManager::create flow, ensuring fluent options(), border(), and
cols() calls affect the rendered frame.

In `@src/Testing/TuiTester.php`:
- Around line 322-351: Update the ThemeInterface branch in TuiTester so the
ScreenController constructor receives the layout configured by layout() instead
of the hardcoded 'default' value. Reuse the existing configured-layout value
from $this->tui, while leaving the non-ThemeInterface controller path unchanged.

In `@tests/phpunit/Unit/Theme/AbstractThemeTest.php`:
- Around line 36-37: Rename all outdated “entry” terminology to “option” in the
specified PHPUnit test labels, comments, and the affected test method around
AbstractThemeTest. Update AbstractThemeTest.php ranges 36-37, 66-70, 97, and
141-147, plus ElementDelegationTest.php ranges 44-46, 60-66, and 82-85; preserve
the existing test callbacks and assertions while ensuring PHPUnit output and
source wording match the fieldOption* API.

---

Outside diff comments:
In `@src/Field/FilePicker.php`:
- Around line 289-303: Update FilePicker::hints() so the Action::Toggle “select”
hint is included only when $this->multiple is true; preserve the remaining hints
and existing single-versus-multiple Accept label behavior.

In `@src/Resolver/InputResolver.php`:
- Around line 125-138: Update InputResolver::parsePrompts to decode JSON without
the associative-array flag, require the decoded value to be an stdClass, and
reject all other values including JSON lists with the existing FormException.
After validation, convert the object properties into the returned associative
map.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f4aee9fb-f8b5-41d7-a93e-d99e13723f54

📥 Commits

Reviewing files that changed from the base of the PR and between 98430f9 and d1eabf0.

📒 Files selected for processing (84)
  • docs/content/output.mdx
  • playground/18-output-box.php
  • playground/themes/OceanTheme.php
  • src/Block/Actions.php
  • src/Block/Element/FieldElementsInterface.php
  • src/Block/Field.php
  • src/Block/Option.php
  • src/Block/OptionType.php
  • src/Block/Prose.php
  • src/Builder/FieldBuilder.php
  • src/Builder/Form.php
  • src/Builder/PanelBuilder.php
  • src/Field/AbstractField.php
  • src/Field/Calendar.php
  • src/Field/Capability/OptionsCapableTrait.php
  • src/Field/Capability/PagingCapableTrait.php
  • src/Field/Capability/SelectionCapableTrait.php
  • src/Field/FieldFactory.php
  • src/Field/FilePicker.php
  • src/Field/Matcher.php
  • src/Field/Pause.php
  • src/Field/Reorder.php
  • src/Field/Select.php
  • src/Field/Suggest.php
  • src/Field/Template.php
  • src/Input/KeyMap.php
  • src/Primitive/Element/PrimitiveElementsInterface.php
  • src/Primitive/Output.php
  • src/Primitive/Progress.php
  • src/Resolver/InputResolver.php
  • src/Schema/SchemaGenerator.php
  • src/Schema/SchemaValidator.php
  • src/Screen/Collector.php
  • src/Screen/Layout/AbstractLayout.php
  • src/Screen/Layout/GridLayout.php
  • src/Screen/Overlay.php
  • src/Screen/Region.php
  • src/Screen/ScreenController.php
  • src/Screen/ScreenRenderer.php
  • src/Screen/Scroller.php
  • src/Terminal/Markup.php
  • src/Terminal/MarkupSegment.php
  • src/Terminal/MarkupType.php
  • src/Terminal/Terminal.php
  • src/Testing/BufferedTerminal.php
  • src/Testing/ScreenTester.php
  • src/Testing/TuiTester.php
  • src/Theme/AbstractTheme.php
  • src/Theme/DefaultTheme.php
  • src/Theme/DosTheme.php
  • src/Theme/EmberTheme.php
  • src/Theme/FrostTheme.php
  • src/Theme/MidnightTheme.php
  • src/Theme/MonoTheme.php
  • src/Theme/Override/FieldOverrides.php
  • src/Theme/Override/ThemeElement.php
  • src/Translation/Translator.php
  • src/Tui.php
  • tests/phpunit/Fixtures/Theme/CapableTheme.php
  • tests/phpunit/Traits/MixedOptionsTrait.php
  • tests/phpunit/Unit/Block/FieldBlockTest.php
  • tests/phpunit/Unit/Block/FieldDeclarationTest.php
  • tests/phpunit/Unit/Block/OptionTest.php
  • tests/phpunit/Unit/Builder/FormTest.php
  • tests/phpunit/Unit/ControlBytesTest.php
  • tests/phpunit/Unit/Field/CalendarTest.php
  • tests/phpunit/Unit/Field/MatcherTest.php
  • tests/phpunit/Unit/Field/ReorderTest.php
  • tests/phpunit/Unit/Field/SearchTest.php
  • tests/phpunit/Unit/Field/SelectTest.php
  • tests/phpunit/Unit/Field/SuggestTest.php
  • tests/phpunit/Unit/Primitive/OutputTest.php
  • tests/phpunit/Unit/Screen/Layout/GridLayoutTest.php
  • tests/phpunit/Unit/Terminal/MarkupTest.php
  • tests/phpunit/Unit/Terminal/TerminalTest.php
  • tests/phpunit/Unit/Testing/BufferedTerminalTest.php
  • tests/phpunit/Unit/Theme/AbstractThemeTest.php
  • tests/phpunit/Unit/Theme/BuiltinThemesTest.php
  • tests/phpunit/Unit/Theme/ElementDelegationTest.php
  • tests/phpunit/Unit/Theme/OutputRenderTest.php
  • tests/phpunit/Unit/Theme/SupportTest.php
  • tests/phpunit/Unit/Theme/ThemeBuilderTest.php
  • tests/phpunit/Unit/Theme/ThemeRenderTest.php
  • tests/phpunit/Unit/Theme/ThemeTest.php

Comment thread docs/content/output.mdx
Comment thread src/Field/FieldFactory.php Outdated
Comment thread src/Primitive/Output.php
Comment thread src/Screen/Scroller.php
Comment thread src/Testing/ScreenTester.php
Comment thread src/Testing/TuiTester.php Outdated
Comment thread tests/phpunit/Unit/Theme/AbstractThemeTest.php Outdated
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/Tui.php (1)

558-569: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Keep progress() callable-compatible.

progress() and Primitive\Progress::run() now reject method references, invokable objects, and callable strings that the previous callable API accepted. Preserve callable support across both APIs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Tui.php` around lines 558 - 569, Update Tui::progress() and
Primitive\Progress::run() to accept the broader callable type instead of
requiring \Closure, preserving support for method references, invokable objects,
and callable strings while retaining the existing callback invocation and return
behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/Tui.php`:
- Around line 558-569: Update Tui::progress() and Primitive\Progress::run() to
accept the broader callable type instead of requiring \Closure, preserving
support for method references, invokable objects, and callable strings while
retaining the existing callback invocation and return behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b176cabd-6e28-47b3-9933-76c16ddd661b

📥 Commits

Reviewing files that changed from the base of the PR and between d1eabf0 and 373b2dd.

📒 Files selected for processing (9)
  • AGENTS.md
  • src/Answers/Answers.php
  • src/Field/FieldFactory.php
  • src/Field/Suggest.php
  • src/Testing/ScreenTester.php
  • src/Testing/TuiTester.php
  • src/Translation/Translator.php
  • src/Tui.php
  • tests/phpunit/Unit/Theme/AbstractThemeTest.php

@github-actions

Copy link
Copy Markdown
Code Coverage Report:
  2026-08-11 23:59:32

 Summary:
  Classes: 80.67% (121/150)
  Methods: 95.76% (1492/1558)
  Lines:   98.05% (5936/6054)

DrevOps\Tui\Answers\Answer
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  1/  1)
DrevOps\Tui\Answers\Answers
  Methods: 100.00% (11/11)   Lines: 100.00% ( 23/ 23)
DrevOps\Tui\Answers\Provenance
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  7/  7)
DrevOps\Tui\Answers\SummaryFormatter
  Methods: 100.00% ( 6/ 6)   Lines: 100.00% ( 22/ 22)
DrevOps\Tui\Answers\ValueFormatter
  Methods: 100.00% ( 2/ 2)   Lines: 100.00% (  6/  6)
DrevOps\Tui\Block\AbstractBlock
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  3/  3)
DrevOps\Tui\Block\Actions
  Methods: 100.00% ( 9/ 9)   Lines: 100.00% ( 25/ 25)
DrevOps\Tui\Block\Breadcrumb
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% (  6/  6)
DrevOps\Tui\Block\Buttons
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  1/  1)
DrevOps\Tui\Block\Capability\BindCapableTrait
  Methods:  80.00% ( 4/ 5)   Lines:  90.00% (  9/ 10)
DrevOps\Tui\Block\Capability\DependCapableTrait
  Methods: 100.00% (10/10)   Lines: 100.00% ( 19/ 19)
DrevOps\Tui\Block\Capability\FocusCapableTrait
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% (  5/  5)
DrevOps\Tui\Block\DateBounds
  Methods: 100.00% ( 6/ 6)   Lines: 100.00% ( 28/ 28)
DrevOps\Tui\Block\Field
  Methods:  97.69% (127/130)   Lines:  95.74% (382/399)
DrevOps\Tui\Block\FieldType
  Methods: 100.00% ( 6/ 6)   Lines: 100.00% ( 24/ 24)
DrevOps\Tui\Block\FilePickerConstraints
  Methods: 100.00% ( 8/ 8)   Lines: 100.00% ( 53/ 53)
DrevOps\Tui\Block\Legend
  Methods: 100.00% ( 5/ 5)   Lines: 100.00% ( 34/ 34)
DrevOps\Tui\Block\Markup
  Methods: 100.00% (10/10)   Lines: 100.00% ( 27/ 27)
DrevOps\Tui\Block\NumberBounds
  Methods:  83.33% ( 5/ 6)   Lines:  95.24% ( 20/ 21)
DrevOps\Tui\Block\Option
  Methods: 100.00% ( 5/ 5)   Lines: 100.00% ( 18/ 18)
DrevOps\Tui\Block\Panel
  Methods:  91.89% (34/37)   Lines:  95.73% (112/117)
DrevOps\Tui\Block\Progress
  Methods: 100.00% (13/13)   Lines: 100.00% ( 37/ 37)
DrevOps\Tui\Block\Prose
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% ( 16/ 16)
DrevOps\Tui\Block\SelectionBounds
  Methods: 100.00% ( 4/ 4)   Lines: 100.00% ( 23/ 23)
DrevOps\Tui\Block\TableSpec
  Methods: 100.00% ( 2/ 2)   Lines: 100.00% (  9/  9)
DrevOps\Tui\Block\Template
  Methods: 100.00% (19/19)   Lines: 100.00% ( 69/ 69)
DrevOps\Tui\Block\Tree
  Methods: 100.00% ( 9/ 9)   Lines: 100.00% ( 52/ 52)
DrevOps\Tui\Block\Weekday
  Methods: 100.00% ( 4/ 4)   Lines: 100.00% ( 15/ 15)
DrevOps\Tui\Builder\FieldBuilder
  Methods:  98.41% (62/63)   Lines:  99.08% (216/218)
DrevOps\Tui\Builder\Fixup
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  1/  1)
DrevOps\Tui\Builder\Form
  Methods:  87.50% (21/24)   Lines:  96.27% (129/134)
DrevOps\Tui\Builder\PanelBuilder
  Methods:  96.97% (32/33)   Lines:  98.86% ( 87/ 88)
DrevOps\Tui\Condition\CompositeCondition
  Methods: 100.00% ( 4/ 4)   Lines: 100.00% ( 19/ 19)
DrevOps\Tui\Condition\Condition
  Methods: 100.00% (10/10)   Lines: 100.00% ( 38/ 38)
DrevOps\Tui\Derive\Derive
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% ( 10/ 10)
DrevOps\Tui\Derive\Deriver
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% ( 13/ 13)
DrevOps\Tui\Derive\Transform
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% (  7/  7)
DrevOps\Tui\Discovery\AbstractDiscover
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  1/  1)
DrevOps\Tui\Discovery\Dotenv
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% ( 19/ 19)
DrevOps\Tui\Discovery\JsonValue
  Methods: 100.00% ( 4/ 4)   Lines: 100.00% ( 16/ 16)
DrevOps\Tui\Discovery\PathExists
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% (  3/  3)
DrevOps\Tui\Discovery\Scan
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% ( 20/ 20)
DrevOps\Tui\Field\AbstractField
  Methods:  91.30% (21/23)   Lines:  96.88% ( 62/ 64)
DrevOps\Tui\Field\Calendar
  Methods: 100.00% (13/13)   Lines: 100.00% ( 52/ 52)
DrevOps\Tui\Field\Capability\CompletionCapableTrait
  Methods: 100.00% ( 5/ 5)   Lines: 100.00% ( 16/ 16)
DrevOps\Tui\Field\Capability\FilterCapableTrait
  Methods: 100.00% ( 4/ 4)   Lines: 100.00% ( 15/ 15)
DrevOps\Tui\Field\Capability\OptionsCapableTrait
  Methods: 100.00% (10/10)   Lines: 100.00% ( 36/ 36)
DrevOps\Tui\Field\Capability\PagingCapableTrait
  Methods:  80.00% ( 4/ 5)   Lines:  94.74% ( 18/ 19)
DrevOps\Tui\Field\Capability\PlaceholderCapableTrait
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% (  7/  7)
DrevOps\Tui\Field\Capability\QueryOptionsCapableTrait
  Methods: 100.00% ( 8/ 8)   Lines: 100.00% ( 36/ 36)
DrevOps\Tui\Field\Capability\SearchCapableTrait
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% (  4/  4)
DrevOps\Tui\Field\Capability\SelectionBoundedTrait
  Methods: 100.00% ( 2/ 2)   Lines: 100.00% (  4/  4)
DrevOps\Tui\Field\Capability\SelectionCapableTrait
  Methods: 100.00% (14/14)   Lines: 100.00% ( 95/ 95)
DrevOps\Tui\Field\Capability\TextEditCapableTrait
  Methods: 100.00% ( 9/ 9)   Lines: 100.00% ( 36/ 36)
DrevOps\Tui\Field\Confirm
  Methods: 100.00% ( 7/ 7)   Lines: 100.00% ( 24/ 24)
DrevOps\Tui\Field\FieldFactory
  Methods: 100.00% (12/12)   Lines: 100.00% ( 59/ 59)
DrevOps\Tui\Field\FilePicker
  Methods: 100.00% (32/32)   Lines: 100.00% (180/180)
DrevOps\Tui\Field\MatchResult
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  1/  1)
DrevOps\Tui\Field\MatchTier
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  6/  6)
DrevOps\Tui\Field\Matcher
  Methods: 100.00% ( 9/ 9)   Lines: 100.00% ( 75/ 75)
DrevOps\Tui\Field\Number
  Methods: 100.00% ( 8/ 8)   Lines: 100.00% ( 31/ 31)
DrevOps\Tui\Field\Password
  Methods: 100.00% ( 9/ 9)   Lines: 100.00% ( 45/ 45)
DrevOps\Tui\Field\PasswordDisplay
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  5/  5)
DrevOps\Tui\Field\Pause
  Methods: 100.00% ( 5/ 5)   Lines: 100.00% ( 11/ 11)
DrevOps\Tui\Field\Rating
  Methods: 100.00% ( 9/ 9)   Lines: 100.00% ( 25/ 25)
DrevOps\Tui\Field\Reorder
  Methods: 100.00% (11/11)   Lines: 100.00% ( 58/ 58)
DrevOps\Tui\Field\Search
  Methods: 100.00% ( 8/ 8)   Lines: 100.00% ( 17/ 17)
DrevOps\Tui\Field\Select
  Methods: 100.00% ( 5/ 5)   Lines: 100.00% (  8/  8)
DrevOps\Tui\Field\Suggest
  Methods: 100.00% (19/19)   Lines: 100.00% ( 75/ 75)
DrevOps\Tui\Field\Template
  Methods: 100.00% (14/14)   Lines: 100.00% ( 63/ 63)
DrevOps\Tui\Field\Text
  Methods: 100.00% ( 6/ 6)   Lines: 100.00% ( 18/ 18)
DrevOps\Tui\Field\Textarea
  Methods: 100.00% ( 8/ 8)   Lines: 100.00% ( 48/ 48)
DrevOps\Tui\Field\Toggle
  Methods: 100.00% ( 8/ 8)   Lines: 100.00% ( 30/ 30)
DrevOps\Tui\Handler\HandlerRegistry
  Methods:  85.71% ( 6/ 7)   Lines:  95.45% ( 21/ 22)
DrevOps\Tui\Input\Binding
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  1/  1)
DrevOps\Tui\Input\DefaultKeyMap
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% ( 48/ 48)
DrevOps\Tui\Input\Hint
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  2/  2)
DrevOps\Tui\Input\Key
  Methods: 100.00% ( 8/ 8)   Lines: 100.00% ( 11/ 11)
DrevOps\Tui\Input\KeyMap
  Methods: 100.00% (11/11)   Lines: 100.00% ( 61/ 61)
DrevOps\Tui\Input\KeyMapManager
  Methods: 100.00% ( 2/ 2)   Lines: 100.00% (  8/  8)
DrevOps\Tui\Input\KeyParser
  Methods:  85.71% ( 6/ 7)   Lines:  98.95% ( 94/ 95)
DrevOps\Tui\Input\Scope
  Methods: 100.00% ( 7/ 7)   Lines: 100.00% ( 17/ 17)
DrevOps\Tui\Input\ScopedKeyMap
  Methods: 100.00% ( 4/ 4)   Lines: 100.00% (  4/  4)
DrevOps\Tui\Input\VimKeyMap
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% ( 12/ 12)
DrevOps\Tui\Primitive\Output
  Methods: 100.00% (17/17)   Lines: 100.00% ( 25/ 25)
DrevOps\Tui\Primitive\Progress
  Methods: 100.00% ( 6/ 6)   Lines: 100.00% ( 29/ 29)
DrevOps\Tui\Primitive\ProgressReporter
  Methods: 100.00% ( 2/ 2)   Lines: 100.00% (  2/  2)
DrevOps\Tui\Resolver\EnvNameResolver
  Methods: 100.00% ( 6/ 6)   Lines: 100.00% (  9/  9)
DrevOps\Tui\Resolver\InputResolver
  Methods: 100.00% ( 5/ 5)   Lines: 100.00% ( 30/ 30)
DrevOps\Tui\Schema\AgentHelp
  Methods: 100.00% ( 4/ 4)   Lines: 100.00% ( 75/ 75)
DrevOps\Tui\Schema\DefaultResolver
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  8/  8)
DrevOps\Tui\Schema\OptionsResolver
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  6/  6)
DrevOps\Tui\Schema\SchemaGenerator
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% ( 51/ 51)
DrevOps\Tui\Schema\SchemaValidator
  Methods: 100.00% ( 7/ 7)   Lines: 100.00% ( 41/ 41)
DrevOps\Tui\Screen\Assembler
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% ( 21/ 21)
DrevOps\Tui\Screen\Capability\BorderCapableTrait
  Methods: 100.00% ( 5/ 5)   Lines: 100.00% (  9/  9)
DrevOps\Tui\Screen\Capability\ScrollCapableTrait
  Methods: 100.00% ( 5/ 5)   Lines: 100.00% (  9/  9)
DrevOps\Tui\Screen\Collector
  Methods: 100.00% (30/30)   Lines: 100.00% (195/195)
DrevOps\Tui\Screen\ExternalEditor
  Methods: 100.00% ( 6/ 6)   Lines: 100.00% ( 27/ 27)
DrevOps\Tui\Screen\KeyRouter
  Methods:  90.91% (30/33)   Lines:  97.92% (188/192)
DrevOps\Tui\Screen\Layout\AbstractLayout
  Methods: 100.00% (15/15)   Lines: 100.00% ( 79/ 79)
DrevOps\Tui\Screen\Layout\DefaultLayout
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  4/  4)
DrevOps\Tui\Screen\Layout\GridLayout
  Methods: 100.00% ( 8/ 8)   Lines: 100.00% ( 28/ 28)
DrevOps\Tui\Screen\Layout\LayoutManager
  Methods:  75.00% ( 6/ 8)   Lines:  59.38% ( 19/ 32)
DrevOps\Tui\Screen\Layout\TwoColumnLayout
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  3/  3)
DrevOps\Tui\Screen\Overlay
  Methods: 100.00% ( 4/ 4)   Lines: 100.00% ( 24/ 24)
DrevOps\Tui\Screen\Region
  Methods:  94.44% (17/18)   Lines:  93.94% ( 31/ 33)
DrevOps\Tui\Screen\Screen
  Methods: 100.00% ( 5/ 5)   Lines: 100.00% (  9/  9)
DrevOps\Tui\Screen\ScreenController
  Methods:  96.83% (61/63)   Lines:  98.83% (424/429)
DrevOps\Tui\Screen\ScreenRenderer
  Methods:  90.70% (39/43)   Lines:  98.25% (280/285)
DrevOps\Tui\Screen\Scroller
  Methods: 100.00% ( 4/ 4)   Lines: 100.00% ( 14/ 14)
DrevOps\Tui\Screen\Viewport
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  1/  1)
DrevOps\Tui\Terminal\Ansi
  Methods: 100.00% (13/13)   Lines: 100.00% ( 63/ 63)
DrevOps\Tui\Terminal\Box
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% ( 15/ 15)
DrevOps\Tui\Terminal\Markup
  Methods: 100.00% (10/10)   Lines: 100.00% ( 69/ 69)
DrevOps\Tui\Terminal\MarkupSegment
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  1/  1)
DrevOps\Tui\Terminal\Table
  Methods: 100.00% ( 9/ 9)   Lines: 100.00% ( 64/ 64)
DrevOps\Tui\Terminal\Terminal
  Methods:  95.65% (22/23)   Lines:  96.97% ( 64/ 66)
DrevOps\Tui\Terminal\TerminalControl
  Methods: 100.00% (11/11)   Lines: 100.00% ( 11/ 11)
DrevOps\Tui\Testing\ArrayKeyStream
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% ( 12/ 12)
DrevOps\Tui\Testing\BufferedTerminal
  Methods: 100.00% ( 7/ 7)   Lines: 100.00% ( 12/ 12)
DrevOps\Tui\Testing\FieldRunner
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  5/  5)
DrevOps\Tui\Testing\KeyEncoder
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% ( 22/ 22)
DrevOps\Tui\Testing\ScreenTester
  Methods:  91.67% (22/24)   Lines:  94.87% ( 74/ 78)
DrevOps\Tui\Testing\TuiTester
  Methods:  76.47% (13/17)   Lines:  86.67% ( 52/ 60)
DrevOps\Tui\Theme\AbstractTheme
  Methods:  84.29% (59/70)   Lines:  84.42% ( 65/ 77)
DrevOps\Tui\Theme\Capability\ColorSchemeCapableTrait
  Methods: 100.00% ( 4/ 4)   Lines: 100.00% (  9/  9)
DrevOps\Tui\Theme\Capability\UnicodeCapableTrait
  Methods: 100.00% ( 2/ 2)   Lines: 100.00% (  2/  2)
DrevOps\Tui\Theme\DefaultTheme
  Methods:  92.19% (118/128)   Lines:  96.68% (349/361)
DrevOps\Tui\Theme\DosTheme
  Methods: 100.00% (12/12)   Lines: 100.00% ( 14/ 14)
DrevOps\Tui\Theme\EmberTheme
  Methods: 100.00% ( 5/ 5)   Lines: 100.00% (  5/  5)
DrevOps\Tui\Theme\FrostTheme
  Methods: 100.00% ( 5/ 5)   Lines: 100.00% (  5/  5)
DrevOps\Tui\Theme\MidnightTheme
  Methods: 100.00% ( 5/ 5)   Lines: 100.00% (  5/  5)
DrevOps\Tui\Theme\MonoTheme
  Methods: 100.00% ( 6/ 6)   Lines: 100.00% (  6/  6)
DrevOps\Tui\Theme\Override\BreadcrumbOverrides
  Methods: 100.00% ( 2/ 2)   Lines: 100.00% (  3/  3)
DrevOps\Tui\Theme\Override\FieldOverrides
  Methods:  85.71% ( 6/ 7)   Lines:  84.62% ( 11/ 13)
DrevOps\Tui\Theme\Override\Glyph
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  1/  1)
DrevOps\Tui\Theme\Override\LegendOverrides
  Methods:  66.67% ( 2/ 3)   Lines:  60.00% (  3/  5)
DrevOps\Tui\Theme\Override\Overrides
  Methods: 100.00% ( 6/ 6)   Lines: 100.00% (  6/  6)
DrevOps\Tui\Theme\Sgr
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  1/  1)
DrevOps\Tui\Theme\ThemeBuilder
  Methods: 100.00% ( 5/ 5)   Lines: 100.00% (  8/  8)
DrevOps\Tui\Theme\ThemeManager
  Methods:  85.71% ( 6/ 7)   Lines:  97.44% ( 38/ 39)
DrevOps\Tui\Translation\Translator
  Methods: 100.00% (18/18)   Lines: 100.00% ( 87/ 87)
DrevOps\Tui\Tui
  Methods: 100.00% (34/34)   Lines: 100.00% (118/118)
DrevOps\Tui\Utils\Strings
  Methods: 100.00% ( 6/ 6)   Lines: 100.00% ( 31/ 31)

@AlexSkrypnyk
AlexSkrypnyk merged commit 5068050 into main Aug 12, 2026
12 checks passed
@AlexSkrypnyk
AlexSkrypnyk deleted the feature/converge-conventions branch August 12, 2026 01:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Needs review Pull request needs a review from assigned developers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant