Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/browser/view/viewController.ts
3294 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { IKeyboardEvent } from '../../../base/browser/keyboardEvent.js';
7
import { CoreNavigationCommands, NavigationCommandRevealType } from '../coreCommands.js';
8
import { IEditorMouseEvent, IPartialEditorMouseEvent } from '../editorBrowser.js';
9
import { ViewUserInputEvents } from './viewUserInputEvents.js';
10
import { Position } from '../../common/core/position.js';
11
import { Selection } from '../../common/core/selection.js';
12
import { IEditorConfiguration } from '../../common/config/editorConfiguration.js';
13
import { IViewModel } from '../../common/viewModel.js';
14
import { IMouseWheelEvent } from '../../../base/browser/mouseEvent.js';
15
import { EditorOption } from '../../common/config/editorOptions.js';
16
import * as platform from '../../../base/common/platform.js';
17
18
export interface IMouseDispatchData {
19
position: Position;
20
/**
21
* Desired mouse column (e.g. when position.column gets clamped to text length -- clicking after text on a line).
22
*/
23
mouseColumn: number;
24
revealType: NavigationCommandRevealType;
25
startedOnLineNumbers: boolean;
26
27
inSelectionMode: boolean;
28
mouseDownCount: number;
29
altKey: boolean;
30
ctrlKey: boolean;
31
metaKey: boolean;
32
shiftKey: boolean;
33
34
leftButton: boolean;
35
middleButton: boolean;
36
onInjectedText: boolean;
37
}
38
39
export interface ICommandDelegate {
40
paste(text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null): void;
41
type(text: string): void;
42
compositionType(text: string, replacePrevCharCnt: number, replaceNextCharCnt: number, positionDelta: number): void;
43
startComposition(): void;
44
endComposition(): void;
45
cut(): void;
46
}
47
48
export class ViewController {
49
50
private readonly configuration: IEditorConfiguration;
51
private readonly viewModel: IViewModel;
52
private readonly userInputEvents: ViewUserInputEvents;
53
private readonly commandDelegate: ICommandDelegate;
54
55
constructor(
56
configuration: IEditorConfiguration,
57
viewModel: IViewModel,
58
userInputEvents: ViewUserInputEvents,
59
commandDelegate: ICommandDelegate
60
) {
61
this.configuration = configuration;
62
this.viewModel = viewModel;
63
this.userInputEvents = userInputEvents;
64
this.commandDelegate = commandDelegate;
65
}
66
67
public paste(text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null): void {
68
this.commandDelegate.paste(text, pasteOnNewLine, multicursorText, mode);
69
}
70
71
public type(text: string): void {
72
this.commandDelegate.type(text);
73
}
74
75
public compositionType(text: string, replacePrevCharCnt: number, replaceNextCharCnt: number, positionDelta: number): void {
76
this.commandDelegate.compositionType(text, replacePrevCharCnt, replaceNextCharCnt, positionDelta);
77
}
78
79
public compositionStart(): void {
80
this.commandDelegate.startComposition();
81
}
82
83
public compositionEnd(): void {
84
this.commandDelegate.endComposition();
85
}
86
87
public cut(): void {
88
this.commandDelegate.cut();
89
}
90
91
public setSelection(modelSelection: Selection): void {
92
CoreNavigationCommands.SetSelection.runCoreEditorCommand(this.viewModel, {
93
source: 'keyboard',
94
selection: modelSelection
95
});
96
}
97
98
private _validateViewColumn(viewPosition: Position): Position {
99
const minColumn = this.viewModel.getLineMinColumn(viewPosition.lineNumber);
100
if (viewPosition.column < minColumn) {
101
return new Position(viewPosition.lineNumber, minColumn);
102
}
103
return viewPosition;
104
}
105
106
private _hasMulticursorModifier(data: IMouseDispatchData): boolean {
107
switch (this.configuration.options.get(EditorOption.multiCursorModifier)) {
108
case 'altKey':
109
return data.altKey;
110
case 'ctrlKey':
111
return data.ctrlKey;
112
case 'metaKey':
113
return data.metaKey;
114
default:
115
return false;
116
}
117
}
118
119
private _hasNonMulticursorModifier(data: IMouseDispatchData): boolean {
120
switch (this.configuration.options.get(EditorOption.multiCursorModifier)) {
121
case 'altKey':
122
return data.ctrlKey || data.metaKey;
123
case 'ctrlKey':
124
return data.altKey || data.metaKey;
125
case 'metaKey':
126
return data.ctrlKey || data.altKey;
127
default:
128
return false;
129
}
130
}
131
132
public dispatchMouse(data: IMouseDispatchData): void {
133
const options = this.configuration.options;
134
const selectionClipboardIsOn = (platform.isLinux && options.get(EditorOption.selectionClipboard));
135
const columnSelection = options.get(EditorOption.columnSelection);
136
const scrollOnMiddleClick = options.get(EditorOption.scrollOnMiddleClick);
137
if (data.middleButton && !selectionClipboardIsOn) {
138
if (scrollOnMiddleClick) {
139
// nothing to do here, handled in the contribution
140
} else {
141
this._columnSelect(data.position, data.mouseColumn, data.inSelectionMode);
142
}
143
} else if (data.startedOnLineNumbers) {
144
// If the dragging started on the gutter, then have operations work on the entire line
145
if (this._hasMulticursorModifier(data)) {
146
if (data.inSelectionMode) {
147
this._lastCursorLineSelect(data.position, data.revealType);
148
} else {
149
this._createCursor(data.position, true);
150
}
151
} else {
152
if (data.inSelectionMode) {
153
this._lineSelectDrag(data.position, data.revealType);
154
} else {
155
this._lineSelect(data.position, data.revealType);
156
}
157
}
158
} else if (data.mouseDownCount >= 4) {
159
this._selectAll();
160
} else if (data.mouseDownCount === 3) {
161
if (this._hasMulticursorModifier(data)) {
162
if (data.inSelectionMode) {
163
this._lastCursorLineSelectDrag(data.position, data.revealType);
164
} else {
165
this._lastCursorLineSelect(data.position, data.revealType);
166
}
167
} else {
168
if (data.inSelectionMode) {
169
this._lineSelectDrag(data.position, data.revealType);
170
} else {
171
this._lineSelect(data.position, data.revealType);
172
}
173
}
174
} else if (data.mouseDownCount === 2) {
175
if (!data.onInjectedText) {
176
if (this._hasMulticursorModifier(data)) {
177
this._lastCursorWordSelect(data.position, data.revealType);
178
} else {
179
if (data.inSelectionMode) {
180
this._wordSelectDrag(data.position, data.revealType);
181
} else {
182
this._wordSelect(data.position, data.revealType);
183
}
184
}
185
}
186
} else {
187
if (this._hasMulticursorModifier(data)) {
188
if (!this._hasNonMulticursorModifier(data)) {
189
if (data.shiftKey) {
190
this._columnSelect(data.position, data.mouseColumn, true);
191
} else {
192
// Do multi-cursor operations only when purely alt is pressed
193
if (data.inSelectionMode) {
194
this._lastCursorMoveToSelect(data.position, data.revealType);
195
} else {
196
this._createCursor(data.position, false);
197
}
198
}
199
}
200
} else {
201
if (data.inSelectionMode) {
202
if (data.altKey) {
203
this._columnSelect(data.position, data.mouseColumn, true);
204
} else {
205
if (columnSelection) {
206
this._columnSelect(data.position, data.mouseColumn, true);
207
} else {
208
this._moveToSelect(data.position, data.revealType);
209
}
210
}
211
} else {
212
this.moveTo(data.position, data.revealType);
213
}
214
}
215
}
216
}
217
218
private _usualArgs(viewPosition: Position, revealType: NavigationCommandRevealType): CoreNavigationCommands.MoveCommandOptions {
219
viewPosition = this._validateViewColumn(viewPosition);
220
return {
221
source: 'mouse',
222
position: this._convertViewToModelPosition(viewPosition),
223
viewPosition,
224
revealType
225
};
226
}
227
228
public moveTo(viewPosition: Position, revealType: NavigationCommandRevealType): void {
229
CoreNavigationCommands.MoveTo.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType));
230
}
231
232
private _moveToSelect(viewPosition: Position, revealType: NavigationCommandRevealType): void {
233
CoreNavigationCommands.MoveToSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType));
234
}
235
236
private _columnSelect(viewPosition: Position, mouseColumn: number, doColumnSelect: boolean): void {
237
viewPosition = this._validateViewColumn(viewPosition);
238
CoreNavigationCommands.ColumnSelect.runCoreEditorCommand(this.viewModel, {
239
source: 'mouse',
240
position: this._convertViewToModelPosition(viewPosition),
241
viewPosition: viewPosition,
242
mouseColumn: mouseColumn,
243
doColumnSelect: doColumnSelect
244
});
245
}
246
247
private _createCursor(viewPosition: Position, wholeLine: boolean): void {
248
viewPosition = this._validateViewColumn(viewPosition);
249
CoreNavigationCommands.CreateCursor.runCoreEditorCommand(this.viewModel, {
250
source: 'mouse',
251
position: this._convertViewToModelPosition(viewPosition),
252
viewPosition: viewPosition,
253
wholeLine: wholeLine
254
});
255
}
256
257
private _lastCursorMoveToSelect(viewPosition: Position, revealType: NavigationCommandRevealType): void {
258
CoreNavigationCommands.LastCursorMoveToSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType));
259
}
260
261
private _wordSelect(viewPosition: Position, revealType: NavigationCommandRevealType): void {
262
CoreNavigationCommands.WordSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType));
263
}
264
265
private _wordSelectDrag(viewPosition: Position, revealType: NavigationCommandRevealType): void {
266
CoreNavigationCommands.WordSelectDrag.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType));
267
}
268
269
private _lastCursorWordSelect(viewPosition: Position, revealType: NavigationCommandRevealType): void {
270
CoreNavigationCommands.LastCursorWordSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType));
271
}
272
273
private _lineSelect(viewPosition: Position, revealType: NavigationCommandRevealType): void {
274
CoreNavigationCommands.LineSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType));
275
}
276
277
private _lineSelectDrag(viewPosition: Position, revealType: NavigationCommandRevealType): void {
278
CoreNavigationCommands.LineSelectDrag.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType));
279
}
280
281
private _lastCursorLineSelect(viewPosition: Position, revealType: NavigationCommandRevealType): void {
282
CoreNavigationCommands.LastCursorLineSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType));
283
}
284
285
private _lastCursorLineSelectDrag(viewPosition: Position, revealType: NavigationCommandRevealType): void {
286
CoreNavigationCommands.LastCursorLineSelectDrag.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType));
287
}
288
289
private _selectAll(): void {
290
CoreNavigationCommands.SelectAll.runCoreEditorCommand(this.viewModel, { source: 'mouse' });
291
}
292
293
// ----------------------
294
295
private _convertViewToModelPosition(viewPosition: Position): Position {
296
return this.viewModel.coordinatesConverter.convertViewPositionToModelPosition(viewPosition);
297
}
298
299
public emitKeyDown(e: IKeyboardEvent): void {
300
this.userInputEvents.emitKeyDown(e);
301
}
302
303
public emitKeyUp(e: IKeyboardEvent): void {
304
this.userInputEvents.emitKeyUp(e);
305
}
306
307
public emitContextMenu(e: IEditorMouseEvent): void {
308
this.userInputEvents.emitContextMenu(e);
309
}
310
311
public emitMouseMove(e: IEditorMouseEvent): void {
312
this.userInputEvents.emitMouseMove(e);
313
}
314
315
public emitMouseLeave(e: IPartialEditorMouseEvent): void {
316
this.userInputEvents.emitMouseLeave(e);
317
}
318
319
public emitMouseUp(e: IEditorMouseEvent): void {
320
this.userInputEvents.emitMouseUp(e);
321
}
322
323
public emitMouseDown(e: IEditorMouseEvent): void {
324
this.userInputEvents.emitMouseDown(e);
325
}
326
327
public emitMouseDrag(e: IEditorMouseEvent): void {
328
this.userInputEvents.emitMouseDrag(e);
329
}
330
331
public emitMouseDrop(e: IPartialEditorMouseEvent): void {
332
this.userInputEvents.emitMouseDrop(e);
333
}
334
335
public emitMouseDropCanceled(): void {
336
this.userInputEvents.emitMouseDropCanceled();
337
}
338
339
public emitMouseWheel(e: IMouseWheelEvent): void {
340
this.userInputEvents.emitMouseWheel(e);
341
}
342
}
343
344