Skip to content

input: Paste from the context menu on the web backend - #3244

Open
Muhammad-Owais-Warsi wants to merge 1 commit into
longbridge:mainfrom
Muhammad-Owais-Warsi:input-web-paste
Open

Muhammad-Owais-Warsi wants to merge 1 commit into
longbridge:mainfrom
Muhammad-Owais-Warsi:input-web-paste

Conversation

@Muhammad-Owais-Warsi

Copy link
Copy Markdown
Contributor

Closes #3187

Description

On wasm32-unknown-unknown, right-clicking any Input showed Paste greyed out no matter what was on the clipboard, while Cut / Copy / Select All and Ctrl/Cmd+V worked.

Two places depended on the synchronous clipboard read, which the web platform returns None for by design (gpui-pre-web's read_from_clipboard; the real read is read_from_clipboard_async):

  • The Input context menu enabled Paste only when cx.read_from_clipboard().is_some(), so it was permanently disabled on the web.
  • InputBaseState::paste bailed out on the same read, so un-greying the item alone would have left a clickable Paste that inserts nothing. (Keyboard paste works on the web because the DOM paste event reaches EntityInputHandler::paste directly and never goes through the Paste action.)

This PR fixes both:

  • crates/component/src/input/input.rs: the context menu offers Paste whenever the input is editable, without peeking at the clipboard. This matches the touch-selection edit menu's existing rationale: an empty clipboard pastes nothing, and reading the clipboard just to decide enablement is a side effect on some platforms (the iOS paste banner). The on_paste doc comment now describes the web behaviour accurately.
  • crates/base/src/input/base/state.rs: paste tries the synchronous read first and, when it is None, falls back to cx.read_from_clipboard_async(). The async read is started synchronously inside the action handler so it stays under the user activation (the menu click) the browser requires, then the result is inserted through the same path via cx.spawn_in. The input's editability is re-checked when the read resolves, and ClipboardReadError is logged. The existing insert logic (atomic undo intent, newline stripping on single-line inputs, one-line-per-selection distribution) moved untouched into a private insert_clipboard helper.

Desktop behaviour is unchanged: the synchronous read returns Some there, so the async branch is never reached. As a side effect the touch-selection menu's Paste, which dispatches the same action, now also works on the web instead of being a silent no-op.

Out of scope, as noted in the issue: the on_paste hook still only sees the synchronous read, so pasting images from the context menu on the web is not supported yet; the input falls back to inserting the plain text itself.

The code in this PR was AI-generated (Claude) and reviewed by hand.

Screenshot

No visual change on desktop. On the web backend the only change is that the Input context menu's Paste item is enabled instead of greyed out; I could not capture a wasm build for a screenshot.

How to Test

  • cargo clippy -p gpui-base -p gpui-component --all-targets -- --deny warnings
  • cargo test -p gpui-base --lib -- paste clipboard (4 tests, all pass, covering atomic undo, multi-cursor distribution and the masked-input clipboard guard)
  • cargo test -p gpui-component --lib -- paste context_menu (7 tests, all pass)
  • Manual, desktop: cargo run, open an Input story, right-click an editable input → Paste is enabled and inserts the clipboard text; right-click a read-only or disabled input → Paste is disabled.
  • Manual, web: build crates/story-web, copy some text, right-click an Input → Paste is enabled; choosing it prompts for clipboard permission (first time) and inserts the text.

The async branch has no automated test because the test platform always answers the synchronous read, so it needs the manual web check above.

Checklist

  • I have read the CONTRIBUTING document and followed the guidelines.
  • Reviewed the changes in this PR and confirmed AI generated code (If any) is accurate.
  • Passed cargo run for story tests related to the changes.
  • Tested macOS, Windows and Linux platforms performance (if the change is platform-specific)

On wasm32 the synchronous `read_from_clipboard()` is always `None` by
design; the real read is `read_from_clipboard_async()`. The Input
context menu gated Paste on the synchronous read, so it was permanently
disabled there, and the `Paste` action bailed out on the same read, so
un-greying it alone would have inserted nothing.

- Offer Paste whenever the input is editable, without peeking at the
  clipboard, matching the touch-selection edit menu.
- Let the `Paste` action fall back to the asynchronous clipboard read
  when the synchronous one is empty. The read starts inside the action
  so it stays under the user activation the browser requires.

Fixes longbridge#3187

Co-authored-by: Cursor <cursoragent@cursor.com>
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.

Input: context-menu Paste is permanently disabled on the web backend

1 participant