Skip to content

Added 'ThemeManager' and theme-driven widget rendering with distinct display modes.#3

Merged
AlexSkrypnyk merged 10 commits into
mainfrom
feature/theme-widget-render
Jul 9, 2026
Merged

Added 'ThemeManager' and theme-driven widget rendering with distinct display modes.#3
AlexSkrypnyk merged 10 commits into
mainfrom
feature/theme-widget-render

Conversation

@AlexSkrypnyk

@AlexSkrypnyk AlexSkrypnyk commented Jul 9, 2026

Copy link
Copy Markdown
Member

Summary

This branch moves the theme registry, factory (create()/register()) and terminal capability detection (detectColor()/detectUnicode()) off AbstractTheme and into a new ThemeManager, and turns AbstractTheme from an abstract contract into a complete, neutral base implementation that a concrete theme overrides only in part via + parent::defineStyles() / + parent::defineGlyphs(). All widgets and the panel editor frame now render through the theme instead of emitting plain text, so carets, markers, cursor-row highlights and validation errors are all styled, and an editing field's label is visually distinguishable from its value via a new renderEditorHeader(). Dim chrome (status lines, hints, descriptions) moved from the faint SGR 2 code, which many terminals and the SVG renderer drop entirely, to SGR 90 (bright black), and every regenerated demo SVG under docs/assets/ now shows visibly distinct output across the four display modes (Unicode/ASCII x ANSI/no-ANSI).

Changes

Theme architecture

  • Added src/Theme/ThemeManager.php: the registry and factory (create() resolves a registered name or an AbstractTheme subclass FQCN; default/empty resolve to dark; an unknown name now throws InvalidArgumentException instead of silently falling back to dark) plus detectColor()/detectUnicode(), all moved off AbstractTheme.
  • ThemeManager::register() validates the class is an AbstractTheme subclass at registration time and throws InvalidArgumentException immediately, rather than deferring the failure to a later create() call.
  • AbstractTheme::defineStyles()/defineGlyphs() are no longer abstract: the base class now implements complete neutral defaults (roles title, breadcrumb, label, value, description, marker, badge, cursor, footer, indicator, plus the new highlight, error and rule; the full glyph set including a new rule glyph). DarkTheme/LightTheme shrank to palette-only overrides merged with + parent::defineStyles().
  • The caret glyph changed from /| to /| so Unicode and ASCII text widgets stay visually distinct from each other.
  • Dim chrome roles (footer, breadcrumb, description) moved from SGR 2 (faint - dropped by the SVG renderer and many terminals) to SGR 90 (bright black) so status and hint lines actually render dimmed.
  • Added renderEditorHeader(label) (the label styled with the title role over a dim rule underline, so a field label reads as a label in every display mode, including no-color) and renderHintLine(...hints) (dot-glyph-joined dim hints); renderStatusLine() now calls renderHintLine() internally. Both methods were added to ThemeInterface.

Widget and panel rendering

  • All widgets now style their output through the theme: carets and markers with the marker role, checked boxes with value, cursor-row labels with highlight via a shared highlightLabel() helper added to AbstractWidget, and validation errors with error; PauseWidget and ConfirmWidget pick up the same marker styling.
  • PanelController::frame() renders the editing header with renderEditorHeader() and accurate editing hints (enter accept / esc cancel) via renderHintLine(), replacing a raw unstyled label and the panel's navigation status line.
  • Tui.php now creates the theme and detects terminal capabilities through ThemeManager instead of AbstractTheme.

