Skip to content

Fix markdown preview scrolling editor to wrong position on click#323250

Open
DakshUbhadia wants to merge 3 commits into
microsoft:mainfrom
DakshUbhadia:fix/markdown-preview-scroll-editor-on-click
Open

Fix markdown preview scrolling editor to wrong position on click#323250
DakshUbhadia wants to merge 3 commits into
microsoft:mainfrom
DakshUbhadia:fix/markdown-preview-scroll-editor-on-click

Conversation

@DakshUbhadia

Copy link
Copy Markdown

Fixes #323245

What this PR does

When a .md file is open in split view with the preview, clicking back
into the editor after scrolling the preview causes the editor to jump to
a completely unrelated scroll position. Text between the previous cursor
position and the click target is also spuriously selected.

Root cause

The scrollEditorWithPreview feature works by having the preview
webview post a revealLine message on every scroll event. A
scrollDisabledCount guard in the webview is supposed to suppress
scroll events that result from programmatic scrolls (to prevent feedback
loops). However the guard had two problems:

  1. Webview side (preview-src/index.ts): When
    onDidChangeTextEditorSelection fires, the preview calls
    scrollToRevealSourceLine inside doAfterImagesLoaded — an async
    Promise. The existing guard timers (50ms) expire before
    window.scrollTo actually fires because the async image-load delay
    pushes the scroll past the guard window. The resulting scroll DOM
    event is not suppressed, so a stale revealLine message is posted to
    the extension host, which calls editor.revealLine at the wrong
    position.

  2. Extension host side (src/preview/preview.ts): There was no
    guard in onDidScrollPreview to detect that an incoming revealLine
    message originated from an editor selection change rather than a
    genuine user scroll of the preview.

Changes

preview-src/index.ts — In the onDidChangeTextEditorSelection
message handler, increment scrollDisabledCount with a 300ms guard
window. This covers the full async path of doAfterImagesLoaded +
window.scrollTo + one event loop tick. The counter is decremented
using Math.max(0, count - 1) to prevent it going negative if timers
race.

src/preview/preview.ts — Add a #isSyncingFromEditorSelection
flag that is set for 400ms whenever onDidChangeTextEditorSelection
fires (called via the new notifyEditorSelectionChanged() method before
the message is posted). In onDidScrollPreview, return early when this
flag is active. This is a defensive second layer in case a scroll
message leaks through the webview-side guard due to platform timing
differences. clearTimeout(#editorSelectionSyncTimer) is added to
dispose() to prevent timer leaks.

How to test

  1. Open any .md file with enough content to scroll (150+ lines).
  2. Press Ctrl+K V to open the preview in split view.
  3. Click into the preview pane.
  4. Scroll the preview down to a distant section (e.g. line 100+).
  5. Click back into the editor at a position near the top (e.g. line 5).

Before this fix: the editor jumps to the position the preview just
scrolled to, and text from the original cursor position to the click
target is selected.

After this fix: the cursor lands cleanly at the clicked position
with no spurious scroll or selection.

Copilot AI review requested due to automatic review settings June 27, 2026 10:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Fixes an issue in the built-in Markdown extension where interacting with the Markdown preview (scrolling + then clicking back into the editor) could cause the editor to jump to an unrelated position due to stale preview→editor scroll-sync messages.

Changes:

  • Adds an extension-host-side suppression window (#isSyncingFromEditorSelection) to ignore preview revealLine messages shortly after editor selection changes.
  • Updates the preview webview’s scrollDisabledCount guarding logic to better cover async scroll timing (images-loaded delay + programmatic scroll).

Reviewed changes

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

File Description
extensions/markdown-language-features/src/preview/preview.ts Adds a selection-change sync suppression flag and timer cleanup to avoid reacting to leaked scroll-sync messages.
extensions/markdown-language-features/preview-src/index.ts Adjusts the webview-side scroll event suppression logic around programmatic scrolls and editor-selection updates.

Comment thread extensions/markdown-language-features/preview-src/index.ts Outdated
Comment on lines +158 to +164
scrollDisabledCount++;
doAfterImagesLoaded(() => {
scrollToRevealSourceLine(line, documentVersion, settings);
if (scrollDisabledTimer) { clearTimeout(scrollDisabledTimer); }
scrollDisabledTimer = window.setTimeout(() => {
scrollDisabledCount = Math.max(0, scrollDisabledCount - 1);
}, 100);
Comment on lines +252 to +256
scrollDisabledCount++;
if (scrollDisabledTimer) { clearTimeout(scrollDisabledTimer); }
scrollDisabledTimer = window.setTimeout(() => {
scrollDisabledCount = Math.max(0, scrollDisabledCount - 1);
}, 300);
Comment on lines +372 to +374
if (this.#isSyncingFromEditorSelection) {
return;
}
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.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.

Clicking editor in split view scrolls far away

3 participants