Skip to content

Commit fa9d6e3

Browse files
Jaiclaude
andcommitted
fix(motion): use 'foldedLine' cursorMove unit for j/k over folds
Use VS Code's 'foldedLine' cursorMove unit as the default movement for j/k, which moves by logical lines while treating each folded region as a single step. On VS Code versions without this unit, the command degrades to standard line movement (no regression). The existing foldfix workaround is preserved for users on unpatched VS Code. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent d1080ad commit fa9d6e3

2 files changed

Lines changed: 61 additions & 15 deletions

File tree

src/actions/motion.ts

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,22 @@ class MoveDownFoldFix extends MoveByScreenLineMaintainDesiredColumn {
303303
}
304304
}
305305

306+
class MoveDownByFoldedLine extends MoveByScreenLineMaintainDesiredColumn {
307+
keys = [];
308+
movementType: CursorMovePosition = 'down';
309+
override by: CursorMoveByUnit = 'foldedLine';
310+
override value = 1;
311+
312+
constructor(multicursorIndex: number) {
313+
super();
314+
this.multicursorIndex = multicursorIndex;
315+
}
316+
317+
public override execAction(position: Position, vimState: VimState): Promise<Position> {
318+
return super.execAction(position, vimState) as unknown as Promise<Position>;
319+
}
320+
}
321+
306322
@RegisterAction
307323
export class MoveDown extends BaseMovement {
308324
keys = [['j'], ['<down>'], ['<C-j>'], ['<C-n>']];
@@ -327,14 +343,21 @@ export class MoveDown extends BaseMovement {
327343
return moveDownFoldFix.execAction(position, vimState);
328344
}
329345

330-
if (position.line < vimState.document.lineCount - 1) {
331-
return adjustForDesiredColumn({
332-
position,
333-
desiredColumn: vimState.desiredColumn,
334-
multicursorIndex: this.multicursorIndex,
335-
}).getDown();
346+
if (vimState.currentMode === Mode.VisualBlock) {
347+
if (position.line < vimState.document.lineCount - 1) {
348+
return adjustForDesiredColumn({
349+
position,
350+
desiredColumn: vimState.desiredColumn,
351+
multicursorIndex: this.multicursorIndex,
352+
}).getDown();
353+
}
354+
return position;
336355
}
337-
return position;
356+
357+
// Use 'foldedLine' so VS Code moves by logical lines while skipping folded regions.
358+
// On VS Code versions without this unit, this degrades to standard line movement.
359+
const moveDown = new MoveDownByFoldedLine(this.multicursorIndex ?? 0);
360+
return moveDown.execAction(position, vimState);
338361
}
339362

340363
public override async execActionForOperator(
@@ -370,14 +393,21 @@ export class MoveUp extends BaseMovement {
370393
return moveUpFoldFix.execAction(position, vimState);
371394
}
372395

373-
if (position.line > 0) {
374-
return adjustForDesiredColumn({
375-
position,
376-
desiredColumn: vimState.desiredColumn,
377-
multicursorIndex: this.multicursorIndex,
378-
}).getUp();
396+
if (vimState.currentMode === Mode.VisualBlock) {
397+
if (position.line > 0) {
398+
return adjustForDesiredColumn({
399+
position,
400+
desiredColumn: vimState.desiredColumn,
401+
multicursorIndex: this.multicursorIndex,
402+
}).getUp();
403+
}
404+
return position;
379405
}
380-
return position;
406+
407+
// Use 'foldedLine' so VS Code moves by logical lines while skipping folded regions.
408+
// On VS Code versions without this unit, this degrades to standard line movement.
409+
const moveUp = new MoveUpByFoldedLine(this.multicursorIndex ?? 0);
410+
return moveUp.execAction(position, vimState);
381411
}
382412

383413
public override async execActionForOperator(
@@ -421,6 +451,22 @@ class MoveUpFoldFix extends MoveByScreenLineMaintainDesiredColumn {
421451
}
422452
}
423453

454+
class MoveUpByFoldedLine extends MoveByScreenLineMaintainDesiredColumn {
455+
keys = [];
456+
movementType: CursorMovePosition = 'up';
457+
override by: CursorMoveByUnit = 'foldedLine';
458+
override value = 1;
459+
460+
constructor(multicursorIndex: number) {
461+
super();
462+
this.multicursorIndex = multicursorIndex;
463+
}
464+
465+
public override execAction(position: Position, vimState: VimState): Promise<Position> {
466+
return super.execAction(position, vimState) as unknown as Promise<Position>;
467+
}
468+
}
469+
424470
@RegisterAction
425471
class CommandNextSearchMatch extends BaseMovement {
426472
keys = ['n'];

src/textEditor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,4 +302,4 @@ export type CursorMovePosition =
302302
/**
303303
* Units for Cursor move 'by' argument
304304
*/
305-
export type CursorMoveByUnit = 'line' | 'wrappedLine' | 'character' | 'halfLine';
305+
export type CursorMoveByUnit = 'line' | 'wrappedLine' | 'character' | 'halfLine' | 'foldedLine';

0 commit comments

Comments
 (0)