Skip to content

Added clipboard read and paste support to core input handling#1939

Open
Srushti-Thombre wants to merge 6 commits into
Karanjot786:mainfrom
Srushti-Thombre:EditablePrompt
Open

Added clipboard read and paste support to core input handling#1939
Srushti-Thombre wants to merge 6 commits into
Karanjot786:mainfrom
Srushti-Thombre:EditablePrompt

Conversation

@Srushti-Thombre

@Srushti-Thombre Srushti-Thombre commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Description

This PR fixes bracketed paste handling in @termuijs/core so pasted text is collected correctly even when the start and end markers arrive in separate input chunks. It also keeps any trailing input after the paste marker working normally, and adds a regression test for the split-chunk case.

Related Issue

Closes #1619

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/a59d754a-8095-4997-91d8-2fb4c1577efa

Screenshots / Recordings (UI changes)

Screenshot 2026-07-02 162107

Notes for the Reviewer

I validated the touched package with:

  • bunx vitest run packages/core/src/input/InputParser.test.ts
  • bunx tsc -p packages/core/tsconfig.json --noEmit
  • Reviewer note: repo-wide bun run typecheck and the full test/build pipeline currently fail for unrelated existing issues in packages/testing, packages/jsx, and packages/adapters (resetHooksGlobals, invalidateLayout, and optional dotenv resolution). Those failures are not caused by this clipboard/paste change.

The repo-wide bun run build and bun run typecheck were not run in this session.

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of pasted text so multi-byte input and mixed input streams are processed more reliably.
    • Fixed escape-key behavior so a lone Escape press is recognized consistently, while longer key sequences continue to work as expected.
    • Refined input parsing for special characters and mouse-related terminal sequences to reduce missed or incomplete inputs.

Copilot AI review requested due to automatic review settings July 2, 2026 11:11
@github-actions github-actions Bot added area:core @termuijs/core type:testing +10 pts. Tests. labels Jul 2, 2026
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR updates package.json dependencies and refactors InputParser to change bracketed-paste buffering, lone-escape timeout handling, grapheme batching, and escape-sequence parsing.

Changes

Dependency updates

Layer / File(s) Summary
Package metadata updates
package.json
Adds @termuijs/adapters as a workspace devDependency and updates dotenv to ^17.4.2.

Input parser refactor

Layer / File(s) Summary
Paste buffering and completion
packages/core/src/input/InputParser.ts
Scans incoming input for bracketed-paste markers, buffers paste content across chunks, and finishes paste handling through a helper that emits paste and reprocesses trailing input.
Escape and grapheme buffering
packages/core/src/input/InputParser.ts
Adjusts lone ESC timeout emission, grapheme-buffer batching, and incomplete-grapheme detection, including regional-indicator handling.
Escape sequence parsing
packages/core/src/input/InputParser.ts
Updates mouse parsing, focus events, modifier key mapping, alt-printable handling, and maximum escape-sequence cutoff behavior.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

Suggested labels: type:bug, level:intermediate

Suggested reviewers: Karanjot786

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning package.json dependency bumps for @termuijs/adapters and dotenv are unrelated to the paste-handling objective. Remove the dependency-only package.json changes unless they are required by the fix, and keep the PR scoped to core input/paste handling.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and matches the main change: bracketed paste support in core input handling.
Description check ✅ Passed The description includes the required sections and clearly summarizes the change, related issue, package, and checklist items.
Linked Issues check ✅ Passed The PR addresses the directly relevant paste-handling objective from issue #1619 by fixing bracketed paste decoding and trailing input handling.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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.

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.

Pull request overview

This PR updates @termuijs/core input parsing to better handle terminal bracketed paste mode, aiming to reliably emit paste events when paste start/end markers and pasted content arrive across multiple input chunks. It also adds a regression test around chunk-splitting behavior and adjusts the core package TS config to include Node types.

Changes:

  • Add paste-collection state (_isPasting / _pasteBuffer) so bracketed paste text can span multiple stdin chunks.
  • Ensure non-paste input before/after a paste sequence is still processed normally.
  • Add a regression test for multi-chunk bracketed paste, and update core tsconfig to include Node ambient types.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
packages/core/tsconfig.json Adds Node ambient types for the core package compilation context.
packages/core/src/input/InputParser.ts Refactors bracketed paste handling into a stateful collector to support multi-chunk pastes.
packages/core/src/input/InputParser.test.ts Adds a regression test to validate bracketed paste behavior across chunks.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/core/src/input/InputParser.ts
@Karanjot786

Copy link
Copy Markdown
Owner

Thanks for the contribution. There are issues to fix before this merges.

Issues:

  1. Package fails to build — str used before declaration
    File: packages/core/src/input/InputParser.ts (~lines 132-145)
    Problem: the refactor references str above its const str = data.toString('utf8') declaration → TS2448/TS2454, and @termuijs/core#build exits 1 (the dts build fails).
    Fix: move the const str = ... declaration above its first use (or restructure so it's in scope).

  2. Unrelated / duplicate tsconfig change
    File: packages/core/tsconfig.json (lines 4 and 7)
    Problem: a duplicate "types": ["node"] key was added (tsup warns on it) — unrelated to the clipboard feature.
    Fix: remove the duplicate key.

Checklist before re-requesting review:

  • bun run build passes locally (core compiles)
  • Duplicate tsconfig key removed
  • Tests pass locally (run: bun vitest run)

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/core/src/input/InputParser.ts (2)

132-149: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Paste timeout is never started — an incomplete paste permanently wedges the parser.

_startPasteTimeout() / _clearPasteTimeout() (lines 279–293) are defined but never called anywhere. When a PASTE_START marker arrives without a matching PASTE_END, _isPasting is set to true and stays true forever: every subsequent data chunk falls into the if (this._isPasting) branch at Line 132 and is silently appended to _pasteBuffer, so no further key/mouse/escape events are ever emitted.

The "recovers from partial paste via timeout" test passes only because it asserts the handler was not called; it never verifies that normal input resumes after the 500ms window, so the regression is masked.

Start the timeout when entering/continuing a paste and clear it on completion.

🔒️ Wire up the paste timeout
         if (this._isPasting) {
             this._pasteBuffer += str;
+            this._startPasteTimeout();
             this._finishPasteIfComplete(PASTE_END);
             return;
         }
@@
             this._isPasting = true;
             this._pasteBuffer = str.slice(pasteStartIndex + PASTE_START.length);
+            this._startPasteTimeout();
             this._finishPasteIfComplete(PASTE_END);
             return;
         }

