Skip to content

fix: include actual color values in the style fingerprint to prevent renderer from skipping color-only changes#1807

Merged
Karanjot786 merged 2 commits into
Karanjot786:mainfrom
anshika1179:fix/issue-1773
Jul 11, 2026
Merged

fix: include actual color values in the style fingerprint to prevent renderer from skipping color-only changes#1807
Karanjot786 merged 2 commits into
Karanjot786:mainfrom
anshika1179:fix/issue-1773

Conversation

@anshika1179

@anshika1179 anshika1179 commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Description

This PR fixes the issue where the renderer skips color-only changes because the getStyleLine() fingerprint ignored actual color values and only hashed the color's type string. A new hashColor() function is introduced to incorporate the specific color values (named name, ansi code, rgb values, or hex code) into the line hash so that foreground or background color changes trigger a re-render.

Related Issue

Closes #1773

Which package(s)?

@termuijs/core

Type of Change

  • 🐛 Bug fix (type:bug)
  • ✨ Feature (type:feature)
  • 📝 Docs (type:docs)
  • 🧪 Tests (type:testing)
  • ♻️ Refactor (type:refactor)
  • 🎨 Design / UX (type:design)
  • ♿ Accessibility (type:accessibility)
  • 🚀 Performance (type:performance)
  • 👷 DevOps / CI (type:devops)
  • 🔒 Security (type:security)

Checklist

  • ⭐ You starred the repo. The needs-star check blocks your merge otherwise.
  • Tests pass locally: bun vitest run
  • Build passes: bun run build
  • Typecheck passes: bun run typecheck
  • You read CONTRIBUTING.md.
  • Your PR title follows type: short description.
  • Widget state mutators call markDirty() (if your change affects rendering).
  • No new any types without an inline comment explaining why.
  • No unrelated refactors bundled into this PR.

GSSoC 2026 Participation

  • You are a GSSoC 2026 contributor.
  • Your GSSoC profile: https://gssoc.girlscript.org/profile/anshika1179

Screenshots / Recordings (UI changes)

Notes for the Reviewer

Added hashColor function to handle hashing for none, named, ansi256, rgb, and hex color types, properly shifting and merging the actual color definition fields with the rolling row hash.

Summary by CodeRabbit

  • Refactor
    • Improved how row styling is fingerprinted, making style comparison more consistent across different color types.
    • Preserved existing text-style handling and link detection while refining the underlying style hashing logic.

…event renderer from skipping color-only changes
@anshika1179 anshika1179 requested a review from Karanjot786 as a code owner June 24, 2026 06:00
@github-actions github-actions Bot added type:bug +10 pts. Bug fix. area:core @termuijs/core and removed type:bug +10 pts. Bug fix. labels Jun 24, 2026
@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

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

Next review available in: 19 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a03d30db-c3d6-4e9e-a7c7-0ff5de618f38

📥 Commits

Reviewing files that changed from the base of the PR and between ba8da76 and 6f0b2a6.

📒 Files selected for processing (1)
  • packages/core/src/terminal/Screen.ts
📝 Walkthrough

Walkthrough

Screen.ts adds a new hashColor(color, hash) helper that generates distinct hash contributions for each Color variant (none, named, ansi256, rgb, hex) using actual color values. The getStyleLine(row) method is then refactored to call hashColor for cell.fg and cell.bg instead of the previous type-string-based seed computation.

Changes

Color fingerprint fix in Screen.ts

Layer / File(s) Summary
hashColor helper and getStyleLine refactor
packages/core/src/terminal/Screen.ts
Adds hashColor(color, hash) that branches on Color.type and mixes in actual values (name endpoints, code, RGB components, or hex characters). getStyleLine(row) replaces the old fg.type/bg.type seed with hashColor(cell.fg, hash) and hashColor(cell.bg, hash) calls, while retaining the existing style-bit flag and link hashing logic.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Possibly related issues

  • #1773: This PR directly implements the exact fix described in the issue — introducing hashColor to include actual color values in the getStyleLine fingerprint, preventing the renderer from skipping color-only row changes.
  • [bug] Screen.setStyleLine hash collision silently skips color code updates #1659: The change addresses the same hash-collision bug in Screen.ts described there — refactoring getStyleLine hashing to include full color variant data.

Possibly related PRs

  • Karanjot786/TermUI#709: Modifies the same getStyleLine style fingerprinting logic in Screen.ts, adding the initial per-row style diffing that this PR now corrects.
  • Karanjot786/TermUI#954: Adjusts the renderer's use of the style fingerprint to skip redundant ANSI emission, which depends on the correctness of the hash now fixed here.
  • Karanjot786/TermUI#1231: Normalizes hex color case in Screen.ts, directly affecting the hex branch of the hashColor logic introduced in this PR.

