Skip to content

editor: add 'foldedLine' unit to cursorMove command#296106

Merged
alexdima merged 4 commits intomicrosoft:mainfrom
jaidhyani:cursor-move-foldedline-unit
Feb 28, 2026
Merged

editor: add 'foldedLine' unit to cursorMove command#296106
alexdima merged 4 commits intomicrosoft:mainfrom
jaidhyani:cursor-move-foldedline-unit

Conversation

@jaidhyani
Copy link

Summary

Adds a new foldedLine value to the by parameter of the cursorMove command. When used with up or down directions, the cursor moves by logical lines while treating each folded region as a single step — the entire fold is skipped rather than entered.

Previously only wrappedLine (view-space) and line (model-space) were available. wrappedLine skips folds as a side-effect of operating in view coordinates, but also splits long wrapped lines into multiple steps, which is incorrect for line-oriented movements. line moves in model-space and enters folds. foldedLine moves in model-space but queries viewModel.getHiddenAreas() to detect and skip over folded regions.

Behavior

  • Each fold counts as exactly one step regardless of how many model lines it spans
  • Fold spanning to end-of-file: cursor stays at current position (no visible line to land on)
  • Fold starting at line 1: cursor stays at current position
  • Compatible with multi-cursor and selection (select: true)
  • Only meaningful with up/down directions; other directions ignore the unit and fall back to default behavior

Testing

New test suite: Cursor move command - foldedLine unit in cursorMoveCommand.test.ts

  • move down skips a fold below the cursor
  • move up skips a fold above the cursor
  • count-based movement treats each fold as one step
  • multi-line fold counts as a single step
  • boundary conditions (last line, first line)

Related

Closes #81498

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 adds a new foldedLine unit to the cursorMove command, enabling vim-like cursor movement that treats each folded region as a single step. This addresses a long-standing feature request (#81498) for extensions like VSCodeVim to properly handle fold navigation.

Changes:

  • Adds FoldedLine enum value to CursorMove.Unit and CursorMove.RawUnit
  • Implements _moveDownByFoldedLines and _moveUpByFoldedLines methods that skip over folded regions while moving by logical lines
  • Updates command metadata and documentation to include the new foldedLine unit
  • Adds comprehensive test suite covering fold skipping behavior, multi-line folds, count-based movements, and boundary conditions

Reviewed changes

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

File Description
src/vs/editor/common/cursor/cursorMoveCommands.ts Implements core fold-aware cursor movement logic, adds enum values, updates command schema and documentation
src/vs/editor/test/browser/controller/cursorMoveCommand.test.ts Adds comprehensive test suite for foldedLine unit with 6 test cases covering various scenarios

@jaidhyani
Copy link
Author

@microsoft-github-policy-service agree

@jaidhyani jaidhyani force-pushed the cursor-move-foldedline-unit branch from 405c4d9 to 13f8179 Compare February 18, 2026 20:33
Add a new 'foldedLine' movement unit to the `cursorMove` command that moves
by model lines while treating each folded region as a single step.

When moving down/up by 'wrappedLine' the cursor skips folds naturally because
it operates in view space. When moving by 'line' it uses model coordinates and
can land inside a fold, causing VS Code to auto-unfold it. The new 'foldedLine'
unit moves in model space but queries `viewModel.getHiddenAreas()` to detect
folds and jump to the first visible line past each one, so folds are skipped
without being opened.

This is the semantics needed by vim's j/k motions (VSCodeVim/Vim#1004):
each fold counts as exactly one step, matching how real vim treats folds.

Fixes: VSCodeVim/Vim#1004
@jaidhyani jaidhyani force-pushed the cursor-move-foldedline-unit branch from 13f8179 to a51c7f8 Compare February 18, 2026 21:03
Replace the step-by-step simulation (O(count × folds)) with a single
pass over sorted hidden areas (O(folds in path)). Compute a naive
target, then extend it for each fold encountered, stopping before any
fold that reaches the document boundary.

Also extracts _targetFoldedDown/_targetFoldedUp helpers to eliminate
the duplicated loop structure between the two directions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Member

@alexdima alexdima left a comment

Choose a reason for hiding this comment

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

Hope you don't mind, I used my AI to fix your AI's small mistake

@vs-code-engineering vs-code-engineering bot added this to the March 2026 milestone Feb 28, 2026
@alexdima alexdima merged commit f112245 into microsoft:main Feb 28, 2026
18 checks passed
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.

[api] Allow extensions to determine if a position is within a fold

4 participants