@@ -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
307323export 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
425471class CommandNextSearchMatch extends BaseMovement {
426472 keys = [ 'n' ] ;
0 commit comments