Suggested labels

gssoc:approved, quality:clean, type:bug, area:core, level:beginner

Suggested reviewers

  • Karanjot786

Poem

🐇 Hop, hop — the colors lied,
'none' and 'named' both typed 'n' inside,
Now red stays red and blue stays true,
Each hue gets hashed the whole way through,
The renderer skips no style tonight,
This bunny fixed the fingerprint right! 🎨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.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
Title check ✅ Passed The title accurately and concisely describes the main change: including actual color values in the style fingerprint.
Description check ✅ Passed The description matches the repository template and includes the required sections with relevant details.
Linked Issues check ✅ Passed The code change aligns with #1773 by hashing actual color values for all color types and updating getStyleLine().
Out of Scope Changes check ✅ Passed The PR stays focused on the style fingerprint fix in Screen.ts and introduces no obvious unrelated changes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@github-actions github-actions Bot added the type:bug +10 pts. Bug fix. label Jun 24, 2026

@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 `@packages/core/src/terminal/Screen.ts`:
- Around line 105-113: Update hashColor in Screen.ts so each color variant
contributes a non-zero tag before mixing in its value, preventing none,
ansi256(0), and rgb(0,0,0) from producing the same fingerprint from an initial
hash. Rework the named case to hash the full color.name string rather than only
the first and last characters, and apply the same variant-tag-first pattern
consistently across all switch branches.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0d1951fc-9047-430e-b905-0096506b7eed

📥 Commits

Reviewing files that changed from the base of the PR and between 0fdff96 and ba8da76.

📒 Files selected for processing (1)
  • packages/core/src/terminal/Screen.ts

Comment thread packages/core/src/terminal/Screen.ts
@Karanjot786

Copy link
Copy Markdown
Owner

Thanks — you've correctly identified a real bug: the old charCodeAt(0) fingerprint collides across ansi256/rgb/hex/named colors. The problem is the cost of the fix.

Issues:

  1. Performance regression in the render hot path (CI bench fails)
    File: packages/core/src/terminal/Screen.ts (getStyleLine -> hashColor)
    Problem: hashColor runs a switch + per-char loop over hex strings for every fg and bg of every cell on every dirty row. The bench gate fails (run 28078578899) — this is your change, not base divergence (every other PR passes bench on the same base).
    Fix: make the per-cell fingerprint cheap — parse hex to a number once, avoid the per-char loop and wide multiplies, or precompute/cache a hash on the Color. Get bench under the 20% threshold.

  2. Non-exhaustive switch
    File: Screen.ts (hashColor)
    Problem: no default — a new Color variant would return undefined -> NaN hash.
    Fix: add default: return hash; (or assertNever).

Note: this overlaps with #1646, which makes the same getStyleLine/hashColor change and hits the same bench regression. Coordinate so only one lands.

Checklist before re-requesting review:

  • bench green (faster per-cell fingerprint)
  • switch has a default/exhaustiveness guard
  • Tests pass locally (run: bun vitest run)

The style fingerprint's hashColor() looped over every character of the
hex string per cell (fg + bg, every dirty row, every frame), regressing
render throughput ~20-32% and failing the bench CI gate. Decode the
hex digits directly with charCodeAt/bit-shifts into r/g/b and combine
them numerically, matching the existing O(1) rgb path. No behavior
change to the fingerprint's collision-avoidance property.

Co-authored-by: Karanjot786 <karanjots801@gmail.com>
@Karanjot786

Copy link
Copy Markdown
Owner

Optimized the per-cell color hash in hashColor() to clear the bench gate — the hex branch was looping over every character of the hex string (fg + bg, every dirty row, every frame). It now decodes the 3 byte-pairs directly via charCodeAt/bit-shifts into r/g/b and combines them numerically, same O(1) shape as the existing rgb branch. No allocations, no loops in the hot path anymore. Correctness fix (actual color values in the fingerprint) is unchanged. All Screen/Renderer tests pass locally.

Note: #2150 appears to fix the same underlying bug — worth reconciling/closing one in favor of the other.

@Karanjot786 Karanjot786 merged commit df88154 into Karanjot786:main Jul 11, 2026
6 checks passed
@Karanjot786 Karanjot786 added gssoc:approved Approved PR. Earns +50 base points. quality:clean x 1.2 multiplier. Clean implementation. level:advanced +55 pts. Complex task. labels Jul 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:core @termuijs/core gssoc:approved Approved PR. Earns +50 base points. level:advanced +55 pts. Complex task. quality:clean x 1.2 multiplier. Clean implementation. type:bug +10 pts. Bug fix.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

getStyleLine() fingerprint ignores actual color values — renderer skips color-only changes

2 participants