Playground and documentation

  • All 11 per-widget playground demo scripts and the combined widgets.php in playground/3-widgets/ call renderEditorHeader()/renderHintLine() instead of raw $theme->style('title', ...)/$theme->style('footer', ...).
  • playground/2-custom-theme/OceanTheme.php demonstrates the partial-override merge pattern (+ parent::defineStyles() / + parent::defineGlyphs()), and its docblock and the run.php comment reference ThemeManager::register().
  • README.md: the Themes section is rewritten around ThemeManager, the Quick start example uses a single-expression arrow function (fn), and the logo lost its empty-href anchor.
  • docs/architecture/architecture.puml/.svg gained a ThemeManager node and the widget -> theme edge; docs/architecture/README.md and playground/README.md were updated to match.
  • Recorded form demos (1-scaffolder, 4-nested-panels, 2-custom-theme, 5-discovery) end with the provenance-badged toSummary() output instead of raw JSON, so the closing frame of each capture reads as a result summary rather than an unlabelled data dump.
  • docs/util/update-assets.php anchors each static widget frame to the moment the demo's gate text first appears in its recording - a fixed 800ms capture raced process startup under parallel recording and could grab an empty screen or the leaked spawn echo - and now verifies every generated SVG contains its expected content before the job succeeds.
  • All docs/assets/*.svg demo captures were regenerated - the four display modes (Unicode/ASCII x ANSI/no-ANSI) are now visibly distinct from each other.

Tests

  • Added tests/phpunit/Unit/Theme/ThemeManagerTest.php covering the registry, factory, class validation and capability detection.
  • ThemeTest, ThemeRenderTest, the widget test suites and PanelControllerTest were updated for the new styled rendering, the editor header and the hint-line output.

Before / After

BEFORE - AbstractTheme owns the registry, factory and detection; themes redefine everything

┌──────────────────────────────────────────┐
│              AbstractTheme               │
│ static $registry                         │
│ static create() / register()             │
│ static detectColor() / detectUnicode()   │
│                                           │
│ abstract defineStyles()                  │
│ abstract defineGlyphs()                  │
└──────────────────────────────────────────┘
                      │
                      │ extends, full redefinition
                      ▼
                      │
       ┌──────────────┴──────────────┐
       ▼                             ▼
   DarkTheme                    LightTheme
 full palette                  full palette
 + full glyphs                 + full glyphs

Editing "Site name":                            List, cursor on row 1:
  Site name                                       ❯ Option one
  my-site                                           Option two

Label and value render as identical plain lines - no cue marks which one is the label. Hints and
status text use SGR 2 (faint), which the SVG renderer and many terminals drop entirely.


AFTER - ThemeManager owns the registry, factory and detection; AbstractTheme is a complete base

┌──────────────────────────────────────────┐
│               ThemeManager               │
│ $registry                                │
│ create() - validates, throws             │
│   on an unknown name                     │
│ register() - throws unless the           │
│   class extends AbstractTheme            │
│ detectColor() / detectUnicode()          │
└──────────────────────────────────────────┘
                      │
                      │ creates
                      ▼
┌──────────────────────────────────────────┐
│              AbstractTheme               │
│ defineStyles() - neutral,                │
│   complete default                       │
│ defineGlyphs() - neutral,                │
│   complete default                       │
│ renderEditorHeader()                     │
│ renderHintLine()                         │
└──────────────────────────────────────────┘
                      │
                      │ extends, palette-only override
                      ▼
                      │
       ┌──────────────┴──────────────┐
       ▼                             ▼
   DarkTheme                    LightTheme
  + parent::                    + parent::
defineStyles()                defineStyles()

Editing "Site name":                            List, cursor on row 1:
  Site name                                       ❯ Option one
  ─────────                                         Option two
  █my-site

The label renders bold (title role) over a dim rule underline, so it reads as a label even with
colour off; the caret and markers carry the marker role. Hints and status text use SGR 90 (bright
black), which stays visible on the SVG renderer and across terminals that dropped SGR 2.

Summary by CodeRabbit

  • New Features
    • Added automatic theme management with environment-based capability detection and a simplified API for registering/selecting themes.
    • Interactive editors and widgets now use consistent editor headers plus keyboard hint lines.
    • Widget markers/labels and highlight states are now theme-styled for more uniform visuals.
  • Bug Fixes
    • Improved SVG/screenshot asset generation by verifying rendered output before saving.
    • Updated TUI rendering for timestamp-based captures to avoid incorrect multi-frame output.
    • Playground run outputs now show a readable grouped summary instead of raw JSON.
  • Documentation
    • Refreshed README and architecture docs/examples to match the new theme and header/hint behavior.
  • Tests
    • Extended and adjusted unit tests to cover theme management, hint/header rendering, and updated glyph/styling expectations.

… modes.

Moved the registry, factory and capability detection off 'AbstractTheme' into a dedicated 'ThemeManager'; the base theme now ships complete neutral style and glyph defaults so concrete themes override only their palette via '+ parent::defineStyles()'. Widgets style carets, markers, highlighted rows and errors from the theme; the editor shows an underlined label header; dim chrome uses bright-black (SGR 90) instead of faint, which renderers drop.

Claude-Session: https://claude.ai/code/session_01Sy9dZFyyQJfe5rcusTtK63
…logo markup fix.

The Themes section now documents the manager-based creation and registration, the partial-override merge pattern, and the loud failure on unknown theme names. The Quick start uses a single-expression arrow function, and the logo lost its empty-href anchor.

Claude-Session: https://claude.ai/code/session_01Sy9dZFyyQJfe5rcusTtK63
…ring.

All four display modes are now visually distinct: colour modes differ by the teal accents and gray chrome, glyph modes differ by the block caret, rules and dot separators, and every editor capture shows the underlined label header.

Claude-Session: https://claude.ai/code/session_01Sy9dZFyyQJfe5rcusTtK63
An invalid registration now throws immediately with a clear message instead of surfacing later as an instantiation failure inside 'create()'.

Claude-Session: https://claude.ai/code/session_01Sy9dZFyyQJfe5rcusTtK63
…rm variable names.

The cursor-row label styling repeated across the select, multiselect, search and suggest views now lives on 'AbstractWidget'.

Claude-Session: https://claude.ai/code/session_01Sy9dZFyyQJfe5rcusTtK63
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4ffe4d20-ca3b-4963-82c2-5c5004537417

📥 Commits

Reviewing files that changed from the base of the PR and between f8a1d62 and 2f28273.

📒 Files selected for processing (3)
  • src/Widget/AbstractWidget.php
  • src/Widget/SearchWidget.php
  • src/Widget/SelectWidget.php

📝 Walkthrough

Walkthrough

The PR adds ThemeManager for theme selection and capability detection, refactors theme rendering around shared header/hint helpers, updates widgets and playground scripts to use the new theme APIs, and changes docs asset generation to anchor and verify captured SVG output.

Changes

ThemeManager and themed rendering

Layer / File(s) Summary
ThemeManager and capability detection
src/Theme/ThemeManager.php, tests/phpunit/Unit/Theme/ThemeManagerTest.php
Adds ThemeManager for theme registration, creation, and terminal capability detection, with tests for named themes, direct class creation, registration validation, and locale/TERM detection.
Base theme contract and header/hint rendering
src/Theme/AbstractTheme.php, src/Theme/ThemeInterface.php, src/Theme/DarkTheme.php, src/Theme/LightTheme.php, src/Render/PanelController.php, tests/phpunit/Unit/Render/PanelControllerTest.php, tests/phpunit/Unit/Theme/ThemeRenderTest.php, tests/phpunit/Unit/Theme/ThemeTest.php
Makes AbstractTheme a concrete default theme, adds renderHintLine and renderEditorHeader, switches dark/light themes to merge overrides with parent styles, and updates panel rendering and tests for the new output.
Tui wiring and widget label helpers
src/Tui.php, src/Widget/AbstractWidget.php
Tui::interact() now creates themes through ThemeManager, and AbstractWidget gains helpers for highlighted labels and radio rows.
Widget views and assertions
src/Widget/ConfirmWidget.php, src/Widget/MultiSearchWidget.php, src/Widget/MultiSelectWidget.php, src/Widget/PasswordWidget.php, src/Widget/PauseWidget.php, src/Widget/SearchWidget.php, src/Widget/SelectWidget.php, src/Widget/SuggestWidget.php, src/Widget/TextWidget.php, src/Widget/TextareaWidget.php, tests/phpunit/Unit/Widget/*
Widget views now style carets and markers through the theme, highlight selected labels, and render error/hint output through theme helpers; widget tests were updated for ANSI-stripped assertions and new glyph expectations.
Ocean theme overrides and docs
playground/2-custom-theme/OceanTheme.php, playground/2-custom-theme/run.php, playground/README.md
OceanTheme now merges style and glyph overrides with the parent theme, and the related playground documentation and registration comments reference ThemeManager::register().
Playground editor headers and hint lines
playground/3-widgets/*.php
The widget playground scripts replace title/footer styling with renderEditorHeader and renderHintLine, and the shared widget runner now accepts hint arrays.
Playground summary output
playground/1-scaffolder/run.php, playground/4-nested-panels/run.php, playground/5-discovery/run.php
The run scripts now print toSummary() output instead of toJson().
ThemeManager docs and examples
README.md, docs/architecture/README.md, docs/architecture/architecture.puml
README and architecture docs update theme examples, closure formatting, and architecture references to ThemeManager.

Docs asset rendering utilities

Layer / File(s) Summary
svg-term-render.js rendering flow
docs/util/svg-term-render.js
The SVG renderer now loads asciicast input, normalizes cast events differently for v3 data, merges output for --at rendering, and renders a single derived frame through load().
update-assets.php anchoring and verification
docs/util/update-assets.php
The asset updater adds frame settling, text-anchored captures, verification checks, and new cast scanning and SVG validation helpers while updating job definitions to use them.

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

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 46.27% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 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 core changes: introducing ThemeManager and updating widgets to use theme-driven rendering.
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/theme-widget-render

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

@github-actions

This comment has been minimized.

@codecov

codecov Bot commented Jul 9, 2026

Copy link
Copy Markdown

Welcome to Codecov 🎉

Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests.

Thanks for integrating Codecov - We've got you covered ☂️

A fixed 800ms capture raced the demo startup under parallel recording, producing empty frames or the leaked spawn echo. Static frames are now captured relative to the moment the demo's gate text first appears in the recording, and every generated SVG is verified to contain its expected content before the job succeeds. Recorded form demos now end with the provenance-badged answers summary instead of raw JSON.

Claude-Session: https://claude.ai/code/session_01Sy9dZFyyQJfe5rcusTtK63
Every per-widget capture now shows the widget's initial state - the previously empty textarea, confirm and password frames and the leaked spawn echo are gone - and the form demos close on the panel-grouped answers summary.

Claude-Session: https://claude.ai/code/session_01Sy9dZFyyQJfe5rcusTtK63
@github-actions

This comment has been minimized.

…isible frame.

svg-term picks the frame nearest the requested timestamp and keeps every frame sharing it; the cast loader synthesizes a blank initial screen state at the same quantized stamp, so the blank frame could fill the viewport while the real content sat outside the viewBox - the select ASCII no-ANSI capture rendered as a plain dark rectangle. The renderer now merges all output up to the timestamp and passes svg-term exactly one frame, and the asset generator rejects any static SVG holding more than one frame window.

Claude-Session: https://claude.ai/code/session_01Sy9dZFyyQJfe5rcusTtK63
@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: 1

🤖 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/Widget/MultiSelectWidget.php`:
- Around line 189-192: The marker/highlight row rendering is duplicated across
MultiSelectWidget::view(), SearchWidget::view(), and SelectWidget::view().
Extract the repeated current/styled-on-glyph vs plain-off-glyph plus
highlightLabel logic into a shared helper on AbstractWidget, such as
renderMarkerRow(ThemeInterface $theme, string $onGlyph, string $offGlyph, bool
$current, string $label): string, then update the three widget view methods to
call it and keep the glyph/label selection there only.
🪄 Autofix (Beta)

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: 863aa600-2e61-4800-bf92-2e56ed9d71f8

📥 Commits

Reviewing files that changed from the base of the PR and between 433d169 and f8a1d62.

⛔ Files ignored due to path filters (56)
  • docs/architecture/architecture.svg is excluded by !**/*.svg
  • docs/assets/discovery.svg is excluded by !**/*.svg
  • docs/assets/nested-panels.svg is excluded by !**/*.svg
  • docs/assets/scaffolder-ascii-no-ansi.svg is excluded by !**/*.svg
  • docs/assets/scaffolder-ascii.svg is excluded by !**/*.svg
  • docs/assets/scaffolder-no-ansi.svg is excluded by !**/*.svg
  • docs/assets/scaffolder.svg is excluded by !**/*.svg
  • docs/assets/theme-ocean.svg is excluded by !**/*.svg
  • docs/assets/widget-confirm-ascii-no-ansi.svg is excluded by !**/*.svg
  • docs/assets/widget-confirm-ascii.svg is excluded by !**/*.svg
  • docs/assets/widget-confirm-no-ansi.svg is excluded by !**/*.svg
  • docs/assets/widget-confirm.svg is excluded by !**/*.svg
  • docs/assets/widget-multisearch-ascii-no-ansi.svg is excluded by !**/*.svg
  • docs/assets/widget-multisearch-ascii.svg is excluded by !**/*.svg
  • docs/assets/widget-multisearch-no-ansi.svg is excluded by !**/*.svg
  • docs/assets/widget-multisearch.svg is excluded by !**/*.svg
  • docs/assets/widget-multiselect-ascii-no-ansi.svg is excluded by !**/*.svg
  • docs/assets/widget-multiselect-ascii.svg is excluded by !**/*.svg
  • docs/assets/widget-multiselect-no-ansi.svg is excluded by !**/*.svg
  • docs/assets/widget-multiselect.svg is excluded by !**/*.svg
  • docs/assets/widget-number-ascii-no-ansi.svg is excluded by !**/*.svg
  • docs/assets/widget-number-ascii.svg is excluded by !**/*.svg
  • docs/assets/widget-number-no-ansi.svg is excluded by !**/*.svg
  • docs/assets/widget-number.svg is excluded by !**/*.svg
  • docs/assets/widget-password-ascii-no-ansi.svg is excluded by !**/*.svg
  • docs/assets/widget-password-ascii.svg is excluded by !**/*.svg
  • docs/assets/widget-password-no-ansi.svg is excluded by !**/*.svg
  • docs/assets/widget-password.svg is excluded by !**/*.svg
  • docs/assets/widget-pause-ascii-no-ansi.svg is excluded by !**/*.svg
  • docs/assets/widget-pause-ascii.svg is excluded by !**/*.svg
  • docs/assets/widget-pause-no-ansi.svg is excluded by !**/*.svg
  • docs/assets/widget-pause.svg is excluded by !**/*.svg
  • docs/assets/widget-search-ascii-no-ansi.svg is excluded by !**/*.svg
  • docs/assets/widget-search-ascii.svg is excluded by !**/*.svg
  • docs/assets/widget-search-no-ansi.svg is excluded by !**/*.svg
  • docs/assets/widget-search.svg is excluded by !**/*.svg
  • docs/assets/widget-select-ascii-no-ansi.svg is excluded by !**/*.svg
  • docs/assets/widget-select-ascii.svg is excluded by !**/*.svg
  • docs/assets/widget-select-no-ansi.svg is excluded by !**/*.svg
  • docs/assets/widget-select.svg is excluded by !**/*.svg
  • docs/assets/widget-suggest-ascii-no-ansi.svg is excluded by !**/*.svg
  • docs/assets/widget-suggest-ascii.svg is excluded by !**/*.svg
  • docs/assets/widget-suggest-no-ansi.svg is excluded by !**/*.svg
  • docs/assets/widget-suggest.svg is excluded by !**/*.svg
  • docs/assets/widget-text-ascii-no-ansi.svg is excluded by !**/*.svg
  • docs/assets/widget-text-ascii.svg is excluded by !**/*.svg
  • docs/assets/widget-text-no-ansi.svg is excluded by !**/*.svg
  • docs/assets/widget-text.svg is excluded by !**/*.svg
  • docs/assets/widget-textarea-ascii-no-ansi.svg is excluded by !**/*.svg
  • docs/assets/widget-textarea-ascii.svg is excluded by !**/*.svg
  • docs/assets/widget-textarea-no-ansi.svg is excluded by !**/*.svg
  • docs/assets/widget-textarea.svg is excluded by !**/*.svg
  • docs/assets/widgets-ascii-no-ansi.svg is excluded by !**/*.svg
  • docs/assets/widgets-ascii.svg is excluded by !**/*.svg
  • docs/assets/widgets-no-ansi.svg is excluded by !**/*.svg
  • docs/assets/widgets.svg is excluded by !**/*.svg
📒 Files selected for processing (51)
  • README.md
  • docs/architecture/README.md
  • docs/architecture/architecture.puml
  • docs/util/svg-term-render.js
  • docs/util/update-assets.php
  • playground/1-scaffolder/run.php
  • playground/2-custom-theme/OceanTheme.php
  • playground/2-custom-theme/run.php
  • playground/3-widgets/widget-confirm.php
  • playground/3-widgets/widget-multisearch.php
  • playground/3-widgets/widget-multiselect.php
  • playground/3-widgets/widget-number.php
  • playground/3-widgets/widget-password.php
  • playground/3-widgets/widget-pause.php
  • playground/3-widgets/widget-search.php
  • playground/3-widgets/widget-select.php
  • playground/3-widgets/widget-suggest.php
  • playground/3-widgets/widget-text.php
  • playground/3-widgets/widget-textarea.php
  • playground/3-widgets/widgets.php
  • playground/4-nested-panels/run.php
  • playground/5-discovery/run.php
  • playground/README.md
  • src/Render/PanelController.php
  • src/Theme/AbstractTheme.php
  • src/Theme/DarkTheme.php
  • src/Theme/LightTheme.php
  • src/Theme/ThemeInterface.php
  • src/Theme/ThemeManager.php
  • src/Tui.php
  • src/Widget/AbstractWidget.php
  • src/Widget/ConfirmWidget.php
  • src/Widget/MultiSearchWidget.php
  • src/Widget/MultiSelectWidget.php
  • src/Widget/PasswordWidget.php
  • src/Widget/PauseWidget.php
  • src/Widget/SearchWidget.php
  • src/Widget/SelectWidget.php
  • src/Widget/SuggestWidget.php
  • src/Widget/TextWidget.php
  • src/Widget/TextareaWidget.php
  • tests/phpunit/Unit/Render/PanelControllerTest.php
  • tests/phpunit/Unit/Theme/ThemeManagerTest.php
  • tests/phpunit/Unit/Theme/ThemeRenderTest.php
  • tests/phpunit/Unit/Theme/ThemeTest.php
  • tests/phpunit/Unit/Widget/ConfirmWidgetTest.php
  • tests/phpunit/Unit/Widget/MultiSearchWidgetTest.php
  • tests/phpunit/Unit/Widget/NumberWidgetTest.php
  • tests/phpunit/Unit/Widget/PasswordWidgetTest.php
  • tests/phpunit/Unit/Widget/SearchWidgetTest.php
  • tests/phpunit/Unit/Widget/TextWidgetTest.php
💤 Files with no reviewable changes (1)
  • playground/5-discovery/run.php

Comment thread src/Widget/MultiSelectWidget.php
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Code Coverage Report:
  2026-07-09 06:35:11

 Summary:
  Classes: 89.47% (51/57)
  Methods: 97.67% (293/300)
  Lines:   98.72% (1232/1248)

DrevOps\Tui\Answers\Answer
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  1/  1)
DrevOps\Tui\Answers\Answers
  Methods: 100.00% ( 9/ 9)   Lines: 100.00% ( 20/ 20)
DrevOps\Tui\Answers\SummaryFormatter
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% ( 20/ 20)
DrevOps\Tui\Builder\FieldBuilder
  Methods:  85.71% (12/14)   Lines:  91.11% ( 41/ 45)
DrevOps\Tui\Builder\Form
  Methods: 100.00% (13/13)   Lines: 100.00% ( 47/ 47)
DrevOps\Tui\Builder\PanelBuilder
  Methods: 100.00% (16/16)   Lines: 100.00% ( 28/ 28)
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\Config\Config
  Methods: 100.00% ( 5/ 5)   Lines: 100.00% ( 17/ 17)
DrevOps\Tui\Config\Field
  Methods: 100.00% ( 2/ 2)   Lines: 100.00% (  2/  2)
DrevOps\Tui\Config\Option
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  1/  1)
DrevOps\Tui\Config\Panel
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  1/  1)
DrevOps\Tui\Derive\Derive
  Methods: 100.00% ( 4/ 4)   Lines: 100.00% ( 14/ 14)
DrevOps\Tui\Derive\Deriver
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% ( 13/ 13)
DrevOps\Tui\Derive\Transform
  Methods: 100.00% ( 7/ 7)   Lines: 100.00% ( 16/ 16)
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\Engine\Engine
  Methods: 100.00% (12/12)   Lines: 100.00% ( 89/ 89)
DrevOps\Tui\Handler\HandlerRegistry
  Methods:  85.71% ( 6/ 7)   Lines:  95.45% ( 21/ 22)
DrevOps\Tui\Input\ArrayKeyStream
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% ( 12/ 12)
DrevOps\Tui\Input\Key
  Methods: 100.00% ( 5/ 5)   Lines: 100.00% (  5/  5)
DrevOps\Tui\Input\KeyParser
  Methods: 100.00% ( 6/ 6)   Lines: 100.00% ( 68/ 68)
DrevOps\Tui\Render\Ansi
  Methods: 100.00% ( 4/ 4)   Lines: 100.00% (  5/  5)
DrevOps\Tui\Render\Navigator
  Methods: 100.00% ( 6/ 6)   Lines: 100.00% ( 15/ 15)
DrevOps\Tui\Render\PanelController
  Methods: 100.00% (16/16)   Lines: 100.00% ( 87/ 87)
DrevOps\Tui\Render\Scroller
  Methods: 100.00% ( 4/ 4)   Lines: 100.00% ( 12/ 12)
DrevOps\Tui\Render\Terminal
  Methods: 100.00% ( 5/ 5)   Lines: 100.00% (  6/  6)
DrevOps\Tui\Render\TerminalControl
  Methods: 100.00% ( 8/ 8)   Lines: 100.00% (  8/  8)
DrevOps\Tui\Render\Viewport
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  1/  1)
DrevOps\Tui\Resolver\InputResolver
  Methods: 100.00% ( 6/ 6)   Lines: 100.00% ( 27/ 27)
DrevOps\Tui\Schema\AgentHelp
  Methods: 100.00% ( 2/ 2)   Lines: 100.00% ( 16/ 16)
DrevOps\Tui\Schema\SchemaGenerator
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% ( 25/ 25)
DrevOps\Tui\Schema\SchemaValidator
  Methods: 100.00% ( 7/ 7)   Lines: 100.00% ( 40/ 40)
DrevOps\Tui\Theme\AbstractTheme
  Methods: 100.00% (26/26)   Lines: 100.00% (122/122)
DrevOps\Tui\Theme\DarkTheme
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  7/  7)
DrevOps\Tui\Theme\ThemeManager
  Methods: 100.00% ( 4/ 4)   Lines: 100.00% ( 16/ 16)
DrevOps\Tui\Tui
  Methods: 100.00% (10/10)   Lines: 100.00% ( 16/ 16)
DrevOps\Tui\Widget\AbstractWidget
  Methods: 100.00% ( 9/ 9)   Lines: 100.00% ( 20/ 20)
DrevOps\Tui\Widget\ConfirmWidget
  Methods: 100.00% ( 6/ 6)   Lines: 100.00% ( 23/ 23)
DrevOps\Tui\Widget\MultiSearchWidget
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  1/  1)
DrevOps\Tui\Widget\MultiSelectWidget
  Methods: 100.00% ( 7/ 7)   Lines: 100.00% ( 54/ 54)
DrevOps\Tui\Widget\NumberWidget
  Methods: 100.00% ( 2/ 2)   Lines: 100.00% (  7/  7)
DrevOps\Tui\Widget\PasswordWidget
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  3/  3)
DrevOps\Tui\Widget\PauseWidget
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% (  6/  6)
DrevOps\Tui\Widget\SearchWidget
  Methods:  80.00% ( 4/ 5)   Lines:  94.59% ( 35/ 37)
DrevOps\Tui\Widget\SelectWidget
  Methods: 100.00% ( 4/ 4)   Lines: 100.00% ( 19/ 19)
DrevOps\Tui\Widget\SuggestWidget
  Methods: 100.00% ( 5/ 5)   Lines: 100.00% ( 37/ 37)
DrevOps\Tui\Widget\TextWidget
  Methods: 100.00% ( 6/ 6)   Lines: 100.00% ( 29/ 29)
DrevOps\Tui\Widget\TextareaWidget
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% ( 33/ 33)
DrevOps\Tui\Widget\WidgetFactory
  Methods: 100.00% ( 3/ 3)   Lines: 100.00% ( 25/ 25)
DrevOps\Tui\Widget\WidgetRunner
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  5/  5)

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