And clear it on successful completion in _finishPasteIfComplete:

         this._isPasting = false;
         this._pasteBuffer = '';
+        this._clearPasteTimeout();
 
         this._events.emit('paste', pastedText);
🤖 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/input/InputParser.ts` around lines 132 - 149, The paste
handling in InputParser can get stuck because `_startPasteTimeout()` is never
invoked when `_isPasting` becomes true, so an incomplete paste leaves the parser
permanently wedged. Update `InputParser` so the timeout is started when entering
or continuing paste mode in the `data` handling path, and make sure
`_clearPasteTimeout()` is called when `_finishPasteIfComplete()` successfully
ends a paste. Verify the logic around `_isPasting`, `_pasteBuffer`,
`_startPasteTimeout`, and `_finishPasteIfComplete` so normal input resumes after
the timeout if `PASTE_END` never arrives.

128-133: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Multibyte bracketed paste can still be corrupted
_processInput() decodes paste chunks with data.toString('utf8'), so a UTF-8 code point split across chunks turns into U+FFFD before it reaches _pasteBuffer. Use the existing StringDecoder path here, or buffer raw bytes until PASTE_END and decode once.

🤖 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/input/InputParser.ts` around lines 128 - 133, In
InputParser._processInput(), bracketed paste handling is still decoding each
chunk with data.toString('utf8'), which can corrupt split UTF-8 characters
before they reach _pasteBuffer. Update the paste path to use the existing
StringDecoder-based flow, or keep raw bytes buffered until PASTE_END and decode
once at the end, so multibyte characters survive chunk boundaries intact.
🤖 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 `@package.json`:
- Line 46: The optional peer dependency error in the dotenv adapter still
references the old supported range, so update the missing-dependency message in
packages/adapters/src/dotenv/index.ts to match the new workspace range for
dotenv. Adjust the text in the logic that throws from the dotenv adapter’s parse
path so it points users to install dotenv@^17.4.2 instead of dotenv@^16.0.0,
keeping the rest of the error wording consistent.

---

Outside diff comments:
In `@packages/core/src/input/InputParser.ts`:
- Around line 132-149: The paste handling in InputParser can get stuck because
`_startPasteTimeout()` is never invoked when `_isPasting` becomes true, so an
incomplete paste leaves the parser permanently wedged. Update `InputParser` so
the timeout is started when entering or continuing paste mode in the `data`
handling path, and make sure `_clearPasteTimeout()` is called when
`_finishPasteIfComplete()` successfully ends a paste. Verify the logic around
`_isPasting`, `_pasteBuffer`, `_startPasteTimeout`, and `_finishPasteIfComplete`
so normal input resumes after the timeout if `PASTE_END` never arrives.
- Around line 128-133: In InputParser._processInput(), bracketed paste handling
is still decoding each chunk with data.toString('utf8'), which can corrupt split
UTF-8 characters before they reach _pasteBuffer. Update the paste path to use
the existing StringDecoder-based flow, or keep raw bytes buffered until
PASTE_END and decode once at the end, so multibyte characters survive chunk
boundaries intact.
🪄 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: de1a24b6-74c2-44d2-a862-73a7ada15af8

📥 Commits

Reviewing files that changed from the base of the PR and between 3741651 and a9e01bd.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (2)
  • package.json
  • packages/core/src/input/InputParser.ts

Comment thread package.json
"dependencies": {
"commander": "^15.0.0",
"dotenv": "^16.0.0"
"dotenv": "^17.4.2"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Update stale error message referencing dotenv@^16.0.0.

This bumps the workspace's dotenv range to ^17.4.2, but packages/adapters/src/dotenv/index.ts still tells users to Install dotenv@^16.0.0 in its "missing optional peer dependency" error. Since only dotenv.parse() is used, the major bump itself looks safe, but the error text should match the now-supported range.

💬 Suggested fix in packages/adapters/src/dotenv/index.ts
-      'useDotenv() requires the optional peer dependency `dotenv`. Install `dotenv@^16.0.0` in your app before calling useDotenv().'
+      'useDotenv() requires the optional peer dependency `dotenv`. Install `dotenv@^17.4.2` in your app before calling useDotenv().'
🤖 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 `@package.json` at line 46, The optional peer dependency error in the dotenv
adapter still references the old supported range, so update the
missing-dependency message in packages/adapters/src/dotenv/index.ts to match the
new workspace range for dotenv. Adjust the text in the logic that throws from
the dotenv adapter’s parse path so it points users to install dotenv@^17.4.2
instead of dotenv@^16.0.0, keeping the rest of the error wording consistent.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:core @termuijs/core type:testing +10 pts. Tests.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add clipboard read and paste support to core input handling (Wave 7)

3 participants