Skip to content

Fix/terminal debounce#711

Merged
Karanjot786 merged 1 commit into
Karanjot786:mainfrom
abhijnyan-codes:fix/terminal-debounce
Jun 5, 2026
Merged

Fix/terminal debounce#711
Karanjot786 merged 1 commit into
Karanjot786:mainfrom
abhijnyan-codes:fix/terminal-debounce

Conversation

@abhijnyan-codes
Copy link
Copy Markdown
Contributor

@abhijnyan-codes abhijnyan-codes commented Jun 4, 2026

Description

This PR implements debouncing and deduplication for terminal resize events (SIGWINCH) in the Terminal adapter. It adds a configurable resizeDebounceMs (default 16ms) to prevent rapid, redundant resize dispatches while ensuring the final, accurate dimensions are captured. It also guarantees that timers are properly cleared during restore() to prevent memory leaks.

Related Issue

Closes #[ISSUE_NUMBER]

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/8a07df5d-1e10-436c-b2a5-790d42085965

Screenshots / Recordings (UI changes)

N/A - This is a core event logic change without visual layout modifications.

Notes for the Reviewer

  • The change is strictly confined to packages/core per the issue specifications.
  • Implemented tests using vi.useFakeTimers() and a simulated stdout stream to safely verify debounce timing, deduplication, and cleanup without mutating the global process.

Summary by CodeRabbit

  • New Features

    • Added resizeDebounceMs option to control terminal resize debouncing.
    • Terminal now debounces and deduplicates resize events—multiple rapid resizes collapse into one handler call, unchanged dimensions are skipped, and pending resize actions are cleared when the terminal is restored.
  • Tests

    • New tests covering resize debouncing, deduplication, and timer cleanup behavior.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 4, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8a254b9a-90ff-41b0-9a70-5964d5b909f6

📥 Commits

Reviewing files that changed from the base of the PR and between d759b7b and b79b15a.

📒 Files selected for processing (2)
  • packages/core/src/terminal/Terminal.test.ts
  • packages/core/src/terminal/Terminal.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/core/src/terminal/Terminal.ts
  • packages/core/src/terminal/Terminal.test.ts

📝 Walkthrough

Walkthrough

Terminal class now accepts a resizeDebounceMs configuration option to batch resize events. The resize listener immediately updates cached dimensions, then dispatches handler invocations via a debounced timer that deduplicates unchanged dimensions. The restore() method clears any pending timer. Comprehensive tests verify debounce coalescing, deduplication, and timer cleanup.

Changes

Terminal Resize Debouncing and Deduplication

Layer / File(s) Summary
Debounce configuration and state fields
packages/core/src/terminal/Terminal.ts
TerminalOptions adds optional resizeDebounceMs field; Terminal introduces _resizeDebounceMs, _resizeTimer, and cached _lastDispatchedCols/_lastDispatchedRows to track debounce state and detect dimension changes.
Debounced resize dispatch and cleanup
packages/core/src/terminal/Terminal.ts
Resize listener updates cached _cols/_rows immediately, clears and reschedules a debounce timer, and calls registered handlers only if dimensions differ from last dispatch; restore() clears the pending timer before other cleanup.
Resize debounce test suite
packages/core/src/terminal/Terminal.test.ts
Vitest suite with EventEmitter-based stdout stub and fake timers validates: rapid resizes coalesce into one handler call with final dimensions, identical dimensions skip dispatch, and restore() cancels pending dispatch.

Sequence Diagram

sequenceDiagram
  participant Listener as resize listener
  participant Timer as debounce timer
  participant Handler as resize handler
  Listener->>Listener: update _cols/_rows immediately
  Listener->>Timer: clear prior timer
  Listener->>Timer: schedule dispatch after debounce ms
  Listener->>Listener: (rapid resize received)
  Listener->>Listener: update _cols/_rows
  Listener->>Timer: clear and reschedule
  Timer->>Handler: dispatch with final dimensions
  Handler->>Handler: cache dispatched (cols, rows)
  Listener->>Listener: (identical resize received)
  Listener->>Listener: update _cols/_rows
  Listener->>Timer: clear and reschedule
  Timer->>Handler: skip dispatch (dims unchanged from last dispatch)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Suggested reviewers

  • Karanjot786

Poem

