Skip to content

Visual editor selection support (getSelectedText + selection-change e…#997

Open
stevehaigh wants to merge 3 commits into
quarto-dev:mainfrom
stevehaigh:main
Open

Visual editor selection support (getSelectedText + selection-change e…#997
stevehaigh wants to merge 3 commits into
quarto-dev:mainfrom
stevehaigh:main

Conversation

@stevehaigh

@stevehaigh stevehaigh commented Jun 8, 2026

Copy link
Copy Markdown

Motivation

VS Code extensions can read the active editor's selection via window.activeTextEditor.selection, but Quarto's visual editor is a webview-based custom editor — its selection lives inside the webview and isn't visible to VS Code's text-editor API. As a result, extensions that act on the current selection (e.g. word-count tools, or sending a snippet to another command) work in source mode but go blind in visual mode. This PR exposes the visual editor's selection through Quarto's public extension API so those integrations work in both modes.

Summary

Adds read access to the Quarto visual editor's text selection, in two layers:

1. getSelectedText() — pull the current selection on demand

Plumbs a new getSelectedText() method through every layer of the editor RPC stack:

  • EditorOperations.getSelectedText() and the Editor implementation (packages/editor)
  • The EditorOperations object built in Editor.tsx (packages/editor-ui)
  • The VSCodeVisualEditor interface and the VSC_VE_GetSelectedText RPC constant (packages/editor-types)
  • The webview host server and client transport (apps/vscode-editor/sync.ts, apps/vscode/.../connection.ts)
  • A quarto.editor.getSelectedText command returning the selection, or '' when no visual editor is active (apps/vscode/.../editor.ts)

Editor.getSelectedText() joins blocks with \n\n, preserves hard_break as a newline, and returns '' for an empty selection.

2. onDidChangeVisualEditorSelection — push selection changes to API consumers

Exposes a new event on the already-public QuartoExtensionApi:

onDidChangeVisualEditorSelection: vscode.Event<{ uri: vscode.Uri; selectedText: string }>

It rides the existing StateChangeEvent -> onEditorStateChanged plumbing:

  • The selected text is carried in the onEditorStateChanged RPC payload (sync/cheap), forwarded through the webview transport.
  • It is re-emitted on a vscode.EventEmitter exposed by createQuartoExtensionApi.

Design decisions:

  • Push the text, not just a signal — the webview already has it, avoiding a round-trip.
  • De-duplicate in Quarto (per-document, against the previous selection), but leave time-debouncing to consumersStateChangeEvent fires on every cursor move.
  • Empty selection ('') is a real event so consumers can reset UI on clear/blur.
  • The getSelectedText command remains as a backward-compatible pull-based fallback.

Test plan

  • Build the VS Code extension (yarn build-vscode) — green across all packages
  • API tests pass (yarn test-vscode --label main --grep "Quarto Extension API"), including a new assertion that onDidChangeVisualEditorSelection is exposed
  • Command test asserts quarto.editor.getSelectedText returns '' when no visual editor is active
  • Manually: select text in the visual editor and confirm the command returns it and the event fires; confirm an empty selection emits ''

🤖 AI disclosure - this change was generated with AI assistant Claude Code Sonnet 4.6 and Opus 4.8

…vent) (#1)

* Add getSelectedText to the visual editor

Expose the visual editor's current text selection through the full RPC
stack: the editor operation, the webview host/client transport, the
VSCodeVisualEditor interface, and a new quarto.editor.getSelectedText
command that returns the selection (or '' when no editor is active).

Also tighten Editor.getSelectedText to join blocks with '\n\n' and
return '' for an empty selection.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Emit visual editor selection changes on the public API

Add onDidChangeVisualEditorSelection to QuartoExtensionApi so other
extensions can observe what the user has selected in a Quarto visual
editor, riding the existing StateChangeEvent -> onEditorStateChanged
plumbing.

- Carry the selected text in the onEditorStateChanged RPC payload
  (getSelectedText is synchronous and cheap), forwarding it through the
  webview client/host transport.
- Re-emit it on a vscode.EventEmitter exposed by createQuartoExtensionApi,
  de-duplicating against the previous selection per document. Empty
  selections are emitted as real events so consumers can reset UI; time
  debouncing is left to consumers since StateChangeEvent is noisy.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Address PR review feedback on getSelectedText

- Preserve hard_break as a newline in getSelectedText via a leafText
  function, so selections containing hard line breaks aren't flattened
  and leaf-only selections don't collapse to '' (Copilot review).
- Use activeEditor() (not includeVisible) for the
  quarto.editor.getSelectedText command, matching its documented
  "returns '' when no visual editor is active" contract and the sibling
  visual-editor commands.
- Add an integration test asserting the command returns '' when no
  visual editor is active.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Document visual editor selection API

- Add the new selection event to the copy-paste interface example in
  api.ts so external consumers know to declare it.
- Add a CHANGELOG entry for the getSelectedText command and the
  onDidChangeVisualEditorSelection event.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 8, 2026 21:19
@posit-snyk-bot

posit-snyk-bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

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

Note

Copilot was unable to run its full agentic suite in this review.

This PR exposes the visual editor’s current text selection to VS Code extension consumers by adding a quarto.editor.getSelectedText command and a new public API event (onDidChangeVisualEditorSelection).

Changes:

  • Added getSelectedText() plumbing from the ProseMirror editor through the webview RPC layer to the VS Code extension host.
  • Introduced a public API event emitting { uri, selectedText } on visual editor state changes (with per-document de-duplication).
  • Added VS Code extension tests covering the new command and updated the changelog.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/editor/src/editor/editor.ts Implements selection-to-text extraction with custom separators/leaf handling.
packages/editor-ui/src/editor/Editor.tsx Exposes getSelectedText() via the UI editor ref facade.
packages/editor-types/src/vscode.ts Adds RPC constant + API surface for getSelectedText and extends host callback signature.
apps/vscode/src/providers/editor/connection.ts Wires new RPC method and updated host callback argument mapping.
apps/vscode-editor/src/sync.ts Sends selected text on state change and exposes RPC endpoint to query it.
apps/vscode/src/providers/editor/editor.ts Adds command quarto.editor.getSelectedText and emits selection-change events.
apps/vscode/src/main.ts Creates and wires a shared EventEmitter into the public extension API.
apps/vscode/src/api.ts Defines VisualEditorSelection and adds onDidChangeVisualEditorSelection to the public API.
apps/vscode/src/test/editor-commands.test.ts Adds integration test for the new command when no visual editor is active.
apps/vscode/src/test/api.test.ts Asserts the new API event exists.
apps/vscode/CHANGELOG.md Documents the new command and API event.

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

Comment thread apps/vscode/src/providers/editor/editor.ts
Comment thread apps/vscode/src/providers/editor/editor.ts
Comment thread apps/vscode/src/api.ts
Comment thread apps/vscode/CHANGELOG.md Outdated
stevehaigh and others added 2 commits June 8, 2026 22:32
Updated the changelog to reflect the correct pull request link for the visual editor's text selection feature.
- Clear lastSelectedText map entry on webview dispose to prevent unbounded memory growth
- Replace vscode.* types in copy/paste snippet with structural types to avoid requiring a vscode import

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@stevehaigh

Copy link
Copy Markdown
Author

Note that this PR will help with future work to address issue #717

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.

3 participants