Skip to content

Commit feab94a

Browse files
Brikaaalexdima
andauthored
Add keyboard shortcuts for scrolling horizontally (microsoft#162992)
* Initial horizontal scroll * Use columns as unit in horizontal scrolling shortcuts * Horizontal scroll value 2, remove shortcuts * Unify Horizontal, Vertical scroll Directions and Units, determine the method Co-authored-by: Alexandru Dima <[email protected]>
1 parent 28db47f commit feab94a

File tree

2 files changed

+141
-31
lines changed

2 files changed

+141
-31
lines changed

src/vs/editor/browser/coreCommands.ts

Lines changed: 136 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,9 @@ export namespace EditorScroll_ {
121121
*/
122122
export const RawDirection = {
123123
Up: 'up',
124+
Right: 'right',
124125
Down: 'down',
126+
Left: 'left'
125127
};
126128

127129
/**
@@ -132,7 +134,8 @@ export namespace EditorScroll_ {
132134
WrappedLine: 'wrappedLine',
133135
Page: 'page',
134136
HalfPage: 'halfPage',
135-
Editor: 'editor'
137+
Editor: 'editor',
138+
Column: 'column'
136139
};
137140

138141
/**
@@ -152,9 +155,15 @@ export namespace EditorScroll_ {
152155
case RawDirection.Up:
153156
direction = Direction.Up;
154157
break;
158+
case RawDirection.Right:
159+
direction = Direction.Right;
160+
break;
155161
case RawDirection.Down:
156162
direction = Direction.Down;
157163
break;
164+
case RawDirection.Left:
165+
direction = Direction.Left;
166+
break;
158167
default:
159168
// Illegal arguments
160169
return null;
@@ -177,6 +186,9 @@ export namespace EditorScroll_ {
177186
case RawUnit.Editor:
178187
unit = Unit.Editor;
179188
break;
189+
case RawUnit.Column:
190+
unit = Unit.Column;
191+
break;
180192
default:
181193
unit = Unit.WrappedLine;
182194
}
@@ -201,17 +213,21 @@ export namespace EditorScroll_ {
201213
select: boolean;
202214
}
203215

216+
204217
export const enum Direction {
205218
Up = 1,
206-
Down = 2
219+
Right = 2,
220+
Down = 3,
221+
Left = 4
207222
}
208223

209224
export const enum Unit {
210225
Line = 1,
211226
WrappedLine = 2,
212227
Page = 3,
213228
HalfPage = 4,
214-
Editor = 5
229+
Editor = 5,
230+
Column = 6
215231
}
216232
}
217233

@@ -1294,16 +1310,43 @@ export namespace CoreNavigationCommands {
12941310
});
12951311
}
12961312

1313+
determineScrollMethod(args: EditorScroll_.ParsedArguments) {
1314+
const horizontalUnits = [EditorScroll_.Unit.Column];
1315+
const verticalUnits = [
1316+
EditorScroll_.Unit.Line,
1317+
EditorScroll_.Unit.WrappedLine,
1318+
EditorScroll_.Unit.Page,
1319+
EditorScroll_.Unit.HalfPage,
1320+
EditorScroll_.Unit.Editor,
1321+
EditorScroll_.Unit.Column
1322+
];
1323+
const horizontalDirections = [EditorScroll_.Direction.Left, EditorScroll_.Direction.Right];
1324+
const verticalDirections = [EditorScroll_.Direction.Up, EditorScroll_.Direction.Down];
1325+
1326+
if (horizontalUnits.includes(args.unit) && horizontalDirections.includes(args.direction)) {
1327+
return this._runHorizontalEditorScroll.bind(this);
1328+
}
1329+
if (verticalUnits.includes(args.unit) && verticalDirections.includes(args.direction)) {
1330+
return this._runVerticalEditorScroll.bind(this);
1331+
}
1332+
return null;
1333+
}
1334+
12971335
public runCoreEditorCommand(viewModel: IViewModel, args: Partial<EditorScrollCommandOptions>): void {
12981336
const parsed = EditorScroll_.parse(args);
12991337
if (!parsed) {
13001338
// illegal arguments
13011339
return;
13021340
}
1303-
this._runEditorScroll(viewModel, args.source, parsed);
1341+
const runEditorScroll = this.determineScrollMethod(parsed);
1342+
if (!runEditorScroll) {
1343+
// Incompatible unit and direction
1344+
return;
1345+
}
1346+
runEditorScroll(viewModel, args.source, parsed);
13041347
}
13051348

1306-
_runEditorScroll(viewModel: IViewModel, source: string | null | undefined, args: EditorScroll_.ParsedArguments): void {
1349+
_runVerticalEditorScroll(viewModel: IViewModel, source: string | null | undefined, args: EditorScroll_.ParsedArguments): void {
13071350

13081351
const desiredScrollTop = this._computeDesiredScrollTop(viewModel, args);
13091352

@@ -1361,6 +1404,16 @@ export namespace CoreNavigationCommands {
13611404
const deltaLines = (args.direction === EditorScroll_.Direction.Up ? -1 : 1) * noOfLines;
13621405
return viewModel.viewLayout.getCurrentScrollTop() + deltaLines * viewModel.cursorConfig.lineHeight;
13631406
}
1407+
1408+
_runHorizontalEditorScroll(viewModel: IViewModel, source: string | null | undefined, args: EditorScroll_.ParsedArguments): void {
1409+
const desiredScrollLeft = this._computeDesiredScrollLeft(viewModel, args);
1410+
viewModel.viewLayout.setScrollPosition({ scrollLeft: desiredScrollLeft }, ScrollType.Smooth);
1411+
}
1412+
1413+
_computeDesiredScrollLeft(viewModel: IViewModel, args: EditorScroll_.ParsedArguments) {
1414+
const deltaColumns = (args.direction === EditorScroll_.Direction.Left ? -1 : 1) * args.value;
1415+
return viewModel.viewLayout.getCurrentScrollLeft() + deltaColumns * viewModel.cursorConfig.typicalHalfwidthCharacterWidth;
1416+
}
13641417
}
13651418

13661419
export const EditorScroll: EditorScrollImpl = registerEditorCommand(new EditorScrollImpl());
@@ -1380,12 +1433,13 @@ export namespace CoreNavigationCommands {
13801433
}
13811434

13821435
runCoreEditorCommand(viewModel: IViewModel, args: Partial<BaseCommandOptions>): void {
1383-
EditorScroll._runEditorScroll(viewModel, args.source, {
1384-
direction: EditorScroll_.Direction.Up,
1385-
unit: EditorScroll_.Unit.WrappedLine,
1436+
EditorScroll.runCoreEditorCommand(viewModel, {
1437+
to: EditorScroll_.RawDirection.Up,
1438+
by: EditorScroll_.RawUnit.WrappedLine,
13861439
value: 1,
13871440
revealCursor: false,
1388-
select: false
1441+
select: false,
1442+
source: args.source
13891443
});
13901444
}
13911445
});
@@ -1406,12 +1460,13 @@ export namespace CoreNavigationCommands {
14061460
}
14071461

14081462
runCoreEditorCommand(viewModel: IViewModel, args: Partial<BaseCommandOptions>): void {
1409-
EditorScroll._runEditorScroll(viewModel, args.source, {
1410-
direction: EditorScroll_.Direction.Up,
1411-
unit: EditorScroll_.Unit.Page,
1463+
EditorScroll.runCoreEditorCommand(viewModel, {
1464+
to: EditorScroll_.RawDirection.Up,
1465+
by: EditorScroll_.RawUnit.Page,
14121466
value: 1,
14131467
revealCursor: false,
1414-
select: false
1468+
select: false,
1469+
source: args.source
14151470
});
14161471
}
14171472
});
@@ -1429,12 +1484,13 @@ export namespace CoreNavigationCommands {
14291484
}
14301485

14311486
runCoreEditorCommand(viewModel: IViewModel, args: Partial<BaseCommandOptions>): void {
1432-
EditorScroll._runEditorScroll(viewModel, args.source, {
1433-
direction: EditorScroll_.Direction.Up,
1434-
unit: EditorScroll_.Unit.Editor,
1487+
EditorScroll.runCoreEditorCommand(viewModel, {
1488+
to: EditorScroll_.RawDirection.Up,
1489+
by: EditorScroll_.RawUnit.Editor,
14351490
value: 1,
14361491
revealCursor: false,
1437-
select: false
1492+
select: false,
1493+
source: args.source
14381494
});
14391495
}
14401496
});
@@ -1454,12 +1510,13 @@ export namespace CoreNavigationCommands {
14541510
}
14551511

14561512
runCoreEditorCommand(viewModel: IViewModel, args: Partial<BaseCommandOptions>): void {
1457-
EditorScroll._runEditorScroll(viewModel, args.source, {
1458-
direction: EditorScroll_.Direction.Down,
1459-
unit: EditorScroll_.Unit.WrappedLine,
1513+
EditorScroll.runCoreEditorCommand(viewModel, {
1514+
to: EditorScroll_.RawDirection.Down,
1515+
by: EditorScroll_.RawUnit.WrappedLine,
14601516
value: 1,
14611517
revealCursor: false,
1462-
select: false
1518+
select: false,
1519+
source: args.source
14631520
});
14641521
}
14651522
});
@@ -1480,12 +1537,13 @@ export namespace CoreNavigationCommands {
14801537
}
14811538

14821539
runCoreEditorCommand(viewModel: IViewModel, args: Partial<BaseCommandOptions>): void {
1483-
EditorScroll._runEditorScroll(viewModel, args.source, {
1484-
direction: EditorScroll_.Direction.Down,
1485-
unit: EditorScroll_.Unit.Page,
1540+
EditorScroll.runCoreEditorCommand(viewModel, {
1541+
to: EditorScroll_.RawDirection.Down,
1542+
by: EditorScroll_.RawUnit.Page,
14861543
value: 1,
14871544
revealCursor: false,
1488-
select: false
1545+
select: false,
1546+
source: args.source
14891547
});
14901548
}
14911549
});
@@ -1503,12 +1561,61 @@ export namespace CoreNavigationCommands {
15031561
}
15041562

15051563
runCoreEditorCommand(viewModel: IViewModel, args: Partial<BaseCommandOptions>): void {
1506-
EditorScroll._runEditorScroll(viewModel, args.source, {
1507-
direction: EditorScroll_.Direction.Down,
1508-
unit: EditorScroll_.Unit.Editor,
1564+
EditorScroll.runCoreEditorCommand(viewModel, {
1565+
to: EditorScroll_.RawDirection.Down,
1566+
by: EditorScroll_.RawUnit.Editor,
15091567
value: 1,
15101568
revealCursor: false,
1511-
select: false
1569+
select: false,
1570+
source: args.source
1571+
});
1572+
}
1573+
});
1574+
1575+
export const ScrollLeft: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new class extends CoreEditorCommand<BaseCommandOptions> {
1576+
constructor() {
1577+
super({
1578+
id: 'scrollLeft',
1579+
precondition: undefined,
1580+
kbOpts: {
1581+
weight: CORE_WEIGHT,
1582+
kbExpr: EditorContextKeys.textInputFocus,
1583+
}
1584+
});
1585+
}
1586+
1587+
runCoreEditorCommand(viewModel: IViewModel, args: Partial<BaseCommandOptions>): void {
1588+
EditorScroll.runCoreEditorCommand(viewModel, {
1589+
to: EditorScroll_.RawDirection.Left,
1590+
by: EditorScroll_.RawUnit.Column,
1591+
value: 2,
1592+
revealCursor: false,
1593+
select: false,
1594+
source: args.source
1595+
});
1596+
}
1597+
});
1598+
1599+
export const ScrollRight: CoreEditorCommand<BaseCommandOptions> = registerEditorCommand(new class extends CoreEditorCommand<BaseCommandOptions> {
1600+
constructor() {
1601+
super({
1602+
id: 'scrollRight',
1603+
precondition: undefined,
1604+
kbOpts: {
1605+
weight: CORE_WEIGHT,
1606+
kbExpr: EditorContextKeys.textInputFocus,
1607+
}
1608+
});
1609+
}
1610+
1611+
runCoreEditorCommand(viewModel: IViewModel, args: Partial<BaseCommandOptions>): void {
1612+
EditorScroll.runCoreEditorCommand(viewModel, {
1613+
to: EditorScroll_.RawDirection.Right,
1614+
by: EditorScroll_.RawUnit.Column,
1615+
value: 2,
1616+
revealCursor: false,
1617+
select: false,
1618+
source: args.source
15121619
});
15131620
}
15141621
});

src/vs/editor/common/cursorCommon.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ export class CursorConfiguration {
6666
public readonly stickyTabStops: boolean;
6767
public readonly pageSize: number;
6868
public readonly lineHeight: number;
69+
public readonly typicalHalfwidthCharacterWidth: number;
6970
public readonly useTabStops: boolean;
7071
public readonly wordSeparators: string;
7172
public readonly emptySelectionClipboard: boolean;
@@ -98,7 +99,7 @@ export class CursorConfiguration {
9899
|| e.hasChanged(EditorOption.autoClosingOvertype)
99100
|| e.hasChanged(EditorOption.autoSurround)
100101
|| e.hasChanged(EditorOption.useTabStops)
101-
|| e.hasChanged(EditorOption.lineHeight)
102+
|| e.hasChanged(EditorOption.fontInfo)
102103
|| e.hasChanged(EditorOption.readOnly)
103104
);
104105
}
@@ -113,13 +114,15 @@ export class CursorConfiguration {
113114

114115
const options = configuration.options;
115116
const layoutInfo = options.get(EditorOption.layoutInfo);
117+
const fontInfo = options.get(EditorOption.fontInfo);
116118

117119
this.readOnly = options.get(EditorOption.readOnly);
118120
this.tabSize = modelOptions.tabSize;
119121
this.indentSize = modelOptions.indentSize;
120122
this.insertSpaces = modelOptions.insertSpaces;
121123
this.stickyTabStops = options.get(EditorOption.stickyTabStops);
122-
this.lineHeight = options.get(EditorOption.lineHeight);
124+
this.lineHeight = fontInfo.lineHeight;
125+
this.typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth;
123126
this.pageSize = Math.max(1, Math.floor(layoutInfo.height / this.lineHeight) - 2);
124127
this.useTabStops = options.get(EditorOption.useTabStops);
125128
this.wordSeparators = options.get(EditorOption.wordSeparators);

0 commit comments

Comments
 (0)