Skip to content

Conversation

@ntotten
Copy link
Member

@ntotten ntotten commented Jan 21, 2026

Summary

  • Use Prettier's formatWithCursor() API instead of format() to preserve cursor position after formatting
  • The cursor no longer jumps to an arbitrary position when formatting a document
  • Properly handles edge cases like range formatting (where cursor position doesn't apply) and older Prettier versions

Changes

  • types.ts: Added PrettierCursorOptions and PrettierCursorResult type exports, and added formatWithCursor method to PrettierInstance and PrettierModule interfaces
  • PrettierDynamicInstance.ts: Implemented formatWithCursor method that delegates to the underlying Prettier module
  • ModuleResolverWeb.ts: Added formatWithCursor support for the browser/web extension
  • PrettierEditService.ts:
    • Updated format() to optionally use formatWithCursor() when a cursor offset is available
    • Updated provideEdits() to capture cursor position before formatting and schedule cursor repositioning after VS Code applies the edit
    • Skips cursor handling for range formatting where cursor preservation doesn't make sense

Test plan

  • Open a file with some unformatted code
  • Place cursor somewhere in the middle of the file
  • Format the document (Cmd/Ctrl+Shift+I or format on save)
  • Verify cursor position is preserved at the equivalent location in the formatted output
  • Test range formatting still works correctly (cursor handling is skipped)
  • Test in browser/web extension environment

Fixes #3939

Generated with Claude Code

Copilot AI review requested due to automatic review settings January 21, 2026 23:26
@ntotten ntotten force-pushed the feature/format-with-cursor branch from 6dc6c19 to 16a3a3f Compare January 21, 2026 23:27
Copy link
Contributor

Copilot AI left a comment

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 implements cursor position preservation during document formatting by utilizing Prettier's formatWithCursor() API instead of the regular format() method. This addresses issue #3939 where the cursor would jump to an arbitrary position after formatting.

Changes:

  • Added formatWithCursor method to Prettier type interfaces and implementations
  • Updated the formatting service to capture cursor position before formatting and restore it afterward
  • Properly handles edge cases like range formatting where cursor preservation doesn't apply

Reviewed changes

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

File Description
src/types.ts Added PrettierCursorOptions and PrettierCursorResult type exports; added formatWithCursor method to PrettierInstance and PrettierModule interfaces
src/PrettierDynamicInstance.ts Implemented formatWithCursor method that delegates to the underlying Prettier module
src/ModuleResolverWeb.ts Added formatWithCursor support for browser/web extension
src/PrettierEditService.ts Updated formatting logic to use formatWithCursor() when cursor offset is available; added cursor repositioning logic using setImmediate

!isRangeFormatting &&
result.cursorOffset >= 0
) {
setImmediate(() => {
Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

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

The setImmediate function is not available in browser environments, but this extension supports both Node.js and browser contexts (as indicated by the "browser" field in package.json). This will cause a runtime error when the extension runs in vscode.dev or other browser-based VS Code instances.

Consider using setTimeout(() => {...}, 0) instead, which works in both Node.js and browser environments and provides similar behavior of deferring execution to the next event loop tick.

Copilot uses AI. Check for mistakes.
Comment on lines +491 to +509
// Schedule cursor repositioning after VS Code applies the edit
// We use setImmediate to run after the current event loop completes
if (
editor &&
editor.document === document &&
!isRangeFormatting &&
result.cursorOffset >= 0
) {
setImmediate(() => {
// Verify the editor is still active and document hasn't changed
if (
window.activeTextEditor === editor &&
editor.document === document
) {
const newPosition = document.positionAt(result.cursorOffset);
editor.selection = new Selection(newPosition, newPosition);
}
});
}
Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

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

The new cursor position preservation feature lacks test coverage. Consider adding a test that:

  1. Opens a document with unformatted code
  2. Places the cursor at a specific position
  3. Triggers formatting
  4. Verifies the cursor is at the expected position in the formatted output

This is especially important since this feature involves timing-sensitive operations with setImmediate and the interaction between VS Code's edit application and cursor repositioning.

Copilot uses AI. Check for mistakes.
Previously, the extension used Prettier's format() API which caused the
cursor to jump to an arbitrary position after formatting. This change
uses Prettier's formatWithCursor() API to preserve the cursor position.

Changes:
- Add formatWithCursor to PrettierInstance and PrettierModule interfaces
- Implement formatWithCursor in PrettierDynamicInstance
- Add formatWithCursor to ModuleResolverWeb for browser support
- Update PrettierEditService to use formatWithCursor when cursor
  position is available, and schedule cursor repositioning after
  VS Code applies the edit

Fixes #3939

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@ntotten ntotten force-pushed the feature/format-with-cursor branch from 16a3a3f to 15e68cf Compare January 21, 2026 23:37
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.

Use formatWithCursor() API to preserve cursor position after formatting

2 participants