🐰 I hop through code with ears alert and bright,
Small resizes bundled, saved from frantic flight,
Timers wait a breath, then send the final call,
Duplicates are skipped — no clatter in the hall,
Tests prove the calm; the terminal thanks the night. ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title 'Fix/terminal debounce' does not follow the required format 'type: short description'. It should be 'fix: terminal debounce' or similar. Update the PR title to follow the format 'type: short description', e.g., 'fix: debounce terminal resize events'.
Description check ❓ Inconclusive The description is largely complete with all required sections filled, including objectives, related issue, packages, type of change, and checklist items. However, the Related Issue section contains a placeholder '[ISSUE_NUMBER]' rather than an actual issue link. Replace the placeholder '#[ISSUE_NUMBER]' in the Related Issue section with the actual issue number (e.g., 'Closes #123') to fully complete the requirement.
✅ Passed checks (3 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

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

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

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

@github-actions github-actions Bot added type:devops +15 pts. CI, build, or release. area:jsx @termuijs/jsx area:core @termuijs/core area:dev-server @termuijs/dev-server type:testing +10 pts. Tests. labels Jun 4, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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/Terminal.test.ts`:
- Line 9: The test's fakeStdout variable declares write: any which violates the
"no any without inline comment" rule; update the declaration in Terminal.test.ts
(the fakeStdout variable) by either replacing `any` with the correct function
type for the stream write (e.g., a mock signature) or, if that isn't practical,
add a brief inline comment after `any` explaining why `any` is necessary (for
example: /* uses a simplified mock of stream.write signature for tests */) so
the linter rule is satisfied.
- Line 22: The test uses a double type assertion "fakeStdout as unknown as
NodeJS.WriteStream" without explanation; add an inline comment next to this
assertion in Terminal.test.ts explaining why the assertion is required (e.g.,
fakeStdout is a simplified mock that doesn’t implement the full
NodeJS.WriteStream interface or TS types are incompatible for the test),
referencing the fakeStdout variable and the NodeJS.WriteStream cast so future
readers know the rationale and can safely refactor.
🪄 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: 713a943e-f6e9-4cee-8495-7bb69f58710b

📥 Commits

Reviewing files that changed from the base of the PR and between c36cc8c and 589fd7b.

📒 Files selected for processing (6)
  • packages/core/src/terminal/Terminal.test.ts
  • packages/core/src/terminal/Terminal.ts
  • packages/dev-server/src/server.test.ts
  • packages/jsx/src/index.ts
  • packages/motion/src/index.ts
  • packages/motion/src/sequence.ts
💤 Files with no reviewable changes (2)
  • packages/dev-server/src/server.test.ts
  • packages/motion/src/sequence.ts


describe('Resize Debouncing & Deduplication', () => {
let term: Terminal;
let fakeStdout: EventEmitter & { columns: number; rows: number; write: any };
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add inline comment for any type.

The write: any property violates the TypeScript guideline requiring an inline comment explaining why any is necessary. As per coding guidelines, "No any without an inline comment explaining why."

📝 Proposed fix
-        let fakeStdout: EventEmitter & { columns: number; rows: number; write: any };
+        let fakeStdout: EventEmitter & { columns: number; rows: number; write: any /* mock fn type incompatible with WriteStream.write */ };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let fakeStdout: EventEmitter & { columns: number; rows: number; write: any };
let fakeStdout: EventEmitter & { columns: number; rows: number; write: any /* mock fn type incompatible with WriteStream.write */ };
🤖 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 `@packages/core/src/terminal/Terminal.test.ts` at line 9, The test's fakeStdout
variable declares write: any which violates the "no any without inline comment"
rule; update the declaration in Terminal.test.ts (the fakeStdout variable) by
either replacing `any` with the correct function type for the stream write
(e.g., a mock signature) or, if that isn't practical, add a brief inline comment
after `any` explaining why `any` is necessary (for example: /* uses a simplified
mock of stream.write signature for tests */) so the linter rule is satisfied.

Comment thread packages/core/src/terminal/Terminal.test.ts
@Karanjot786 Karanjot786 added gssoc:approved Approved PR. Earns +50 base points. quality:clean x 1.2 multiplier. Clean implementation. level:intermediate +35 pts. Moderate task. type:feature +10 pts. New feature. labels Jun 4, 2026
@Karanjot786 Karanjot786 force-pushed the fix/terminal-debounce branch from 589fd7b to d759b7b Compare June 4, 2026 17:17
Adds resizeDebounceMs option (default 16ms) to Terminal. Rapid SIGWINCH
signals are coalesced into a single resize dispatch with dedup check to
avoid redundant handler calls when dimensions haven't changed.
@Karanjot786 Karanjot786 force-pushed the fix/terminal-debounce branch from d759b7b to b79b15a Compare June 5, 2026 02:50
@Karanjot786 Karanjot786 merged commit ca11e75 into Karanjot786:main Jun 5, 2026
8 checks passed
@Karanjot786
Copy link
Copy Markdown
Owner

Thank you so much for your contribution, @abhijnyan-codes!

Your PR #711 added resize debouncing to Terminal. Rapid SIGWINCH signals now coalesce into a single dispatch, so resize handlers fire once instead of dozens of times.

Keep contributing. We appreciate your work.

@abhijnyan-codes abhijnyan-codes deleted the fix/terminal-debounce branch June 5, 2026 05:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:core @termuijs/core area:dev-server @termuijs/dev-server area:jsx @termuijs/jsx gssoc:approved Approved PR. Earns +50 base points. level:intermediate +35 pts. Moderate task. quality:clean x 1.2 multiplier. Clean implementation. type:devops +15 pts. CI, build, or release. type:feature +10 pts. New feature. type:testing +10 pts. Tests.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants