Skip to content

of-the-day: font-aware word wrapping with auto-fit for long definitions - #260

Merged
ChuckBuilds merged 2 commits into
mainfrom
claude/of-the-day-word-wrap-odosaq
Aug 6, 2026
Merged

of-the-day: font-aware word wrapping with auto-fit for long definitions#260
ChuckBuilds merged 2 commits into
mainfrom
claude/of-the-day-word-wrap-odosaq

Conversation

@ChuckBuilds

@ChuckBuilds ChuckBuilds commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Pull Request

Summary

Makes the of-the-day plugin's word wrapping fully font-aware: long definitions and subtitles now wrap into as many lines as actually fit the panel (computed from the real font height and available space, not hardcoded line counts), and when the configured font can't fit the whole text, scalable fonts auto-shrink to the largest size that fits everything. Text that can't fit even at the smallest size is cut with a visible ... instead of being silently clipped mid-sentence at the panel bottom.

Type of change

  • Bug fix in an existing plugin
  • New plugin (also fill out the SUBMISSION.md checklist below)
  • New feature for an existing plugin
  • Documentation only
  • Repo-wide change (registry script, hook, top-level docs)

Plugin(s) affected

of-the-day

Related issues

N/A

Test plan

  • Loaded the plugin in LEDMatrix on real hardware
  • Loaded the plugin in LEDMatrix emulator mode
    (EMULATOR=true python3 run.py)
  • Rendered the plugin in the dev preview server / safety harness — ran the core repo's scripts/check_plugin.py across all 8 supported sizes: all PASS, with only the 64x32 golden changing (its subtitle was previously clipped mid-sentence with no indication; it now ends with an ellipsis). Also rendered long-definition and font-size-override scenarios and visually inspected the PNGs.
  • Verified the web UI configuration form against the schema — new auto_fit_text key has type, default, description, and is marked x-advanced
  • N/A — repo-wide / docs-only change

Additionally: added test_text_fitting.py (11 new tests covering wrap correctness, auto-shrink, ellipsize fallback, and the auto-fit-off path) and re-ran the existing test_element_styles.py — all 20 tests pass, confirming untouched configs still render byte-identically on the styling paths.

Required for plugin changes

  • Bumped version in plugins/<id>/manifest.json (1.3.2 → 1.4.0)
  • class_name in manifest.json matches the actual class in manager.py exactly (case-sensitive, no spaces)
  • entry_point matches the real file (or is omitted to use the manager.py default)
  • Updated the plugin's README.md if config keys changed — documented auto_fit_text
  • config_schema.json is the source of truth for the web UI form — any new option is in the schema with a default, description, and constraints
  • Pre-commit hook ran successfully (auto-syncs plugins.json) — update_registry.py run manually; plugins.json now lists 1.4.0

SUBMISSION checklist (new plugins only)

N/A — existing plugin.

Checklist

  • My commits follow the message convention in CONTRIBUTING.md
  • I read CONTRIBUTING.md and CODE_OF_CONDUCT.md
  • I've not committed any secrets

Notes for reviewer

  • Fitting strategy: the auto-shrink only engages when a smaller size makes the entire text fit — if nothing fits (e.g. a 116-char definition on 64x32), the configured font is kept (crisper than a shrunken font that still overflows) and the text is ellipsized. MIN_AUTO_FONT_SIZE = 5 bounds the shrink.
  • Bitmap fonts (BDF freetype.Face, PIL default) can't be resized, so they skip the shrink and go straight to wrap + ellipsize.
  • Also fixed a latent spacing bug: the dynamic-spacing spread's integer rounding could push the last wrapped line one row past the panel bottom, where the overflow guard silently dropped it; the spread is now clamped so a line that fits is never dropped.
  • Only the 64x32 golden changed; the other 7 sizes are pixel-identical to their committed goldens with an untouched config.

Generated by Claude Code

Summary by CodeRabbit

  • New Features

    • Added automatic text fitting for the Of The Day plugin, including font-aware wrapping, font shrinking, and ellipsis truncation.
    • Added an advanced auto_fit_text setting, enabled by default, to control this behavior.
  • Bug Fixes

    • Improved rendering of long titles, subtitles, and definitions to prevent overflow and blank panels.
  • Documentation

    • Documented the new text-fitting configuration option.
  • Chores

    • Updated the Of The Day plugin to version 1.4.0.

Long definitions and subtitles previously wrapped against hardcoded line
counts (10 body / 3 subtitle) and any lines past the panel bottom were
silently dropped, so long content was cut off mid-sentence — and picking a
larger font via the customization UI made it worse.

Wrapping is now fully font-aware: the number of lines is computed from the
real font height and the space below the underline, and line breaks are
measured with the actual font. When the wrapped text still needs more lines
than fit, scalable fonts are retried at progressively smaller sizes (down
to 5px) and the largest size that fits the whole text wins. When no size
fits everything — or the font is a non-scalable bitmap font — the
configured font is kept and the text is cut with a visible '...' instead
of being clipped silently.

Also clamps the dynamic spacing spread so rounding can no longer push the
last wrapped line one row past the panel and drop it.

New advanced config key auto_fit_text (default true) disables the
auto-shrink; wrapping stays font-aware regardless. Consolidates the
repeated text-width/font-height fallback code into helpers, adds
test_text_fitting.py regression tests, and regenerates the 64x32 golden
(the subtitle there was previously clipped mid-sentence; it now shows an
ellipsis).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BRMQBB431aTK2mq6GGmEgk
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@ChuckBuilds, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 55 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

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: CHILL

Plan: Pro Plus

Run ID: 8dbdc083-c671-41d6-8ad3-c8ef536f2fa3

📥 Commits

Reviewing files that changed from the base of the PR and between f57f29a and 9c2d586.

📒 Files selected for processing (3)
  • plugins/of-the-day/manager.py
  • plugins/of-the-day/manifest.json
  • plugins/of-the-day/test_text_fitting.py
📝 Walkthrough

Walkthrough

The Of The Day plugin adds the enabled-by-default auto_fit_text option. Rendering now uses font-aware measurement, dynamic font shrinking, wrapping, ellipsis truncation, and expanded regression tests.

Changes

Of The Day text fitting

Layer / File(s) Summary
Configuration and release metadata
plugins/of-the-day/config_schema.json, plugins/of-the-day/README.md, plugins/of-the-day/manager.py, plugins/of-the-day/manifest.json, plugins.json
Adds the advanced auto_fit_text setting, documents its behavior, reloads it from configuration, and updates plugin version and catalog metadata.
Text fitting and rendering
plugins/of-the-day/manager.py
Adds shared text measurement, font-height, resizing, wrapping, ellipsizing, and spacing helpers. Applies them to title, subtitle, and description rendering.
Text fitting regression coverage
plugins/of-the-day/test_text_fitting.py
Tests wrapping, font reduction, ellipsis fallback, disabled auto-fitting, rendering safety, and short and long content.

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

Sequence Diagram(s)

sequenceDiagram
  participant Configuration
  participant OfTheDayManager
  participant TextFitting
  participant DisplayManager
  Configuration->>OfTheDayManager: Load auto_fit_text
  OfTheDayManager->>TextFitting: Fit title, subtitle, or description
  TextFitting->>DisplayManager: Measure font and text dimensions
  TextFitting-->>OfTheDayManager: Return fitted text
  OfTheDayManager->>DisplayManager: Render fitted text
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% 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 clearly and concisely summarizes the main changes to the of-the-day plugin.
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 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/of-the-day-word-wrap-odosaq

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@codacy-production

codacy-production Bot commented Aug 6, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 24 complexity

Metric Results
Complexity 24

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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 `@plugins/of-the-day/manager.py`:
- Around line 477-481: Update the candidate-acceptance logic in the font-sizing
method around _wrap_text so a candidate is returned only when the wrapped output
preserves every input token without ellipsizing or truncating an oversized word;
otherwise continue evaluating smaller scalable-font candidates. Add a regression
test covering a word wider than max_width where a smaller candidate preserves
the complete word.

In `@plugins/of-the-day/manifest.json`:
- Line 28: Correct the auto_fit_text description in the manifest notes so it
states that disabling the setting prevents auto-shrinking, while the
default-enabled setting enables it.
- Line 27: Replace the deprecated ledmatrix_min field in the new release record
with ledmatrix_min_version, preserving the existing version value.
🪄 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: CHILL

Plan: Pro Plus

Run ID: 492c6ea0-e65c-4863-aef4-52c4c32d86bf

📥 Commits

Reviewing files that changed from the base of the PR and between 5fb40ad and f57f29a.

⛔ Files ignored due to path filters (1)
  • plugins/of-the-day/test/golden/64x32/of_the_day.png is excluded by !**/*.png
📒 Files selected for processing (6)
  • plugins.json
  • plugins/of-the-day/README.md
  • plugins/of-the-day/config_schema.json
  • plugins/of-the-day/manager.py
  • plugins/of-the-day/manifest.json
  • plugins/of-the-day/test_text_fitting.py

Comment thread plugins/of-the-day/manager.py
Comment thread plugins/of-the-day/manifest.json Outdated
Comment thread plugins/of-the-day/manifest.json Outdated
- Use ledmatrix_min_version (not the deprecated ledmatrix_min) in the new
  1.4.0 manifest release record; the core's store manifest validation
  flags the old spelling.
- Fix the 1.4.0 release note, which described auto_fit_text backwards.
- Don't accept a font size as fitting when _wrap_text had to truncate a
  word wider than the panel: keep trying smaller sizes that can hold the
  word whole, with a regression test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BRMQBB431aTK2mq6GGmEgk

Copy link
Copy Markdown
Owner Author

CI status note: the collisions check keeps failing due to a GitHub Actions infrastructure outage — the runner can't download its actions (Failed to resolve action download info. Error: Service Unavailable), so the collision script never executes. Nothing code-related: safety and Codacy are green on this head, and check_module_collisions.py passes locally across all 43 plugins. I've re-queued the run and will keep retrying until it lands in a healthy window.


Generated by Claude Code

@ChuckBuilds
ChuckBuilds merged commit f19e563 into main Aug 6, 2026
4 of 6 checks passed
@ChuckBuilds
ChuckBuilds deleted the claude/of-the-day-word-wrap-odosaq branch August 6, 2026 18:05
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