Skip to content

Commit cb49b23

Browse files
committed
(Kind of) fix vertical motion with multiple cursors
The real fix will be to move `desiredColumn` to `Cursor`, but this is a pretty good half-measure Refs #4797, refs #4585
1 parent 6aac02c commit cb49b23

File tree

2 files changed

+87
-15
lines changed

2 files changed

+87
-15
lines changed

src/actions/motion.ts

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,19 @@ import { SmartQuoteMatcher, WhichQuotes } from './plugins/targets/smartQuotesMat
3030
import { useSmartQuotes } from './plugins/targets/targetsConfig';
3131
import { ModeDataFor } from '../mode/modeData';
3232

33+
function adjustForDesiredColumn(args: {
34+
position: Position;
35+
desiredColumn: number;
36+
multicursorIndex: number | undefined;
37+
}): Position {
38+
const { position, desiredColumn, multicursorIndex } = args;
39+
// HACK: until we put `desiredColumn` on `Cursor`, only the first cursor will respect it (except after `$`)
40+
if (multicursorIndex && multicursorIndex > 0 && desiredColumn !== Number.POSITIVE_INFINITY) {
41+
return position;
42+
}
43+
return position.with({ character: desiredColumn });
44+
}
45+
3346
/**
3447
* A movement is something like 'h', 'k', 'w', 'b', 'gg', etc.
3548
*/
@@ -284,7 +297,11 @@ class MoveDownFoldFix extends MoveByScreenLineMaintainDesiredColumn {
284297
}
285298
prev = t;
286299
}
287-
return t.with({ character: vimState.desiredColumn });
300+
return adjustForDesiredColumn({
301+
position: t,
302+
desiredColumn: vimState.desiredColumn,
303+
multicursorIndex: this.multicursorIndex,
304+
});
288305
}
289306
}
290307

@@ -313,10 +330,13 @@ class MoveDown extends BaseMovement {
313330
}
314331

315332
if (position.line < vimState.document.lineCount - 1) {
316-
return position.with({ character: vimState.desiredColumn }).getDown();
317-
} else {
318-
return position;
333+
return adjustForDesiredColumn({
334+
position,
335+
desiredColumn: vimState.desiredColumn,
336+
multicursorIndex: this.multicursorIndex,
337+
}).getDown();
319338
}
339+
return position;
320340
}
321341

322342
public override async execActionForOperator(
@@ -353,10 +373,13 @@ class MoveUp extends BaseMovement {
353373
}
354374

355375
if (position.line > 0) {
356-
return position.with({ character: vimState.desiredColumn }).getUp();
357-
} else {
358-
return position;
376+
return adjustForDesiredColumn({
377+
position,
378+
desiredColumn: vimState.desiredColumn,
379+
multicursorIndex: this.multicursorIndex,
380+
}).getUp();
359381
}
382+
return position;
360383
}
361384

362385
public override async execActionForOperator(
@@ -392,7 +415,11 @@ class MoveUpFoldFix extends MoveByScreenLineMaintainDesiredColumn {
392415
}
393416
prev = t;
394417
}
395-
return t.with({ character: vimState.desiredColumn });
418+
return adjustForDesiredColumn({
419+
position: t,
420+
desiredColumn: vimState.desiredColumn,
421+
multicursorIndex: this.multicursorIndex,
422+
});
396423
}
397424
}
398425

@@ -1201,10 +1228,13 @@ class MoveUpByScreenLineVisualBlock extends BaseMovement {
12011228
vimState: VimState,
12021229
): Promise<Position | IMovement> {
12031230
if (position.line > 0) {
1204-
return position.with({ character: vimState.desiredColumn }).getUp();
1205-
} else {
1206-
return position;
1231+
return adjustForDesiredColumn({
1232+
position,
1233+
desiredColumn: vimState.desiredColumn,
1234+
multicursorIndex: this.multicursorIndex,
1235+
}).getUp();
12071236
}
1237+
return position;
12081238
}
12091239

12101240
public override async execActionForOperator(
@@ -1230,10 +1260,13 @@ class MoveDownByScreenLineVisualBlock extends BaseMovement {
12301260
vimState: VimState,
12311261
): Promise<Position | IMovement> {
12321262
if (position.line < vimState.document.lineCount - 1) {
1233-
return position.with({ character: vimState.desiredColumn }).getDown();
1234-
} else {
1235-
return position;
1263+
return adjustForDesiredColumn({
1264+
position,
1265+
desiredColumn: vimState.desiredColumn,
1266+
multicursorIndex: this.multicursorIndex,
1267+
}).getDown();
12361268
}
1269+
return position;
12371270
}
12381271

12391272
public override async execActionForOperator(

test/multicursor.test.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as assert from 'assert';
22
import { getAndUpdateModeHandler } from '../extension';
33
import { ModeHandler } from '../src/mode/modeHandler';
44
import { assertEqualLines, setupWorkspace } from './testUtils';
5-
import { newTest } from './testSimplifier';
5+
import { newTest, newTestSkip } from './testSimplifier';
66

77
suite('Multicursor', () => {
88
let modeHandler: ModeHandler;
@@ -12,6 +12,45 @@ suite('Multicursor', () => {
1212
modeHandler = (await getAndUpdateModeHandler())!;
1313
});
1414

15+
suite('Motions', () => {
16+
for (const foldfix of [true, false]) {
17+
suite(`j and k ${foldfix ? '(foldfix)' : ''}`, () => {
18+
newTest({
19+
title: 'j',
20+
config: { foldfix },
21+
start: ['l|ine 1', 'lin|e 2', 'line 3'],
22+
keysPressed: 'j',
23+
end: ['line 1', 'l|ine 2', 'lin|e 3'],
24+
});
25+
26+
newTest({
27+
title: 'j (at bottom)',
28+
config: { foldfix },
29+
start: ['line 1', 'l|ine 2', 'lin|e 3'],
30+
keysPressed: 'j',
31+
end: ['line 1', 'line 2', 'l|in|e 3'],
32+
});
33+
34+
newTest({
35+
title: 'k',
36+
config: { foldfix },
37+
start: ['line 1', 'l|ine 2', 'lin|e 3'],
38+
keysPressed: 'k',
39+
end: ['l|ine 1', 'lin|e 2', 'line 3'],
40+
});
41+
42+
// TODO: Fix for foldfix
43+
(foldfix ? newTestSkip : newTest)({
44+
title: 'k (at top)',
45+
config: { foldfix },
46+
start: ['l|ine 1', 'lin|e 2', 'line 3'],
47+
keysPressed: 'k',
48+
end: ['l|in|e 1', 'line 2', 'line 3'],
49+
});
50+
});
51+
}
52+
});
53+
1554
test('can add multiple cursors below', async () => {
1655
await modeHandler.handleMultipleKeyEvents('i11\n22'.split(''));
1756
await modeHandler.handleMultipleKeyEvents(['<Esc>', 'g', 'g']);

0 commit comments

Comments
 (0)