Skip to content

feat: fluent colour, emoji and layout API on ConsoleUIFormatter - #65

Merged
imanimanyara merged 6 commits into
mainfrom
feat/formatter-fluent-api
Sep 27, 2026
Merged

imanimanyara merged 6 commits into
mainfrom
feat/formatter-fluent-api

Conversation

@imanimanyara

@imanimanyara imanimanyara commented Sep 27, 2026 •

Copy link
Copy Markdown
Member

What

A fluent API on ConsoleUIFormatter, so a whole style is one chain:

ConsoleUIFormatter::create()->txtColorRed()->bgColorWhite()->bold()
    ->message('✓ Deployed 🚀')->padding(2)->lineHeight(3)
    ->addSpaceBefore()->addSpaceAfter(1, ConsoleUIFormatter::TAB)
    ->write($output);
  • txtColor<Name>() / bgColor<Name>(): 38 names, each declared as an @method. fg() / bg() accept any colour that Support\Color parses.
  • message() resolves :shortcodes: through Support\Emoji, which uses laranail/emojis when it is installed and falls back to ASCII otherwise. icon() puts an emoji in front of the message.
  • padding() works inside the background. lineHeight() adds blank background lines above and below. addSpaceBefore() / addSpaceAfter() add spaces or tabs outside the background; the count must be positive, and calls add up.
  • New methods: markup(), capabilities(), write(), toAnsi(), and the style shortcuts.

It extends the existing builder rather than adding a fourth one, and a plain message renders exactly as before.

Fixes (each reproduced first)

  • The 14 BRIGHT_* / BG_BRIGHT_* constants threw when written, because the sanitiser stripped the hyphen.
  • colorize() emitted no colour for BRIGHT_* (bright-red vs bright_red keys).
  • Color names such as orange threw when written; they are now converted to hex.
  • Unknown colours and text styles now fail at the call that sets them.
  • A coloured link lost its colour.

Behaviour change

Message text is now escaped. </> inside a message used to end the style early; now it prints literally. markup() restores the old behaviour for trusted input.

Verification

  • composer test: 533 passed, including 23 new formatter tests.
  • composer pint passes. phpstan reports no errors.
  • composer examples includes the new examples/tools/formatting.php.
  • Mutation checks, each of which fails at least one test:
    • hyphen stripped in the colour sanitiser
    • message escaping removed
    • option validation removed
    • a space count of 0 allowed
    • emoji rendering in message() removed

Adds txtColor<Name>()/bgColor<Name>() for 38 named colours, fg()/bg(),
message() with emoji shortcodes via Support\Emoji, icon(), padding(),
lineHeight(), addSpaceBefore()/addSpaceAfter(), markup(), capabilities(),
write() and toAnsi(). A plain message renders exactly as before.

Fixes found while building it, each reproduced first:
- BRIGHT_* constants threw: the sanitiser stripped the hyphen
- colorize() ignored BRIGHT_* (bright-red vs bright_red keys)
- Color names such as orange threw at write time; now converted to hex
- unknown colours and text styles now fail where they are set
- a coloured link dropped its colour
- message text is escaped, so </> in it cannot end the style early
Rewrites docs/tools/formatting.md around the builder, adds a runnable examples/tools/formatting.php to the composer examples script, and records the additions, fixes and the escaping change under [Unreleased].
Copilot AI lite review requested due to automatic review settings September 27, 2026 22:23

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

message() and icon() resolved shortcodes when called, so a capabilities() call later in the chain was ignored: asking for ASCII after message() still printed the Unicode emoji. Both now resolve in render(). The formatter tests also cleared neither Capabilities::fake() nor EmojisBridge::fake(), which are process-wide, so they leaked into later tests; tearDown resets both. Adds a test proving names resolve through the laranail/emojis catalogue when it is installed.
@imanimanyara
imanimanyara merged commit adc0d58 into main Sep 27, 2026
15 checks passed
@imanimanyara
imanimanyara deleted the feat/formatter-fluent-api branch September 27, 2026 23:57
@imanimanyara imanimanyara mentioned this pull request Sep 27, 2026
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.

2 participants